The purpose of this assignment is to write a program to interpret S-expressions which do not involve user-defined functions (DEFUN) or values for alphabetic atoms (SETQ). It is assumed that you have a working S-expressions reader/writer that will convert an S-expression into internal (linked list) form, and will convert it back in order to write it out. You will need all of the functions you wrote for the previous assignments along with a few more.
Some of the objectives of the assignment are to emphasize modular programming, to practice using list structures and pointers in developing an interpreter for the Lisp primitives, and to introduce you to a functional programming style within a block-structured language. For this assignment it will help if you write code that resembles Lisp itself. Thus you should only write functions that return pointers to S-expressions. There should be no assignment statements or iterative statements, and heavy use should be made of recursion. The final result will be similar in many ways to a Lisp interpreter written in Lisp.
The main loop of your program should now be:
For step 2, remember the way Lisp works:
To implement step 3b: Think recursively! If your function that evaluates is called EVAL, it should have a (two or three line) subfunction EVALARGS that EVAL's a list of S-expressions, returning a list of their values.
To implement step 3c: Write a function APPLY that takes as arguments the function from step 3a and the list from step 3b, and carries out the intent of the function on the list. (APPLY does the actual work.)
You need not worry about the abbreviated syntax for QUOTE, e.g. '(A B C) is not legal input; however, (QUOTE (A B C)) is legal and has value (A B C). Remember that QUOTE does not evaluate its argument, so EVAL will handle it separately.
EVAL will also handle EXIT and COND separately (as well as DEFUN and SETQ in the next assignment). To evaluate a COND expression note that the value of
(COND (t1 e1) (t2 e2) . . . (tn en))is:
if ((t1 e1) (t2 e2) . . . (tn en)) = () i.e. n = 0 then
return NIL
else if the value of t1 <> NIL then return
the value of e1
else return the value of (COND (t2 e2) . . . (tn en)).
Note: Once we get a non-null value for one of the t's, no subsequent ti or ei is evaluated. You may handle COND in this assignment or the next.
One convenient way to handle errors now is to redefine ERR as a function that always returns NIL. Thus when an error is detected, you can return something like ERR(14).
As far a modularity goes you should bear in mind that you will want to expand your program to deal with SETQ and DEFUN later. Therefore make your program modular and easy to change. It is partly for this reason that there are parts 3 and 4 of the Lisp interpreter project: simply handing in the final interpreter, even if it works, will not completely satisfy the course requirements.
What to turn in: A listing, overview documentation, and results of a sample run. You should demonstrate the full capabilities of your interpreter, including deeply nested arithmetic expressions, such as
(PLUS (TIMES 3 (PLUS 5 1)) (QUOTIENT (TIMES 12 3) (PLUS 7 5))),yielding 21, and complex expressions that operate on lists, such as
(CONS (CAR (QUOTE (A B C))) (CDR (QUOTE (A B C)))),yielding (A B C). In case you completed COND, you could also demonstrate this function, using enough examples to really exercise it. (For debugging, remember, try really simple inputs first, then more complex ones.)