19 Interpreter Code
19 Interpreter Code
Arithmetic calculator
2
3 (define (tag-check e sym) (and (pair? e) (eq? (car e) sym)))
4 (define (sum? e) (tag-check e 'plus*))
5
6 (define (eval exp)
7 (cond
10 (else
11 (else
13
14 ; variation on table ADT from March 2 lecture (only difference is
15 ; that table-get returns a binding, while original version
16 ; returned a value):
17 ; make-table void -> table
18 ; table-get table, symbol -> (binding | null)
19 ; table-put! table, symbol, anytype -> undef
20 ; binding-value binding -> anytype
21
22 (define environment (make-table))
23
24 (define (lookup name)
25 (let ((binding (table-get environment name)))
26 (if (null? binding)
28 (binding-value binding))))
29
30 (define (eval-define exp)
31 (let ((name (cadr exp))
32 (defined-to-be (caddr exp)))
34 'undefined))
35
36 (eval '(define* x* (plus* 4 5)))
37 (eval '(plus* x* 2))
38
39
40
41 ; Index to procedures that have not changed:
42 ; procedure page line
43 ; sum? 1 4
44 ; eval-sum 1 13
45
1 3. Conditionals and if
2
3 (define (greater? exp) (tag-check exp 'greater*))
4 (define (if? exp) (tag-check exp 'if*))
5
6 (define (eval exp)
7 (cond
14 (else
16
17 (define (eval-greater exp)
18 (> (eval (cadr exp)) (eval (caddr exp))))
19
20 (define (eval-if exp)
21 (let ((predicate (cadr exp))
33
34
35 ; Index to procedures that have not changed:
36 ; procedure page line
37 ; sum? 1 4
38 ; eval-sum 1 13
39 ; lookup 2 22
40 ; define? 2 3
41 ; eval-define 2 28
42
43
1 4. Store operators in the environment
2
3 (define (application? e) (pair? e))
4
5 (define (eval exp)
6 (cond
13 (else
15
16 ;; rename scheme’s apply so we can reuse the name
17 (define scheme-apply apply)
18
19 (define (apply operator operands)
20 (if (primitive? operator)
21 (scheme-apply (get-scheme-procedure operator) operands)
22 (error "operator not a procedure: " operator)))
23
24 ;; primitive: an ADT that stores scheme procedures
25
26 (define prim-tag 'primitive)
30
31 (define environment (make-table))
35
36 (eval '(define* z* 9))
39
40
41 ; Index to procedures that have not changed:
42 ; procedure evaluator line
43 ; lookup 2 22
44 ; define? 2 3
45 ; eval-define 2 28
46 ; if? 3 4
47 ; eval-if 3 20
1 5. Environment as explicit parameter
2
3 ;This change is boring! Exactly the same functionality as #4.
4
5 (define (eval exp env)
6 (cond
21 (binding-value binding))))
22
23 (define (eval-define exp env)
24 (let ((name (cadr exp))
25 (defined-to-be (caddr exp)))
27 'undefined))
28
29 (define (eval-if exp env)
30 (let ((predicate (cadr exp))
38 predicate))))))
39
40 (eval '(define* z* (plus* 4 5)) environment)
41 (eval '(if* (greater* z* 6) 10 15) environment)
42
43
44 Index to procedures that have not changed:
45 procedure evaluator line
46 define? 2 3
47 if? 3 4
48 application? 4 3
49 apply 4 19
50
51
1 6. Defining new procedures
2
3 (define (lambda? e) (tag-check e 'lambda*))
4
5 (define (eval exp env)
6 (cond
29 (extend-env-with-new-frame
30 (parameters operator)
31 operands
32 (env operator))))
33 (else
34 (error "operator not a procedure: " operator))))
35
36
37
38 ;; ADT that implements the “double bubble”
39
40 (define compound-tag 'compound)
41 (define (make-compound parameters body env)
42 (list compound-tag parameters body env))
43 (define (compound? exp) (tag-check exp compound-tag))
44
45 (define (parameters compound) (cadr compound))
46 (define (body compound) (caddr compound))
47 (define (env compound) (cadddr compound))
48
49
1 ; Environment model code (part of eval 6)
2
3 ; Environment = list<table>
4
5 (define (extend-env-with-new-frame names values env)
6 (let ((new-frame (make-table)))
9
10 (define (make-bindings! names values table)
11 (for-each
12 (lambda (name value) (table-put! table name value))
13 names values))
14
15 ; the initial global environment
16 (define GE
17 (extend-env-with-new-frame
20 nil))
21
22
23 ; lookup searches the list of frames for the first match
24 (define (lookup name env)
25 (if (null? env)