Chapter 5, Computing with Register Machines
Exercise 5.48
We can build a special form for compile-and-run
in the evaluator and then in its instructions simply compile the expression and store the results in val
and then jump over to external-entry
.
Note that external-entry
already take cares for continue
and setting up the env
.
Changes in file ch5-syntax.scm to support special form compile-and-run
:
1
2
3
(define (compile-and-run? exp) (tagged-list? exp 'compile-and-run))
(define (compile-and-run-expression exp) (text-of-quotation (cadr exp)))
Changes in file ch5-eceval-compiler.scm for compile and assmbling instructions:
1
2
3
4
5
;;new procedure for compiling and return the assembled instructions.
(define (compile-and-assemble expression)
(assemble (statements
(compile expression 'val 'return the-empty-cenv))
eceval))
Now add special form in evaluator ch5-eceval-compiler.scm
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
;;add these procedures in eceval-operations
;;ex-5.48
(list 'compile-and-run? compile-and-run?)
(list 'compile-and-run-expression compile-and-run-expression)
(list 'compile-and-assemble compile-and-assemble)
;;now setup for eval-dispatch for special form:
;;change marked with ;;;
eval-dispatch
(test (op self-evaluating?) (reg exp))
(branch (label ev-self-eval))
(test (op variable?) (reg exp))
(branch (label ev-variable))
(test (op quoted?) (reg exp))
(branch (label ev-quoted))
(test (op assignment?) (reg exp))
(branch (label ev-assignment))
(test (op definition?) (reg exp))
(branch (label ev-definition))
(test (op if?) (reg exp))
(branch (label ev-if))
(test (op lambda?) (reg exp))
(branch (label ev-lambda))
(test (op begin?) (reg exp))
(branch (label ev-begin))
(test (op compile-and-run?) (reg exp)) ;;;
(branch (label ev-compile-and-run)) ;;;
(test (op application?) (reg exp))
(branch (label ev-application))
(goto (label unknown-expression-type))
;;And finally the instructions for special form:
ev-compile-and-run
(assign exp (op compile-and-run-expression) (reg exp))
(assign val (op compile-and-assemble) (reg exp))
(goto (label external-entry))
I had some difficulty in setting up the things in correct order so that no compilation error should come in a fresh start.
On a fresh start, I first load the compiler, ch5-compiler.scm
and then load the file load-eceval-compiler.scm
.
Here’s the output:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
1 ]=> (start-eceval)
;;; EC-Eval input:
(compile-and-run
'(define (factorial n)
(if (= n 1)
1
(* (factorial (- n 1)) n))))
(total-pushes = 0 maximum-depth = 0)
;;; EC-Eval value:
ok
;;; EC-Eval input:
(+ 5 4)
(total-pushes = 8 maximum-depth = 5)
;;; EC-Eval value:
9
;;; EC-Eval input:
(factorial 5)
(total-pushes = 13 maximum-depth = 8)
;;; EC-Eval value:
120
;;; EC-Eval input:
((lambda(x) (factorial x)) 6)
(total-pushes = 20 maximum-depth = 10)
;;; EC-Eval value:
720
;;; EC-Eval input:
(compile-and-run '(define (dummy x) (+ 500 x)))
(total-pushes = 0 maximum-depth = 0)
;;; EC-Eval value:
ok
;;; EC-Eval input:
(define rs (dummy 5))
(total-pushes = 8 maximum-depth = 6)
;;; EC-Eval value:
ok
;;; EC-Eval input:
rs
(total-pushes = 0 maximum-depth = 0)
;;; EC-Eval value:
505
;;; EC-Eval input:
I first tried this by installing compile-and-run
as a primitive procedure. First problem is that there is a call (start eceval)
that starts the evaluator. It can work fine but this means that compile-and-run
call never returns! Because (start eceval)
will go into a read-eval-print loop.
A simple solution could be to set flag
and branch in primitive procedure to extrenal-entry
when flag is set. This did not work and even did not seem to be a good design as it will introduce a branching instruction for every primitive application.