/
5_40.scm
234 lines (213 loc) · 8.86 KB
/
5_40.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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
(load "5_33.scm")
(load "5_39.scm")
(load "5_41.scm") ; In my opinion exercises 5.40 & 5.41 are in the wrong order,
; that's why I'm loading it in here
(load "load-eceval-compiler.scm")
(load "ch5-eceval-compiler-lexical")
(define (compile exp target linkage comp-time-env)
(cond ((self-evaluating? exp)
(compile-self-evaluating exp target linkage comp-time-env))
((quoted? exp) (compile-quoted exp target linkage comp-time-env))
((variable? exp)
(compile-variable exp target linkage comp-time-env))
((assignment? exp)
(compile-assignment exp target linkage comp-time-env))
((definition? exp)
(compile-definition exp target linkage comp-time-env))
((if? exp) (compile-if exp target linkage comp-time-env))
((lambda? exp) (compile-lambda exp target linkage comp-time-env))
((begin? exp)
(compile-sequence (begin-actions exp)
target
linkage comp-time-env))
((cond? exp) (compile (cond->if exp) target linkage comp-time-env))
((application? exp)
(compile-application exp target linkage comp-time-env))
(else
(error "Unknown expression type -- COMPILE" exp))))
(define (make-instruction-sequence needs modifies statements)
(list needs modifies statements))
(define (empty-instruction-sequence)
(make-instruction-sequence '() '() '()))
(define (compile-self-evaluating exp target linkage comp-time-env)
(end-with-linkage linkage
(make-instruction-sequence '() (list target)
`((assign ,target (const ,exp))))))
(define (compile-quoted exp target linkage comp-time-env)
(end-with-linkage linkage
(make-instruction-sequence '() (list target)
`((assign ,target (const ,(text-of-quotation exp)))))))
(define (compile-variable exp target linkage comp-time-env)
(end-with-linkage linkage
(make-instruction-sequence '(env) (list target)
`((assign ,target
(op lookup-variable-value)
(const ,exp)
(reg env))))))
(define (compile-assignment exp target linkage comp-time-env)
(let ((var (assignment-variable exp))
(get-value-code
(compile (assignment-value exp) 'val 'next comp-time-env)))
(end-with-linkage linkage
(preserving '(env)
get-value-code
(make-instruction-sequence '(env val) (list target)
`((perform (op set-variable-value!)
(const ,var)
(reg val)
(reg env))
(assign ,target (const ok))))))))
(define (compile-definition exp target linkage comp-time-env)
(let ((var (definition-variable exp))
(get-value-code
(compile (definition-value exp) 'val 'next comp-time-env)))
(end-with-linkage linkage
(preserving '(env)
get-value-code
(make-instruction-sequence '(env val) (list target)
`((perform (op define-variable!)
(const ,var)
(reg val)
(reg env))
(assign ,target (const ok))))))))
(define (compile-if exp target linkage comp-time-env)
(let ((t-branch (make-label 'true-branch))
(f-branch (make-label 'false-branch))
(after-if (make-label 'after-if)))
(let ((consequent-linkage
(if (eq? linkage 'next) after-if linkage)))
(let ((p-code (compile (if-predicate exp) 'val 'next comp-time-env))
(c-code
(compile
(if-consequent exp) target consequent-linkage comp-time-env))
(a-code
(compile (if-alternative exp) target linkage comp-time-env)))
(preserving '(env continue)
p-code
(append-instruction-sequences
(make-instruction-sequence '(val) '()
`((test (op false?) (reg val))
(branch (label ,f-branch))))
(parallel-instruction-sequences
(append-instruction-sequences t-branch c-code)
(append-instruction-sequences f-branch a-code))
after-if))))))
(define (compile-sequence seq target linkage comp-time-env)
(if (last-exp? seq)
(compile (first-exp seq) target linkage comp-time-env)
(preserving '(env continue)
(compile (first-exp seq) target 'next comp-time-env)
(compile-sequence (rest-exps seq) target linkage comp-time-env))))
(define (compile-lambda exp target linkage comp-time-env)
(let ((proc-entry (make-label 'entry))
(after-lambda (make-label 'after-lambda)))
(let ((lambda-linkage
(if (eq? linkage 'next) after-lambda linkage)))
(append-instruction-sequences
(tack-on-instruction-sequence
(end-with-linkage lambda-linkage
(make-instruction-sequence '(env) (list target)
`((assign ,target
(op make-compiled-procedure)
(label ,proc-entry)
(reg env)))))
(compile-lambda-body exp proc-entry comp-time-env))
after-lambda))))
(define (compile-lambda-body exp proc-entry comp-time-env)
(let ((formals (lambda-parameters exp)))
(let ((new-comp-time-env (extend-comp-time-env formals comp-time-env)))
(append-instruction-sequences
(make-instruction-sequence '(env proc argl) '(env)
`(,proc-entry
(assign env (op compiled-procedure-env) (reg proc))
(assign env
(op extend-environment)
(const ,formals)
(reg argl)
(reg env))))
(compile-sequence (lambda-body exp) 'val 'return new-comp-time-env)))))
(define (compile-application exp target linkage comp-time-env)
(let ((proc-code (compile (operator exp) 'proc 'next comp-time-env))
(operand-codes
(map (lambda (operand) (compile operand 'val 'next comp-time-env))
(operands exp))))
(preserving '(env continue)
proc-code
(preserving '(proc continue)
(construct-arglist operand-codes)
(compile-procedure-call target linkage comp-time-env)))))
(define (compile-procedure-call target linkage comp-time-env)
(let ((primitive-branch (make-label 'primitive-branch))
(compiled-branch (make-label 'compiled-branch))
(after-call (make-label 'after-call)))
(let ((compiled-linkage
(if (eq? linkage 'next) after-call linkage)))
(append-instruction-sequences
(make-instruction-sequence '(proc) '()
`((test (op primitive-procedure?) (reg proc))
(branch (label ,primitive-branch))))
(parallel-instruction-sequences
(append-instruction-sequences
compiled-branch
(compile-proc-appl target compiled-linkage comp-time-env))
(append-instruction-sequences
primitive-branch
(end-with-linkage linkage
(make-instruction-sequence '(proc argl)
(list target)
`((assign ,target
(op apply-primitive-procedure)
(reg proc)
(reg argl)))))))
after-call))))
(define (compile-proc-appl target linkage comp-time-env)
(cond ((and (eq? target 'val) (not (eq? linkage 'return)))
(make-instruction-sequence '(proc) all-regs
`((assign continue (label ,linkage))
(assign val (op compiled-procedure-entry)
(reg proc))
(goto (reg val)))))
((and (not (eq? target 'val))
(not (eq? linkage 'return)))
(let ((proc-return (make-label 'proc-return)))
(make-instruction-sequence '(proc) all-regs
`((assign continue (label ,proc-return))
(assign val (op compiled-procedure-entry)
(reg proc))
(goto (reg val))
,proc-return
(assign ,target (reg val))
(goto (label ,linkage))))))
((and (eq? target 'val) (eq? linkage 'return))
(make-instruction-sequence '(proc continue) all-regs
'((assign val (op compiled-procedure-entry)
(reg proc))
(goto (reg val)))))
((and (not (eq? target 'val)) (eq? linkage 'return))
(error "return linkage, target not val -- COMPILE"
target))))
(define (extend-comp-time-env formals comp-time-env)
(cons formals comp-time-env))
(define empty-comp-time-env '())
(define (compile-and-go expression)
(let ((instructions
(assemble (statements
(compile expression 'val 'return empty-comp-time-env))
eceval)))
(set! the-global-environment (setup-environment))
(set-register-contents! eceval 'val instructions)
(set-register-contents! eceval 'flag true)
(start eceval)))
;(define code
;'(define (factorial n)
;(if (= n 1)
;1
;(* (factorial (- n 1)) n))))
;(compile-and-go code)
;(compile-and-go '((lambda (x y)
;(lambda (a b c d e)
;((lambda (y z) (* x y z))
;(* a b x)
;(+ c d x))))
;3
;4))