{Begin SubSec The Assembler and LAP}
{Title The Assembler and LAP}
{Text


{index compiler structure}

The Interlisp-10 compiler has two principal passes.  The first compiles its input into a macro assembly language called {index LAP}{lisp LAP}.{foot 
The exact form of the macro assembly language is extremely implementation dependent, as well as being influenced by the architecture and instruction set for the machine that will run the compiled program.
}{comment endfootnote}
The second pass expands the LAP code, producing (numerical) machine language instructions.  The output of the second pass{index second pass (of the compiler)} is written on a file and/or stored in binary program space.


Input to the compiler is usually a standard Interlisp {lisp EXPR} definition.  However, in Interlisp-10, machine language coding can be included within a function by the use of one or more {lisp ASSEMBLE} forms as described below.  In other words, {lisp ASSEMBLE} allows the user to write portions of a function in {lisp LAP}.  Note that {lisp ASSEMBLE} is only a compiler directive; it has no independent definition.  Therefore, functions which use {lisp ASSEMBLE} must normally be compiled in order to run.{foot
The {lisp MACROTRAN} package ({PageRef Tag MACROTRAN}) does permit the user to run programs interpretively which contain {lisp ASSEMBLE} directives.  Each {lisp ASSEMBLE} directive is compiled as a separate function. There is some loss in efficiency over compiling the entire function as a unit, and not all {lisp ASSEMBLE} expressions are tractable to this procedure.
}{comment endfootnote}
 




{Begin SubSec Assemble}
{Title Assemble}
{Text

{Tag ASSEMBLE}
{Tag Assembler}


{it
Note:  {lisp ASSEMBLE} is provided for situations where its use is unavoidable.  However, its use is definitely not encouraged.  The disadvantages are several.  {lisp ASSEMBLE} code is unavoidably dependent on the PDP-10, Tenex, and implementation details of Interlisp-10.  Thus, {lisp ASSEMBLE} code is not transportable to Interlisp on another machine or operating system, and implementation changes to Interlisp-10 can (and frequently do) require changes to existing {lisp ASSEMBLE} code.
}

The format of {lisp ASSEMBLE} is similar to that of {fn PROG}:

{lispcode (ASSEMBLE V S{sub 1} S{sub 2} . . . S{sub N})}


{lisp V} is a list of variables to be bound during the first pass of the compilation, {it not} during the running of the object code.
The assemble statements {lisp S{sub 1} ... S{sub N}} are compiled sequentially, each resulting in one or more instructions of object code.
When run, the value of the {lisp ASSEMBLE} "form" is the contents of {index AC1}AC1 at the end of the execution of the assemble instructions.
Note that {lisp ASSEMBLE} may appear anywhere in an Interlisp-10 function.
For example, one may write:


{lispcode
(IGREATERP (IQUOTIENT (LOC (ASSEMBLE NIL
                                     (MOVEI 1 , -5)
                                     (JSYS 13)))
                           1000)
           4)}


to test if job runtime exceeds 4 seconds.{foot
This example is to illustrate use of {lisp ASSEMBLE}, and is {it not} a recommendation to use the above code.  The function {fn JSYS} ({PageRef Fn JSYS}) is the appropriate method.
}{comment endfootnote}


{Begin Note}
Date: 16 SEP 1977 1149-PDT
From: MASINTER
Subject: results from ASSEMBLE

It is generally NOT ALLOWED to return anything in the left half of AC1 from a function (the interpreter routinely discards this information).

In addition, this can confuse the garbage collector no end. Users should avoid writing macros or ASSEMBLE statements which return something in the left half (unless the ASSEMBLE is immediately wrapped in a LOC which will "box" the full word into a number box).
{End Note}


{Begin SubSec Assemble Statements}
{Title Assemble Statements}
{Text

{index *BEGIN* ASSEMBLE statements}

If an assemble statement is an atom, it is treated as a label identifying the location of the next statement that will be assembled.{foot 
A label can be the last thing in an {lisp ASSEMBLE} form, in which case it labels the location of the first instruction {it after} the {lisp ASSEMBLE} form.
}{comment endfootnote}
Such labels defined in an {lisp ASSEMBLE} form are like {fn PROG} labels in that they may be referenced from the current and lower level nested {fn PROG}s or {lisp ASSEMBLE}s.


If an assemble statement is not an atom, {fn CAR} of the statement must be an atom and one of:  (1) a number; (2) a {lisp LAP} op-def{index LAP op-defs} (i.e., has a property value {index OPD Prop}{lisp OPD}); (3) an assembler macro (i.e., has a property value {index AMAC Prop}{lisp AMAC}); or (4) one of the special assemble instructions given below, e.g., {lisp C, CQ,} etc.  Anything else will cause the error message {lisp OPCODE? - ASSEMBLE.}{index OPCODE? - ASSEMBLE Error}


The types of assemble statements are described here in the order of priority used in the {lisp ASSEMBLE} processor; that is, if an atom has both properties {lisp OPD} and {lisp AMAC}, the {lisp OPD} will be used.  Similarly a special {lisp ASSEMBLE} instruction may be redefined via an {lisp AMAC}.  The following descriptions are of the first pass processing of {lisp ASSEMBLE} statements.  The second pass processing is described in the section on {lisp LAP}, {PageRef Tag LAP}.


(1)   numbers

If {fn CAR} of an assemble statement is a number, the statement is not processed in the first pass (see {PageRef Tag LAP}).


(2)   LAP op-defs

{index LAP op-defs}
{index LAP macros}


The property {index *PRIMARY* OPD Prop}{lisp OPD} is used for two different types of op-defs:  PDP-10 machine instructions, and {lisp LAP} macros.  If the {lisp OPD} definition (i.e., the property value) is a number, the op-def is a machine instruction.  When a machine instruction, e.g., {lisp HRRZ}, appears as {fn CAR} of an assemble statement, the statement is not processed during the first pass but is passed to {lisp LAP}.  The forms and processing of machine instructions by {lisp LAP} are described on {PageRef Tag LAPinstructions}.


{Tag LAPopdefs}

If the {lisp OPD} definition is not a number, then the op-def is a {lisp LAP} macro.{index LAP macros}  When a {lisp LAP} macro is encountered in an assemble statement, its arguments are evaluated and processing of the statement with evaluated arguments is left for the second pass and {lisp LAP}.  For example, {lisp LDV} is a {lisp LAP} macro, and {lisp (LDV (QUOTE X) SP)} in assemble code results in {lisp (LDV X N)} in the {lisp LAP} code, where {lisp N} is the value of {lisp SP}.  The form and processing of {lisp LAP} macros are described on {PageRef Tag LAPmacros}.


(3)   assemble macros

{index ASSEMBLE macros}

If {fn CAR} of an assemble statement has a property {index AMAC Prop}{lisp AMAC}, the statement is an assemble macro call.  There are two types of assemble macros: lambda and substitution.  If {fn CAR} of the macro definition is the atom {lisp LAMBDA}, the definition will be {it applied} to the arguments of the call and the resulting list of statements will be assembled.  For example, {lisp REPEAT} could be defined as a {lisp LAMBDA} macro with two arguments, {lisp N} and {lisp M}, which expands into {lisp N} occurrences of {lisp M}, e.g., {lisp (REPEAT 3 (CAR1))} expands to {lisp ((CAR1) (CAR1) (CAR1))}.
The definition (i.e., value of property {lisp AMAC}) for {lisp REPEAT} could be:

{lispcode
(LAMBDA (N M)
  (PROG (YY)
     A  (COND
           ((ILESSP N 1)
            (RETURN (CAR YY)))
           (T (SETQ YY (TCONC YY M))
              (SETQ N (SUB1 N))
              (GO A)))))}


If {fn CAR} of the macro definition is not the atom {lisp LAMBDA}, it must be a list of dummy symbols.  The arguments of the macro call will be substituted for corresponding appearances of the dummy symbols in {fn CDR} of the definition, and the resulting list of statements will be assembled.{foot 
Note that assemble macros produce a list of statements to be assembled, whereas compiler macros produce a single expression.  An assemble macro which {it computes} a list of statements begins with {lisp LAMBDA} and may be {it either} spread or no-spread.  The analogous compiler macro begins with an atom, (i.e., is always no-spread) and the {lisp LAMBDA} is understood.
}{comment endfootnote}
For example, {fn ABS} could be a substitution macro which takes one argument, a number, and expands into instructions to place the absolute value of the number in AC1:

{lispcode
((X)
 (CQ (VAG X))
 (CAIGE 1 , 0))
 (MOVN 1 , 1))}



(4)   special assemble statements 


{Begin LabeledList special assemble statements}

{Name {lisp (CQ {arg E{sub 1}} {ellipsis} {arg E{sub N}})}}
{Text
{index CQ (in an ASSEMBLE statement)}{lisp CQ} (compile quote) takes any number of arguments which are assumed to be regular Interlisp expressions and are compiled in the normal way.  E.g.

{lispcode
(CQ (COND
       ((NULL Y)
        (SETQ Y 1)))
    (SETQ X (IPLUS Y Z)))}


Note: to avoid confusion and minimize dependence on the current implementation, it is best to have as much of a function as possible compiled in the normal way, e.g., to load the value of {lisp X} to {lisp AC1, (CQ X)} is preferred to {lisp (LDV (QUOTE X) SP)}.
}


{Name {lisp (C {arg E{sub 1}} {ellipsis} {arg E{sub N}})}}
{Text
{index C  (in an ASSEMBLE statement)}{lisp C} (Compile) takes any number of arguments which are first evaluated, then compiled in the usual way.  Both {lisp C} and {lisp CQ} permit the inclusion of regular compilation within an assemble form.
}


{Name {lisp (E {arg E{sub 1}} {ellipsis} {arg E{sub N}})}}
{Text
{index E  (in an ASSEMBLE statement)}{lisp E} (Evaluate) takes any number of arguments which are evaluated in sequence.  For example, {lisp (PSTEP)}{index PSTEP FN} calls a function which increments the compiler variable {index SP (in an ASSEMBLE statement)}{lisp SP}.
}


{Name {lisp (SETQ {arg VAR})}}
{Text
{index SETQ (in an ASSEMBLE statement)}Compiles code to set the variable {arg VAR} to the contents of {index AC1}{lisp AC1}.
}


{Name {lisp (VAR ({arg OP} {arg AC} , {arg VARNAME}))}}
{Text
Permits writing a machine instruction with the value of a variable as the operand.  Generates the appropriate address and index fields to reference the value of {arg VARNAME}.  {arg VARNAME} may be a locally bound variable, free variable, {lisp GLOBALVAR}, etc.  Note that {lisp VAR} may generate more than one instruction.
}


{Name {lisp (* ... )}}
{Text
{index *  (in an ASSEMBLE statement)}Used to indicate a comment; the statement
is ignored.
}


{End LabeledList special assemble statements}


{index *END* ASSEMBLE statements}

}{End SubSec Assemble Statements}




{Begin SubSec COREVALs}
{Title COREVALs}
{Text

{index COREVALS}

There are several locations in the basic machine code of Interlisp-10 which may be referenced from compiled code.  The current value of each location is stored on the property list under the property {index *PRIMARY* COREVAL Prop}{prop COREVAL}.{foot 
The value of {index COREVALS Var}{var COREVALS} is a list of all atoms with {lisp COREVAL} properties.
}{comment endfootnote}
Since these locations may change in different reassemblies of Interlisp-10, they are written symbolically on compiled code files, i.e., the name of the corresponding {prop COREVAL} is written, not its value.  Some of the {prop COREVAL}s used frequently in {lisp ASSEMBLE} are:


{Begin LabeledList COREVAL used frequently}

{Indent 15percent}

{Name {lisp KT}}  {Text contains (pointer to) atom {lisp T}}

{Name {lisp KNIL}}  {Text Contains (a pointer to) the atom {lisp NIL}.}

{Name {lisp MKN}}  {Text Routine to box an integer.}

{Name {lisp MKFN}}  {Text Routine to box floating number.}

{Name {lisp IUNBOX}}  {Text Routine to unbox an integer.}

{Name {lisp FUNBOX}}  {Text Routine to unbox floating number.}

{End LabeledList COREVAL used frequently}



The index registers used for the push-down stack pointers are also included as {index COREVALS}{lisp COREVAL}S.  These are not expected to change, and are not stored symbolically on compiled code files; however, they should be referenced symbolically in assemble code.
They are:

{Begin LabeledList index registers}

{Indent 15percent}

{Name {lisp PP}}  {Text Parameter stack.}

{Name {lisp CP}}  {Text Control stack.}

{Name {lisp VP}}  {Text Basic frame pointer.}

{End LabeledList index registers}

}{End SubSec COREVALs}



}{End SubSec Assemble}




