3.2. Procedure Call Conventions

ECL employs standard C calling conventions to achieve efficiency and interoperability with other languages. Each Lisp function is implemented as a C function which takes as many argument as the Lisp original plus one additional integer argument which holds the number of actual arguments. The function sets NValues to the number of Lisp values produced, it returns the first one and the remaining ones are kept in a global (per thread) array (VALUES).

To show the argument/value passing mechanism, here we list the actual code for the Common-Lisp function cons.

   cl_cons(int narg, object car, object cdr)
   {       object x;
   x = alloc_object(t_cons);
   CAR(x) = car;
   CDR(x) = cdr;
   NValues = 1;
   return x;

ECL adopts the convention that the name of a function that implements a Common-Lisp function begins with a short package name (cl for COMMON-LISP, si for SYSTEM, etc), followed by L, and followed by the name of the Common-Lisp function. (Strictly speaking, `-' and `*' in the Common-Lisp function name are replaced by `_' and `A', respectively, to obey the syntax of C.)

check_arg(2) in the code of cl_cons checks that exactly two arguments are supplied to cons. That is, it checks that narg is 2, and otherwise, it causes an error. allocate_object(t_cons) allocates a cons cell in the heap and returns the pointer to the cell. After the CAR and the CDR fields of the cell are set, the cell pointer is returned directly. The number assigned to NValues set by the function (1 in this case) represents the number of values of the function.

In general, if one is to play with the C kernel of ECL there is no need to know about all these conventions. There is a preprocessor that takes care of the details, by using a lisp representation of the statements that output values, and of the function definitions. For instance, the actual source code for cl_cons in src/c/lists.d

   @(defun cons (car cdr)
   @(return CONS(car, cdr))