Please note, this is a STATIC archive of website www.tutorialspoint.com from 11 May 2019, cach3.com does not collect or store any user information, there is no "phishing" involved.
Tutorialspoint

Execute LISP Online

;; 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 v) nil)
    ( (eq v (car (car alist))) (car alist)) 
    (t (my-assoc v (cdr alist)) )
  )
 )

;; This one is done
(defun my-eval (e alist)
    (cond ((atom e) (my-eval-atom e alist))
          (t (my-apply (car e) (cdr e) alist))
    )
)

(trace my-eval)
;; You need to write this one.
(defun my-eval-atom (e alist)
;; how do you evaluate an atom???
;; Remember there are special cases: T, NIL, ASYMBOL, 10, "Hello"
    (cond 
        ((eq t e) t)
        ((null e) nil)
        ((symbolp e) (cdr (my-assoc e alist)))
        (t e)
    )
)
(trace my-eval-atom)

;; This one is done, but you must write the functions it calls
(defun my-apply (fn args alist)
    (cond ((atom fn)  (my-apply-atom fn args alist))
          ( t (my-apply-lambda fn args alist)))
)
(trace my-apply)
;; You need to write this one.
;; Utility function for eval-cond and apply-lambda.  Evaluates each expression
;; in l and returns the value of the last expression
(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) )
    )
)
(trace my-eval-list)
;; You need to write this one.
(defun my-apply-lambda (fn 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).
    (my-eval-list (cdr (cdr fn)) (my-bind-formals (cadr fn) args alist))
)
(trace my-apply-lambda)

;; You need to write this one.
(defun my-bind-formals (formals actuals 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.
    (cond 
            ((null formals) alist)
            
            (t (cons (cons (car formals) (my-eval (car actuals) alist)) 
                     (my-bind-formals (cdr formals) (cdr actuals) alist)))
    
    )
)
(trace my-bind-formals)
;; You need to write this one.  Handle the primitives as special cases, then
;; handle user defined functions (defined via defun) in the default case.
;; These are the only functions we handle: eq, car, cdr, cons, quote, cond,
;; defun, eval, setq, and user defined functions (defined via defun) that
;; we have evaluated.  You can add more built-ins (like plus, times, atom,
;; listp) as you like for testing.

(defun my-apply-atom (fn args alist)
    (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 (my-eval (car args) alist)))
          ((eq fn 'cdr)
          (cdr (my-eval (car args) alist)))
          ((eq fn 'cons)
          (cons (my-eval (car args) alist) (my-eval (cadr args) alist)))
          ((eq fn 'quote) 
          (car args))
          ((eq fn 'null)
          (eq (my-eval (car args) alist) nil ))
          ((eq fn 'setq) (my-eval-setq (car args) (my-eval(cadr args) alist)))
          ;; 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);; get the lambda from the alist, 
                       args alist))
    )
)
(trace my-apply-atom)




;; You need to write this one.
(defun my-eval-setq (var val)
;; just push a new association of the var and its evaluated val onto the
;; global alist
    (setq global-alist (cons (cons var val) global-alist))
) 
(trace my-eval-setq)

;; You need to write this one.  You should know how cond works at this point.
(defun my-eval-cond (clauses alist)
    (cond 
        ((null clauses) nil)
        ((eq t (my-eval (car (car clauses)) alist)) (my-eval-list (cdr (car clauses)) alist))
        (t (my-eval-cond (cdr clauses) alist))
    )
)
(trace my-eval-cond)
;; You need to write this one.
(defun my-eval-defun (body alist)
;; 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.
    (my-eval-setq (car body) (cdr body))

)
(trace my-eval-defun)
;; 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)
(print (my-bind-formals '(a d) '((quote b) (quote c) )'((x (a) a))))
(print (my-eval '(x (quote b)) '((x (a) (cond ((eq a 'b ) 1 (cons 3 a)) (t 2))))))
(print (my-eval '(defun x (a) a) nil))
(print (my-eval ' (defun rev (L A) (cond ((null L) A) (t (rev (cdr L) (cons (car L) A))))) global-alist))
(print (my-eval '(setq a '(a b c)) global-alist))
;(print (my-eval '(rev '(A B C D E) nil) global-alist))
(print (my-eval '(rev a nil) global-alist))

;; 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
    )
)

Advertisements
Loading...

We use cookies to provide and improve our services. By using our site, you consent to our Cookies Policy.