{Begin SubSec The Stack and the Interpreter}
{Title The Stack and the Interpreter}
{Text


{index *PRIMARY* Stack and the interpreter}
{index *PRIMARY* Interpreter and the stack}

{index *PRIMARY* Blips on the stack}

{index *PRIMARY* Interpretor blips on the stack}

{Tag InterpreterBlips}

In addition to the names and values of arguments for functions, information regarding partially-evaluated expressions is kept on the push-down list.  For example, consider the following definition of the function {lisp FACT} (intentionally faulty):


{lispcode
(FACT
   [LAMBDA (N)
      (COND
         ((ZEROP N)
           L)
         (T (ITIMES N (FACT (SUB1 N])}


In evaluating the form {lisp (FACT 1)}, as soon as {lisp FACT} is entered, the interpreter begins evaluating the implicit {fn PROGN} following the {lisp LAMBDA}.  The first function entered in this process is {fn COND}.  {fn COND} begins to process its list of clauses.  After calling {fn ZEROP} and getting a {lisp NIL} value, {fn COND} proceeds to the next clause and evaluates {lisp T}.  Since {lisp T} is true, the evaluation of the implicit {fn PROGN} that is the consequent of the {lisp T} clause is begun.  This requires calling the function {fn ITIMES}.  However before {fn ITIMES} can be called, its arguments must be evaluated.  The first argument is evaluated by retrieving the current binding of {lisp N} from its value cell; the second involves a recursive call to {lisp FACT}, and another implicit {fn PROGN}, etc.


Note that at each stage of this process, some portion of an expression has been evaluated, and another is awaiting evaluation.  The output below (from Interlisp-10) illustrates this by showing the state of the push-down list at the point in the computation of {lisp (FACT 1)} when the unbound atom {lisp L} is reached.

{Note this example isn't very clear}

{lispcode
←FACT(1)
u.b.a. L {bracket in FACT} in ((ZEROP N) L)
(L broken)
:BTV!

   *TAIL* (L)

   *ARG1 (((ZEROP N) L) (T (ITIMES N (FACT (SUB1 N)))))
COND

   *FORM* (COND ((ZEROP N) L) (T (ITIMES N (FACT (SUB1 N)))))
   *TAIL* ((COND ((ZEROP N) L) (T (ITIMES N (FACT (SUB1 N))))))

   N 0
FACT

   *FORM* (FACT (SUB1 N))
   *FN* ITIMES
   *TAIL* ((FACT (SUB1 N)))
   *ARGVAL* 1
   *FORM* (ITIMES N (FACT (SUB1 N)))
   *TAIL* ((ITIMES N (FACT (SUB1 N))))

   *ARG1 (((ZEROP N) L) (T (ITIMES N (FACT (SUB1 N)))))
COND

   *FORM* (COND ((ZEROP N) L) (T (ITIMES N (FACT (SUB1 N)))))
   *TAIL* ((COND ((ZEROP N) L) (T (ITIMES N (FACT (SUB1 N))))))

   N 1
FACT

**TOP**}



Internal calls to {fn EVAL}, e.g., from {fn COND} and the interpreter, are marked on the push-down list by a special mark or blip which the backtrace prints as {lisp *FORM*}.  The genealogy of {lisp *FORM*}'s is thus a history of the computation.  Other temporary information stored on the stack by the interpreter includes the tail of a partially evaluated implicit {fn PROGN} (e.g., a cond clause or lambda expression) and the tail of a partially evaluated form (i.e., those arguments not yet evaluated), both indicated on the backtrace by {lisp *TAIL*}, the values of arguments that have already been evaluated, indicated by {lisp *ARGVAL*}, and the names of functions waiting to be called, indicated by {lisp *FN*}.  {indexX {Name ARG} {Type Stack blip} {Text {lisp *ARG{arg N}}}}{indexX {Name *ARG} {Type Stack blip} {Text {lisp *ARG{arg N}}}}{lisp *ARG1}, {ellipsis}, {lisp *ARGn} are used by the backtrace to indicate the (unnamed) arguments to {lisp SUBR}s.


Note that a function is not actually entered and does not appear on the stack, until its arguments have been evaluated (except for nlambda functions, of course).  Also note that the {lisp *ARG1}, {lisp *FORM*}, {lisp *TAIL*}, etc. "bindings" comprise the actual working storage.  In other words, in the above example, if a (lower) function changed the value of the {lisp *ARG1} binding, the {fn COND} would continue interpreting the new binding as a list of {fn COND} clauses.  Similarly, if the {lisp *ARGVAL*} binding were changed, the new value would be given to {fn ITIMES} as its first argument after its second argument had been evaluated, and {fn ITIMES} was actually called.





Note that {lisp *FORM*}, {lisp *TAIL*}, {lisp *ARGVAL*}, etc., do not actually appear as variables on the stack, i.e., evaluating {lisp *FORM*} or calling {fn STKSCAN} to search for it will not work.  However, the functions {fn BLIPVAL}, {fn SETBLIPVAL}, and {fn BLIPSCAN} described below are available for accessing these internal blips.  These functions currently know about four different types of blips:


{Begin Labeledlist blips}

{Label {indexX {Name FN} {Type stack blip} {Text {lisp *FN*}}}{index *PRIMARY* *FN* (stack blip)}{lisp *FN*}}
{Text The name of a function about to be called.}

{Label {indexX {Name ARGVAL} {Type stack blip} {Text {lisp *ARGVAL*}}}{index *PRIMARY* *ARGVAL* (stack blip)}{lisp *ARGVAL*}}
{Text An argument for a function about to be called.}

{Label {indexX {Name FORM} {Type stack blip} {Text {lisp *FORM*}}}{index *PRIMARY* *FORM* (stack blip)}{lisp *FORM*}}
{Text A form in the process of evaluation.}

{Label{indexX {Name TAIL} {Type stack blip} {Text {lisp *TAIL*}}}{index *PRIMARY* *TAIL* (stack blip)}{lisp *TAIL*}}
{Text The tail of a {fn COND} clause, implicit {fn PROGN}, {fn PROG}, etc.}

{End Labeledlist blips}



{FnDef {FnName BLIPVAL} {FnArgs BLIPTYP IPOS FLG}
{Text
Returns the value of the specified blip of type {arg BLIPTYP}.  If {arg FLG} is a number {lisp N}, finds the {lisp N}th blip of the desired type, searching the control chain beginning at the frame specified by the stack descriptor {arg IPOS}.  If {arg FLG} is {lisp NIL}, 1 is used.  If {arg FLG} is {lisp T}, returns the number of blips of the specified type at {arg IPOS}.
}}



{FnDef {FnName SETBLIPVAL} {FnArgs BLIPTYP IPOS N VAL}
{Text
Sets the value of the specified blip of type {arg BLIPTYP}.  Searches for the {arg N}th blip of the desired type, beginning with the frame specified by the stack descriptor {arg IPOS}, and following the control chain.
}}



{FnDef {FnName BLIPSCAN} {FnArgs BLIPTYP IPOS}
{Text
Returns a stack pointer to the frame in which a blip of type {arg BLIPTYP} is located.  Search begins at the frame specified by the stack descriptor {arg IPOS} and follows the control chain.
}}



}{End SubSec The Stack and the Interpreter}