{Begin SubSec LAP}
{Title LAP}
{Text

{index *BEGIN* LAP}
{index *PRIMARY* LAP}
{index *PRIMARY* machine instructions}


{Tag LAP}


LAP (for LISP Assembly Processor) expands the output of the first pass of compilation to produce numerical machine instructions.



{Begin SubSec LAP Statements}
{Title LAP Statements}
{Text

{index *BEGIN* LAP statements}

If a LAP statement is an atom, it is treated as a label identifying the location of the next statement to be processed.  If a LAP statement is not an atom, {fn CAR} of the statement must be an atom and either: (1) a number; (2) a machine instruction; or (3) a LAP macro.

(1)   numbers

If {fn CAR} of a LAP statement is a number, a location containing the number is produced in the object code.{foot
Note that if a function is intended to be swappable, it may not contain any relocatable, indexed instructions.
}{comment endfootnote}
E.g.,

{lispcode
(ADD 1 , A (1))     
   .
   .
   .
A    (1)
     (4)
     (9)}


Statements of this type are processed like machine instructions, with the initial number serving as a 36-bit op-code.


(2)   Machine Instructions

{Tag LAPinstructions}

{index *BEGIN* machine instructions}

If {fn CAR} of a LAP statement has a numeric value for the property {index OPD Prop}{lisp OPD,}{foot 
The value is an 18 bit quantity (rather than 9), since some UUO's also use the AC field of the instruction.
}{comment endfootnote}
the statement is a machine instruction.  The general form of a machine instruction is:

{lispcode
({arg OPCODE} {arg AC} , @ {arg ADDRESS} (index))}


{arg OPCODE} is any PDP-10 instruction mnemonic or Interlisp UUO.{foot 
The TENEX JSYS's are not defined, that is, one must write {lisp (JSYS 107)} instead of {lisp (KFORK)}.
}{comment endfootnote}

{arg AC}, the accumulator field, is optional.  However, if present, it {it must} be followed by a comma.  {arg AC} is either a number or an atom with a {index COREVAL Prop}{lisp COREVAL} property.  The low order 4 bits of the number or {lisp COREVAL} are OR'd to the AC field of the instruction.

{index @  (in a LAP statement)}{lisp @} may be used anywhere in the instruction to specify indirect addressing (bit 13 set in the instruction) e.g., {lisp (HRRZ 1 , @ 1 (VP))}.


{arg ADDRESS} is the address field which may be any of the following:


{Begin LabeledList the address field which may be any of the following}

{Name {lisp = {arg CONSTANT}}{index = (in a LAP statement)}}
{Text
Reference to an unboxed constant.  A location containing the unboxed constant will be created in a region at the end of the function, and the address of the location containing the constant is placed in the address field of the current instruction.  The constant may be a number e.g., {lisp (CAME 1 , = 3596)}; an atom with a property {lisp COREVAL} (in which case the constant is the value of the property, at {lisp LOAD} time); any other atom which is treated as a label (the constant is then the address of the labeled location) e.g., {lisp (MOVE 1 , = TABLE)} is equivalent to {lisp (MOVEI 1 , TABLE)}; or an
expression whose value is a number.
}


{Name {lisp ' {arg POINTER}}{index ' (in a LAP statement)}}
{Text
The address is a reference to a Interlisp pointer, e.g., a list, number, string, etc.
A location containing the pointer is assembled at the end of the function, and the current instruction will have the address of this location, e.g.,

{lispcode (HRRZ 1 , ' "IS NOT DEFINED")}

{lispcode (HRRZ 1 , ' (NOT FOUND))}
}


{Name {lisp *}{index * (in a LAP statement)}}
{Text
Specifies the current location in the compiled function; e.g., {lisp (JRST * 2)} has the same effect as {lisp (SKIPA)}.
}


{Name a literal atom}
{Text
If the atom has a property {index COREVAL Prop}{lisp COREVAL}, it is a reference to a system location, e.g., {lisp (SKIPA 1 , KNIL)}, and the address used is the value of the {lisp COREVAL}. Otherwise the atom is a label referencing a location in the LAP code, e.g., {lisp (JRST A)}.
}


{Name a number}
{Text
The number is the address; e.g.,

{lispcode
(MOVSI 1 , 400000Q)
(HLRZ 2 , 1 (1))}
}


{Name a list}
{Text
The form is evaluated, and its value is the address.
}


{End LabeledList the address field which may be any of the following}



Anything else in the address field causes an error message, e.g., {lisp (SKIPA 1 , KNILL) - LAPERROR}.  A number may follow the address field and will be added to it, e.g., {lisp (JRST A 2)}.


{lisp INDEX} is denoted by a {it list} following the address field, i.e., the address field {it must} be present if an index field is to be used.  The index ({fn CAR} of the list) must be either a number, or an atom with a property {lisp COREVAL}, e.g., {lisp (HRRZ 1 , 0 (1))}.

{index *END* machine instructions}



(3)   LAP macros


{Tag LAPmacros}

{index *PRIMARY* LAP macros}

If {fn CAR} of a LAP statement is the name of a LAP macro, i.e., has the property {index OPD Prop}{lisp OPD}, the statement is a macro call.  The arguments of the call follow the macro name: e.g., {lisp (LQ2 FIE 3)}.


LAP macro calls comprise most of the output of the first pass of the compiler, and may also be used in {lisp ASSEMBLE}.  The definitions of these macros are stored on the property list under the property {lisp OPD}, and like assembler macros, may be either lambda or substitution macros.  In the first case, the macro definition is applied to the arguments of the call;{foot 
The arguments were already evaluated in the first pass, see {PageRef Tag LAPopdefs}.
}{comment endfootnote}
in the second case, the arguments of the call are substituted for occurrences of the dummy symbols in the definition.  In both cases, the resulting list of statements is again processed, with macro expansion continuing till the level of machine instructions is reached.


Some examples of LAP macros are shown below.

{lispcode
(DEFLIST
'[(LQ ((X)                            (* LOAD QUOTE TO AC1)
       (HRRZ 1 , ' X)))
  (LQ2 ((X AC)                        (* LOAD QUOTE TO AC)
        (HRRZ AC , ' X)))
  (LDV ((A SP)                        (* LOAD LOCAL VARIABLE TO AC1)
        (HRRZ 1 , (VREF A SP))))
  (STV ((A SP)                        (* SET LOCAL VARIABLE FROM AC1)
        (HRRM 1 , (VREF A SP))))
  (LDV2 ((A SP AC)                    (* LOAD LOCAL VARIABLE TO AC)
         (HRRZ AC , (VREF A SP))))
  (LDF ((A SP)                        (* LOAD FREE VARIABLE TO AC1)
        (HRRZ 1 , (FREF A SP))))
  (STF ((A SP)                        (* SET FREE VARIABLE FROM AC1)
        (HRRM 1 , (FREF A SP))))
  (LDF2 ((A SP)                       (* LOAD FREE VARIABLE TO AC)
         (HRRZ 2 , (FREF A SP))))
  (CAR1 (NIL                          (* CAR OF AC1 TO AC1)
         (HRRZ 1 , 0 (1))))
  (CDR1 (NIL                          (* CDR OF AC1 TO AC1)
         (HLRZ 1 , 0 (1))))
  (CAR2 ((AC)                         (* CAR OF AC TO AC)
         (HRRZ AC , 0 (AC))))
  (CLL ((NAM N)                       (* CALL FN WITH N ARGS GIVEN)
        (CCALL N , ' NAM)))
  (LCLL ((NAM N)                      (* LINKED CALL WITH N ARGS)
         (LNCALL N , (MKLCL NAM))))
  (RET (NIL                           (* RETURN FROM FN)
       (POPJ CP ,))
  (PUSHP (NIL (PUSH PP , 1)))
  (PUSHQ ((X)                         (* PUSH QUOTE)
          (PUSH PP , ' X)))]
'OPD)}


{index *END* LAP statements}

{index *END* LAP}

}{End SubSec LAP Statements}


}{End SubSec LAP}




{Begin SubSec Using Assemble}
{Title Using Assemble}
{Text


In order to use {lisp ASSEMBLE}, it is helpful to know the following things about how compiled code is run.  All variable bindings and temporary pointers are stored on the parameter pushdown stack (addressed by index register {lisp PP}).  Control information is stored on the control pushdown stack (addressed by index register {lisp CP}).  A function call proceeds as follows:


1.  The calling function pushes the argument values on the parameter stack.


2.  The calling function invokes a routine that adjusts the number of arguments if too few or too many were supplied, and binds the arguments.  Binding usually implies the creation of a basic frame.{foot
Whether a basic frame is created for a {fn PROG} or open lambda depends on whether any of the variables are specvars.
}{comment endfootnote}


3.  Then the called function is run.

The arguments in the basic frame are referenced relative to index register {lisp VP}, e.g., 1{lisp (VP)} addresses the first argument.  However, it is better to reference variables in less implementation dependent ways, such as {lisp (CQ ...)} or {lisp (VAR ( ... ))}.  The compiler will then generate the correct code whether the variable is bound locally, is a free reference, is a {lisp GLOBALVAR}, etc.


The parameter stack may be used for temporary storage of pointers.  Both halves of a word on the parameter stack may be pointers.  On the control stack the right half of a word must be a pointer, the left a non-pointer.  Anything else can cause the garbage collector to fail.


For temporary storage of unboxed numbers, the following {lisp ASSEMBLE} macros are provided:


{Begin LabeledList ASSEMBLE macros}


{Name {lisp (PUSHN {arg ADDR})}}
{Text
"Pushes" the number referenced by {arg ADDR}.  {arg ADDR} may be any legal {lisp ASSEMBLE} code address field, for example: {lisp (PUSHN 1)}, {lisp (PUSHN = 0)}, {lisp (PUSHN @ 2)}
}


{Name {lisp (POPN {arg ADDR})}}
{Text
"Pops" the most recent number to {arg ADDR}.
}


{Name {lisp (NREF ({arg OP} {arg AC} , {arg N}))}}
{Text
References a previously pushed number.  {arg OP} is the opcode, {arg AC} is the accumulator, {arg N} is the relative position of the desired number on the pseudo number stack.  That is, {arg N} = 0 refers to the most recent number, {arg N} = -1 to the next most recent, etc.  For example: {lisp (NREF (MOVN 1, -1))}
}


{Name {lisp (PUSHNN {arg N{sub 1}} {ellipsis} {arg N{sub M}})}}
{Text
"Pushes" a sequence of numbers specified by {arg N{sub i}} where {arg N{sub i}} is a list of any legal address field.  For example: {lisp (PUSHNN (1) (2) (= 0))} pushes the contents of {lisp AC1}, the contents of {lisp AC2}, and the constant 0.
}


{Name {lisp (POPNN {arg N})}}
{Text
"Pops" the {arg N} most recent numbers, discarding the values.
}


{End LabeledList ASSEMBLE macros}


Use of these macros is subject to the following restrictions:

1.   {lisp PUSHN}'s and {lisp POPN}'s must be seen by the compiler in the same order and number in which they are executed.  The compiler does not analyze the code; it assumes when it encounters a {lisp PUSHN} in the sequential processing of the code that the {lisp PUSHN} will in fact be executed.


2.   Every number that is pushed must be popped.


3.   In nested {lisp ASSEMBLE} statements, if a {fn PROG} or open lambda occurs between the inner and outer level {lisp ASSEMBLE}, numbers pushed in the outer {lisp ASSEMBLE} may not be referenced from the inner {lisp ASSEMBLE}.



The value of a function is always returned in {index *PRIMARY* AC1}{lisp AC1}.  Therefore, the pseudo-function, {index AC  (in an ASSEMBLE statement)}{lisp AC}, is available for obtaining the current contents of {lisp AC1}.  For example {lisp (CQ (FOO (AC)))} compiles a call to {lisp FOO} with the current contents of AC1 as argument, and is equivalent to:

{lispcode
(PUSHP)
(E (PSTEP))
(CLL (QUOTE FOO) 1)
(E (PSTEPN -1))}

{index PSTEPN FN}


In using {lisp AC}, be sure that it appears as the first argument to be evaluated in the expression.  For example: {lisp (CQ (IPLUS (LOC (AC)) 2))}


There are several ways to reference the values of variables in assemble code.
For example:


{Begin LabeledList ways to reference the values of variables}

{Name {lisp (CQ X)}}
{Text Puts the value of {lisp X} in AC1.}

{Name {lisp (LDV2 (QUOTE X) SP 3)}}
{Text Puts the value of {lisp X} in AC3.}

{Name {lisp (SETQ X)}}
{Text Sets {lisp X} to the contents of AC1.}

{Name {lisp (VAR (HRRM 2 , X))}}
{Text Sets {lisp X} to the contents of AC2.}

{Name {lisp (CQ (LOC (AC)))}}
{Text Boxes the contents of AC1.}

{Name {lisp (FASTCALL MKFN)}}
{Text Floating boxes the contents of AC1.}

{Name {lisp (CQ (VAG X))}}
{Text Puts the unboxed value of {lisp X} in AC1.}

{Name {lisp (FASTCALL FUNBOX)}}
{Text Gets the floating unbox of AC1.}

{End LabeledList ways to reference the values of variables}




To call a function directly, the arguments must be pushed on the parameter stack, and {lisp SP} must be updated, and then the function called: e.g.,

{lispcode
(CQ (CAR X))
(PUSHP)                  (* stack first argument)
(E (PSTEP))
(PUSHQ 3.14)
(E (PSTEP))              (* stack second argument)
(CLL (QUOTE FUM) 2)      (* call FUM with 2 arguments)
(E (PSTEPN -2))          (* adjust stack count)}


and is equivalent to:


{lispcode (CQ (FUM (CAR X) 3.14))}


}{End SubSec Using Assemble}


}{End SubSec The Assembler and LAP}