COMPILE-FILE
may be called by C
programs directly, or through FUNCALL
.
COMPILE-FILE
.
COMPILE-FILE
from Lisp source code or can be written by
hand. Since Eclipse provides all Common Lisp functions through its
COMPILE-FILE
generated library, any Common Lisp function
can be called from C using either approach.5
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
clObject
s 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:
DEFUN
or DEFGENERIC
within the current compilation environment, or is
otherwise declared to exist.
(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.''
usrMyFunction()
itself begins with some argument
parsing code. clVdecl()
, clBeginParse()
, clEndParse()
, _clVp()
,
clVpop()
, and clVargs()
are all macros dealing with variable argument
parsing. clMissingArgs()
and clExtraArgs()
are ordinary Lisp
functions. The returned value is a direct call to the Lisp function
clList()
.
usrMyFile()
is the Eclipse-generated
initialization function for the file. (See Section 2.4.2.) In keeping with
ANSI requirements for LOAD
, it temporarily binds
*PACKAGE*
, *READTABLE*
,
*LOAD-TRUENAME*
and *LOAD-PATHNAME*
. Within
this context, it first creates the symbols and fixnums needed, and
then sets the SYMBOL-FUNCTION
for the symbol
MY-FUNCTION
to a closure that it creates. #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:
L_0
and L_1
are introduced in
usrMyFunction()
to guarantee correct left-to-right
evaluation of the arguments to clList()
, because C does
not define the order of evaluation of arguments to functions. In this
case, they are not necessary and could have been eliminated by the
compiler.6
usrMyFile()
initialization
function. For example, STR_MY_FUNCTION_0
,
STR_USER__1
, I_1
, and I_2
and
the closure clObject
could all be defined in this way.
EVAL
and LOAD
, and the
&KEY
named argument facility introduce other
possibilities in calling Lisp functions from C code.
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));
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 clObject
s 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 clObject
s 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));