[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4. The interpreter

4.1 ECL stacks  
4.2 Procedure Call Conventions  
4.3 The lexical environment  
4.4 The interpreter stack  


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.1 ECL stacks

ECL uses the following stacks:

FRAME STACK
consisting of catch, block, tagbody frames

BIND STACK
for shallow binding of dynamic variables

INTERPRETER STACK
acts as a Forth data stack, keeping intermediate arguments to interpreted functions, plus a history of called functions.

C CONTROL STACK
used for arguments/values passing, typed lexical variables, temporary values, and function invocation.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.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

 
clLcons(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 si for SYSTEM, etc), followed by L, and followed by the name of the Common-Lisp Common-Lisp to obey the syntax of C.)

check_arg(2) in the code of clLcons 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 clLcons in `src/c/lists.d'

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


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.3 The lexical environment

The ECL interpreter uses two A-lists (Association lists) to represent lexical environments.

When a function closure is created, the current two A-lists are saved in the closure along with the lambda expression. Later, when the closure is invoked, the saved A-lists are used to recover the lexical environment.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.4 The interpreter stack

The bytecodes interpreter uses a stack of its own to save and restore values from intermediate calculations. This Forth-like data stack is also used in other parts of the C kernel for various purposes, such as saving compiled code, keeping arguments to FORMAT, etc.

However, one of the most important roles of the Interpreter Stack is to keep a log of the functions which are called during the execution of bytecodes. For each function invoked, the interpreter keeps three lisp objects on the stack:
 
+----------+------------------------------------------------+
| function | lexical environment | index to previous record |
+----------+---------------------+--------------------------+

The first item is the object which is funcalled. It can be a bytecodes object, a compiled function or a generic function. In the last two cases the lexical environment is just NIL. In the first case, the second item on the stack is the lexical environment on which the code is executed. Each of these records are popped out of the stack after function invocation.

Let us see how these invocation records are used for debugging.

 
>(defun fact (x)                ;;;  Wrong definition of the 
   (if (= x 0)                  ;;;  factorial function. 
       one                      ;;;  one  should be  1. 
       (* x (fact (1- x)))))
FACT

>(fact 3)                       ;;;  Tries  3!
Error: The variable ONE is unbound.
Error signalled by IF.
Broken at IF.
>>:b                            ;;;  Backtrace. 
Backtrace: eval > fact > if > fact > if > fact > if > fact > IF
                                ;;;  Currently at the last  IF.
>>:h                            ;;;  Help. 

Break commands:
:q(uit)         Return to some previous break level.
:pop            Pop to previous break level.
:c(ontinue)     Continue execution.
:b(acktrace)    Print backtrace.
:f(unction)     Show current function.
:p(revious)     Go to previous function.
:n(ext)         Go to next function.
:g(o)           Go to next function.
:fs             Search forward for function.
:bs             Search backward for function.
:v(ariables)    Show local variables, functions, blocks, and tags.
:l(ocal)        Return the nth local value on the stack.
:hide           Hide function.
:unhide         Unhide function.
:hp             Hide package.
:unhp           Unhide package.
:unhide-all     Unhide all variables and packages.
:bds            Show binding stack.
:m(essage)      Show error message.
:hs             Help stack.
Top level commands:
:cf             Compile file.
:exit or ^D     Exit Lisp.
:ld             Load file.
:step           Single step form.
:tr(ace)        Trace function.
:untr(ace)      Untrace function.

Help commands:
:apropos        Apropos.
:doc(ument)     Document.
:h(elp) or ?    Help.  Type ":help help" for more information.

>>:p                        ;;;  Move to the last call of  FACT.
Broken at IF.

>>:b
Backtrace: eval > fact > if > fact > if > fact > if > FACT > if
                            ;;;  Now at the last  FACT.
>>:v                        ;;;  The environment at the last call 
Local variables:            ;;;  to  FACT  is recovered. 
  X: 0                      ;;;  X  is the only bound variable. 
Block names: FACT.          ;;;  The block  FACT  is established. 
                   
>>x
0                           ;;;  The value of  x  is  0.
        
>>(return-from fact 1)      ;;;  Return from the last call of 
6                           ;;;  FACT  with the value of  0.
                            ;;;  The execution is resumed and 
>                           ;;;  the value  6  is returned. 
                            ;;;  Again at the top-level loop. 


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Juan Jose Garcia Ripoll on May, 30 2005 using texi2html