;; A simple LISP interpreter written by Dr Klefstad for ICS 141 at UCI ;; Of course, I deleted lots of it to let you learn more about evaluation. ;; my-assoc returns the association (binding) of a variable in the association ;; list. An alist is a list of this form: ;; ((var1 . val1) (var2 . val2) ... (varN . valN)) ;; where each vari is a symbol representing a variable (or parameter) name ;; and each vali is the value of the variable. ;; assoc returns the association of a given symbol, e.g, ;; (assoc 'myvar '((a . 10)(b a b c)(myvar d e f))) ;; returns (myvar d e f) and you take the cdr of that to get myvar's value ;; (d e f) ;; We will use alists for the stack of variables and their values. Assoc ;; always finds the first association of a variable, and this is how we ;; implement dynamic scoping. New defintions of a variable will hide older ;; definitions, but the older definitions will come back into scope when ;; recursive evaluation unwinds. ;; setq and defun will push a new association on the global-alist. ;; whenever we apply a function, we will bind the formals to the evaluated ;; actuals pushing these new bindings onto the local alist and then ;; evaluate the body of the function in that new scoping context. ;; You need to write this one. (defun my-assoc (v alist) (cond ((null alist) nil) ((eq v (car (car alist))) (car alist)) (t (my-assoc v (cdr alist))) ) ) ;; This one is done (defun my-eval (e alist) ; (write " in my-eval ") (cond ((atom e) (my-eval-atom e alist)) (t (my-apply (car e) (cdr e) alist)) ) ) (defun my-eval-atom (e alist) (cond ((null e) nil) ((symbolp e) (cdr (my-assoc e alist))) (t e) ) ) ;; This one is done, but you must write the functions it calls (defun my-apply (fn args alist) ; (write "in my-apply") (cond ((atom fn) (my-apply-atom fn args alist)) ( t (my-apply-lambda fn args alist))) ) (defun my-eval-list (l alist) (cond ((null (cdr l)) (my-eval (car l) alist)) (t (my-eval (car l) alist) (my-eval-list (cdr l) alist)) ) ) ;; You need to write this one. (defun my-apply-lambda (fn args alist) ; (write "in lambda!") (write fn) (write args) (write alist) (write-line "") (my-eval-list fn (my-bind-formals fn alist) args alist) ;; bind the formals to the evaluated actuals then evaluate the body in that ;; new scoping context (i.e., that becomes the new alist for recursive ;; evaluation of the function body. Return the value of the last ;; expression in the body (using eval-list). ) ;; You need to write this one. (defun my-bind-formals (formals actuals alist) (cond ((null (car formals)) alist) ((null (car actuals)) alist) (t (my-bind-formals (cdr formals) (cdr actuals) (cons (cons (car formals) (my-eval (car actuals) alist)) alist))) ) ;; This takes a list of formals and unevaluated actuals. It should evaluate ;; each actual and bind it to its corresponding formal placing them all on ;; the front of the alist. It should return the alist with the new bindings ;; on the front. This will be used to evaluate calls to functions defined ;; via defun. ;; e.g., (my-bind-formals '(a) '((add 1 b)) '((b . 10))) ;; will return ((a . 11) (b . 10)) ;; Note there will be one actual parameter for each formal parameter. ) (defun my-apply-atom (fn args alist) ; (write "in my-apply-atom") (write args) (cond ((eq fn 'eq) (eq (my-eval (car args) alist) (my-eval (cadr args) alist))) ;; I wrote the first one, eq, for you, you write the rest ((eq fn 'car) (car args) ) ((eq fn 'cdr) (cdr args) ) ((eq fn 'cons) (cons (car args) (cdr args)) ) ((eq fn 'quote) args ) ((eq fn 'setq) (my-eval-setq (car args) (cadr args))) ;; these are (nearly) done, but you must write the sub-functions ((eq fn 'cond) (my-eval-cond args alist)) ((eq fn 'defun) (my-eval-defun args alist)) ((eq fn 'eval) (my-eval (my-eval (car args) alist) alist)) (T (my-apply (my-assoc fn alist) args alist)) ) ) (defun my-eval-setq (var val) (setq global-alist (cons (cons var val) global-alist)) ) ;; You need to write this one. You should know how cond works at this point. (defun my-eval-cond (clauses alist) (write "in cond") ) ;; You need to write this one. (defun my-eval-defun (body alist) (write "in defun") (my-eval-setq (car body) (cdr body)) ;; just push the function body onto the global alist. It is already an ;; association, e.g., (equal (L1 L2) (cond (...))) and (assoc 'equal in ;; the global alist will return this. You can then take the cdr and you ;; have a list containing the formal parameters and the expressions in ;; the function body. ) ;; This one is done, it just initializes the global alist where global ;; settings, like those defined via setq and defun, go. (setq global-alist nil) ;; to push a new value, (setq global-alist (cons (cons 'newvar 'newval) global-alist)) ;; This one is done, it will become the new top-level for LISP. After you ;; load this file, call (my-top) and then you can type in expressions and ;; define and call functions to test your my-eval. (defun my-top () (prog () top (print (my-eval (read) global-alist)) (terpri) ;; prints a newline (go top) ;; loops forever ) ) ; (setq x 4) ; (write x) (my-top) ; (defun X (A) A) (defun X (A) A) ( X ' B ) ; (write (MY-APPLY-LAMBDA 'X '((QUOTE B)) '((A . B) (X (A) A)) )) ; (write (MY-EVAL-LIST '(A) '((A . B) (X (A) A)))) ; (write (my-eval '(eq 10 b) '((b . 10)))) ; (write (my-bind-formals '(a) '((eq 10 b)) '((b . 10)))) ; (write (my-eval-list '(10 x 8) global-alist)) ; (write (my-eval-setq 'A 10)) ; (write (my-apply-atom 'setq '(A 10) '(a ))) ; (write (my-apply-atom 'quote '(a b c) '(a)))
We use cookies to provide and improve our services. By using our site, you consent to our Cookies Policy. Accept Learn more