Functions written in C without concern about linking with EusLisp can be loaded onto EusLisp, too. These functions are called foreign functions. Such programs are loaded by load-foreign macro which returns an instance of foreign-module. External symbol definitions in the object file is registered in the module object. Defforeign is used to make entries to C functions to be called from EusLisp. Defun-c-callable defines lisp functions callable from C. C-callable functions have special code piece called pod-code for converting parameters and transferring control to the corresponding EusLisp function. Pod-address returns the address of this code piece which should be informed to C functions.
Here is an example of C program and its interface functions to EusLisp.
/* C program named cfunc.c*/ static int (*g)(); /* variable to store Lisp function entry */ double sync(x) double x; { extern double sin(); return(sin(x)/x);} char *upperstring(s) char *s; { char *ss=s; while (*s) { if (islower(*s)) *s=toupper(*s); s++;} return(ss);} int setlfunc(f) /* remember the argument in g just to see */ int (*f)(); /* how Lisp function can be called from C */ { g=f;} int callfunc(x) /* apply the Lisp function saved in g to the arg.*/ int x; { return((*g)(x));} ;;;; Example program for EusLisp's foreign language interface ;;;; make foreign-module (setq m (load-foreign "cfunc.o")) ;; define foreign functions so that they can be callable from lisp (defforeign sync m "sync" (:float) :float) (defforeign toupper m "upperstring" (:string) :string) (defforeign setlfunc m "setlfunc" (:integer) :integer) (defforeign callfunc m "callfunc" (:integer) :integer) ;; call them (sync 1.0) --> 0.841471 (print (toupper "abc123")) --> "ABC123" ;; define a test function which is callable from C. (defun-c-callable TEST ((a :integer)) :integer (format t "TEST is called, arg=~s~%" a) (* a a)) ;; return the square of the arg ;; call it from C ;;setlfunc remembers the entry address of Lisp TEST function. (setlfunc (pod-address (intern "TEST"))) (callfunc 12) --> TEST is called, arg=12 144
Data representations in EusLisp are converted to those of C in the following manners: EusLisp's 30-bits integer (including character) is sign-extended and passed to a C function via stack. 30-bit float is extended to double and passed via stack. As for string, integer-vector and float-vector, only the address of the first element is passed on the stack, and the entire array remains uncopied. The string can either be a normal string or a foreign-string. A string may contain null codes, though it is guaranteed that the string also has a null code at the end. EusLisp does not know how to pass arrays of more than one dimension. Every array of more than one dimension has correspoiding one dimensional vector that holds the entire elements linearly. This vector is obtained by the array-entity macro. Also, note that a two-dimensional matrix should be transposed if it is sent to the FORTRAN subroutines, since rows and columns are ordered oppositely in FORTRAN.
Since EusLisp's representation of floating-point numbers is always single precision, conversion is required when you pass a vector of double precision floating point numbers. For this purpose, the conversion functions, double2float and float2double are provided by clib/double.c. For an instance, if you have a 3x3 float-matrix and want to pass it to a C function named cfun as a matrix of double, use the following forms.
(setq mat (make-matrix 3 3)) (cfun (float2double (array-entity mat)))
Struct in C can be defined by the defcstruct macro. Defcstruct accepts struct-name followed by field definition forms.
(defcstruct <struct-name> {(<field> <type> [*] [size])}*)For example, following struct definition is represented by the next defcstruct.
/* C definition */ struct example { char a[2]; short b; long *c; float *d[2];}; /* equivalent EusLisp definition */ (defcstruct example (a :char 2) (b :short) (c :long *) (d :float * 2))
load-foreign objfile &key symbol-input symbol-output (symbol-file objfile) ld-option) [macro]
As shown below, the intermediate symbol file can be removed by unix:unlink. However, if you are loading more than one foreign modules both of which refer to the same library, and if you want to avoid loading the library duplicatedly, you have to use symbol-input argument. Suppose you have loaded all the functions in "linpack.a" in the above example and you are going to load another file "linapp.o" that calls functions in "linpack.a". The following call of load-foreign should be issued before you unlink "euslinpack". (load-foreign "linapp.o" :symbol-input "euslinpack") See *eusdir*/llib/linpack.l for more complete examples of load-foreign and defforeign.
(setq linpack-module (load-foreign "/usr/local/eus/clib/linpackref.o" :ld-option "-L/usr/local/lib -llinpack -lF77 -lm -lc" :symbol-output "euslinpack" :symbol-file "euslinpack" )) (unix:unlink "euslinpack")
defforeign funcname module cname paramspec resulttype [macro]
Fortran users should note that every argument to a Fortran function or a subroutine is passed by call-by-reference. Therefore, even a simple integer or float type argument must be put in a integer-vector or a float-vector before it is passed to Fortran.
defun-c-callable funcname paramspec resulttype . body [macro]
pod-address funcname [function]
array-entity array-of-more-than-one-dimension [macro]
float2double float-vector [doublevector] [function]
double2float doublevector [float-vector] [function]
k-okada 2013-05-21