[mercury-users] need help: Mercury+C

Tyson Dowd trd at cs.mu.OZ.AU
Wed Sep 2 10:53:02 AEST 1998


On 01-Sep-1998, tcklnbrg <at at ingenuity-sw.com> wrote:
> I have looked over the examples and docs
> for calling C-code from Mercury and I can't
> figure out hot to make it work for me.
> 
> I have created a Flex grammar which yields
> a single file implementing a lexer (lets call it "lexer.c").  
> 
> The code in this file is mechanically generated by Flex and
> is very ugly (typedef'd and #define'd to abstraction).  
> 
> There are many functions in lexer.c,
> but there is only one I am interested in calling
> from Mercury code.  It has the signature:
> 
> char* tokenize(char *);
> 
> tokenize takes a filename as its only argument, and
> returns a single malloc'ed string of tokens.
> 
> The lexer.c file contains one global var, "char * tokenStr",
> which many of the functions in lexer.c use.  
> 
> The "tokenize(...)" prototype and tokenStr var are both
> declared and defined in lexer.c. No header file is created.
> 
> Given the preprocessor spaghetti threaded through lexer.c, 
> I haven't been successful in using Mercury's 
> pragma's, c_code, c_header_code to directly create a .m file
> from the lexer.c.  
> 
> It may be possible, but its going to be
> ugly and complicated.  And every time I make a slight change
> in the grammar file, I will lose my Mercury modifications.
> 
> lexer.c must be linked with one library (libfl.a) to form
> an executable.
> 
> What is the *easiest* way to make the lexer.cc "tokenize" function
> available to Mercury code and make sure that the tokenize function
> has access to the global var, token?
> 
> Can I create an ordinary C library from lexer.c and libfl.a to be
> used by Mercury---then how do I declare the tokenize function for
> use in Mercury code since there is no corresponding .m file?
> Since there is no .h file for tokenize, how do I make the function
> signature known to Mercury? (extern...??)

You will need to use `Mmake' to solve this problem.

First tell it that you have a object file you want to link with:

MLOBJS=lexer.o

and you want to link with the flex library.

MLLIBS=-lfl

So now `mmake' should link with lexer.o and the library, and should
build lexer.o from the .c file (and even from the .l file if necessary).

You can make the function signature available to Mercury in a few ways.

:- pragma c_header_code("
extern char* tokenize(char *);
").

would be enough (particularly if you are sure it will not change).
If you want a bit of extra security, try creating "lexer.h" by
hand which contains
	extern char* tokenize(char *);
and make sure it is #included in lexer.c (which will probably mean
#including it in lexer.l).  Then your Mercury file would contain

:- pragma c_header_code("
#include ""lexer.h""
").

> 
> The tokenize(..) c code in lexer.c does open and "read-only" a file.  
> Does this mean that the Mercury function that corresponds to c
> tokenize(..)
> in file lexer.c, must be declared with the 2 extra io__state args?  

Maybe.  You will need to have some sort of state arguments to represent
the state of the lexer, so io__state is a good choice to start with.

:- pragma c_code(get_next_token(Token::out, IO0::di, IO::uo),
		will_not_call_mercury, "
	Token = tokenize(NULL);
	update_io(IO0, IO);
").

(I'm assuming here that tokenize works by opening the file if given
a file name, and returning the next token of the currently open file
if given NULL.  If it doesn't you may have to do things a little bit 
differently).

get_next_token needs to be in the same .m files as the c_header_code
above, because it uses the "tokenize" function.

-- 
Those who would give up essential liberty to purchase a little temporary
safety deserve neither liberty nor safety.     - Benjamin Franklin

Tyson Dowd   <tyson at tyse.net>   http://tyse.net



More information about the users mailing list