Implement 5.50 compiled meta-circular evaluator executed by regsim
This commit is contained in:
@@ -1,24 +1,88 @@
|
|||||||
(load "shared/util")
|
(load "shared/util")
|
||||||
(load "shared/sicp-load-eceval-compiler")
|
(load "shared/ch5-regsim")
|
||||||
(load "shared/sicp-compiler")
|
(load "shared/ch5-compiler")
|
||||||
|
(load "shared/ch5-eceval-support")
|
||||||
|
|
||||||
(display "\nex-5.50 - compile-metacircular-evaluator\n")
|
(display "\nex-5.50 - compile-metacircular-evaluator\n")
|
||||||
|
|
||||||
; Exercise 5.50. Use the compiler to compile the metacircular evaluator of
|
(define mceval-code
|
||||||
; section 4.1 and run this program using the register-machine simulator. (To
|
(let ((port (open-input-file "shared/ch4-mceval.scm")))
|
||||||
; compile more than one definition at a time, you can package the definitions
|
(read port)))
|
||||||
; in a begin.) The resulting interpreter will run very slowly because of the
|
|
||||||
; multiple levels of interpretation, but getting all the details to work is an
|
|
||||||
; instructive exercise.
|
|
||||||
|
|
||||||
(compile-and-go
|
(define mceval-compiled
|
||||||
'(begin
|
(append
|
||||||
(define (factorial n)
|
(list '(assign env (op get-global-environment)))
|
||||||
(if (= n 1)
|
(statements (compile mceval-code 'val 'next))))
|
||||||
1
|
|
||||||
(* (factorial (- n 1)) n)))
|
;; write assembly to file for debug purposes
|
||||||
(factorial 10)))
|
; (let ((port (open-output-file "f-mceval-compiled.scm")))
|
||||||
|
; (define (write-list-to-port xs port)
|
||||||
|
; (if (null? xs) '()
|
||||||
|
; (begin (display (car xs) port) (display "\n" port)
|
||||||
|
; (write-list-to-port (cdr xs) port))))
|
||||||
|
; (write-list-to-port mceval-compiled port)
|
||||||
|
; (close-output-port port))
|
||||||
|
|
||||||
|
(define eceval-operations (list
|
||||||
|
(list 'list list)
|
||||||
|
(list 'cons cons)
|
||||||
|
|
||||||
|
(list 'true? true?)
|
||||||
|
(list 'false? false?) ;for compiled code
|
||||||
|
(list 'make-procedure make-procedure)
|
||||||
|
(list 'compound-procedure? compound-procedure?)
|
||||||
|
(list 'procedure-parameters procedure-parameters)
|
||||||
|
(list 'procedure-body procedure-body)
|
||||||
|
(list 'procedure-environment procedure-environment)
|
||||||
|
(list 'extend-environment extend-environment)
|
||||||
|
(list 'lookup-variable-value lookup-variable-value)
|
||||||
|
(list 'set-variable-value! set-variable-value!)
|
||||||
|
(list 'define-variable! define-variable!)
|
||||||
|
(list 'primitive-procedure? primitive-procedure?)
|
||||||
|
(list 'apply-primitive-procedure apply-primitive-procedure)
|
||||||
|
(list 'prompt-for-input prompt-for-input)
|
||||||
|
(list 'announce-output announce-output)
|
||||||
|
(list 'user-print user-print)
|
||||||
|
(list 'empty-arglist empty-arglist)
|
||||||
|
(list 'adjoin-arg adjoin-arg)
|
||||||
|
(list 'last-operand? last-operand?)
|
||||||
|
(list 'no-more-exps? no-more-exps?) ;for non-tail-recursive machine
|
||||||
|
(list 'get-global-environment get-global-environment)
|
||||||
|
|
||||||
|
;;for compiled code (also in eceval-support.scm)
|
||||||
|
(list 'make-compiled-procedure make-compiled-procedure)
|
||||||
|
(list 'compiled-procedure? compiled-procedure?)
|
||||||
|
(list 'compiled-procedure-entry compiled-procedure-entry)
|
||||||
|
(list 'compiled-procedure-env compiled-procedure-env)
|
||||||
|
))
|
||||||
|
|
||||||
|
(define the-global-environment (setup-environment))
|
||||||
|
(define mceval-machine
|
||||||
|
(make-machine
|
||||||
|
'(exp env val proc argl continue unev)
|
||||||
|
eceval-operations
|
||||||
|
mceval-compiled))
|
||||||
|
|
||||||
|
(start mceval-machine)
|
||||||
|
;; (factorial 5) computed by compiled mceval executed by register simulator
|
||||||
|
(assert (get-register-contents mceval-machine 'val) 120)
|
||||||
|
|
||||||
|
;; Uncomment driver loop within shared/ch4-mceval.scm and load in mit-scheme
|
||||||
|
;; for REPL:
|
||||||
|
|
||||||
|
; λ symposium sicp → λ git master* → mit-scheme
|
||||||
|
; 1 ]=> (load "ex-5_50-52")
|
||||||
|
; ;;; M-Eval input:
|
||||||
|
; (define (f n) (if (= n 1) 1 (* n (f (- n 1)))))
|
||||||
|
; ;;; M-Eval value:
|
||||||
|
; ok
|
||||||
|
; ;;; M-Eval input:
|
||||||
|
; (f 10)
|
||||||
|
; ;;; M-Eval value:
|
||||||
|
; 3628800
|
||||||
|
; #magic
|
||||||
|
|
||||||
(display "\nex-5.51\n")
|
(display "\nex-5.51\n")
|
||||||
|
|
||||||
(display "\nex-5.52\n")
|
;(display "\nex-5.52\n")
|
||||||
|
|
||||||
|
|||||||
369
shared/ch4-mceval.scm
Normal file
369
shared/ch4-mceval.scm
Normal file
@@ -0,0 +1,369 @@
|
|||||||
|
;;;;METACIRCULAR EVALUATOR FROM CHAPTER 4 (SECTIONS 4.1.1-4.1.4) of
|
||||||
|
;;;; STRUCTURE AND INTERPRETATION OF COMPUTER PROGRAMS
|
||||||
|
|
||||||
|
;;;;Matches code in ch4.scm
|
||||||
|
|
||||||
|
;;;;This file can be loaded into Scheme as a whole.
|
||||||
|
;;;;Then you can initialize and start the evaluator by evaluating
|
||||||
|
;;;; the two commented-out lines at the end of the file (setting up the
|
||||||
|
;;;; global environment and starting the driver loop).
|
||||||
|
|
||||||
|
;;;;**WARNING: Don't load this file twice (or you'll lose the primitives
|
||||||
|
;;;; interface, due to renamings of apply).
|
||||||
|
|
||||||
|
;;;from section 4.1.4 -- must precede def of metacircular apply
|
||||||
|
|
||||||
|
(begin
|
||||||
|
(define apply-in-underlying-scheme apply)
|
||||||
|
|
||||||
|
;;;SECTION 4.1.1
|
||||||
|
|
||||||
|
(define (eval exp env)
|
||||||
|
(cond ((self-evaluating? exp) exp)
|
||||||
|
((variable? exp) (lookup-variable-value exp env))
|
||||||
|
((quoted? exp) (text-of-quotation exp))
|
||||||
|
((assignment? exp) (eval-assignment exp env))
|
||||||
|
((definition? exp) (eval-definition exp env))
|
||||||
|
((if? exp) (eval-if exp env))
|
||||||
|
((lambda? exp)
|
||||||
|
(make-procedure (lambda-parameters exp)
|
||||||
|
(lambda-body exp)
|
||||||
|
env))
|
||||||
|
((begin? exp)
|
||||||
|
(eval-sequence (begin-actions exp) env))
|
||||||
|
((cond? exp) (eval (cond->if exp) env))
|
||||||
|
((application? exp)
|
||||||
|
(apply (eval (operator exp) env)
|
||||||
|
(list-of-values (operands exp) env)))
|
||||||
|
(else
|
||||||
|
(error "Unknown expression type -- EVAL" exp))))
|
||||||
|
|
||||||
|
(define (apply procedure arguments)
|
||||||
|
(cond ((primitive-procedure? procedure)
|
||||||
|
(apply-primitive-procedure procedure arguments))
|
||||||
|
((compound-procedure? procedure)
|
||||||
|
(eval-sequence
|
||||||
|
(procedure-body procedure)
|
||||||
|
(extend-environment
|
||||||
|
(procedure-parameters procedure)
|
||||||
|
arguments
|
||||||
|
(procedure-environment procedure))))
|
||||||
|
(else
|
||||||
|
(error
|
||||||
|
"Unknown procedure type -- APPLY" procedure))))
|
||||||
|
|
||||||
|
|
||||||
|
(define (list-of-values exps env)
|
||||||
|
(if (no-operands? exps)
|
||||||
|
'()
|
||||||
|
(cons (eval (first-operand exps) env)
|
||||||
|
(list-of-values (rest-operands exps) env))))
|
||||||
|
|
||||||
|
(define (eval-if exp env)
|
||||||
|
(if (true? (eval (if-predicate exp) env))
|
||||||
|
(eval (if-consequent exp) env)
|
||||||
|
(eval (if-alternative exp) env)))
|
||||||
|
|
||||||
|
(define (eval-sequence exps env)
|
||||||
|
(cond ((last-exp? exps) (eval (first-exp exps) env))
|
||||||
|
(else (eval (first-exp exps) env)
|
||||||
|
(eval-sequence (rest-exps exps) env))))
|
||||||
|
|
||||||
|
(define (eval-assignment exp env)
|
||||||
|
(set-variable-value! (assignment-variable exp)
|
||||||
|
(eval (assignment-value exp) env)
|
||||||
|
env)
|
||||||
|
'ok)
|
||||||
|
|
||||||
|
(define (eval-definition exp env)
|
||||||
|
(define-variable! (definition-variable exp)
|
||||||
|
(eval (definition-value exp) env)
|
||||||
|
env)
|
||||||
|
'ok)
|
||||||
|
|
||||||
|
;;;SECTION 4.1.2
|
||||||
|
|
||||||
|
(define (self-evaluating? exp)
|
||||||
|
(cond ((number? exp) true)
|
||||||
|
((string? exp) true)
|
||||||
|
(else false)))
|
||||||
|
|
||||||
|
(define (quoted? exp)
|
||||||
|
(tagged-list? exp 'quote))
|
||||||
|
|
||||||
|
(define (text-of-quotation exp) (cadr exp))
|
||||||
|
|
||||||
|
(define (tagged-list? exp tag)
|
||||||
|
(if (pair? exp)
|
||||||
|
(eq? (car exp) tag)
|
||||||
|
false))
|
||||||
|
|
||||||
|
(define (variable? exp) (symbol? exp))
|
||||||
|
|
||||||
|
(define (assignment? exp)
|
||||||
|
(tagged-list? exp 'set!))
|
||||||
|
|
||||||
|
(define (assignment-variable exp) (cadr exp))
|
||||||
|
|
||||||
|
(define (assignment-value exp) (caddr exp))
|
||||||
|
|
||||||
|
|
||||||
|
(define (definition? exp)
|
||||||
|
(tagged-list? exp 'define))
|
||||||
|
|
||||||
|
(define (definition-variable exp)
|
||||||
|
(if (symbol? (cadr exp))
|
||||||
|
(cadr exp)
|
||||||
|
(caadr exp)))
|
||||||
|
|
||||||
|
(define (definition-value exp)
|
||||||
|
(if (symbol? (cadr exp))
|
||||||
|
(caddr exp)
|
||||||
|
(make-lambda (cdadr exp)
|
||||||
|
(cddr exp))))
|
||||||
|
|
||||||
|
(define (lambda? exp) (tagged-list? exp 'lambda))
|
||||||
|
|
||||||
|
(define (lambda-parameters exp) (cadr exp))
|
||||||
|
(define (lambda-body exp) (cddr exp))
|
||||||
|
|
||||||
|
(define (make-lambda parameters body)
|
||||||
|
(cons 'lambda (cons parameters body)))
|
||||||
|
|
||||||
|
|
||||||
|
(define (if? exp) (tagged-list? exp 'if))
|
||||||
|
|
||||||
|
(define (if-predicate exp) (cadr exp))
|
||||||
|
|
||||||
|
(define (if-consequent exp) (caddr exp))
|
||||||
|
|
||||||
|
(define (if-alternative exp)
|
||||||
|
(if (not (null? (cdddr exp)))
|
||||||
|
(cadddr exp)
|
||||||
|
'false))
|
||||||
|
|
||||||
|
(define (make-if predicate consequent alternative)
|
||||||
|
(list 'if predicate consequent alternative))
|
||||||
|
|
||||||
|
|
||||||
|
(define (begin? exp) (tagged-list? exp 'begin))
|
||||||
|
|
||||||
|
(define (begin-actions exp) (cdr exp))
|
||||||
|
|
||||||
|
(define (last-exp? seq) (null? (cdr seq)))
|
||||||
|
(define (first-exp seq) (car seq))
|
||||||
|
(define (rest-exps seq) (cdr seq))
|
||||||
|
|
||||||
|
(define (sequence->exp seq)
|
||||||
|
(cond ((null? seq) seq)
|
||||||
|
((last-exp? seq) (first-exp seq))
|
||||||
|
(else (make-begin seq))))
|
||||||
|
|
||||||
|
(define (make-begin seq) (cons 'begin seq))
|
||||||
|
|
||||||
|
|
||||||
|
(define (application? exp) (pair? exp))
|
||||||
|
(define (operator exp) (car exp))
|
||||||
|
(define (operands exp) (cdr exp))
|
||||||
|
|
||||||
|
(define (no-operands? ops) (null? ops))
|
||||||
|
(define (first-operand ops) (car ops))
|
||||||
|
(define (rest-operands ops) (cdr ops))
|
||||||
|
|
||||||
|
|
||||||
|
(define (cond? exp) (tagged-list? exp 'cond))
|
||||||
|
|
||||||
|
(define (cond-clauses exp) (cdr exp))
|
||||||
|
|
||||||
|
(define (cond-else-clause? clause)
|
||||||
|
(eq? (cond-predicate clause) 'else))
|
||||||
|
|
||||||
|
(define (cond-predicate clause) (car clause))
|
||||||
|
|
||||||
|
(define (cond-actions clause) (cdr clause))
|
||||||
|
|
||||||
|
(define (cond->if exp)
|
||||||
|
(expand-clauses (cond-clauses exp)))
|
||||||
|
|
||||||
|
(define (expand-clauses clauses)
|
||||||
|
(if (null? clauses)
|
||||||
|
'false ; no else clause
|
||||||
|
(let ((first (car clauses))
|
||||||
|
(rest (cdr clauses)))
|
||||||
|
(if (cond-else-clause? first)
|
||||||
|
(if (null? rest)
|
||||||
|
(sequence->exp (cond-actions first))
|
||||||
|
(error "ELSE clause isn't last -- COND->IF"
|
||||||
|
clauses))
|
||||||
|
(make-if (cond-predicate first)
|
||||||
|
(sequence->exp (cond-actions first))
|
||||||
|
(expand-clauses rest))))))
|
||||||
|
|
||||||
|
;;;SECTION 4.1.3
|
||||||
|
|
||||||
|
(define (true? x)
|
||||||
|
(not (eq? x false)))
|
||||||
|
|
||||||
|
(define (false? x)
|
||||||
|
(eq? x false))
|
||||||
|
|
||||||
|
|
||||||
|
(define (make-procedure parameters body env)
|
||||||
|
(list 'procedure parameters body env))
|
||||||
|
|
||||||
|
(define (compound-procedure? p)
|
||||||
|
(tagged-list? p 'procedure))
|
||||||
|
|
||||||
|
|
||||||
|
(define (procedure-parameters p) (cadr p))
|
||||||
|
(define (procedure-body p) (caddr p))
|
||||||
|
(define (procedure-environment p) (cadddr p))
|
||||||
|
|
||||||
|
|
||||||
|
(define (enclosing-environment env) (cdr env))
|
||||||
|
|
||||||
|
(define (first-frame env) (car env))
|
||||||
|
|
||||||
|
(define the-empty-environment '())
|
||||||
|
|
||||||
|
(define (make-frame variables values)
|
||||||
|
(cons variables values))
|
||||||
|
|
||||||
|
(define (frame-variables frame) (car frame))
|
||||||
|
(define (frame-values frame) (cdr frame))
|
||||||
|
|
||||||
|
(define (add-binding-to-frame! var val frame)
|
||||||
|
(set-car! frame (cons var (car frame)))
|
||||||
|
(set-cdr! frame (cons val (cdr frame))))
|
||||||
|
|
||||||
|
(define (extend-environment vars vals base-env)
|
||||||
|
(if (= (length vars) (length vals))
|
||||||
|
(cons (make-frame vars vals) base-env)
|
||||||
|
(if (< (length vars) (length vals))
|
||||||
|
(error "Too many arguments supplied" vars vals)
|
||||||
|
(error "Too few arguments supplied" vars vals))))
|
||||||
|
|
||||||
|
(define (lookup-variable-value var env)
|
||||||
|
(define (env-loop env)
|
||||||
|
(define (scan vars vals)
|
||||||
|
(cond ((null? vars)
|
||||||
|
(env-loop (enclosing-environment env)))
|
||||||
|
((eq? var (car vars))
|
||||||
|
(car vals))
|
||||||
|
(else (scan (cdr vars) (cdr vals)))))
|
||||||
|
(if (eq? env the-empty-environment)
|
||||||
|
(error "Unbound variable" var)
|
||||||
|
(let ((frame (first-frame env)))
|
||||||
|
(scan (frame-variables frame)
|
||||||
|
(frame-values frame)))))
|
||||||
|
(env-loop env))
|
||||||
|
|
||||||
|
(define (set-variable-value! var val env)
|
||||||
|
(define (env-loop env)
|
||||||
|
(define (scan vars vals)
|
||||||
|
(cond ((null? vars)
|
||||||
|
(env-loop (enclosing-environment env)))
|
||||||
|
((eq? var (car vars))
|
||||||
|
(set-car! vals val))
|
||||||
|
(else (scan (cdr vars) (cdr vals)))))
|
||||||
|
(if (eq? env the-empty-environment)
|
||||||
|
(error "Unbound variable -- SET!" var)
|
||||||
|
(let ((frame (first-frame env)))
|
||||||
|
(scan (frame-variables frame)
|
||||||
|
(frame-values frame)))))
|
||||||
|
(env-loop env))
|
||||||
|
|
||||||
|
(define (define-variable! var val env)
|
||||||
|
(let ((frame (first-frame env)))
|
||||||
|
(define (scan vars vals)
|
||||||
|
(cond ((null? vars)
|
||||||
|
(add-binding-to-frame! var val frame))
|
||||||
|
((eq? var (car vars))
|
||||||
|
(set-car! vals val))
|
||||||
|
(else (scan (cdr vars) (cdr vals)))))
|
||||||
|
(scan (frame-variables frame)
|
||||||
|
(frame-values frame))))
|
||||||
|
|
||||||
|
;;;SECTION 4.1.4
|
||||||
|
|
||||||
|
(define (setup-environment)
|
||||||
|
(let ((initial-env
|
||||||
|
(extend-environment (primitive-procedure-names)
|
||||||
|
(primitive-procedure-objects)
|
||||||
|
the-empty-environment)))
|
||||||
|
(define-variable! 'true true initial-env)
|
||||||
|
(define-variable! 'false false initial-env)
|
||||||
|
initial-env))
|
||||||
|
|
||||||
|
;[do later] (define the-global-environment (setup-environment))
|
||||||
|
|
||||||
|
(define (primitive-procedure? proc)
|
||||||
|
(tagged-list? proc 'primitive))
|
||||||
|
|
||||||
|
(define (primitive-implementation proc) (cadr proc))
|
||||||
|
|
||||||
|
(define primitive-procedures
|
||||||
|
(list (list 'car car)
|
||||||
|
(list 'cdr cdr)
|
||||||
|
(list '+ +)
|
||||||
|
(list '- -)
|
||||||
|
(list '= =)
|
||||||
|
(list '* *)
|
||||||
|
(list 'cons cons)
|
||||||
|
(list 'null? null?)
|
||||||
|
))
|
||||||
|
|
||||||
|
(define (primitive-procedure-names)
|
||||||
|
(map car
|
||||||
|
primitive-procedures))
|
||||||
|
|
||||||
|
(define (primitive-procedure-objects)
|
||||||
|
(map (lambda (proc) (cadr proc))
|
||||||
|
primitive-procedures))
|
||||||
|
|
||||||
|
;[moved to start of file] (define apply-in-underlying-scheme apply)
|
||||||
|
|
||||||
|
(define (apply-primitive-procedure proc args)
|
||||||
|
(apply-in-underlying-scheme
|
||||||
|
(primitive-implementation proc) args))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(define input-prompt ";;; M-Eval input:")
|
||||||
|
(define output-prompt ";;; M-Eval value:")
|
||||||
|
|
||||||
|
(define (driver-loop)
|
||||||
|
(prompt-for-input input-prompt)
|
||||||
|
(let ((input (read)))
|
||||||
|
(let ((output (eval input the-global-environment)))
|
||||||
|
(announce-output output-prompt)
|
||||||
|
(user-print output)))
|
||||||
|
(driver-loop))
|
||||||
|
|
||||||
|
(define (prompt-for-input string)
|
||||||
|
(newline) (newline) (display string) (newline))
|
||||||
|
|
||||||
|
(define (announce-output string)
|
||||||
|
(newline) (display string) (newline))
|
||||||
|
|
||||||
|
(define (user-print object)
|
||||||
|
(if (compound-procedure? object)
|
||||||
|
(display (list 'compound-procedure
|
||||||
|
(procedure-parameters object)
|
||||||
|
(procedure-body object)
|
||||||
|
'<procedure-env>))
|
||||||
|
(display object)))
|
||||||
|
|
||||||
|
; ;;;Following are commented out so as not to be evaluated when
|
||||||
|
; ;;; the file is loaded.
|
||||||
|
(define (map f xs)
|
||||||
|
(if (null? xs)
|
||||||
|
(list)
|
||||||
|
(cons (f (car xs)) (map f (cdr xs)))))
|
||||||
|
|
||||||
|
(define the-global-environment (setup-environment))
|
||||||
|
(eval '(begin
|
||||||
|
(define (f n) (if (= n 1) 1 (* n (f (- n 1)))))
|
||||||
|
(f 5)) the-global-environment)
|
||||||
|
;(driver-loop)
|
||||||
|
)
|
||||||
397
shared/ch5-compiler.scm
Normal file
397
shared/ch5-compiler.scm
Normal file
@@ -0,0 +1,397 @@
|
|||||||
|
;;;;COMPILER FROM SECTION 5.5 OF
|
||||||
|
;;;; STRUCTURE AND INTERPRETATION OF COMPUTER PROGRAMS
|
||||||
|
|
||||||
|
;;;;Matches code in ch5.scm
|
||||||
|
|
||||||
|
;;;;This file can be loaded into Scheme as a whole.
|
||||||
|
;;;;**NOTE**This file loads the metacircular evaluator's syntax procedures
|
||||||
|
;;;; from section 4.1.2
|
||||||
|
;;;; You may need to change the (load ...) expression to work in your
|
||||||
|
;;;; version of Scheme.
|
||||||
|
|
||||||
|
;;;;Then you can compile Scheme programs as shown in section 5.5.5
|
||||||
|
|
||||||
|
;;**implementation-dependent loading of syntax procedures
|
||||||
|
(load "shared/ch5-syntax") ;section 4.1.2 syntax procedures
|
||||||
|
|
||||||
|
|
||||||
|
;;;SECTION 5.5.1
|
||||||
|
|
||||||
|
|
||||||
|
(define (let? exp) (tagged-list? exp 'let))
|
||||||
|
(define (let-bindings exp) (cadr exp))
|
||||||
|
(define (let-body exp) (cddr exp))
|
||||||
|
(define (let-binding-var binding) (car binding))
|
||||||
|
(define (let-binding-exp binding) (cadr binding))
|
||||||
|
(define (let-vars exp) (map let-binding-var (let-bindings exp)))
|
||||||
|
(define (let-exps exp) (map let-binding-exp (let-bindings exp)))
|
||||||
|
|
||||||
|
(define (let->combination exp)
|
||||||
|
(let ((let-variables (let-vars exp))
|
||||||
|
(let-expressions (let-exps exp)))
|
||||||
|
(cons (make-lambda let-variables (let-body exp))
|
||||||
|
let-expressions)))
|
||||||
|
|
||||||
|
|
||||||
|
(define (compile exp target linkage)
|
||||||
|
(cond ((self-evaluating? exp)
|
||||||
|
(compile-self-evaluating exp target linkage))
|
||||||
|
((quoted? exp) (compile-quoted exp target linkage))
|
||||||
|
((variable? exp)
|
||||||
|
(compile-variable exp target linkage))
|
||||||
|
((assignment? exp)
|
||||||
|
(compile-assignment exp target linkage))
|
||||||
|
((definition? exp)
|
||||||
|
(compile-definition exp target linkage))
|
||||||
|
((if? exp) (compile-if exp target linkage))
|
||||||
|
((lambda? exp) (compile-lambda exp target linkage))
|
||||||
|
((let? exp) (compile (let->combination exp) target linkage))
|
||||||
|
((begin? exp)
|
||||||
|
(compile-sequence (begin-actions exp)
|
||||||
|
target
|
||||||
|
linkage))
|
||||||
|
((cond? exp) (compile (cond->if exp) target linkage))
|
||||||
|
((application? exp)
|
||||||
|
(compile-application exp target linkage))
|
||||||
|
(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 '() '() '()))
|
||||||
|
|
||||||
|
|
||||||
|
;;;SECTION 5.5.2
|
||||||
|
|
||||||
|
;;;linkage code
|
||||||
|
|
||||||
|
(define (compile-linkage linkage)
|
||||||
|
(cond ((eq? linkage 'return)
|
||||||
|
(make-instruction-sequence '(continue) '()
|
||||||
|
'((goto (reg continue)))))
|
||||||
|
((eq? linkage 'next)
|
||||||
|
(empty-instruction-sequence))
|
||||||
|
(else
|
||||||
|
(make-instruction-sequence '() '()
|
||||||
|
`((goto (label ,linkage)))))))
|
||||||
|
|
||||||
|
(define (end-with-linkage linkage instruction-sequence)
|
||||||
|
(preserving '(continue)
|
||||||
|
instruction-sequence
|
||||||
|
(compile-linkage linkage)))
|
||||||
|
|
||||||
|
|
||||||
|
;;;simple expressions
|
||||||
|
|
||||||
|
(define (compile-self-evaluating exp target linkage)
|
||||||
|
(end-with-linkage linkage
|
||||||
|
(make-instruction-sequence '() (list target)
|
||||||
|
`((assign ,target (const ,exp))))))
|
||||||
|
|
||||||
|
(define (compile-quoted exp target linkage)
|
||||||
|
(end-with-linkage linkage
|
||||||
|
(make-instruction-sequence '() (list target)
|
||||||
|
`((assign ,target (const ,(text-of-quotation exp)))))))
|
||||||
|
|
||||||
|
(define (compile-variable exp target linkage)
|
||||||
|
(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)
|
||||||
|
(let ((var (assignment-variable exp))
|
||||||
|
(get-value-code
|
||||||
|
(compile (assignment-value exp) 'val 'next)))
|
||||||
|
(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)
|
||||||
|
(let ((var (definition-variable exp))
|
||||||
|
(get-value-code
|
||||||
|
(compile (definition-value exp) 'val 'next)))
|
||||||
|
(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))))))))
|
||||||
|
|
||||||
|
|
||||||
|
;;;conditional expressions
|
||||||
|
|
||||||
|
;;;labels (from footnote)
|
||||||
|
(define label-counter 0)
|
||||||
|
|
||||||
|
(define (new-label-number)
|
||||||
|
(set! label-counter (+ 1 label-counter))
|
||||||
|
label-counter)
|
||||||
|
|
||||||
|
(define (make-label name)
|
||||||
|
(string->symbol
|
||||||
|
(string-append (symbol->string name)
|
||||||
|
(number->string (new-label-number)))))
|
||||||
|
;; end of footnote
|
||||||
|
|
||||||
|
(define (compile-if exp target linkage)
|
||||||
|
(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))
|
||||||
|
(c-code
|
||||||
|
(compile
|
||||||
|
(if-consequent exp) target consequent-linkage))
|
||||||
|
(a-code
|
||||||
|
(compile (if-alternative exp) target linkage)))
|
||||||
|
(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))))))
|
||||||
|
|
||||||
|
;;; sequences
|
||||||
|
|
||||||
|
(define (compile-sequence seq target linkage)
|
||||||
|
(if (last-exp? seq)
|
||||||
|
(compile (first-exp seq) target linkage)
|
||||||
|
(preserving '(env continue)
|
||||||
|
(compile (first-exp seq) target 'next)
|
||||||
|
(compile-sequence (rest-exps seq) target linkage))))
|
||||||
|
|
||||||
|
;;;lambda expressions
|
||||||
|
|
||||||
|
(define (compile-lambda exp target linkage)
|
||||||
|
(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))
|
||||||
|
after-lambda))))
|
||||||
|
|
||||||
|
(define (compile-lambda-body exp proc-entry)
|
||||||
|
(let ((formals (lambda-parameters exp)))
|
||||||
|
(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))))
|
||||||
|
|
||||||
|
|
||||||
|
;;;SECTION 5.5.3
|
||||||
|
|
||||||
|
;;;combinations
|
||||||
|
|
||||||
|
(define (compile-application exp target linkage)
|
||||||
|
(let ((proc-code (compile (operator exp) 'proc 'next))
|
||||||
|
(operand-codes
|
||||||
|
(map (lambda (operand) (compile operand 'val 'next))
|
||||||
|
(operands exp))))
|
||||||
|
(preserving '(env continue)
|
||||||
|
proc-code
|
||||||
|
(preserving '(proc continue)
|
||||||
|
(construct-arglist operand-codes)
|
||||||
|
(compile-procedure-call target linkage)))))
|
||||||
|
|
||||||
|
(define (construct-arglist operand-codes)
|
||||||
|
(let ((operand-codes (reverse operand-codes)))
|
||||||
|
(if (null? operand-codes)
|
||||||
|
(make-instruction-sequence '() '(argl)
|
||||||
|
'((assign argl (const ()))))
|
||||||
|
(let ((code-to-get-last-arg
|
||||||
|
(append-instruction-sequences
|
||||||
|
(car operand-codes)
|
||||||
|
(make-instruction-sequence '(val) '(argl)
|
||||||
|
'((assign argl (op list) (reg val)))))))
|
||||||
|
(if (null? (cdr operand-codes))
|
||||||
|
code-to-get-last-arg
|
||||||
|
(preserving '(env)
|
||||||
|
code-to-get-last-arg
|
||||||
|
(code-to-get-rest-args
|
||||||
|
(cdr operand-codes))))))))
|
||||||
|
|
||||||
|
(define (code-to-get-rest-args operand-codes)
|
||||||
|
(let ((code-for-next-arg
|
||||||
|
(preserving '(argl)
|
||||||
|
(car operand-codes)
|
||||||
|
(make-instruction-sequence '(val argl) '(argl)
|
||||||
|
'((assign argl
|
||||||
|
(op cons) (reg val) (reg argl)))))))
|
||||||
|
(if (null? (cdr operand-codes))
|
||||||
|
code-for-next-arg
|
||||||
|
(preserving '(env)
|
||||||
|
code-for-next-arg
|
||||||
|
(code-to-get-rest-args (cdr operand-codes))))))
|
||||||
|
|
||||||
|
;;;applying procedures
|
||||||
|
|
||||||
|
(define (compile-procedure-call target linkage)
|
||||||
|
(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))
|
||||||
|
(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))))
|
||||||
|
|
||||||
|
;;;applying compiled procedures
|
||||||
|
|
||||||
|
(define (compile-proc-appl target linkage)
|
||||||
|
(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))))
|
||||||
|
|
||||||
|
;; footnote
|
||||||
|
(define all-regs '(env proc val argl continue))
|
||||||
|
|
||||||
|
|
||||||
|
;;;SECTION 5.5.4
|
||||||
|
|
||||||
|
(define (registers-needed s)
|
||||||
|
(if (symbol? s) '() (car s)))
|
||||||
|
|
||||||
|
(define (registers-modified s)
|
||||||
|
(if (symbol? s) '() (cadr s)))
|
||||||
|
|
||||||
|
(define (statements s)
|
||||||
|
(if (symbol? s) (list s) (caddr s)))
|
||||||
|
|
||||||
|
(define (needs-register? seq reg)
|
||||||
|
(memq reg (registers-needed seq)))
|
||||||
|
|
||||||
|
(define (modifies-register? seq reg)
|
||||||
|
(memq reg (registers-modified seq)))
|
||||||
|
|
||||||
|
|
||||||
|
(define (append-instruction-sequences . seqs)
|
||||||
|
(define (append-2-sequences seq1 seq2)
|
||||||
|
(make-instruction-sequence
|
||||||
|
(list-union (registers-needed seq1)
|
||||||
|
(list-difference (registers-needed seq2)
|
||||||
|
(registers-modified seq1)))
|
||||||
|
(list-union (registers-modified seq1)
|
||||||
|
(registers-modified seq2))
|
||||||
|
(append (statements seq1) (statements seq2))))
|
||||||
|
(define (append-seq-list seqs)
|
||||||
|
(if (null? seqs)
|
||||||
|
(empty-instruction-sequence)
|
||||||
|
(append-2-sequences (car seqs)
|
||||||
|
(append-seq-list (cdr seqs)))))
|
||||||
|
(append-seq-list seqs))
|
||||||
|
|
||||||
|
(define (list-union s1 s2)
|
||||||
|
(cond ((null? s1) s2)
|
||||||
|
((memq (car s1) s2) (list-union (cdr s1) s2))
|
||||||
|
(else (cons (car s1) (list-union (cdr s1) s2)))))
|
||||||
|
|
||||||
|
(define (list-difference s1 s2)
|
||||||
|
(cond ((null? s1) '())
|
||||||
|
((memq (car s1) s2) (list-difference (cdr s1) s2))
|
||||||
|
(else (cons (car s1)
|
||||||
|
(list-difference (cdr s1) s2)))))
|
||||||
|
|
||||||
|
(define (preserving regs seq1 seq2)
|
||||||
|
(if (null? regs)
|
||||||
|
(append-instruction-sequences seq1 seq2)
|
||||||
|
(let ((first-reg (car regs)))
|
||||||
|
(if (and (needs-register? seq2 first-reg)
|
||||||
|
(modifies-register? seq1 first-reg))
|
||||||
|
(preserving (cdr regs)
|
||||||
|
(make-instruction-sequence
|
||||||
|
(list-union (list first-reg)
|
||||||
|
(registers-needed seq1))
|
||||||
|
(list-difference (registers-modified seq1)
|
||||||
|
(list first-reg))
|
||||||
|
(append `((save ,first-reg))
|
||||||
|
(statements seq1)
|
||||||
|
`((restore ,first-reg))))
|
||||||
|
seq2)
|
||||||
|
(preserving (cdr regs) seq1 seq2)))))
|
||||||
|
|
||||||
|
(define (tack-on-instruction-sequence seq body-seq)
|
||||||
|
(make-instruction-sequence
|
||||||
|
(registers-needed seq)
|
||||||
|
(registers-modified seq)
|
||||||
|
(append (statements seq) (statements body-seq))))
|
||||||
|
|
||||||
|
(define (parallel-instruction-sequences seq1 seq2)
|
||||||
|
(make-instruction-sequence
|
||||||
|
(list-union (registers-needed seq1)
|
||||||
|
(registers-needed seq2))
|
||||||
|
(list-union (registers-modified seq1)
|
||||||
|
(registers-modified seq2))
|
||||||
|
(append (statements seq1) (statements seq2))))
|
||||||
|
|
||||||
|
'(COMPILER LOADED)
|
||||||
211
shared/ch5-eceval-support.scm
Normal file
211
shared/ch5-eceval-support.scm
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
;;;;SIMULATION OF ECEVAL MACHINE OPERATIONS --
|
||||||
|
;;;;loaded by load-eceval.scm and by load-eceval-compiler.scm
|
||||||
|
|
||||||
|
;;;;FIRST A LOT FROM 4.1.2-4.1.4
|
||||||
|
|
||||||
|
(load "shared/ch5-syntax.scm"); ;section 4.1.2 syntax procedures
|
||||||
|
|
||||||
|
;;;SECTION 4.1.3
|
||||||
|
;;; operations used by compiled code and eceval except as noted
|
||||||
|
|
||||||
|
(define (true? x)
|
||||||
|
(not (eq? x false)))
|
||||||
|
|
||||||
|
;;* not used by eceval itself -- used by compiled code when that
|
||||||
|
;; is run in the eceval machine
|
||||||
|
(define (false? x)
|
||||||
|
(eq? x false))
|
||||||
|
|
||||||
|
;;following compound-procedure operations not used by compiled code
|
||||||
|
(define (make-procedure parameters body env)
|
||||||
|
(list 'procedure parameters body env))
|
||||||
|
|
||||||
|
(define (compound-procedure? p)
|
||||||
|
(tagged-list? p 'procedure))
|
||||||
|
|
||||||
|
(define (procedure-parameters p) (cadr p))
|
||||||
|
(define (procedure-body p) (caddr p))
|
||||||
|
(define (procedure-environment p) (cadddr p))
|
||||||
|
;;(end of compound procedures)
|
||||||
|
|
||||||
|
|
||||||
|
(define (enclosing-environment env) (cdr env))
|
||||||
|
|
||||||
|
(define (first-frame env) (car env))
|
||||||
|
|
||||||
|
(define the-empty-environment '())
|
||||||
|
|
||||||
|
(define (make-frame variables values)
|
||||||
|
(cons variables values))
|
||||||
|
|
||||||
|
(define (frame-variables frame) (car frame))
|
||||||
|
(define (frame-values frame) (cdr frame))
|
||||||
|
|
||||||
|
(define (add-binding-to-frame! var val frame)
|
||||||
|
(set-car! frame (cons var (car frame)))
|
||||||
|
(set-cdr! frame (cons val (cdr frame))))
|
||||||
|
|
||||||
|
(define (extend-environment vars vals base-env)
|
||||||
|
(if (= (length vars) (length vals))
|
||||||
|
(cons (make-frame vars vals) base-env)
|
||||||
|
(if (< (length vars) (length vals))
|
||||||
|
(error "Too many arguments supplied" vars vals)
|
||||||
|
(error "Too few arguments supplied" vars vals))))
|
||||||
|
|
||||||
|
|
||||||
|
(define (lookup-variable-value var env)
|
||||||
|
(define (env-loop env)
|
||||||
|
(define (scan vars vals)
|
||||||
|
(cond ((null? vars)
|
||||||
|
(env-loop (enclosing-environment env)))
|
||||||
|
((eq? var (car vars))
|
||||||
|
(car vals))
|
||||||
|
(else (scan (cdr vars) (cdr vals)))))
|
||||||
|
(if (eq? env the-empty-environment)
|
||||||
|
(error "Unbound variable" var)
|
||||||
|
(let ((frame (first-frame env)))
|
||||||
|
(scan (frame-variables frame)
|
||||||
|
(frame-values frame)))))
|
||||||
|
(env-loop env))
|
||||||
|
|
||||||
|
(define (set-variable-value! var val env)
|
||||||
|
(define (env-loop env)
|
||||||
|
(define (scan vars vals)
|
||||||
|
(cond ((null? vars)
|
||||||
|
(env-loop (enclosing-environment env)))
|
||||||
|
((eq? var (car vars))
|
||||||
|
(set-car! vals val))
|
||||||
|
(else (scan (cdr vars) (cdr vals)))))
|
||||||
|
(if (eq? env the-empty-environment)
|
||||||
|
(error "Unbound variable -- SET!" var)
|
||||||
|
(let ((frame (first-frame env)))
|
||||||
|
(scan (frame-variables frame)
|
||||||
|
(frame-values frame)))))
|
||||||
|
(env-loop env))
|
||||||
|
|
||||||
|
(define (define-variable! var val env)
|
||||||
|
(let ((frame (first-frame env)))
|
||||||
|
(define (scan vars vals)
|
||||||
|
(cond ((null? vars)
|
||||||
|
(add-binding-to-frame! var val frame))
|
||||||
|
((eq? var (car vars))
|
||||||
|
(set-car! vals val))
|
||||||
|
(else (scan (cdr vars) (cdr vals)))))
|
||||||
|
(scan (frame-variables frame)
|
||||||
|
(frame-values frame))))
|
||||||
|
|
||||||
|
|
||||||
|
;;;SECTION 4.1.4
|
||||||
|
|
||||||
|
(define (setup-environment)
|
||||||
|
(let ((initial-env
|
||||||
|
(extend-environment (primitive-procedure-names)
|
||||||
|
(primitive-procedure-objects)
|
||||||
|
the-empty-environment)))
|
||||||
|
(define-variable! 'true true initial-env)
|
||||||
|
(define-variable! 'false false initial-env)
|
||||||
|
initial-env))
|
||||||
|
|
||||||
|
(define (primitive-procedure? proc)
|
||||||
|
(tagged-list? proc 'primitive))
|
||||||
|
|
||||||
|
(define (primitive-implementation proc) (cadr proc))
|
||||||
|
|
||||||
|
(define primitive-procedures
|
||||||
|
(list (list 'car car)
|
||||||
|
(list 'cadr cadr)
|
||||||
|
(list 'caddr caddr)
|
||||||
|
(list 'cadddr cadddr)
|
||||||
|
(list 'caadr caadr)
|
||||||
|
(list 'cdr cdr)
|
||||||
|
(list 'cddr cddr)
|
||||||
|
(list 'cdddr cdddr)
|
||||||
|
(list 'cdadr cdadr)
|
||||||
|
(list 'cons cons)
|
||||||
|
(list 'eq? eq?)
|
||||||
|
(list 'length length)
|
||||||
|
(list 'list list)
|
||||||
|
(list 'null? null?)
|
||||||
|
(list 'number? number?)
|
||||||
|
(list 'pair? pair?)
|
||||||
|
(list 'set-car! set-car!)
|
||||||
|
(list 'set-cdr! set-cdr!)
|
||||||
|
(list 'string? string?)
|
||||||
|
(list 'symbol? symbol?)
|
||||||
|
;;above from book -- here are some more
|
||||||
|
(list '+ +)
|
||||||
|
(list '- -)
|
||||||
|
(list '* *)
|
||||||
|
(list '= =)
|
||||||
|
(list '/ /)
|
||||||
|
(list '> >)
|
||||||
|
(list '< <)
|
||||||
|
(list 'apply apply)
|
||||||
|
(list 'not not)
|
||||||
|
|
||||||
|
;; for driver loop and debugging
|
||||||
|
(list 'display display)
|
||||||
|
(list 'newline newline)
|
||||||
|
(list 'error error)
|
||||||
|
(list 'read read)
|
||||||
|
))
|
||||||
|
|
||||||
|
(define (primitive-procedure-names)
|
||||||
|
(map car
|
||||||
|
primitive-procedures))
|
||||||
|
|
||||||
|
(define (primitive-procedure-objects)
|
||||||
|
(map (lambda (proc) (list 'primitive (cadr proc)))
|
||||||
|
primitive-procedures))
|
||||||
|
|
||||||
|
(define apply-in-underlying-scheme apply)
|
||||||
|
|
||||||
|
(define (apply-primitive-procedure proc args)
|
||||||
|
(apply-in-underlying-scheme
|
||||||
|
(primitive-implementation proc) args))
|
||||||
|
|
||||||
|
|
||||||
|
(define (prompt-for-input string)
|
||||||
|
(newline) (newline) (display string) (newline))
|
||||||
|
|
||||||
|
(define (announce-output string)
|
||||||
|
(newline) (display string) (newline))
|
||||||
|
|
||||||
|
(define (user-print object)
|
||||||
|
(if (compound-procedure? object)
|
||||||
|
(display (list 'compound-procedure
|
||||||
|
(procedure-parameters object)
|
||||||
|
(procedure-body object)
|
||||||
|
'<procedure-env>))
|
||||||
|
(display object)))
|
||||||
|
|
||||||
|
;;; Simulation of new machine operations needed by
|
||||||
|
;;; eceval machine (not used by compiled code)
|
||||||
|
|
||||||
|
;;; From section 5.4.1 footnote
|
||||||
|
(define (empty-arglist) '())
|
||||||
|
(define (adjoin-arg arg arglist)
|
||||||
|
(append arglist (list arg)))
|
||||||
|
(define (last-operand? ops)
|
||||||
|
(null? (cdr ops)))
|
||||||
|
|
||||||
|
;;; From section 5.4.2 footnote, for non-tail-recursive sequences
|
||||||
|
(define (no-more-exps? seq) (null? seq))
|
||||||
|
|
||||||
|
;;; From section 5.4.4 footnote
|
||||||
|
(define (get-global-environment)
|
||||||
|
the-global-environment)
|
||||||
|
;; will do following when ready to run, not when load this file
|
||||||
|
;;(define the-global-environment (setup-environment))
|
||||||
|
|
||||||
|
|
||||||
|
;;; Simulation of new machine operations needed for compiled code
|
||||||
|
;;; and eceval/compiler interface (not used by plain eceval machine)
|
||||||
|
;;; From section 5.5.2 footnote
|
||||||
|
(define (make-compiled-procedure entry env)
|
||||||
|
(list 'compiled-procedure entry env))
|
||||||
|
(define (compiled-procedure? proc)
|
||||||
|
(tagged-list? proc 'compiled-procedure))
|
||||||
|
(define (compiled-procedure-entry c-proc) (cadr c-proc))
|
||||||
|
(define (compiled-procedure-env c-proc) (caddr c-proc))
|
||||||
|
|
||||||
407
shared/ch5-regsim.scm
Normal file
407
shared/ch5-regsim.scm
Normal file
@@ -0,0 +1,407 @@
|
|||||||
|
;;;;REGISTER-MACHINE SIMULATOR FROM SECTION 5.2 OF
|
||||||
|
;;;; STRUCTURE AND INTERPRETATION OF COMPUTER PROGRAMS
|
||||||
|
|
||||||
|
;;;;Matches code in ch5.scm
|
||||||
|
|
||||||
|
;;;;This file can be loaded into Scheme as a whole.
|
||||||
|
;;;;Then you can define and simulate machines as shown in section 5.2
|
||||||
|
|
||||||
|
;;;**NB** there are two versions of make-stack below.
|
||||||
|
;;; Choose the monitored or unmonitored one by reordering them to put the
|
||||||
|
;;; one you want last, or by commenting one of them out.
|
||||||
|
;;; Also, comment in/out the print-stack-statistics op in make-new-machine
|
||||||
|
;;; To find this stack code below, look for comments with **
|
||||||
|
|
||||||
|
|
||||||
|
(define (make-machine register-names ops controller-text)
|
||||||
|
(let ((machine (make-new-machine)))
|
||||||
|
(for-each (lambda (register-name)
|
||||||
|
((machine 'allocate-register) register-name))
|
||||||
|
register-names)
|
||||||
|
((machine 'install-operations) ops)
|
||||||
|
((machine 'install-instruction-sequence)
|
||||||
|
(assemble controller-text machine))
|
||||||
|
machine))
|
||||||
|
|
||||||
|
(define (make-register name)
|
||||||
|
(let ((contents '*unassigned*))
|
||||||
|
(define (dispatch message)
|
||||||
|
(cond ((eq? message 'get) contents)
|
||||||
|
((eq? message 'set)
|
||||||
|
(lambda (value) (set! contents value)))
|
||||||
|
(else
|
||||||
|
(error "Unknown request -- REGISTER" message))))
|
||||||
|
dispatch))
|
||||||
|
|
||||||
|
(define (get-contents register)
|
||||||
|
(register 'get))
|
||||||
|
|
||||||
|
(define (set-contents! register value)
|
||||||
|
((register 'set) value))
|
||||||
|
|
||||||
|
;;**original (unmonitored) version from section 5.2.1
|
||||||
|
(define (make-stack)
|
||||||
|
(let ((s '()))
|
||||||
|
(define (push x)
|
||||||
|
(set! s (cons x s)))
|
||||||
|
(define (pop)
|
||||||
|
(if (null? s)
|
||||||
|
(error "Empty stack -- POP")
|
||||||
|
(let ((top (car s)))
|
||||||
|
(set! s (cdr s))
|
||||||
|
top)))
|
||||||
|
(define (initialize)
|
||||||
|
(set! s '())
|
||||||
|
'done)
|
||||||
|
(define (dispatch message)
|
||||||
|
(cond ((eq? message 'push) push)
|
||||||
|
((eq? message 'pop) (pop))
|
||||||
|
((eq? message 'initialize) (initialize))
|
||||||
|
(else (error "Unknown request -- STACK"
|
||||||
|
message))))
|
||||||
|
dispatch))
|
||||||
|
|
||||||
|
(define (pop stack)
|
||||||
|
(stack 'pop))
|
||||||
|
|
||||||
|
(define (push stack value)
|
||||||
|
((stack 'push) value))
|
||||||
|
|
||||||
|
;;**monitored version from section 5.2.4
|
||||||
|
(define (make-stack)
|
||||||
|
(let ((s '())
|
||||||
|
(number-pushes 0)
|
||||||
|
(max-depth 0)
|
||||||
|
(current-depth 0))
|
||||||
|
(define (push x)
|
||||||
|
(set! s (cons x s))
|
||||||
|
(set! number-pushes (+ 1 number-pushes))
|
||||||
|
(set! current-depth (+ 1 current-depth))
|
||||||
|
(set! max-depth (max current-depth max-depth)))
|
||||||
|
(define (pop)
|
||||||
|
(if (null? s)
|
||||||
|
(error "Empty stack -- POP")
|
||||||
|
(let ((top (car s)))
|
||||||
|
(set! s (cdr s))
|
||||||
|
(set! current-depth (- current-depth 1))
|
||||||
|
top)))
|
||||||
|
(define (initialize)
|
||||||
|
(set! s '())
|
||||||
|
(set! number-pushes 0)
|
||||||
|
(set! max-depth 0)
|
||||||
|
(set! current-depth 0)
|
||||||
|
'done)
|
||||||
|
(define (print-statistics)
|
||||||
|
(newline)
|
||||||
|
(display (list 'total-pushes '= number-pushes
|
||||||
|
'maximum-depth '= max-depth)))
|
||||||
|
(define (dispatch message)
|
||||||
|
(cond ((eq? message 'push) push)
|
||||||
|
((eq? message 'pop) (pop))
|
||||||
|
((eq? message 'initialize) (initialize))
|
||||||
|
((eq? message 'print-statistics)
|
||||||
|
(print-statistics))
|
||||||
|
(else
|
||||||
|
(error "Unknown request -- STACK" message))))
|
||||||
|
dispatch))
|
||||||
|
|
||||||
|
(define (make-new-machine)
|
||||||
|
(let ((pc (make-register 'pc))
|
||||||
|
(flag (make-register 'flag))
|
||||||
|
(stack (make-stack))
|
||||||
|
(the-instruction-sequence '()))
|
||||||
|
(let ((the-ops
|
||||||
|
(list (list 'initialize-stack
|
||||||
|
(lambda () (stack 'initialize)))
|
||||||
|
;;**next for monitored stack (as in section 5.2.4)
|
||||||
|
;; -- comment out if not wanted
|
||||||
|
(list 'print-stack-statistics
|
||||||
|
(lambda () (stack 'print-statistics)))))
|
||||||
|
(register-table
|
||||||
|
(list (list 'pc pc) (list 'flag flag))))
|
||||||
|
(define (allocate-register name)
|
||||||
|
(if (assoc name register-table)
|
||||||
|
(error "Multiply defined register: " name)
|
||||||
|
(set! register-table
|
||||||
|
(cons (list name (make-register name))
|
||||||
|
register-table)))
|
||||||
|
'register-allocated)
|
||||||
|
(define (lookup-register name)
|
||||||
|
(let ((val (assoc name register-table)))
|
||||||
|
(if val
|
||||||
|
(cadr val)
|
||||||
|
(error "Unknown register:" name))))
|
||||||
|
(define (execute)
|
||||||
|
(let ((insts (get-contents pc)))
|
||||||
|
(if (null? insts)
|
||||||
|
'done
|
||||||
|
(begin
|
||||||
|
((instruction-execution-proc (car insts)))
|
||||||
|
(execute)))))
|
||||||
|
(define (dispatch message)
|
||||||
|
(cond ((eq? message 'start)
|
||||||
|
(set-contents! pc the-instruction-sequence)
|
||||||
|
(execute))
|
||||||
|
((eq? message 'install-instruction-sequence)
|
||||||
|
(lambda (seq) (set! the-instruction-sequence seq)))
|
||||||
|
((eq? message 'allocate-register) allocate-register)
|
||||||
|
((eq? message 'get-register) lookup-register)
|
||||||
|
((eq? message 'install-operations)
|
||||||
|
(lambda (ops) (set! the-ops (append the-ops ops))))
|
||||||
|
((eq? message 'stack) stack)
|
||||||
|
((eq? message 'operations) the-ops)
|
||||||
|
(else (error "Unknown request -- MACHINE" message))))
|
||||||
|
dispatch)))
|
||||||
|
|
||||||
|
|
||||||
|
(define (start machine)
|
||||||
|
(machine 'start))
|
||||||
|
|
||||||
|
(define (get-register-contents machine register-name)
|
||||||
|
(get-contents (get-register machine register-name)))
|
||||||
|
|
||||||
|
(define (set-register-contents! machine register-name value)
|
||||||
|
(set-contents! (get-register machine register-name) value)
|
||||||
|
'done)
|
||||||
|
|
||||||
|
(define (get-register machine reg-name)
|
||||||
|
((machine 'get-register) reg-name))
|
||||||
|
|
||||||
|
(define (assemble controller-text machine)
|
||||||
|
(extract-labels controller-text
|
||||||
|
(lambda (insts labels)
|
||||||
|
(update-insts! insts labels machine)
|
||||||
|
insts)))
|
||||||
|
|
||||||
|
(define (extract-labels text receive)
|
||||||
|
(if (null? text)
|
||||||
|
(receive '() '())
|
||||||
|
(extract-labels (cdr text)
|
||||||
|
(lambda (insts labels)
|
||||||
|
(let ((next-inst (car text)))
|
||||||
|
(if (symbol? next-inst)
|
||||||
|
(receive insts
|
||||||
|
(cons (make-label-entry next-inst
|
||||||
|
insts)
|
||||||
|
labels))
|
||||||
|
(receive (cons (make-instruction next-inst)
|
||||||
|
insts)
|
||||||
|
labels)))))))
|
||||||
|
|
||||||
|
(define (update-insts! insts labels machine)
|
||||||
|
(let ((pc (get-register machine 'pc))
|
||||||
|
(flag (get-register machine 'flag))
|
||||||
|
(stack (machine 'stack))
|
||||||
|
(ops (machine 'operations)))
|
||||||
|
(for-each
|
||||||
|
(lambda (inst)
|
||||||
|
(set-instruction-execution-proc!
|
||||||
|
inst
|
||||||
|
(make-execution-procedure
|
||||||
|
(instruction-text inst) labels machine
|
||||||
|
pc flag stack ops)))
|
||||||
|
insts)))
|
||||||
|
|
||||||
|
(define (make-instruction text)
|
||||||
|
(cons text '()))
|
||||||
|
|
||||||
|
(define (instruction-text inst)
|
||||||
|
(car inst))
|
||||||
|
|
||||||
|
(define (instruction-execution-proc inst)
|
||||||
|
(cdr inst))
|
||||||
|
|
||||||
|
(define (set-instruction-execution-proc! inst proc)
|
||||||
|
(set-cdr! inst proc))
|
||||||
|
|
||||||
|
(define (make-label-entry label-name insts)
|
||||||
|
(cons label-name insts))
|
||||||
|
|
||||||
|
(define (lookup-label labels label-name)
|
||||||
|
(let ((val (assoc label-name labels)))
|
||||||
|
(if val
|
||||||
|
(cdr val)
|
||||||
|
(error "Undefined label -- ASSEMBLE" label-name))))
|
||||||
|
|
||||||
|
|
||||||
|
(define (make-execution-procedure inst labels machine
|
||||||
|
pc flag stack ops)
|
||||||
|
(cond ((eq? (car inst) 'assign)
|
||||||
|
(make-assign inst machine labels ops pc))
|
||||||
|
((eq? (car inst) 'test)
|
||||||
|
(make-test inst machine labels ops flag pc))
|
||||||
|
((eq? (car inst) 'branch)
|
||||||
|
(make-branch inst machine labels flag pc))
|
||||||
|
((eq? (car inst) 'goto)
|
||||||
|
(make-goto inst machine labels pc))
|
||||||
|
((eq? (car inst) 'save)
|
||||||
|
(make-save inst machine stack pc))
|
||||||
|
((eq? (car inst) 'restore)
|
||||||
|
(make-restore inst machine stack pc))
|
||||||
|
((eq? (car inst) 'perform)
|
||||||
|
(make-perform inst machine labels ops pc))
|
||||||
|
(else (error "Unknown instruction type -- ASSEMBLE"
|
||||||
|
inst))))
|
||||||
|
|
||||||
|
|
||||||
|
(define (make-assign inst machine labels operations pc)
|
||||||
|
(let ((target
|
||||||
|
(get-register machine (assign-reg-name inst)))
|
||||||
|
(value-exp (assign-value-exp inst)))
|
||||||
|
(let ((value-proc
|
||||||
|
(if (operation-exp? value-exp)
|
||||||
|
(make-operation-exp
|
||||||
|
value-exp machine labels operations)
|
||||||
|
(make-primitive-exp
|
||||||
|
(car value-exp) machine labels))))
|
||||||
|
(lambda () ; execution procedure for assign
|
||||||
|
(set-contents! target (value-proc))
|
||||||
|
(advance-pc pc)))))
|
||||||
|
|
||||||
|
(define (assign-reg-name assign-instruction)
|
||||||
|
(cadr assign-instruction))
|
||||||
|
|
||||||
|
(define (assign-value-exp assign-instruction)
|
||||||
|
(cddr assign-instruction))
|
||||||
|
|
||||||
|
(define (advance-pc pc)
|
||||||
|
(set-contents! pc (cdr (get-contents pc))))
|
||||||
|
|
||||||
|
(define (make-test inst machine labels operations flag pc)
|
||||||
|
(let ((condition (test-condition inst)))
|
||||||
|
(if (operation-exp? condition)
|
||||||
|
(let ((condition-proc
|
||||||
|
(make-operation-exp
|
||||||
|
condition machine labels operations)))
|
||||||
|
(lambda ()
|
||||||
|
(set-contents! flag (condition-proc))
|
||||||
|
(advance-pc pc)))
|
||||||
|
(error "Bad TEST instruction -- ASSEMBLE" inst))))
|
||||||
|
|
||||||
|
(define (test-condition test-instruction)
|
||||||
|
(cdr test-instruction))
|
||||||
|
|
||||||
|
|
||||||
|
(define (make-branch inst machine labels flag pc)
|
||||||
|
(let ((dest (branch-dest inst)))
|
||||||
|
(if (label-exp? dest)
|
||||||
|
(let ((insts
|
||||||
|
(lookup-label labels (label-exp-label dest))))
|
||||||
|
(lambda ()
|
||||||
|
(if (get-contents flag)
|
||||||
|
(set-contents! pc insts)
|
||||||
|
(advance-pc pc))))
|
||||||
|
(error "Bad BRANCH instruction -- ASSEMBLE" inst))))
|
||||||
|
|
||||||
|
(define (branch-dest branch-instruction)
|
||||||
|
(cadr branch-instruction))
|
||||||
|
|
||||||
|
|
||||||
|
(define (make-goto inst machine labels pc)
|
||||||
|
(let ((dest (goto-dest inst)))
|
||||||
|
(cond ((label-exp? dest)
|
||||||
|
(let ((insts
|
||||||
|
(lookup-label labels
|
||||||
|
(label-exp-label dest))))
|
||||||
|
(lambda () (set-contents! pc insts))))
|
||||||
|
((register-exp? dest)
|
||||||
|
(let ((reg
|
||||||
|
(get-register machine
|
||||||
|
(register-exp-reg dest))))
|
||||||
|
(lambda ()
|
||||||
|
(set-contents! pc (get-contents reg)))))
|
||||||
|
(else (error "Bad GOTO instruction -- ASSEMBLE"
|
||||||
|
inst)))))
|
||||||
|
|
||||||
|
(define (goto-dest goto-instruction)
|
||||||
|
(cadr goto-instruction))
|
||||||
|
|
||||||
|
(define (make-save inst machine stack pc)
|
||||||
|
(let ((reg (get-register machine
|
||||||
|
(stack-inst-reg-name inst))))
|
||||||
|
(lambda ()
|
||||||
|
(push stack (get-contents reg))
|
||||||
|
(advance-pc pc))))
|
||||||
|
|
||||||
|
(define (make-restore inst machine stack pc)
|
||||||
|
(let ((reg (get-register machine
|
||||||
|
(stack-inst-reg-name inst))))
|
||||||
|
(lambda ()
|
||||||
|
(set-contents! reg (pop stack))
|
||||||
|
(advance-pc pc))))
|
||||||
|
|
||||||
|
(define (stack-inst-reg-name stack-instruction)
|
||||||
|
(cadr stack-instruction))
|
||||||
|
|
||||||
|
(define (make-perform inst machine labels operations pc)
|
||||||
|
(let ((action (perform-action inst)))
|
||||||
|
(if (operation-exp? action)
|
||||||
|
(let ((action-proc
|
||||||
|
(make-operation-exp
|
||||||
|
action machine labels operations)))
|
||||||
|
(lambda ()
|
||||||
|
(action-proc)
|
||||||
|
(advance-pc pc)))
|
||||||
|
(error "Bad PERFORM instruction -- ASSEMBLE" inst))))
|
||||||
|
|
||||||
|
(define (perform-action inst) (cdr inst))
|
||||||
|
|
||||||
|
(define (make-primitive-exp exp machine labels)
|
||||||
|
(cond ((constant-exp? exp)
|
||||||
|
(let ((c (constant-exp-value exp)))
|
||||||
|
(lambda () c)))
|
||||||
|
((label-exp? exp)
|
||||||
|
(let ((insts
|
||||||
|
(lookup-label labels
|
||||||
|
(label-exp-label exp))))
|
||||||
|
(lambda () insts)))
|
||||||
|
((register-exp? exp)
|
||||||
|
(let ((r (get-register machine
|
||||||
|
(register-exp-reg exp))))
|
||||||
|
(lambda () (get-contents r))))
|
||||||
|
(else
|
||||||
|
(error "Unknown expression type -- ASSEMBLE" exp))))
|
||||||
|
|
||||||
|
(define (register-exp? exp) (tagged-list? exp 'reg))
|
||||||
|
|
||||||
|
(define (register-exp-reg exp) (cadr exp))
|
||||||
|
|
||||||
|
(define (constant-exp? exp) (tagged-list? exp 'const))
|
||||||
|
|
||||||
|
(define (constant-exp-value exp) (cadr exp))
|
||||||
|
|
||||||
|
(define (label-exp? exp) (tagged-list? exp 'label))
|
||||||
|
|
||||||
|
(define (label-exp-label exp) (cadr exp))
|
||||||
|
|
||||||
|
|
||||||
|
(define (make-operation-exp exp machine labels operations)
|
||||||
|
(let ((op (lookup-prim (operation-exp-op exp) operations))
|
||||||
|
(aprocs
|
||||||
|
(map (lambda (e)
|
||||||
|
(make-primitive-exp e machine labels))
|
||||||
|
(operation-exp-operands exp))))
|
||||||
|
(lambda ()
|
||||||
|
(apply op (map (lambda (p) (p)) aprocs)))))
|
||||||
|
|
||||||
|
(define (operation-exp? exp)
|
||||||
|
(and (pair? exp) (tagged-list? (car exp) 'op)))
|
||||||
|
(define (operation-exp-op operation-exp)
|
||||||
|
(cadr (car operation-exp)))
|
||||||
|
(define (operation-exp-operands operation-exp)
|
||||||
|
(cdr operation-exp))
|
||||||
|
|
||||||
|
|
||||||
|
(define (lookup-prim symbol operations)
|
||||||
|
(let ((val (assoc symbol operations)))
|
||||||
|
(if val
|
||||||
|
(cadr val)
|
||||||
|
(error "Unknown operation -- ASSEMBLE" symbol))))
|
||||||
|
|
||||||
|
;; from 4.1
|
||||||
|
(define (tagged-list? exp tag)
|
||||||
|
(if (pair? exp)
|
||||||
|
(eq? (car exp) tag)
|
||||||
|
false))
|
||||||
|
|
||||||
|
'(REGISTER SIMULATOR LOADED)
|
||||||
120
shared/ch5-syntax.scm
Normal file
120
shared/ch5-syntax.scm
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
;;;;SCHEME SYNTAX FROM SECTION 4.1.2 OF STRUCTURE AND INTERPRETATION OF
|
||||||
|
;;; COMPUTER PROGRAMS, TO SUPPORT CHAPTER 5
|
||||||
|
;;;;Loaded by compiler.scm (for use by compiler), and by eceval-support.scm
|
||||||
|
;;;; (for simulation of eceval machine operations)
|
||||||
|
|
||||||
|
(define (self-evaluating? exp)
|
||||||
|
(cond ((number? exp) true)
|
||||||
|
((string? exp) true)
|
||||||
|
(else false)))
|
||||||
|
|
||||||
|
|
||||||
|
(define (quoted? exp)
|
||||||
|
(tagged-list? exp 'quote))
|
||||||
|
|
||||||
|
(define (text-of-quotation exp) (cadr exp))
|
||||||
|
|
||||||
|
(define (tagged-list? exp tag)
|
||||||
|
(if (pair? exp)
|
||||||
|
(eq? (car exp) tag)
|
||||||
|
false))
|
||||||
|
|
||||||
|
|
||||||
|
(define (variable? exp) (symbol? exp))
|
||||||
|
|
||||||
|
(define (assignment? exp)
|
||||||
|
(tagged-list? exp 'set!))
|
||||||
|
|
||||||
|
(define (assignment-variable exp) (cadr exp))
|
||||||
|
|
||||||
|
(define (assignment-value exp) (caddr exp))
|
||||||
|
|
||||||
|
|
||||||
|
(define (definition? exp)
|
||||||
|
(tagged-list? exp 'define))
|
||||||
|
|
||||||
|
(define (definition-variable exp)
|
||||||
|
(if (symbol? (cadr exp))
|
||||||
|
(cadr exp)
|
||||||
|
(caadr exp)))
|
||||||
|
|
||||||
|
(define (definition-value exp)
|
||||||
|
(if (symbol? (cadr exp))
|
||||||
|
(caddr exp)
|
||||||
|
(make-lambda (cdadr exp)
|
||||||
|
(cddr exp))))
|
||||||
|
|
||||||
|
(define (lambda? exp) (tagged-list? exp 'lambda))
|
||||||
|
|
||||||
|
(define (lambda-parameters exp) (cadr exp))
|
||||||
|
(define (lambda-body exp) (cddr exp))
|
||||||
|
|
||||||
|
(define (make-lambda parameters body)
|
||||||
|
(cons 'lambda (cons parameters body)))
|
||||||
|
|
||||||
|
(define (if? exp) (tagged-list? exp 'if))
|
||||||
|
|
||||||
|
(define (if-predicate exp) (cadr exp))
|
||||||
|
|
||||||
|
(define (if-consequent exp) (caddr exp))
|
||||||
|
|
||||||
|
(define (if-alternative exp)
|
||||||
|
(if (not (null? (cdddr exp)))
|
||||||
|
(cadddr exp)
|
||||||
|
'false))
|
||||||
|
|
||||||
|
|
||||||
|
(define (begin? exp) (tagged-list? exp 'begin))
|
||||||
|
(define (begin-actions exp) (cdr exp))
|
||||||
|
|
||||||
|
(define (last-exp? seq) (null? (cdr seq)))
|
||||||
|
(define (first-exp seq) (car seq))
|
||||||
|
(define (rest-exps seq) (cdr seq))
|
||||||
|
|
||||||
|
(define (application? exp) (pair? exp))
|
||||||
|
(define (operator exp) (car exp))
|
||||||
|
(define (operands exp) (cdr exp))
|
||||||
|
|
||||||
|
(define (no-operands? ops) (null? ops))
|
||||||
|
(define (first-operand ops) (car ops))
|
||||||
|
(define (rest-operands ops) (cdr ops))
|
||||||
|
|
||||||
|
;;;**following needed only to implement COND as derived expression,
|
||||||
|
;;; not needed by eceval machine in text. But used by compiler
|
||||||
|
|
||||||
|
;; from 4.1.2
|
||||||
|
(define (make-if predicate consequent alternative)
|
||||||
|
(list 'if predicate consequent alternative))
|
||||||
|
|
||||||
|
|
||||||
|
(define (sequence->exp seq)
|
||||||
|
(cond ((null? seq) seq)
|
||||||
|
((last-exp? seq) (first-exp seq))
|
||||||
|
(else (make-begin seq))))
|
||||||
|
|
||||||
|
(define (make-begin seq) (cons 'begin seq))
|
||||||
|
|
||||||
|
(define (cond? exp) (tagged-list? exp 'cond))
|
||||||
|
(define (cond-clauses exp) (cdr exp))
|
||||||
|
(define (cond-else-clause? clause)
|
||||||
|
(eq? (cond-predicate clause) 'else))
|
||||||
|
(define (cond-predicate clause) (car clause))
|
||||||
|
(define (cond-actions clause) (cdr clause))
|
||||||
|
|
||||||
|
(define (cond->if exp)
|
||||||
|
(expand-clauses (cond-clauses exp)))
|
||||||
|
|
||||||
|
(define (expand-clauses clauses)
|
||||||
|
(if (null? clauses)
|
||||||
|
'false ; no else clause
|
||||||
|
(let ((first (car clauses))
|
||||||
|
(rest (cdr clauses)))
|
||||||
|
(if (cond-else-clause? first)
|
||||||
|
(if (null? rest)
|
||||||
|
(sequence->exp (cond-actions first))
|
||||||
|
(error "ELSE clause isn't last -- COND->IF"
|
||||||
|
clauses))
|
||||||
|
(make-if (cond-predicate first)
|
||||||
|
(sequence->exp (cond-actions first))
|
||||||
|
(expand-clauses rest))))))
|
||||||
|
;; end of Cond support
|
||||||
Reference in New Issue
Block a user