[Paper Contents] [Previous] [Next] [Eclipse Home Page]

3: Using Lisp from C

The functions created by Eclipse COMPILE-FILE may be called by C programs directly, or through FUNCALL.

The examples given here assume a C file is produced by Eclipse using (COMPILE-FILE "my-file.lisp" :OUTPUT-FILE "my-file.c") and that ``my-file.lisp'' contains a function USER:MY-FUNCTION, defined as:

   (DEFUN MY-FUNCTION (A B)
     (LIST A B))

This section discusses direct calls and the use of FUNCALL, and gives a listing of ``my-file.c.'' The section ends with some notes on how C programs use such Lisp utilities as EVAL, LOAD, and the passing of clObjects such as keywords, fixnums, and so on.

3.1: Direct Calls

In Lisp, one can call MY-FUNCTION directly like this:
   (SETQ X (MY-FUNCTION Y Z))

The Eclipse-generated C function usrMyFunction() can be directly called by other C functions as follows:

   clObject usrMyFunction(clProto);
   ...
   { clObject x, y, z;
     ...
     clSetq(x, usrMyFunction(y, z, clEOA));
     ... }

This code declares the C function to return an clObject. clProto is a macro defined in ``eclipse.h'' that indicates that a variable number of clObject arguments are accepted. (Eclipse conditionally defines clProto for different compilers to correctly use prototypes, varargs/stdargs, and so forth.)

The C function called in this example takes the same arguments as the original Lisp function did, with one additional argument, clEOA, used by the function for argument parsing. (See Section 2.2.2.)

The use of the Eclipse-defined macro clSetq(x, call), rather than x = call, gives a more Lisp-like syntax to the C code, and allows cleaner linting. (See Section 2.2.1.)

This is the easiest, most idiomatic C way to call Lisp functions. Like all C function calls, the called code must be defined in C (or a compatible language), compiled, and linked before the application is run. This technique can only be used when the definition of MY-FUNCTION will not change at run time. When hand-coding C that uses direct calls, the programmer must be certain that these conditions are met, just as for any other direct C call.

Eclipse COMPILE-FILE can automatically use this direct function call technique in code it generates only when:

(In fact, the currently released compiler uses the direct approach only for ordinary system function calls.)

3.2: Funcall

