F.G.H. 6/6/85 LispCourse #34: Variable Binding and the Interlisp Stack LispCourse #34: Variable Binding and the Interlisp Stack Variable Reference Inside Functions: Bound and Free Variables Consider the following function definition from the solution to Homework #30: (DEFINEQ (LC.ParseNameString (LAMBDA (String) (SETQ String (CONCAT String)) (SETQ Comma (STRPOS "," String)) (SETQ Space (STRPOS " " String Comma)) (create LC.Name Last _ (MKATOM (SUBSTRING String 1 (SUB1 Comma))) First _ (MKATOM (SUBSTRING String (ADD1 Comma ) (SUB1 Space))) Middle _ (MKATOM (SUBSTRING String (ADD1 Space)))) In this function, there are three variables: String, Comma, and Space. String differs from Comma and Space in that before the function is entered during a function call evaluation, the value of String is temporarily set (i.e., bound) to the value of the argument in the function call. Moreover, the old value of String is reset to its previous value when the function is exited, despite the new value assigned to String by the SETQ in the function. In contrast, Comma and Space have unknown values when the function is entered and the SETQ operations on Comma and Space permanently change the value of these variables. String is known as a bound variable within the function LC.ParseNameString. A bound variable is one whose value is set when the function is entered and reset to the previous value when the function is exited. In particular, a bound variable has the following property: You can change the name of the variable, and the operation of the function will not change. Substituting NameString for String throughout the definition of LC.ParseNameString would not change how the function worked. Comma and Space are known as free variables within the function LC.ParseNameString. A variable is a free variable in a function definition if it is not bound within that function definition. The value of a free variable when the function is entered cannot be specified a priori. The free variable may have a value or it may not. Moreover, when the function is exited, the free variable is not reset to its previous value. In particular, a free variable has the following property: If you change the name of the variable, and the operation of the function may change, depending on the context of the evaluation. For example, if the variables ListSize and StringSize were used by the Lisp Exec to hold important information, then changing Comma to ListSize and Space to StringSize in the definition of LC.ParseNameString might have serious side-effects on the Lisp Exec, since evaluating a call to LC.ParseNameString would change the value of these variables. The problem with free variables in a function definition is that there is some ambiguity as to what is being refered to by the free variable. Interpreting the free variable reference depends on some context outside of the function itself. Consider the following example: 1_ (DEFINEQ (LC.FindComma (LAMBDA (String SearchLetter) (SETQ SearchLetter ",") (LC.FindLetter String))) (LC.FindLetter (LAMBDA (String) (STRPOS SearchLetter String)))) (LC.FindComma LC.FindLetter) 2_ (SETQ SearchLetter "+") "+" 3_ (LC.FindLetter "AB,CD+EF") 6 4_(LC.FindComma "AB,CD+EF") ???? Problem: What is the value of this function call? There are two possible answers, depending on how the free variable SearchLetter is resolved in the call to LC.FindLetter. 1. If SearchLetter in LC.FindLetter refers to the global value in the Exec environment, then the result would be 6 since LC.FindLetter would be searching for a "+" as determined by event 2. 2. If SearchLetter in LC.FindLetter refers to the most recent binding of SearchLetter anywhere, then the result would be 3 since LC.FindLetter would be searching for a "," as determined by the binding and SETQ statements in LC.FindComma. In fact, in Interlisp the value returned by (LC.FindComma "AB,CD+EF") in event 4 would be 3, because a free variable reference in a function always references the most recent binding of that variable. The following several sections, explain in detail how Interlisp handles variable references, both free and bound, within function definitions. The main point of these sections is that the model of variables we have been using until now is far too simple. Until now, we have assumed that the value of a variable in a function definition is the value of the atom with the same name as the varaible. This is true "at the top level", i.e. for variable references typed directly to the Lisp Exec. However, for variable references within a function, Interlisp uses a much more complex scheme to set and determine the value of an variable. Review: Evaluating S-expressions using EVAL and APPLY Recall that all of the significant work in Lisp is done by the Lisp evaluator during the EVAL part of the read-EVAL-print loop. Recall also that the Lisp evaluator is built around two functions: EVAL and APPLY. Hence, understanding Lisp function evaluation requires understanding the two functions EVAL and APPLY. EVAL The following defines a function that could be used by the Lisp evaluator to evaluate arbitrary S-expressions (i.e., EVAL): (DEFINEQ (EVAL (LAMBDA (SExpr) (COND ((NLISTP SExpr) (LookUpValue SExpr)) (T (APPLY (CAR SExpr) (FOR Arg IN (CDR SExpr) COLLECT (EVAL Arg))) Note: The function LookUpValue is some mysterious function that can look up the value of atoms, arrays, etc. in the Lisp environment. In natural language, EVAL does the following: If SExpr is not a list, then look up the value of SExpr and return it. If SExpr is a list, then APPLY the function named by the first element (i.e., CAR) of SExpr to the list obtained by collecting the evaluation each item in the rest (i.e., CDR) of SExpr. Aside from LookUpValue (which will remain mysterious for a while), the central function used in defining EVAL is the function APPLY. APPLY APPLY could be defined as follows: (DEFINEQ (APPLY (LAMBDA (Function Arguments) (FOR Parameter IN (CADR (GetFunctionDefn Function)) AS Argument IN Arguments DO (Bind Parameter Argument)) (FOR SExpr IN (CDDR (GetFunctionDefn Function)) AS Ctr FROM 1 TO (DIFFERENCE (LENGTH (GetFunctionDefn Function)) 3) DO (EVAL SExpr)) (SETQ Result (EVAL (CAR (LAST (GetFunctionDefn Function))))) (FOR Parameter IN (CADR (GetFunctionDefn Function)) DO (Unbind Parameter)) Result))) Note: The functions GetFunctionDefn, Bind, and Unbind are some mysterious functions that can look up the defintion of a function, bind a parameter to a value, and unbind a parameter, respectively. In natural language, APPLY does the following: For each parameter in the parameters list in the function definition of Function, bind that parameter to the corresponding argument in the Arguments list. Then, for each S-expression in the body of the function definition except for the last, EVAL the S-expression. Then, EVAL the last S-expression in the body of the function definition and hold on to the resulting value. Then, for each parameter in the parameters list in the function definition of Function, unbind that parameter. Finally, return the result already derived by EVALing the last S-expression. EXAMPLE (from LispCourse #3, page 6) (DEFINEQ (MOVEFILE (LAMBDA (FromFile ToFile) (COPYFILE FromFile ToFile) (DELFILE FromFile) (QUOTE AllDone)))) Evaluating (MOVEFILE 'OLD.LISP 'NEW.LISP) proceeds as follows: EVAL: 1. 'OLD.LISP evaluates to OLD.LISP 2. 'NEW.LISP evaluates to NEW.LISP 3. APPLY the function MOVEFILE to (OLD.LISP NEW.LISP) APPLY: 1. FromFile is bound to OLD.LISP 2. ToFile is bound to NEW.LISP 3. (COPYFILE FromFile ToFile) is evaluated using current bindings of FromFile and ToFile (i.e., FromFile will evaluate to OLD.LISP and ToFile will evaluate to NEW.LISP). 4. (DELFILE FromFile) is evaluated similarly. 5. (QUOTE AllDone) is evaluated to AllDone. 6. FromFile and ToFile are reset to their previous values (if any). 7. APPLY returns AllDone. Missing Pieces The foregoing explanation references several functions that have not yet been explained. In particular, LookUpValue, Bind, Unbind, and GetFunctionDefn are critical functions used by EVAL and/or APPLY in the process of evaluating S-expressions. The following sections explain the operation of these functions in the Interlisp-D evaluator. The Lisp Stack, Variable Binding, Variable Lookup, and Related Topics In the APPLY phase of evaluating a Lisp function call, the first step is to bind the parameters of the function to the corresponding arguments in the function call. In LispCourse #3 (page 6), binding a parameter to an argument was described as "temporarily SETQing the parameter to the argument value". The implication was that binding simply temporarily resets the value assigned to the atom of the same name as the parameter. In actuality, binding is much more complex and relies on a special data structure called the stack. The Lisp Stack The stack is a data structure that contains a variable number of stack frames arranged in an ordered one-dimensional vector. Each stack frame contains a variable number of binding records. Each binding record is a pair consisting of a variable name (i.e., a litatom) and a value. The stack has a top and a bottom. Stack frames can only be added to the bottom of the stack. Stack frames can only be removed from the bottom of the stack. (NIL ((.05 15.0 NIL) (TEXT (232.0 . 304.0) ("Adding a stack frame to the bottom of the stack" "") 1.0 (CENTER BASELINE) (HELVETICA 12 (BOLD REGULAR REGULAR)) ((59.0 308.0 347.0 14.0) ( 232.0 294.0 0.0 14.0)) NIL)) ((.03866667 11.6 NIL) (TEXT (28.8 . 214.4) ("Top" "Frame") .7733334 (LEFT BASELINE) (HELVETICA 14) ((29.14667 217.84 23.2 11.6) (29.14667 206.24 36.34667 11.6)) NIL)) ((.03925926 11.77778 NIL) (TEXT (22.4 . 99.2) ("Bottom" "Frame") .7851852 (LEFT BASELINE) (HELVETICA 14) ((22.28148 102.3704 42.4 11.77778) (22.28148 90.5926 36.9037 11.77778)) NIL)) ((.0496 56.80001 NIL) (BOX (67.2 80.0 113.6 49.6) 2)) ((.0496 56.80001 NIL) (BOX (67.2 137.6 113.6 49.6) 2)) ((.04960001 56.80001 NIL) (BOX (67.2 195.2 113.6 49.60001) 2)) ((.04865672 11.67761 NIL) (TEXT (73.6 . 118.4) ("ZAP Frame") .9731344 ( LEFT BASELINE) (HELVETICA 10) ((73.41492 116.2328 65.2 11.67761)) NIL)) ((.04911765 11.78824 NIL) (TEXT (73.6 . 176.0) ("XYZ Frame") .982353 (LEFT BASELINE) (HELVETICA 10) ((73.95883 174.1589 66.80001 11.78824)) NIL)) ((.04898551 11.75652 NIL) (TEXT (73.6 . 233.6) ("FOO Frame" ) .9797102 (LEFT BASELINE) (HELVETICA 10) ((73.8029 231.5363 67.60002 11.75652)) NIL)) (( .03946667 11.84 NIL) (TEXT (80.0 . 208.0) ("(BAR 7)") .7893333 (LEFT BASELINE) (HELVETICA 14) ((79.936 205.44 59.2 11.84)) NIL)) ((.03948052 11.84416 NIL) (TEXT (80.0 . 220.8) ( "(FOO 5)") .7896105 (LEFT BASELINE) (HELVETICA 14) ((79.95845 218.1403 60.80001 11.84416)) NIL)) ((.03954546 11.86364 NIL) (TEXT (86.4 . 92.8) ("(ITEM A)") .7909091 (LEFT BASELINE) (HELVETICA 14) ((86.39092 90.34546 69.6 11.86364)) NIL)) ((.03959184 11.87755 NIL) (TEXT ( 86.4 . 105.6) ("(SUMX 12)") .7918368 (LEFT BASELINE) (HELVETICA 14) ((86.47348 103.1021 77.6 11.87755)) NIL)) ((.03951807 11.85542 NIL) (TEXT (86.4 . 150.4) ("(BAZ 88)") .7903614 (LEFT BASELINE) (HELVETICA 14) ((86.34216 147.9904 65.6 11.85542)) NIL)) ((.03944444 11.83333 NIL) (TEXT (86.4 . 163.2) ("(FOO 6)") .7888888 (LEFT BASELINE) (HELVETICA 14) ((86.21112 161.1556 56.8 11.83333)) NIL)) ((.03972603 11.91781 NIL) (TEXT (118.4 . 252.8) ( "Stack Before Add" "") .7945206 (CENTER BASELINE) (HELVETICA 14 (BOLD REGULAR REGULAR)) (( 64.98632 255.863 106.4658 11.91781) (118.2192 243.9452 0.0 11.91781)) NIL)) ((.03972973 11.91892 NIL) (TEXT (331.2 . 259.2) ("Stack After Add") .7945947 (CENTER BASELINE) (HELVETICA 14 (BOLD REGULAR REGULAR)) ((282.1892 256.6919 99.32434 11.91892)) NIL)) ((.04960001 56.80001 NIL) (BOX (273.6 195.2 113.6 49.60001) 2)) ((.04898551 11.75652 NIL) (TEXT (280.0 . 233.6) ("FOO Frame") .9797102 (LEFT BASELINE) (HELVETICA 10) ((280.3537 231.5363 67.60002 11.75652)) NIL)) ((.03948053 11.84416 NIL) (TEXT (286.4 . 220.8) ("(FOO 5)") .7896106 (LEFT BASELINE) (HELVETICA 14) ((286.5663 218.1403 60.80002 11.84416)) NIL)) ((.03946668 11.84 NIL) (TEXT ( 286.4 . 208.0) ("(BAR 7)") .7893335 (LEFT BASELINE) (HELVETICA 14) ((286.4854 205.4401 59.20002 11.84)) NIL)) ((.03866666 11.6 NIL) (TEXT (235.2 . 214.4) ("Top" "Frame") .7733333 (LEFT BASELINE) (HELVETICA 14) ((235.4133 217.84 23.2 11.6) (235.4133 206.24 36.34667 11.6)) NIL)) ((.0496 56.80001 NIL) (BOX (273.6 137.6 113.6 49.6) 2)) ((.03944445 11.83333 NIL) ( TEXT (292.8 . 163.2) ("(FOO 6)") .788889 (LEFT BASELINE) (HELVETICA 14) ((292.6667 161.1556 56.80001 11.83333)) NIL)) ((.04911764 11.78823 NIL) (TEXT (280.0 . 176.0) ("XYZ Frame") .9823528 (LEFT BASELINE) (HELVETICA 10) ((279.9765 174.1588 66.79999 11.78823)) NIL)) (( .0486567 11.67761 NIL) (TEXT (280.0 . 118.4) ("ZAP Frame") .973134 (LEFT BASELINE) (HELVETICA 10) ((279.8208 116.2328 65.19998 11.67761)) NIL)) ((.0496 56.80001 NIL) (BOX (273.6 80.0 113.6 49.6) 2)) ((.03951807 11.85542 NIL) (TEXT (292.8 . 150.4) ("(BAZ 88)") .7903614 ( LEFT BASELINE) (HELVETICA 14) ((293.1084 147.9904 65.59999 11.85542)) NIL)) ((.03954545 11.86364 NIL) (TEXT (292.8 . 92.8) ("(ITEM A)") .790909 (LEFT BASELINE) (HELVETICA 14) (( 292.4818 90.34544 69.59999 11.86364)) NIL)) ((.03959183 11.87755 NIL) (TEXT (292.8 . 105.6) ( "(SUMX 12)") .7918366 (LEFT BASELINE) (HELVETICA 14) ((292.7592 103.102 77.59999 11.87755)) NIL)) ((.04944955 11.86789 NIL) (TEXT (280.0 . 60.80001) ("MOVEFILE Frame") .988991 (LEFT BASELINE) (HELVETICA 10) ((279.512 58.52661 107.8 11.86789)) NIL)) ((.0496 56.80001 NIL) (BOX (273.6 22.4 113.6 49.6) 2)) ((.03925926 11.77778 NIL) (TEXT (228.8 . 41.60001) ("Bottom" "Frame") .7851851 (LEFT BASELINE) (HELVETICA 14) ((228.7407 45.05185 42.4 11.77778) (228.7407 33.27408 36.9037 11.77778)) NIL)) ((.03975308 11.92592 NIL) (TEXT (280.0 . 41.60001) ( "(FromFile Old.Lisp)") .7950617 (LEFT BASELINE) (HELVETICA 14) ((280.2074 39.05679 128.8 11.92592)) NIL)) ((.04946903 11.87257 NIL) (TEXT (280.0 . 28.8) ("(ToFile New.Lisp)") .9893806 (LEFT BASELINE) (HELVETICA 10) ((279.6 26.88318 111.8 11.87257)) NIL))) (0 0 417.0 328.0) 1.0 8.0 The stack implements a first-in/last-out access scheme. If we add Frame X to the bottom of the stack and subsequently add N more frames to the bottom of the stack, then we have to remove the last N frames before we can remove Frame X. The analogy is to a stack of boxes. To remove the Nth box down in the stack, you have to first remove the N-1 boxes sitting on top of that box. (Contrast the stack with the queue data structure in Homework #32, which implemented a first-in/first-out access scheme.) Variable Binding Every time the Lisp evaluator evaluates a new function call, APPLY creates a new stack frame and adds it to the bottom of the Interlisp stack. When APPLY binds the parameters of the function to the arguments of the function call, it simply adds a binding record to this stack frame for each parameter. When APPLY unbinds the parameters at the end, it simply removes this stack frame from the stack. Example: (NIL ((.05 15.0 NIL) (TEXT (312.0 . 376.0) ( "Evaluating the function call: (MOVEFILE 'Old.Lisp 'New.Lisp)" "") 1.0 (CENTER BASELINE) ( HELVETICA 14 (BOLD REGULAR REGULAR)) ((78.0 380.0 469.0 15.0) (312.0 365.0 0.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (128.0 . 328.0) ("Stack Before APPLY" "") 1.0 (CENTER BASELINE) ( HELVETICA 14 (BOLD REGULAR REGULAR)) ((50.0 332.0 157.0 15.0) (128.0 317.0 0.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (64.0 256.0 143.0 63.0) 2)) ((.05 15.0 NIL) (TEXT (80.0 . 288.0) ( "(FOO 5)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((80.0 285.0 77.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (224.0 . 280.0) ("Top" "Frame") 1.0 (LEFT BASELINE) (HELVETICA 14) ((224.0 284.0 30.0 15.0) (224.0 269.0 47.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (80.0 . 272.0) ( "(BAR 7)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((80.0 269.0 75.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (64.0 184.0 143.0 63.0) 2)) ((.05 15.0 NIL) (TEXT (88.0 . 216.0) ("(FOO 6)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((88.0 213.0 72.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT ( 88.0 . 200.0) ("(BAZ 88)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((88.0 197.0 83.0 15.0)) NIL )) ((.05 15.0 NIL) (TEXT (88.0 . 144.0) ("(SUMX 12)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((88.0 141.0 98.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (88.0 . 128.0) ("(ITEM A)") 1.0 ( LEFT BASELINE) (HELVETICA 14) ((88.0 125.0 88.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (64.0 112.0 143.0 63.0) 2)) ((.05 15.0 NIL) (TEXT (216.0 . 64.0) ("Bottom" "Frame") 1.0 (LEFT BASELINE) (HELVETICA 14) ((216.0 68.0 54.0 15.0) (216.0 53.0 47.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (280.0 . 64.0) ("(FromFile Old.Lisp)") 1.0 (LEFT BASELINE) (HELVETICA 14) (( 280.0 61.0 162.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (272.0 40.0 143.0 63.0) 2)) ((.05 15.0 NIL) (TEXT (16.0 . 280.0) ("Top" "Frame") 1.0 (LEFT BASELINE) (HELVETICA 14) ((16.0 284.0 30.0 15.0) (16.0 269.0 47.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (8.0 . 136.0) ("Bottom" "Frame") 1.0 (LEFT BASELINE) (HELVETICA 14) ((8.0 140.0 54.0 15.0) (8.0 125.0 47.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (344.0 . 336.0) ("Stack During APPLY") 1.0 (CENTER BASELINE) ( HELVETICA 14 (BOLD REGULAR REGULAR)) ((265.0 333.0 159.0 15.0)) NIL)) ((.0625 15.0 NIL) (TEXT (280.0 . 88.0) ("MOVEFILE Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((280.25 85.75 136.25 15.0)) NIL)) ((.0625 15.0 NIL) (TEXT (280.0 . 48.0) ("(ToFile New.Lisp)") 1.25 (LEFT BASELINE) (HELVETICA 10) ((280.25 45.75 141.25 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (552.0 . 328.0) ("Stack After APPLY" "") 1.0 (CENTER BASELINE) (HELVETICA 14 (BOLD REGULAR REGULAR)) (( 481.0 332.0 143.0 15.0) (552.0 317.0 0.0 15.0)) NIL)) ((.0625 15.0 NIL) (TEXT (72.0 . 304.0) ("FOO Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((71.5 301.25 86.25 15.0)) NIL)) (( .0625 15.0 NIL) (TEXT (72.0 . 232.0) ("XYZ Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((71.5 230.0 85.0 15.0)) NIL)) ((.0625 15.0 NIL) (TEXT (72.0 . 160.0) ("ZAP Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((71.5 157.5 83.75 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (288.0 . 288.0) ("(FOO 5)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((288.0 285.0 77.0 15.0)) NIL)) (( .0625 15.0 NIL) (TEXT (280.0 . 304.0) ("FOO Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) (( 279.5 301.25 86.25 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (288.0 . 272.0) ("(BAR 7)") 1.0 ( LEFT BASELINE) (HELVETICA 14) ((288.0 269.0 75.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (272.0 256.0 143.0 63.0) 2)) ((.0625 15.0 NIL) (TEXT (280.0 . 232.0) ("XYZ Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((279.5 230.0 85.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (296.0 . 216.0) ("(FOO 6)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((296.0 213.0 72.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (296.0 . 200.0) ("(BAZ 88)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((296.0 197.0 83.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (272.0 184.0 143.0 63.0) 2)) ((.0625 15.0 NIL ) (TEXT (280.0 . 160.0) ("ZAP Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((279.5 157.5 83.75 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (296.0 . 144.0) ("(SUMX 12)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((296.0 141.0 98.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (296.0 . 128.0) ( "(ITEM A)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((296.0 125.0 88.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (272.0 112.0 143.0 63.0) 2)) ((.05 15.0 NIL) (TEXT (440.0 . 280.0) ("Top" "Frame") 1.0 (LEFT BASELINE) (HELVETICA 14) ((440.0 284.0 30.0 15.0) (440.0 269.0 47.0 15.0 )) NIL)) ((.0625 15.0 NIL) (TEXT (496.0 . 304.0) ("FOO Frame") 1.25 (LEFT BASELINE) ( HELVETICA 10) ((495.5 301.25 86.25 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (504.0 . 288.0) ( "(FOO 5)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((504.0 285.0 77.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (504.0 . 272.0) ("(BAR 7)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((504.0 269.0 75.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (488.0 256.0 143.0 63.0) 2)) ((.0625 15.0 NIL) ( TEXT (496.0 . 232.0) ("XYZ Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((495.5 230.0 85.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (488.0 184.0 143.0 63.0) 2)) ((.063 71.5 NIL) (BOX ( 488.0 112.0 143.0 63.0) 2)) ((.05 15.0 NIL) (TEXT (432.0 . 136.0) ("Bottom" "Frame") 1.0 ( LEFT BASELINE) (HELVETICA 14) ((432.0 140.0 54.0 15.0) (432.0 125.0 47.0 15.0)) NIL)) (( .0625 15.0 NIL) (TEXT (496.0 . 160.0) ("ZAP Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) (( 495.5 157.5 83.75 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (512.0 . 128.0) ("(ITEM A)") 1.0 ( LEFT BASELINE) (HELVETICA 14) ((512.0 125.0 88.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (512.0 . 144.0) ("(SUMX 12)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((512.0 141.0 98.0 15.0)) NIL)) ( (.05 15.0 NIL) (TEXT (512.0 . 200.0) ("(BAZ 88)") 1.0 (LEFT BASELINE) (HELVETICA 14) (( 512.0 197.0 83.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (512.0 . 216.0) ("(FOO 6)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((512.0 213.0 72.0 15.0)) NIL))) (0 0 633.75 405.0) 1.25 8.0 Looking up the Value of a Variable After binding all of the parameters, APPLY calls EVAL on each S-expression in the function body. These S-expression often refer to variables. Example: Inside the body of MOVEFILE is the S-expression (COPYFILE FromFile ToFile), which refers to 2 variables FromFile and ToFile. EVALualting these S-expressions involves EVALuating these variables. Looking at EVAL, evaluating a variable (i.e., a NLISTP) involves a function, LookUpValue, that looks up the value of the variable. The LookUpValue function works as follows: Starting at the bottom of the stack, search each stack frame for a binding record with a variable name EQ to the variable being looked up. Return the value associated with the FIRST such binding record found on the stack. If there is no binding record on the stack, then get the value attached to the atom with the same name as the variable being looked up. If the atom has no value, then break with an "unbound atom" error. Examples: Given the following stack and atom values: (NIL ((.05 15.0 NIL) (TEXT (24.0 . 256.0) ("Top" "Frame") 1.0 (LEFT BASELINE) (HELVETICA 14) ((24.0 260.0 30.0 15.0) (24.0 245.0 47.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (16.0 . 40.0 ) ("Bottom" "Frame") 1.0 (LEFT BASELINE) (HELVETICA 14) ((16.0 44.0 54.0 15.0) (16.0 29.0 47.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (80.0 . 40.0) ("(FromFile Old.Lisp)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((80.0 37.0 162.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (72.0 16.0 143.0 63.0) 2)) ((.05 15.0 NIL) (TEXT (144.0 . 312.0) ("Stack") 1.0 (CENTER BASELINE) ( HELVETICA 14 (BOLD REGULAR REGULAR)) ((123.0 309.0 43.0 15.0)) NIL)) ((.0625 15.0 NIL) (TEXT (80.0 . 64.0) ("MOVEFILE Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((80.25 61.75 136.25 15.0)) NIL)) ((.0625 15.0 NIL) (TEXT (80.0 . 24.0) ("(ToFile New.Lisp)") 1.25 (LEFT BASELINE) (HELVETICA 10) ((80.25 21.75 141.25 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (88.0 . 264.0) ("(FOO 5)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((88.0 261.0 77.0 15.0)) NIL)) (( .0625 15.0 NIL) (TEXT (80.0 . 280.0) ("FOO Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((79.5 277.25 86.25 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (88.0 . 248.0) ("(BAR 7)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((88.0 245.0 75.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (72.0 232.0 143.0 63.0) 2)) ((.0625 15.0 NIL) (TEXT (80.0 . 208.0) ("XYZ Frame") 1.25 (LEFT BASELINE) ( HELVETICA 10) ((79.5 206.0 85.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (96.0 . 192.0) ( "(FOO 6)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((96.0 189.0 72.0 15.0)) NIL)) ((.05 15.0 NIL ) (TEXT (96.0 . 176.0) ("(BAZ 88)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((96.0 173.0 83.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (72.0 160.0 143.0 63.0) 2)) ((.0625 15.0 NIL) (TEXT ( 80.0 . 136.0) ("ZAP Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((79.5 133.5 83.75 15.0)) NIL )) ((.05 15.0 NIL) (TEXT (96.0 . 120.0) ("(SUMX 12)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((96.0 117.0 98.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (96.0 . 104.0) ("(ITEM A)") 1.0 ( LEFT BASELINE) (HELVETICA 14) ((96.0 101.0 88.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (72.0 88.0 143.0 63.0) 2)) ((.0625 15.0 NIL) (TEXT (280.0 . 256.0) ("XYZ") 1.25 (CENTER BASELINE) (HELVETICA 12 (MEDIUM REGULAR REGULAR)) ((261.25 252.5 38.75 16.25)) NIL)) ((.0625 15.0 NIL) (TEXT (360.0 . 256.0) ("567") 1.25 (CENTER BASELINE) (HELVETICA 12 (MEDIUM REGULAR REGULAR)) ( (343.75 252.5 33.75 16.25)) NIL)) ((0.0 20.0 NIL) (WIRE ((304.0 . 256.0) (344.0 . 256.0)) 2 (NIL (LINE 30.0 15.0)) NIL))) (0 0 437.5 340.0) 1.25 8.0 (LookUpValue 'FromFile) would return Old.Lisp (LookUpValue 'FOO) would return 6 (LookUpValue 'BAR) would return 7 (LookUpValue 'XYZ) would return 567 (LookUpValue 'PRQ) would return u.b.a. error Setting the Value of a Variable Within a function body being processed by APPLY, the SET functions work in a manner analogous to variable lookup. In particular, (SETQQ Variable Value) will search up the stack starting at the bottom for a binding record for the variable Variable. If it finds one, it will change the value portion of this binding record to be Value. If no binding record is found on the stack, then SETQQ will set the value of the atom Variable. SET and SETQ work analogously. Examples of variable setting: All of the following assume that the SET statement is part of the MOVEFILE function definition. (NIL ((.05 15.0 NIL) (TEXT (240.0 . 376.0) ("Evaluating: (SETQQ FromFile XYZZY)" "") 1.0 ( CENTER BASELINE) (HELVETICA 14 (BOLD REGULAR REGULAR)) ((95.0 380.0 291.0 15.0) (240.0 365.0 0.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (256.0 . 64.0) ("Bottom" "Frame") 1.0 (LEFT BASELINE) (HELVETICA 14) ((256.0 68.0 54.0 15.0) (256.0 53.0 47.0 15.0)) NIL)) ((.05 15.0 NIL) ( TEXT (320.0 . 64.0) ("(FromFile XYZZY)") 1.0 (LEFT BASELINE) (HELVETICA 14 (BOLD REGULAR REGULAR)) ((320.0 61.0 153.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (312.0 40.0 143.0 63.0) 2)) ((.05 15.0 NIL) (TEXT (384.0 . 336.0) ("Stack After SETQQ") 1.0 (CENTER BASELINE) (HELVETICA 14 (BOLD REGULAR REGULAR)) ((311.0 333.0 147.0 15.0)) NIL)) ((.0625 15.0 NIL) (TEXT (320.0 . 88.0) ("MOVEFILE Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((320.25 85.75 136.25 15.0)) NIL)) ((.0625 15.0 NIL) (TEXT (320.0 . 48.0) ("(ToFile New.Lisp)") 1.25 (LEFT BASELINE) ( HELVETICA 10) ((320.25 45.75 141.25 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (328.0 . 288.0) ( "(FOO 5)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((328.0 285.0 77.0 15.0)) NIL)) ((.0625 15.0 NIL) (TEXT (320.0 . 304.0) ("FOO Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((319.5 301.25 86.25 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (328.0 . 272.0) ("(BAR 7)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((328.0 269.0 75.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (312.0 256.0 143.0 63.0) 2)) ((.0625 15.0 NIL) (TEXT (320.0 . 232.0) ("XYZ Frame") 1.25 (LEFT BASELINE) ( HELVETICA 10) ((319.5 230.0 85.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (336.0 . 216.0) ( "(FOO 6)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((336.0 213.0 72.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (336.0 . 200.0) ("(BAZ 88)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((336.0 197.0 83.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (312.0 184.0 143.0 63.0) 2)) ((.0625 15.0 NIL) ( TEXT (320.0 . 160.0) ("ZAP Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((319.5 157.5 83.75 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (336.0 . 144.0) ("(SUMX 12)") 1.0 (LEFT BASELINE) ( HELVETICA 14) ((336.0 141.0 98.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (336.0 . 128.0) ( "(ITEM A)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((336.0 125.0 88.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (312.0 112.0 143.0 63.0) 2)) ((.05 15.0 NIL) (TEXT (264.0 . 280.0) ("Top" "Frame") 1.0 (LEFT BASELINE) (HELVETICA 14) ((264.0 284.0 30.0 15.0) (264.0 269.0 47.0 15.0 )) NIL)) ((.05 15.0 NIL) (TEXT (16.0 . 280.0) ("Top" "Frame") 1.0 (LEFT BASELINE) (HELVETICA 14) ((16.0 284.0 30.0 15.0) (16.0 269.0 47.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (80.0 . 272.0) ("(BAR 7)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((80.0 269.0 75.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (80.0 . 288.0) ("(FOO 5)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((80.0 285.0 77.0 15.0)) NIL)) ((.0625 15.0 NIL) (TEXT (72.0 . 304.0) ("FOO Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((71.5 301.25 86.25 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (136.0 . 336.0) ("Stack Before SETQQ") 1.0 (CENTER BASELINE) (HELVETICA 14 (BOLD REGULAR REGULAR)) ((56.0 333.0 161.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (64.0 256.0 143.0 63.0) 2)) ((.063 71.5 NIL) (BOX (64.0 184.0 143.0 63.0) 2)) ((.0625 15.0 NIL) (TEXT (72.0 . 232.0) ("XYZ Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((71.5 230.0 85.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT ( 88.0 . 216.0) ("(FOO 6)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((88.0 213.0 72.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (88.0 . 200.0) ("(BAZ 88)") 1.0 (LEFT BASELINE) (HELVETICA 14) (( 88.0 197.0 83.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (64.0 112.0 143.0 63.0) 2)) ((.0625 15.0 NIL) (TEXT (72.0 . 160.0) ("ZAP Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((71.5 157.5 83.75 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (88.0 . 144.0) ("(SUMX 12)") 1.0 (LEFT BASELINE ) (HELVETICA 14) ((88.0 141.0 98.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (88.0 . 128.0) ( "(ITEM A)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((88.0 125.0 88.0 15.0)) NIL)) ((.0625 15.0 NIL) (TEXT (72.0 . 88.0) ("MOVEFILE Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((72.25 85.75 136.25 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (8.0 . 64.0) ("Bottom" "Frame") 1.0 (LEFT BASELINE) (HELVETICA 14) ((8.0 68.0 54.0 15.0) (8.0 53.0 47.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (72.0 . 64.0) ("(FromFile Old.Lisp)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((72.0 61.0 162.0 15.0)) NIL)) ((.0625 15.0 NIL) (TEXT (72.0 . 48.0) ("(ToFile New.Lisp)") 1.25 ( LEFT BASELINE) (HELVETICA 10) ((72.25 45.75 141.25 15.0)) NIL)) ((.063 71.5 NIL) (BOX (64.0 40.0 143.0 63.0) 2))) (0 0 478.75 400.0) 1.25 8.0 (NIL ((.05 15.0 NIL) (TEXT (240.0 . 376.0) ("Evaluating: (SETQQ FOO (A B C))" "") 1.0 (CENTER BASELINE) (HELVETICA 14 (BOLD REGULAR REGULAR)) ((109.0 380.0 262.0 15.0) (240.0 365.0 0.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (256.0 . 64.0) ("Bottom" "Frame") 1.0 (LEFT BASELINE) ( HELVETICA 14) ((256.0 68.0 54.0 15.0) (256.0 53.0 47.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (320.0 . 64.0) ("(FromFile XYZZY)") 1.0 (LEFT BASELINE) (HELVETICA 14 (MEDIUM REGULAR REGULAR )) ((320.0 61.0 153.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (312.0 40.0 143.0 63.0) 2)) ((.05 15.0 NIL) (TEXT (384.0 . 336.0) ("Stack After SETQQ") 1.0 (CENTER BASELINE) (HELVETICA 14 ( BOLD REGULAR REGULAR)) ((311.0 333.0 147.0 15.0)) NIL)) ((.0625 15.0 NIL) (TEXT (320.0 . 88.0 ) ("MOVEFILE Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((320.25 85.75 136.25 15.0)) NIL)) ( (.0625 15.0 NIL) (TEXT (320.0 . 48.0) ("(ToFile New.Lisp)") 1.25 (LEFT BASELINE) (HELVETICA 10) ((320.25 45.75 141.25 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (328.0 . 288.0) ("(FOO 5)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((328.0 285.0 77.0 15.0)) NIL)) ((.0625 15.0 NIL) (TEXT (320.0 . 304.0) ("FOO Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((319.5 301.25 86.25 15.0) ) NIL)) ((.05 15.0 NIL) (TEXT (328.0 . 272.0) ("(BAR 7)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((328.0 269.0 75.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (312.0 256.0 143.0 63.0) 2)) (( .0625 15.0 NIL) (TEXT (320.0 . 232.0) ("XYZ Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) (( 319.5 230.0 85.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (336.0 . 216.0) ("(FOO (A B C))") 1.0 (LEFT BASELINE) (HELVETICA 14 (BOLD REGULAR REGULAR)) ((336.0 213.0 119.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (336.0 . 200.0) ("(BAZ 88)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((336.0 197.0 83.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (312.0 184.0 143.0 63.0) 2)) ((.0625 15.0 NIL ) (TEXT (320.0 . 160.0) ("ZAP Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((319.5 157.5 83.75 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (336.0 . 144.0) ("(SUMX 12)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((336.0 141.0 98.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (336.0 . 128.0) ( "(ITEM A)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((336.0 125.0 88.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (312.0 112.0 143.0 63.0) 2)) ((.05 15.0 NIL) (TEXT (264.0 . 280.0) ("Top" "Frame") 1.0 (LEFT BASELINE) (HELVETICA 14) ((264.0 284.0 30.0 15.0) (264.0 269.0 47.0 15.0 )) NIL)) ((.05 15.0 NIL) (TEXT (16.0 . 280.0) ("Top" "Frame") 1.0 (LEFT BASELINE) (HELVETICA 14) ((16.0 284.0 30.0 15.0) (16.0 269.0 47.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (80.0 . 272.0) ("(BAR 7)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((80.0 269.0 75.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (80.0 . 288.0) ("(FOO 5)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((80.0 285.0 77.0 15.0)) NIL)) ((.0625 15.0 NIL) (TEXT (72.0 . 304.0) ("FOO Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((71.5 301.25 86.25 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (136.0 . 336.0) ("Stack Before SETQQ") 1.0 (CENTER BASELINE) (HELVETICA 14 (BOLD REGULAR REGULAR)) ((56.0 333.0 161.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (64.0 256.0 143.0 63.0) 2)) ((.063 71.5 NIL) (BOX (64.0 184.0 143.0 63.0) 2)) ((.0625 15.0 NIL) (TEXT (72.0 . 232.0) ("XYZ Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((71.5 230.0 85.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT ( 88.0 . 216.0) ("(FOO 6)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((88.0 213.0 72.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (88.0 . 200.0) ("(BAZ 88)") 1.0 (LEFT BASELINE) (HELVETICA 14) (( 88.0 197.0 83.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (64.0 112.0 143.0 63.0) 2)) ((.0625 15.0 NIL) (TEXT (72.0 . 160.0) ("ZAP Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((71.5 157.5 83.75 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (88.0 . 144.0) ("(SUMX 12)") 1.0 (LEFT BASELINE ) (HELVETICA 14) ((88.0 141.0 98.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (88.0 . 128.0) ( "(ITEM A)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((88.0 125.0 88.0 15.0)) NIL)) ((.0625 15.0 NIL) (TEXT (72.0 . 88.0) ("MOVEFILE Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((72.25 85.75 136.25 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (8.0 . 64.0) ("Bottom" "Frame") 1.0 (LEFT BASELINE) (HELVETICA 14) ((8.0 68.0 54.0 15.0) (8.0 53.0 47.0 15.0)) NIL)) ((.0625 15.0 NIL ) (TEXT (72.0 . 48.0) ("(ToFile New.Lisp)") 1.25 (LEFT BASELINE) (HELVETICA 10) ((72.25 45.75 141.25 15.0)) NIL)) ((.063 71.5 NIL) (BOX (64.0 40.0 143.0 63.0) 2)) ((.05 15.0 NIL) (TEXT (72.0 . 64.0) ("(FromFile XYZZY)") 1.0 (LEFT BASELINE) (HELVETICA 14 (MEDIUM REGULAR REGULAR)) ((72.0 61.0 153.0 15.0)) NIL))) (0 0 478.75 400.0) 1.25 8.0 (NIL ((.05 15.0 NIL) (TEXT (240.0 . 512.0) ("Evaluating: (SETQ XYZ 9995)" "") 1.0 (CENTER BASELINE) (HELVETICA 14 (BOLD REGULAR REGULAR)) ((127.0 516.0 226.0 15.0) (240.0 501.0 0.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (256.0 . 200.0) ("Bottom" "Frame") 1.0 (LEFT BASELINE) ( HELVETICA 14) ((256.0 204.0 54.0 15.0) (256.0 189.0 47.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (320.0 . 200.0) ("(FromFile XYZZY)") 1.0 (LEFT BASELINE) (HELVETICA 14 (MEDIUM REGULAR REGULAR)) ((320.0 197.0 153.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (312.0 176.0 143.0 63.0) 2 )) ((.05 15.0 NIL) (TEXT (384.0 . 472.0) ("Stack After SETQ") 1.0 (CENTER BASELINE) ( HELVETICA 14 (BOLD REGULAR REGULAR)) ((317.0 469.0 134.0 15.0)) NIL)) ((.0625 15.0 NIL) (TEXT (320.0 . 224.0) ("MOVEFILE Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((320.25 221.75 136.25 15.0)) NIL)) ((.0625 15.0 NIL) (TEXT (320.0 . 184.0) ("(ToFile New.Lisp)") 1.25 (LEFT BASELINE) (HELVETICA 10) ((320.25 181.75 141.25 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (328.0 . 424.0) ("(FOO 5)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((328.0 421.0 77.0 15.0)) NIL)) (( .0625 15.0 NIL) (TEXT (320.0 . 440.0) ("FOO Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) (( 319.5 437.25 86.25 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (328.0 . 408.0) ("(BAR 7)") 1.0 ( LEFT BASELINE) (HELVETICA 14) ((328.0 405.0 75.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (312.0 392.0 143.0 63.0) 2)) ((.0625 15.0 NIL) (TEXT (320.0 . 368.0) ("XYZ Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((319.5 366.0 85.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (336.0 . 352.0) ("(FOO (A B C))") 1.0 (LEFT BASELINE) (HELVETICA 14 (MEDIUM REGULAR REGULAR)) ((336.0 349.0 119.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (336.0 . 336.0) ("(BAZ 88)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((336.0 333.0 83.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (312.0 320.0 143.0 63.0) 2)) ((.0625 15.0 NIL) (TEXT (320.0 . 296.0) ("ZAP Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((319.5 293.5 83.75 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (336.0 . 280.0) ( "(SUMX 12)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((336.0 277.0 98.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (336.0 . 264.0) ("(ITEM A)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((336.0 261.0 88.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (312.0 248.0 143.0 63.0) 2)) ((.05 15.0 NIL) ( TEXT (264.0 . 416.0) ("Top" "Frame") 1.0 (LEFT BASELINE) (HELVETICA 14) ((264.0 420.0 30.0 15.0) (264.0 405.0 47.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (16.0 . 416.0) ("Top" "Frame") 1.0 (LEFT BASELINE) (HELVETICA 14) ((16.0 420.0 30.0 15.0) (16.0 405.0 47.0 15.0)) NIL)) (( .05 15.0 NIL) (TEXT (80.0 . 408.0) ("(BAR 7)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((80.0 405.0 75.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (80.0 . 424.0) ("(FOO 5)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((80.0 421.0 77.0 15.0)) NIL)) ((.0625 15.0 NIL) (TEXT (72.0 . 440.0) ("FOO Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((71.5 437.25 86.25 15.0)) NIL)) (( .05 15.0 NIL) (TEXT (136.0 . 472.0) ("Stack Before SETQ") 1.0 (CENTER BASELINE) (HELVETICA 14 (BOLD REGULAR REGULAR)) ((62.0 469.0 148.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (64.0 392.0 143.0 63.0) 2)) ((.063 71.5 NIL) (BOX (64.0 320.0 143.0 63.0) 2)) ((.0625 15.0 NIL) (TEXT (72.0 . 368.0) ("XYZ Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((71.5 366.0 85.0 15.0)) NIL )) ((.05 15.0 NIL) (TEXT (88.0 . 336.0) ("(BAZ 88)") 1.0 (LEFT BASELINE) (HELVETICA 14) ( (88.0 333.0 83.0 15.0)) NIL)) ((.063 71.5 NIL) (BOX (64.0 248.0 143.0 63.0) 2)) ((.0625 15.0 NIL) (TEXT (72.0 . 296.0) ("ZAP Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((71.5 293.5 83.75 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (88.0 . 280.0) ("(SUMX 12)") 1.0 (LEFT BASELINE ) (HELVETICA 14) ((88.0 277.0 98.0 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (88.0 . 264.0) ( "(ITEM A)") 1.0 (LEFT BASELINE) (HELVETICA 14) ((88.0 261.0 88.0 15.0)) NIL)) ((.0625 15.0 NIL) (TEXT (72.0 . 224.0) ("MOVEFILE Frame") 1.25 (LEFT BASELINE) (HELVETICA 10) ((72.25 221.75 136.25 15.0)) NIL)) ((.05 15.0 NIL) (TEXT (8.0 . 200.0) ("Bottom" "Frame") 1.0 ( LEFT BASELINE) (HELVETICA 14) ((8.0 204.0 54.0 15.0) (8.0 189.0 47.0 15.0)) NIL)) ((.0625 15.0 NIL) (TEXT (72.0 . 184.0) ("(ToFile New.Lisp)") 1.25 (LEFT BASELINE) (HELVETICA 10) (( 72.25 181.75 141.25 15.0)) NIL)) ((.063 71.5 NIL) (BOX (64.0 176.0 143.0 63.0) 2)) ((.05 15.0 NIL) (TEXT (72.0 . 200.0) ("(FromFile XYZZY)") 1.0 (LEFT BASELINE) (HELVETICA 14 ( MEDIUM REGULAR REGULAR)) ((72.0 197.0 153.0 15.0)) NIL)) ((.0625 15.0 NIL) (TEXT (136.0 . 112.0) ("Atoms" "Before SETQ") 1.25 (CENTER BASELINE) (HELVETICA 10 (BOLD REGULAR REGULAR)) (( 112.5 116.0 47.5 16.25) (90.0 99.75 92.5 16.25)) NIL)) ((.0625 15.0 NIL) (TEXT (88.0 . 48.0) ("XYZ") 1.25 (CENTER BASELINE) (HELVETICA 12 (BOLD REGULAR REGULAR)) ((71.75 44.75 33.75 17.5)) NIL)) ((0.0 24.0 NIL) (WIRE ((112.0 . 56.0) (160.0 . 56.0)) 2 (NIL (LINE 30.0 15.0 )) NIL)) ((.0625 15.0 NIL) (TEXT (184.0 . 48.0) ("678") 1.25 (CENTER BASELINE) (HELVETICA 12 (BOLD REGULAR REGULAR)) ((167.25 44.75 33.75 17.5)) NIL)) ((.05 15.0 NIL) (TEXT (88.0 . 352.0) ("(FOO (A B C))") 1.0 (LEFT BASELINE) (HELVETICA 14 (MEDIUM REGULAR REGULAR)) ((88.0 349.0 119.0 15.0)) NIL)) ((.0625 15.0 NIL) (TEXT (384.0 . 120.0) ("Atoms" "After SETQ") 1.25 (CENTER BASELINE) (HELVETICA 10 (BOLD REGULAR REGULAR)) ((360.0 123.5 47.5 16.25) (342.5 107.25 83.75 16.25)) NIL)) ((0.0 24.0 NIL) (WIRE ((360.0 . 64.0) (408.0 . 64.0)) 2 (NIL ( LINE 30.0 15.0)) NIL)) ((.0625 15.0 NIL) (TEXT (336.0 . 56.0) ("XYZ") 1.25 (CENTER BASELINE) (HELVETICA 12 (BOLD REGULAR REGULAR)) ((319.75 52.75 33.75 17.5)) NIL)) ((.0625 15.0 NIL) ( TEXT (432.0 . 56.0) ("9995") 1.25 (CENTER BASELINE) (HELVETICA 12 (BOLD REGULAR REGULAR)) (( 410.0 52.25 45.0 17.5)) NIL))) (0 0 505.0 548.5) 1.25 8.0 Function Definition Lookup There is no such thing as binding a function name in Interlisp. All function names in Interlisp refer to the function definition attached to the atom of the same name. The function GetFunctionDefn in the definition of APPLY simply accesses the function definition for the named atom. In particular, it does not search the stack for new bindings of the function name. Note: This is different in other dialects of Lisp. Some Lisps allow binding of function names as well as variables names on the stack. Variable Reference in Practice: LET and PROG are used to bind variables Avoid Free Variables! In practice the rule is: Bound variables are good, free variables are bad. The effect of evaluating a function with bound variables is always predictable. In contrast, evaluating a function that uses free variables can lead to differing results, depending on the context of the evaluation. Examples: Interference between variable names 1_ (DEFINEQ (Circumference (LAMBDA (Radius) (TIMES 2 PI Radius)))) (Circumference) 2_ (SETQ PI 3.1416) 3.1416 3_ (DEFINEQ (MakeProgrammersInterface (LAMBDA NIL (SETQ PI (CREATE ProgInt ....))))) (MakeProgrammersInterface) 4_ (MakeProgrammersInterface) {ProgInt}#32,33412 5_ (Circumference 5) NON-NUMBERIC ARG {ProgInt}#32,33412 Inadvertantly altering system parameters 6_ (DEFINEQ (FontNameToFontNumber (LAMBDA (FontName) (SETQ DEFAULTFONT 1) (FOR Name in '(Helvetica TimesRoman Gacha Modern) AS Number FROM 1 WHEN (EQ FontName Name) DO (SETQ DEFAULTFONT Number)) DEFAULTFONT) (FontNameToFontNumber ) 7_ (FontNameToFontNumber 'Gacha) 3 8_ (TEDIT "XXXXXX") ILLEGAL ARG {FONTCLASS}#71,10500 (because DEFAULTFONT has been reset to an illegal value) The Funarg Problem 9_ (DEFINEQ (Sum (LAMBDA (List Transform) (FOR N IN List SUM (APPLY* Transform N))))) (Sum) 10_(DEFINEQ (SumSquares#1 (LAMBDA (List) (Sum List (FUNCTION SQUARE)))) (SumSquares#2 (LAMBDA (List) (SETQ N 2) (Sum List (FUNCTION NthPower)))) (SumCubes (LAMBDA (List) (SETQ N 3) (Sum List (FUNCTION NthPower)))) (NthPower (LAMBDA (X) (EXPT X N)))) (SumSquares#1 SumSquares#2 SumCubes NthPower) 11_ (SumSquares#1 (LIST 1 2 3 4 5)) 55 12_ (SumSquares#2 (LIST 1 2 3 4 5)) 3413 13_ (SumCubes (LIST 1 2 3 4 5)) 3413 The examples illustrate the problems involved in using free variables in defining functions. Because of these problems, it is best to avoid using free variables. The LET Special Form Consider the following function that computes the average of all the numbers in a list of numbers and litatoms: (DEFINEQ (AverageOfNumbers (List) (SETQ Sum 0.0) (SETQ N 0) (FOR Item IN List WHEN (NUMBERP Item) DO (SETQ Sum (PLUS Sum Item)) (SETQ N (ADD1 N))) (COND ((NOT (ZEROP N)) (QUOTIENT Sum N)) (T NIL))))) It would not be possible to write this function without the Sum and N variables, since they are used to store intermediate results as the function iterates through the list. There is no reason, however, for Sum and N to be free variables. Their function should be limited to the scope of the AverageOfNumbers function body. On the other hand, Sum and N are not a parameters either and therefore should not be made into a bound variables by placing them in the parameter list of the function. The LET special form provides the means to bind variables without making them part of the parameter list. LET has the format: (LET BindingList S-Expression1 S-Expression2 ...) BindingList is a list of variable-value pairs, i.e., (VariableName InitialValue). A variable can also be expressed by just its VariableName, which is equivalent to the list (VariableName NIL). The S-Expressioni are arbitrary Lisp S-expressions to be evaluated. LET works as follows: The variables specified in the binding list are bound on the stack and set to the specified initial values. The S-expressions are evaluated in order. The LET form returns the value of the last S-expression, unbinding the variables in the binding list before it exits. Variables in the binding list are bound "in parallel" and thus the order of mention in the binding list is unimportant. If the binding list is ((X 55) (Y X)), the value of X within the LET will be 55 and the value of Y will be whatever was the value of X before the LET (and not 55 as might be expected). The same effect could have been achieved by the binding list ((Y X) (X 55)). The proper defintion for AverageOfList would thus be: (DEFINEQ (AverageOfList (List) (LET ((Sum 0.0)(N 0)) (FOR Item IN List WHEN (NUMBERP Item) DO (SETQ Sum (PLUS Sum Item)) (SETQ N (ADD1 N))) (COND ((NOT (ZEROP N)) (QUOTIENT Sum N)) (T NIL))))) In this definition, List, Sum, and N are all bound variables. When the function is enetered, List is bound since it is in the parameter list. When the LET is entered, Sum and N are bound on the stack and set to their initial values of zero. When the LET is exited, Sum and N are unbound. When the function is exited, List is unbound. As a second example, consider a function (slightly modified) from the solution to Homework#32: (DEFINEQ (LC.PrintQueue (LAMBDA (Q) (COND ((NOT (LC.QueueEmptyP Q)) (SETQ NextPtr (fetch (LC.Queue Head) of Q)) (PRINT (CAR NextPtr)) (until (EQ (SETQ NextPtr (CDR NextPtr)) (fetch (LC.Queue Tail) of Q) DO (PRIN1 (CAR NextPtr))) (TERPRI)))) Note the unnecessary use of NextPtr as free variable. The proper defintion for LC.PrintQueue is: (DEFINEQ (LC.PrintQueue (LAMBDA (Q) (LET (NextPtr) (COND ((NOT (LC.QueueEmptyP Q)) (SETQ NextPtr (fetch (LC.Queue Head) of Q)) (PRINT (CAR NextPtr)) (until (EQ (SETQ NextPtr (CDR NextPtr)) (fetch (LC.Queue Tail) of Q) DO (PRIN1 (CAR NextPtr))) (TERPRI))))) In this definition, NextPtr is bound within the context of the LET statement (and hence within the entire function body). The PROG Special Form The PROG special form is very much like the LET special form, but it allows a little more flexibility in how and when the special form is exited. PROG has the format: (PROG BindingList S-Expression1 S-Expression2 ...) BindingList is as in the LET special form. The S-Expressioni are arbitrary Lisp S-expressions to be evaluated. One or more of these S-expressions may contain a sub-expression of the form (RETURN S-expression) PROG works as follows: The variables specified in the binding list are bound on the stack and set to the specified initial values. The S-expressions are evaluated in order until an expression (or sub-expression) of the form (RETURN S-expression) is evaluated. Evaluating this RETURN expression evaluates the embedded S-expression, then causes the PROG special form to be exited, returning the value of this evaluation. On exit, the variables in the binding list are unbound. If no RETURN statement is encountered while evaluating the S-expressions, PROG unbinds the variables in the binding list and returns NIL. As in LET, variables in the PROG binding list are bound "in parallel" and thus the order of mention in the binding list is unimportant. PROG should be used where one might want to exit at one of several places in a function, depending on certain conditions. For example, the following is a function that transfers a list of numbers to an array and then places the sum of the numbers in the last cell of the array. The program immediately exits with NIL if the Array is not on larger than the length of the list. (DEFINEQ (TransferListToArray (LAMBDA (List Array) (PROG ((LstLen (LENGTH List)) (ArrSize (ARRAYSIZE Array)) (Sum 0.0)) (COND ((OR (ZEROP LstLen)) (NEQ LstLen (SUB1 ArrSize))) (RETURN NIL)) (FOR Item IN List AS Index FROM 1 DO (ELT Array Index Item) (SETQ Sum (PLUS Sum Item))) (ELT Array ArrSize Sum) (RETURN Sum)) FOR and WHILE are implemented using PROG The FOR and WHILE clisp forms are implemented using the PROG special form. An important side-effect of this is that the (RETURN S-expr) form can be used to exit from FOR or WHILE loops before their normal termination. For example, the following will sum the item in a list until a negative number is reached. (DEFINEQ (SumTillMinus (LAMBDA (List) (PROG ((Sum 0.0)) (FOR Item IN List DO (COND ((MINUSP Item)(RETURN NIL))) (SETQ Sum (PLUS Sum Item))) (RETURN Sum))))) In this example, the RETURN inside the FOR loop will exit only out of the PROG implicit in the FOR. It will not exit out of the PROG that contains the FOR loop. This is true for all RETURN statements: each RETURN exits out only the lowest level enclosing PROG and not out of any PROGs that in turn enclose the lowest level PROG. Note also that the previous example, would probably best be written using a LET as follows: (DEFINEQ (SumTilLMinus (LAMBDA (List) (LET ((Sum 0.0)) (FOR Item IN List DO (COND ((MINUSP Item)(RETURN NIL))) (SETQ Sum (PLUS Sum Item))) Sum)))) As another example, the following function takes a list of numbers and returns a list of as many of the initial numbers as necessary to sum to just of 100. If any of the items in the initial list is non-numeric the function exits and returns the bad item. (DEFINEQ (FirstHundred (LAMBDA (List) (LET ((Sum 0.0)) (WHILE (LESSP Sum 100) FOR Item IN List COLLECT (COND ((NOT (NUMBERP Item)) (RETURN Item))) (SETQ Sum (PLUS Sum Item)) Item))))) Note: The RETURN statement inside of a COLLECT loop will cause the COLLECT loop to return with the value of the S-expr in the RETURN clause instead of the list being COLLECTed. 3_ (FirstHundred (LIST 1 2 3 44 55 66 77 88)) (1 2 3 44 55) 4_ (FirstHundred (LIST 1 2 'A 44 55 66 77)) A Global Variables: Free variables used as system or package parameters Free variables are sometimes necessary. In particular, system or package parameters (e.g., DEFAULTPRINTINGHOST, CHAT.FONT, DEFAULTFONT, LAFITEDEFAULTHPOST&DIR, etc.) are set outside of any function (e.g., in an Init file or in the Lisp Exec) but must be used (and sometinmes set) within various system or user functions. These system/package parameters must be globally accessible, i.e., avaialable to all functions in all contexts. Therefore, they cannot be bound on the stack inside of some particular function. When setting or retrieving the value of one of these global parameters, you want to go directly to the value attached to the atom, skipping the search up the stack for other bindings. For example, when a function definition includes the form (SEND.FILE.TO.PRINTER '{DSK}FOO (CAR DEFAULTPRINTINGHOST)), the DEFAULTPRINTINGHOST variable should reference the global value of this variable. If one of the calling functions of this function has stupidly rebound DEFAULTPRINTINGHOST, the rebinding should probably be ignored. The functions GETTOPVAL and SETTOPVAL can be used to directly access the global value of a variable (i.e., the value attached to the atom) skipping the search for rebindings on the stack. GETTOPVAL takes a single LITATOM as an argument and returns the value attached to that LITATOM. SETTOPVAL takes a LITATOM and a value and sets the value of the LITATOM to be value, returning the value. Example: 1_ (SETQ LineLength 107) 107 2_ (DEFINEQ (Tester (LAMBDA NIL (PROG ((LineLength 223)) (PRINT (CONCAT "Initial values: " LineLength " " (GETTOPVAL 'LineLength))) (SETQ LineLength 55) (SETTOPVAL 'LineLength 88) (PRINT (CONCAT "LineLength: " LineLength " TopVal of LineLength: " (GETTOPVAL 'LineLength))))))) (Tester) 3_ (Tester) Initial values: 223 107 LineLength: 55 TopVal of LineLength: 88 NIL References In the IRM: PROG is on Page 4.3. LET is not in the IRM, but is essentially the same as PROG, except for the RETURN and GO features. GETTOPVAL and SETTOPVAL are on page 2.5 Free variables and binding are covered in both Winston & Horn and Touretzky. But be careful. CommonLisp uses a different sort of binding scheme than does Interlisp, so not everything said in these books applies to Interlisp. Look at Chapter 5 of Touretzky and page 53 of Winston and Horn. Also LET is explained starting on page 57 of W&H and on page 250 of T. Exercise Overall Task: Write a simple Lisp evaluator. For each of the functions you write, put a print statement at the ned of the function that prints on the screen some information about what the function just did. This way, you can watch you evaluator in action when it all gets put together. 1. Write a function to do variable binding on a stack. The stack should just be a list: use CONS and CDR to add and remove items. The binding function should take two equal length lists, one of variables and one of values. It should put a marker on the stack (e.g., the litatom MARKER) and then put a binding pair on the stack for each variable and its corresponding value in the lists. 2. Write a function that unbinds variables. It should basically remove items from the stack up to and including the next marker. 3. Write a function that looks up the value of a variable on the binding stack. If its not on the stack, get its top level value using GETTOPVAL. 4. Write a function that sets the value of a variable. If the variable is on the binding stack, then just reset the value in that binding. Otherwise, set its top level value using SETTOPVAL. 5. Rewrite the EVAL and APPLY procedures from the course notes. A. Rename the functions so as not to mess up the original EVAL and APPLY in Interlisp. B. Use your bind, unbind and lookup functions. C. In your apply, if the function name is SET, SETQ, or SETQQ, then use your set value of variable function to carry out the appropriate setting action instead of looking the definition of SET, SETQ, or SETQQ. D. In your apply use GETD to get a function definition. If the value of GETD is a list, then proceed as in the course notes. If the value of GETD is not a list, then assume it is a primitive function and just invoke the standard APPLY function instead of the rest of your apply function. 6. Write a procedure (called CountAtoms) that recursively counts all the atoms in a list. (See page 12 of LispCourse #5). 7. Use your eval to evaluate (CountAtoms '(A (B C D) (E (F (G (H) I) J K) L))) and watch the evaluator in action as it prints out its action summaries. (LIST ((PAGE NIL NIL (0 0 17 22) ((HEADING NIL (HEADINGTYPE YYY) (540 756 72 36) NIL) (TEXT NIL NIL (72 72 468 648) NIL))) (PAGE NIL NIL (0 0 17 22) ((FOLIO NIL (PARALOOKS (QUAD RIGHT) CHARLOOKS (SUPERSCRIPT 0 SIZE 12 FAMILY TIMESROMAN OVERLINE OFF STRIKEOUT OFF UNDERLINE OFF SLOPE REGULAR WEIGHT MEDIUM)) (468 756 72 36) NIL) (HEADING NIL (HEADINGTYPE XXX) (72 756 72 36) NIL) (TEXT NIL NIL (72 72 468 648) NIL))) (PAGE NIL NIL (0 0 17 22) ((FOLIO NIL (PARALOOKS (QUAD RIGHT) CHARLOOKS (SUPERSCRIPT 0 SIZE 12 FAMILY TIMESROMAN OVERLINE OFF STRIKEOUT OFF UNDERLINE OFF SLOPE REGULAR WEIGHT MEDIUM)) (468 756 72 36) NIL) (HEADING NIL (HEADINGTYPE XXX) (72 756 72 36) NIL) (TEXT NIL NIL (72 72 468 648) NIL)))))TH` `HH $$ HHüüŘŘ´´llHH´´´´ŘŘ´´llhh  ´´´´ ŘŘ DDll llŘŘ´´  DD´´  ´´ll  ´´üüllll¨ ¨llHH$$HH$$$$ŘŘ´´llHHHHHH $$ ll$$l„„´´ll  HH $$$$ llHHll llüüŘŘ´´llHH$$ˆ PAGEHEADINGXXXH PAGEHEADINGYYY TIMESROMAN  TIMESROMAN  TIMESROMAN  TIMESROMAN TIMESROMAN TIMESROMAN  TIMESROMAN  TIMESROMAN  TIMESROMAN TIMESROMAN T S: R: Q? EN E 1 6  5   5   <    5 4 3 3   4 3 3    4 3 3   0-    0  X  5 : _  /  M  2 0 ) 7… 7™ F  [ .  ) 7k 7N 5 5] 7ž F  I    ´ =ń - , 4 3 2 2 4 3 2 5< 5< << <C3 HC   + Ź + 7 ™ CÉ E Ep CŽ C_ C Q7 E€ EC   Eg =O| I N M M L  L L  K J H h G. F    F  8 X  G h  DC F N M L  K K  L  K J B  K L L  L  K  L H   G/ FH  5  Fp Fl FN   FM D%O A @ ? ? ? ? O  C ># ># >6 C >! > >Ş >. >, >D > DCY <    ^ G^ QF =L U ; ;]  ;:A 0 I/  9.   :   I&  I*  =Ô SKIO.GETFN.2 TIMESROMAN  G  Hł H‘ :W  =: :  : O : Qc SKIO.GETFN.2 TIMESROMAN  =#: H:    :E :M + :  H‹ HS Hˆ HC : H+ 8 î SKIO.GETFN.2 TIMESROMAN  H I I I I = Gq C W R  FV  F 7F` )™ SKIO.GETFN.2 TIMESROMAN  * *Ď SKIO.GETFN.2 TIMESROMAN  * *Í SKIO.GETFN.2 TIMESROMAN  =G@ Cj C X FS CˆQI G# 1 'P '‡ ( $$" 2 &  33 33 2& &  33 33 33!)" 2) & &2       & %%! 33 3 329!" 2 &, 3 2 & 2 & &! 2 & &! 2 & 3.$ $  (¤ G(p  L K  K  K J J B   B   K J  B   J (<   _   X   Œ , c #        - "  2 j* v x"  ,# =  6  L K   J B B       J B     B !   "P "  A "   ". _ ' 3 3 2 & &  &  &     &  &   + ' 3 3 2  2 & &  &  &     &  & ! _ G( ‰ (         j]   9 “ Š  }z˙ K*JB#BBBBBG)K $ [  K J B B   B  ˘ ¨ \  K J B B   B , ' L K J B B       ˛  . , QH =(PCpIQI¸I:<…,=  —G`Gj=      F^  ,Q P Oy O( Pă O@ OG Q ó8K]¤ƒ”ÂAW/Ň#|1Jŕ)zš