1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2 ;; Mandatory SICP Metacircular Evaluator ;;
3 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5 (define apply-in-underlying-scheme apply)
9 ;; Verbatim code from SICP
11 (display "eval and apply\n")
13 (define (eval exp env)
14 (cond ((self-evaluating? exp)
17 (lookup-variable-value exp env))
19 (text-of-quotation exp))
21 (eval-assignment exp env))
23 (eval-definition exp env))
28 (lambda-parameters exp)
36 (eval (cond->if exp) env))
38 (apply (eval (operator exp) env)
43 (error "Unknown expression type: EVAL" exp))))
45 (define (apply procedure arguments)
46 (cond ((primitive-procedure? procedure)
47 (apply-primitive-procedure
50 ((compound-procedure? procedure)
52 (procedure-body procedure)
57 (procedure-environment
60 (error "Unknown procedure type: APPLY"
63 (define (list-of-values exps env)
64 (if (no-operands? exps)
66 (cons (eval (first-operand exps) env)
71 (define (eval-if exp env)
72 (if (true? (eval (if-predicate exp) env))
73 (eval (if-consequent exp) env)
74 (eval (if-alternative exp) env)))
76 (define (eval-sequence exps env)
77 (cond ((last-exp? exps)
78 (eval (first-exp exps) env))
80 (eval (first-exp exps) env)
81 (eval-sequence (rest-exps exps)
84 (define (eval-assignment exp env)
86 (assignment-variable exp)
87 (eval (assignment-value exp) env)
91 (define (eval-definition exp env)
93 (definition-variable exp)
94 (eval (definition-value exp) env)
98 (define (self-evaluating? exp)
99 (cond ((number? exp) true)
103 (define (variable? exp) (symbol? exp))
105 (define (quoted? exp)
106 (tagged-list? exp 'quote))
108 (define (text-of-quotation exp)
111 (define (tagged-list? exp tag)
116 (define (assignment? exp)
117 (tagged-list? exp 'set!))
119 (define (assignment-variable exp)
122 (define (assignment-value exp) (caddr exp))
124 (define (definition? exp)
125 (tagged-list? exp 'define))
127 (define (definition-variable exp)
128 (if (symbol? (cadr exp))
132 (define (definition-value exp)
133 (if (symbol? (cadr exp))
136 (cdadr exp) ; formal parameters
140 (display "lambda... \n")
142 (define (lambda? exp)
143 (tagged-list? exp 'lambda))
144 (define (lambda-parameters exp) (cadr exp))
145 (define (lambda-body exp) (cddr exp))
147 (define (make-lambda parameters body)
148 (cons 'lambda (cons parameters body)))
150 (define (if? exp) (tagged-list? exp 'if))
151 (define (if-predicate exp) (cadr exp))
152 (define (if-consequent exp) (caddr exp))
153 (define (if-alternative exp)
154 (if (not (null? (cdddr exp)))
158 (define (make-if predicate
167 (tagged-list? exp 'begin))
168 (define (begin-actions exp) (cdr exp))
169 (define (last-exp? seq) (null? (cdr seq)))
170 (define (first-exp seq) (car seq))
171 (define (rest-exps seq) (cdr seq))
173 (define (sequence->exp seq)
174 (cond ((null? seq) seq)
175 ((last-exp? seq) (first-exp seq))
176 (else (make-begin seq))))
178 (define (make-begin seq) (cons 'begin seq))
180 (define (application? exp) (pair? exp))
181 (define (operator exp) (car exp))
182 (define (operands exp) (cdr exp))
183 (define (no-operands? ops) (null? ops))
184 (define (first-operand ops) (car ops))
185 (define (rest-operands ops) (cdr ops))
188 (display "cond... \n")
191 (tagged-list? exp 'cond))
192 (define (cond-clauses exp) (cdr exp))
193 (define (cond-else-clause? clause)
194 (eq? (cond-predicate clause) 'else))
195 (define (cond-predicate clause)
197 (define (cond-actions clause)
199 (define (cond->if exp)
200 (expand-clauses (cond-clauses exp)))
201 (define (expand-clauses clauses)
203 'false ; no else clause
204 (let ((first (car clauses))
205 (rest (cdr clauses)))
206 (if (cond-else-clause? first)
209 (cond-actions first))
210 (error "ELSE clause isn't last: COND->IF"
212 (make-if (cond-predicate first)
214 (cond-actions first))
226 (display "make-procedure...\n")
229 (define (make-procedure parameters body env)
230 (list 'procedure parameters body env))
231 (define (compound-procedure? p)
232 (tagged-list? p 'procedure))
233 (define (procedure-parameters p) (cadr p))
234 (define (procedure-body p) (caddr p))
235 (define (procedure-environment p) (cadddr p))
237 (define (enclosing-environment env) (cdr env))
238 (define (first-frame env) (car env))
239 (define the-empty-environment '())
242 (display "make-frame\n")
244 (define (make-frame variables values)
245 (cons variables values))
246 (define (frame-variables frame) (car frame))
247 (define (frame-values frame) (cdr frame))
248 (define (add-binding-to-frame! var val frame)
249 (display "Adding binding to frame... ")
250 (set-car! frame (cons var (car frame)))
251 (set-cdr! frame (cons val (cdr frame))))
253 (display "extend-environment\n")
255 (define (extend-environment vars vals base-env)
256 (if (= (length vars) (length vals))
257 (cons (make-frame vars vals) base-env)
258 (if (< (length vars) (length vals))
259 (error "Too many arguments supplied"
262 (error "Too few arguments supplied"
266 (display "lookup-variable\n")
268 (define (lookup-variable-value var env)
269 (define (env-loop env)
270 (define (scan vars vals)
273 (enclosing-environment env)))
274 ((eq? var (car vars))
276 (else (scan (cdr vars)
278 (if (eq? env the-empty-environment)
279 (error "Unbound variable" var)
280 (let ((frame (first-frame env)))
281 (scan (frame-variables frame)
282 (frame-values frame)))))
285 (display "set-variable\n")
287 (define (set-variable-value! var val env)
288 (define (env-loop env)
289 (define (scan vars vals)
292 (enclosing-environment env)))
293 ((eq? var (car vars))
295 (else (scan (cdr vars)
297 (if (eq? env the-empty-environment)
298 (error "Unbound variable: SET!" var)
299 (let ((frame (first-frame env)))
300 (scan (frame-variables frame)
301 (frame-values frame)))))
304 (display "define-variable\n")
306 (define (define-variable! var val env)
307 (display "Defining a variable...\n")
308 (let ((frame (first-frame env)))
309 (define (scan vars vals)
310 (display "Scanning for ") (display var) (display " in ") (display vars) (display "...\n")
312 (begin (display "adding binding\n")
313 (add-binding-to-frame!
315 ((eq? var (car vars))
316 (begin (display "replacing binding\n")
317 (set-car! vals val)))
320 (display "iterating\n")
323 (scan (frame-variables frame)
324 (frame-values frame))))
326 (display "setup-environment...\n")
328 (define (setup-environment)
331 (primitive-procedure-names)
332 (primitive-procedure-objects)
333 the-empty-environment)))
334 (display "Setting up the environment..\n")
335 (define-variable! 'true true initial-env)
336 (define-variable! 'false false initial-env)
340 (define (primitive-procedure? proc)
341 (tagged-list? proc 'primitive))
343 (define (primitive-implementation proc)
346 (define primitive-procedures
347 (list (list 'car car)
355 (define (primitive-procedure-names)
356 (map car primitive-procedures))
358 (define (primitive-procedure-objects)
360 (list 'primitive (cadr proc)))
361 primitive-procedures))
363 (define (apply-primitive-procedure proc args)
364 (apply-in-underlying-scheme
365 (primitive-implementation proc) args))
367 (define input-prompt ";;; M-Eval input:")
368 (define output-prompt ";;; M-Eval value:")
371 (display "driver-loop...\n")
373 (define (driver-loop)
374 (prompt-for-input input-prompt)
375 (let ((input (read)))
378 the-global-environment)))
379 (announce-output output-prompt)
380 (user-print output)))
383 (define (prompt-for-input string)
385 (display string) (newline))
387 (define (announce-output string)
388 (newline) (display string) (newline))
390 (define (user-print object)
391 (if (compound-procedure? object)
393 (list 'compound-procedure
394 (procedure-parameters object)
395 (procedure-body object)
400 (define the-global-environment (setup-environment))