ecl_bds_bind
— Bind a special variableecl_bds_unwind
— Undo one variable bindingecl_setq
C equivalent of setqecl_symbol_value
C equivalent of symbol-valueecl_va_arg
— Accepting a variable number of argumentsecl_nth_value
, ecl_nvalues
— Accessing output valuesecl_return0
, ecl_return1
, ... — Returning multiple valuesECL_BLOCK_BEGIN
C macro for blockECL_CATCH_BEGIN
C macro for catchECL_UNWIND_PROTECT_BEGIN
C macro for unwind-protectFormer versions of ECL, as well as many other lisps, used linked lists to represent code. Executing code thus meant traversing these lists and performing code transformations, such as macro expansion, every time that a statement was to be executed. The result was a slow and memory hungry interpreter.
Beginning with version 0.3, ECL was shipped with a bytecodes compiler and interpreter which circumvent the limitations of linked lists. When you enter code at the lisp prompt, or when you load a source file, ECL begins a process known as minimal compilation. Barely this process consists on parsing each form, macroexpanding it and translating it into an intermediate language made of bytecodes.
The bytecodes compiler is implemented in
src/c/compiler.d
. The main entry point is the lisp
function si::make-lambda
, which takes a name for the
function and the body of the lambda lists, and produces a lisp object that
can be invoked. For instance,
> (defvar fun (si::make-lambda 'f '((x) (1+ x)))) *FUN* > (funcall fun 2) 3
ECL can only execute bytecodes. When a list is passed to
EVAL
it must be first compiled to bytecodes and, if the
process succeeds, the resulting bytecodes are passed to the
interpreter. Similarly, every time a function object is created, such as in
DEFUN
or DEFMACRO
, the compiler
processes the lambda form to produce a suitable bytecodes object.
The fact that ECL performs this eager compilation means that changes on a macro are not immediately seen in code which was already compiled. This has subtle implications. Take the following code:
> (defmacro f (a b) `(+ ,a ,b)) F > (defun g (x y) (f x y)) G > (g 1 2) 3 > (defmacro f (a b) `(- ,a ,b)) F > (g 1 2) 3
The last statement always outputs 3
while in former
implementations based on simple list traversal it would produce
-1
.