Interpreters

Interpreters!

(define eval-exp
  (lambda (exp)
    (variant-case exp
      [lit (datum) datum]
      [varref (var) (apply-env init-env var)]
      [app (rator rands)
	(let ([proc (eval-exp rator)]
	      [args (eval-rands rands)])
	  (apply-proc proc args))]
      [else (error
	      'Eval-exp
	      "Invalid abstract syntax: ~s"
	      exp)])))

(define eval-rands
  (lambda (rands)
    (map eval-exp rands)))



(define apply-proc
  (lambda (proc args)
    (variant-case proc
      [prim-proc (prim-op) (apply-prim-op prim-op args)]
      [else (error
	      'apply-proc
	      "Invalid Procedure")])))

(define the-empty-env (create-empty-ff))
(define extend-env extend-ff*)
(define apply-env apply-ff)
(define-record prim-proc (prim-op))

(define apply-prim-op
  (lambda (prim-op args)
    (case prim-op
      [(+) (+ (car args) (cadr args))]
      [(-) (- (car args) (cadr args))]
      [(*) (* (car args) (cadr args))]
      [(add1) (+ (car args) 1)]
      [(sub1) (- (car args) 1)]
      [else (error
	      'apply-prim-op
	      "invalid primitive operator name: ~s"
	      prim-op)])))

