This final part of the assignment expands the program developed in the first three parts to accept function definitions (DEFUN . . . ) and assignment statements (SETQ . . . ).
Examples of use: (here ">" means "user types".)
> (SETQ ABC (QUOTE (A B C ) ) ) (A B C) > (SETQ TWO 2) TWO > (SETQ THREE 3) THREE > (PLUS TWO THREE) 5 > (CONS TWO ABC) (2 A B C)Note that SETQ evaluates its second argument but not its first argument.
( (name1 value1) (name2 value2) . . . (namen valuen) ),where each namei is an alphabetic atom and each valuei is any S-expression. This data structure is called an Association-list or A-list. It is to be interpreted that each name has a corresponding value. At the end of the examples above VARLIST would have the value
( (THREE 3) (TWO 2) (ABC (A B C) ) )Thus evaluating (SETQ N VAL) is accomplished by
At this point, it will be legal to evaluate alphabetic atoms: their values may appear on VARLIST. To evaluate these atoms, write a function GETASSOC that takes a name N and a list of pairs ALIST and returns the first pair (X Y) that occurs on ALIST such that X = N, or NIL if there is no pair on ALIST whose first element is N. The function header should be:
Sp getassoc (Sp N, Sp ALIST); /* returns first occurrence of (N VALUE) or NIL */(Note: it will not do to return just VALUE, instead of the pair. Why?)
(DEFUN MYADD (X Y) (COND ((EQUAL X 0) Y) (T (PLUS 1 (MYADD (MINUS X 1) Y))) )) (SETQ FIVE (MYADD TWO THREE))if used with the earlier SETQ's, should produce the same result as
(SETQ FIVE 5).
( (D 4) (C (A B C)) (A D) )is D; in that environment C has value (A B C) and Q is undefined. In every environment, numeric atoms, T, and NIL have themselves as values, and F has value NIL. EVAL will only handleDEFUN's and SETQ's, while the rest of the work will be done by a new function ENVEVA (=EVAL in an ENVironment).
EVAL(S) now works as follows:
if S is a list with CAR = "DEFUN"
or "SETQ" then
handle it using PUTASSOC as suggested above
else return ENVEVAL(S, VARLIST)
ENVEVAL(S, ALIST) works as follows:
if S is NIL then return NIL> else if S is a number then return S else if S is an alphabetic atom then use GETASSOC(S, ALIST) else if CAR (S) is a user-defined function then begin ENVEVAL the arguments (use ENVEVALARGS); suppose (<funcname> (<varlist> <funcbody>) ) is the result of GETASSOC(CAR (S), FUNCLIST); return ENVEVAL(<funcbody>, NEWALIST), where NEWALIST is the result of LISTPUTASSOC (<varlist>, CDR (S), ALIST) end else if CAR (S) is a builtin function then ENVEVAL the arguments and APPLY the function to the evaluated arguments else ERROR /* undefined function name -- note that SETQ and DEFUN are not allowed here */Note: It's actually not necessary to have the separate EVAL and ENVEVAL, but one can get along with just one. We'll discuss this in class.