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; check_arg(2); 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)) @)