(define prim-op-names
  '(+ - * add1 sub1))

(define init-env
  (extend-env
    prim-op-names
    (map make-prim-proc prim-op-names)
    the-empty-env))

(define run
  (lambda (exp)
    (eval-exp (parse exp))))

(define repl
  (lambda ()
    (display "==> ")
    (write (eval-exp (parse (read))))
    (newline)
    (repl)))


Extend the initial environment with  unary minus

(define apply-prim-op
  (lambda (prim-op args)
    (case prim-op
      [(+) (+ (car args) (cadr args))]
      [(-) (- (car args) (cadr args))]
      [(*) (* (car args) (cadr args))]
      [(add1) (+ (car args) 1)]
      [(sub1) (- (car args) 1)]
      [(minus) (- 0 (car args))]
      [else (error
	      'apply-prim-op
	      "invalid primitive operator name: ~s"
	      prim-op)])))

(define prim-op-names
  '(+ - * add1 sub1 minus))

(define init-env
    (extend-env
      prim-op-names
      (map make-prim-proc prim-op-names)
      the-empty-env))



Extend the initial environment with cons, car, cdr, list
(define apply-prim-op
  (lambda (prim-op args)
    (case prim-op
      [(+) (+ (car args) (cadr args))]
      [(-) (- (car args) (cadr args))]
      [(*) (* (car args) (cadr args))]
      [(add1) (+ (car args) 1)]
      [(sub1) (- (car args) 1)]
      [(minus) (- 0 (car args))]
      [(cons) (cons (car args) (cadr args))]
      [(car) (caar args)]
      [(cdr) (cdar args)]
      [(list) args ]
      [else (error
	      'apply-prim-op
	      "invalid primitive operator name: ~s"
	      prim-op)])))

(define prim-op-names
  '(+ - * add1 sub1 minus null cons car cdr list))

(define init-env
    (extend-env
      prim-op-names
      (map make-prim-proc prim-op-names)
      the-empty-env))
  


Add primitive VARIABLE emptylist <==> '()

(define init-env
  (extend-env '(emptylist) '(())
    (extend-env
      prim-op-names
      (map make-prim-proc prim-op-names)
      the-empty-env)))


Conditional evaluation?

(if test then else)

	0 is false
	else true

(define true-value?
  (lambda (x)
    (not (zero? x))))

(define eval-exp
  (lambda (exp) 
    (variant-case exp
      [lit (datum) datum]
      [varref (var) (apply-env  var)] 
      [if (test-exp then-exp else-exp)
	  (if (true-value? (eval-exp test-exp))
	      (eval-exp then-exp)
	      (eval-exp else-exp))]
      [app (rator rands)
	(let ([proc (eval-exp rator)]
	      [args (eval-rands rands)])
	  (apply-proc proc args))]
      [else (error
	      'Eval-exp
	      "Invalid abstract syntax: ~s"
	      exp)])))

--> (if 1 2 3)
??
--> (if (minus 3) (add1 3) (sub1 3))
??


Can't do much unless we add 
numberic equality, zero testing
Add order predicates: 
	equal, zero, greater, less

--> (equal 3 3)
1
--> (zero (sub1 5))
0
--> (if (greater 2 3) 5 6)
6

(define apply-prim-op
  (lambda (prim-op args)
    (case prim-op
      [(+) (+ (car args) (cadr args))]
      [(-) (- (car args) (cadr args))]
      [(*) (* (car args) (cadr args))]
      [(add1) (+ (car args) 1)]
      [(sub1) (- (car args) 1)]
      [(minus) (- 0 (car args))]
      [(null) (if (null? (car args)) 1 0)] 
;; also added
      [(cons) (cons (car args) (cadr args))]
      [(car) (caar args)]
      [(cdr) (cdar args)]
      [(list) args]
      [(equal) (if (= (car args) (cadr args)) 1 0)]
      [(zero)  (if (zero? (car args)) 1 0)]
      [(greater)
	(if (> (car args) (cadr args)) 1 0)]
      [(less)  (if (< (car args) (cadr args)) 1 0)]
      [else (error
	      'apply-prim-op
	      "invalid primitive operator name: ~s"
	      prim-op)])))

(define prim-op-names
  '(+ - * add1 sub1 minus null cons 
	car cdr list equal zero greater less))

(define init-env
  (extend-env '(emptylist) '(())
    (extend-env
      prim-op-names
      (map make-prim-proc prim-op-names)
      the-empty-env)))

Local bindings?

==> (let ([x 5][y 6]) (+ x y))
11

EXP ::== (let DECLS EXP)
DECLS ::== (DECL+)
DECL ::== (VAR EXP)

(define-record let (decls body))
(define-record decl (var exp))

The body of a let expressions should be evaluated
in an ENVIRONMENT in which the declared variables
are bound the the values of the expressions
	(define-record decl (var exp))

Different expressions may be evaluated using
different environments!

Our current interpreter evaluates all expressions
in a SINGLE environment init-env

Solution:
Step1: rewrite eval-exp to take two arguments
	1. exp
	2. environment

eval-exp now evaluates exp WITH RESPECT TO THE
GIVEN ENVIRONMENT.

(define eval-exp
  (lambda (exp env) ;; changed
    (variant-case exp
      [lit (datum) datum]
      [varref (var) (apply-env env var)] 
;; changed
      [if (test-exp then-exp else-exp)
	  (if (true-value? (eval-exp test-exp env));;
	      (eval-exp then-exp env);;
	      (eval-exp else-exp env))];;
      [app (rator rands)
	(let ([proc (eval-exp rator env)];;
	      [args (eval-rands rands env)]);;
	  (apply-proc proc args))]
      [else (error
	      'Eval-exp
	      "Invalid abstract syntax: ~s"
	      exp)])))

(define eval-rands;;
  (lambda (rands env);;
    (map (lambda (rand);;
	   (eval-exp rand env));;
      rands)));;


Now for let expressions....
==> (let ([x 5][y 6]) (+ x y))
11
EXP ::== (let DECLS EXP)
DECLS ::== (DECL+)
DECL ::== (VAR EXP)
(define-record let (decls body))
(define-record decl (var exp))

Step 1: evaluate subexp on RHSs of DECLS in
CURRENT environment

(scope of let's bindings is BODY of let expression
NOT DECLS)

Step 2: Evaluate BODY of let in a NEW environment
obtained by EXTENDING current environment to bind
the declared variables to the values of the RHS
subexpressions


(define eval-exp
  (lambda (exp env) ;; changed
    (variant-case exp
      [lit (datum) datum]
      [varref (var) (apply-env env var)] 
      [if (test-exp then-exp else-exp)
	  (if (true-value? (eval-exp test-exp env))
	      (eval-exp then-exp env)
	      (eval-exp else-exp env))]
      [app (rator rands)
	(let ([proc (eval-exp rator env)]
	      [args (eval-rands rands env)])
	  (apply-proc proc args))]
      [let (decls body)
	(let ([vars (map decl->var decls)]
	      [exps (map decl->exp decls)])
	  (let ([new-env (extend-env
			   vars
			   (eval-rands exps env)
			   env)])
;	    (displayln new-env)
	    (eval-exp body new-env)))]
      [else (error
	      'Eval-exp
	      "Invalid abstract syntax: ~s"
	      exp)])))

(define eval-rands
  (lambda (rands env)
    (map (lambda (rand)
	   (eval-exp rand env))
      rands)))

    

Sushil Louis
Last modified: Mon Nov 8 12:34:39 PST 1999