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