In Lisp, one can indirectly ``funcall'' MY-FUNCTION through it's symbol:
   (SETQ X (FUNCALL 'MY-FUNCTION Y Z)

To do this in C, we use three functions that Eclipse makes available for direct use by C programmers: clCharpSimpleBaseString(), clIntern(), and clFuncall(). The latter two are simply direct calls to Lisp functions, as described in Section 3.1. clCharpSimpleBaseString() is not a ``Lisp function'' at all, but rather a constructor that creates a Lisp string clObject from a C char pointer. The C call looks like:

   clObject usrMY_FUNCTION, my_function_string, x, y, z; 
   clSetq(my_function_string, clCharpSimpleBaseString("MY-FUNCTION"));
   clSetq(usrMY_FUNCTION, clIntern(my_function_string, clEOA)); 
   ...
   clSetq(x, clFuncall(usrMY_FUNCTION, y, z, clEOA));

Of course, usrMY_FUNCTION can be a global or static variable that is initialized just once, and used in each funcall.

There is no need to declare usrMyFunction() in C when using this FUNCALL approach. In fact, usrMyFunction() does not even have to be defined in C. For example, it could be defined as an interpreted function at run time. It does not matter if the definition of MY-FUNCTION changes at run time; funcallers will see the new definition.

3.3: Example Of Generated Code

There are several parts to our example Eclipse-generated ``my-file.c.''

Listing of Eclipse-generated C code ``my-file.c'':

   #include <eclipse.h>

   clObject clCharpSimpleBaseString __P((clCharp)), clExtraArgs(clProto),
     clIntern(clProto), clList(clProto), clMissingArgs(clProto), clPkg(clProto);

   static clObject I_1, I_2, PKG_USER, STR_MY_FUNCTION__0, STR_USER__1, usrMY_FUNCTION;

   clObject usrMyFunction clVdecl(_ap)
   { clObject a, b;
     { clBeginParse(_ap); 
       clSetq(a, (_clVp(_ap) ? clVpop(_ap) : clMissingArgs(I_1, clEOA)));
       clSetq(b, (_clVp(_ap) ? clVpop(_ap) : clMissingArgs(I_2, clEOA))); 
     if (_clVp(_ap)) clExtraArgs(clVargs(_ap), clEOA);
     clEndParse(_ap); }
     { clObject L_1, L_0; 
       clSetq(L_0, a); 
       clSetq(L_1, b); 
     return(clList(L_0, L_1, clEOA)); } }

   void usrMyFile __P((void))
   { clDbind(clstarPACKAGEstar);
     clDbind(clstarREADTABLEstar); 
     clDbind(clstarLOAD_TRUENAMEstar); 
     clDbind(clstarLOAD_PATHNAMEstar); 
     clSetq(STR_MY_FUNCTION__0, clCharpSimpleBaseString("MY-FUNCTION")); 
     clSetq(STR_USER__1, clCharpSimpleBaseString("USER"));
     clSetq(PKG_USER, clPkg(STR_USER__1, clEOA));
     clSetq(usrMY_FUNCTION, clIntern(STR_MY_FUNCTION__0, PKG_USER, clEOA));
     clSetq(I_1, clIntFixnum(1)); 
     clSetq(I_2, clIntFixnum(2));

     clSetSymbolFunctionValue(usrMY_FUNCTION,
			      clMakeClosure(0,
					    usrMyFunction,
					    clNULL_HOOK));
     (void) usrMY_FUNCTION;
     clUnwind(4); }

The example shown is the actual code generated by the released Eclipse 1.1 compiler, presented without editing or formatting. Current compiler development is aimed at producing the following changes:

3.5: Other Lisp Utilities and Their Effect on Calling Lisp Functions

The Lisp functions EVAL and LOAD, and the &KEY named argument facility introduce other possibilities in calling Lisp functions from C code.

3.5.1: Eval

The function EVAL executes (e.g., interprets) arbitrary Lisp code, including function call expressions. The argument to EVAL is a Lisp expression; such as a number, a symbol, or a list beginning with a symbol that names an operator.

Like most Lisp implementations, Eclipse provides an EVAL function which interprets arbitrary Lisp code represented as s-expression data.7 The Eclipse implementation of this function can create arbitrary interpreted closures at run time. Interpreted and compiled code can call each other, use each other's cleanups and catch tags, and so forth.

As with FUNCALL, Eclipse makes EVAL available for direct use by C programmers as clEval(). Of course, it is necessary to give clEval() an clObject as its argument.

For example, MY-FUNCTION could also be called from C as:

   clSetq(x, clEval(clList(usrMY_FUNCTION, y, z, clEOA), 
		    clEOA));

Note the use of clList() and the symbol usrMY_FUNCTION to create the argument to clEval. Compare this with the FUNCALL version given above:

   clSetq(x, clFuncall(usrMY_FUNCTION, y, z, clEOA));

3.5.2: Load

The function clLoad() is also provided in the development library. Alas, as currently implemented by Eclipse, this function cannot be used to load compiled machine code (e.g., .o or .obj files) into a running application.

In general, the C language and its implementations do not provide any portable and easy way to load compiled machine code into a running application. Outside of Eclipse, there are ways to do this on specific platforms, and Eclipse users are free to utilize them. The Eclipse system behavior with respect to such techniques is just like that of any other C library, and Eclipse makes no special arrangements to automatically update SYMBOL-FUNCTION values based on newly loaded machine code.

3.5.3: Passing Lisp Data

The preceding examples show clObjects being passed to and returned from Lisp functions. No ``Lisp function'' accepts C data of other types such as int, enum, double, and so forth. Instead, it is necessary for the caller to create clObjects using other Lisp functions, such as clIntern(), or constructors provided in ``eclipse.h,'' such as clCharpSimpleBaseString() or clIntFixnum(). Examples in ``my-function.c'' include the use of usrMY_FUNCTION and I_1.

Named (i.e., &KEY) arguments are used just as they are in Lisp: the ``names'' are ordinary symbol arguments. Suppose MY-FUNCTION had been defined as:

   (DEFUN MY-FUNCTION (A &KEY B) (LIST A B))

In Lisp, a direct call might look like:

   (MY-FUNCTION X)
or
   (MY-FUNCTION X :B Y)

The corresponding direct C calls are:

   usrMyFunction(x, clEOA)
and
   usrMyFunction(x, keyB, y, clEOA)

Here keyB is an clObject that might have been defined similarly to usrMY_FUNCTION in ``my-function.c'':

   clObject clMakeKeyword(clProto); 
   clObject keyB, b_string; 
   ...
   clSetq(b_string, clCharpSimpleBaseString("B"));
   clSetq(keyB, clMakeKeyword(b_string, clEOA));

[Paper Contents] [Previous] [Next] [Eclipse Home Page]