|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T c
Length: 38073 (0x94b9)
Types: TextFile
Names: »chapter5.code«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
└─⟦this⟧ »EUUGD11/gnu-31mar87/scheme/examples/chapter5.code«
;;; Section 5.1 -- Programs we implement as register machines
;;; GCD from section 1.2.5
(define (gcd a b)
(if (= b 0)
a
(gcd b (remainder a b))))
;;; Exercise 5.1 -- FACTORIAL from section 1.2.1 (block-structured)
(define (factorial n)
(define (iter product counter)
(if (> counter n)
product
(iter (* counter product)
(+ counter 1))))
(iter 1 1))
;;; Section 5.1.1
;;; GCD machine definition
(define-machine gcd
(registers a b t)
(controller
test-b
(branch (zero? (fetch b)) gcd-done)
(assign t (remainder (fetch a) (fetch b)))
(assign a (fetch b))
(assign b (fetch t))
(goto test-b)
gcd-done))
;;; GCD machine with I/O (Figure 5.4)
(define-machine gcd
(registers a b t)
(controller
gcd-loop
(assign a (read))
(assign b (read))
test-b
(branch (zero? (fetch b)) gcd-done)
(assign t (remainder (fetch a) (fetch b)))
(assign a (fetch b))
(assign b (fetch t))
(goto test-b)
gcd-done
(perform (print (fetch a)))
(goto gcd-loop)))
;;; Section 5.1.2
(define (remainder n d)
(if (< n d)
n
(remainder (- n d) d)))
;;; GCD machine with nonprimitive REMAINDER computation
(define-machine gcd
(registers a b t)
(controller
test-b
(branch (zero? (fetch b)) gcd-done)
(assign t (fetch a))
rem-loop
(branch (< (fetch t) (fetch b)) rem-done)
(assign t (- (fetch t) (fetch b)))
(goto rem-loop)
rem-done
(assign a (fetch b))
(assign b (fetch t))
(goto test-b)
gcd-done))
;;; Section 5.1.4 -- Recursion
;;; FACTORIAL same as in section 1.2.1 but with args reversed
(define (factorial n)
(if (= n 1)
1
(* (factorial (- n 1)) n)))
;;; FACTORIAL machine (Figure 5.10)
(define-machine factorial
(registers n val continue)
(controller
(assign continue fact-done) ;set up final return address
fact-loop
(branch (=1? (fetch n)) base-case)
(save continue)
(save n)
(assign n (-1+ (fetch n)))
(assign continue after-fact)
(goto fact-loop)
after-fact
(restore n)
(restore continue)
(assign val
(* (fetch n) (fetch val)))
(goto (fetch continue))
base-case
(assign val (fetch n))
(goto (fetch continue))
fact-done))
;;; FIB as in 1.2.2 but with base case written differently
(define (fib n)
(if (< n 2)
n
(+ (fib (- n 1)) (fib (- n 2)))))
;;; FIB machine (Figure 5.11)
(define-machine fib
(registers n val continue)
(controller
(assign continue fib-done)
fib-loop
(branch (< (fetch n) 2) immediate-answer)
(save continue)
(assign continue afterfib-n-1)
(save n)
(assign n (- (fetch n) 1))
(goto fib-loop)
afterfib-n-1
(restore n)
(restore continue)
(assign n (- (fetch n) 2))
(save continue)
(assign continue afterfib-n-2)
(save val)
(goto fib-loop)
afterfib-n-2
(assign n (fetch val))
(restore val)
(restore continue)
(assign val
(+ (fetch val)(fetch n)))
(goto (fetch continue))
immediate-answer
(assign val (fetch n))
(goto (fetch continue))
fib-done))
;;; Exercise 5.4
;;; Recursive EXPT from section 1.2.4
(define (expt b n)
(if (= n 0)
1
(* b (expt b (- n 1)))))
;;; Iterative EXPT from section 1.2.4 but block-structured
(define (expt b n)
(define (exp-iter counter product)
(if (= counter 0)
product
(exp-iter (- counter 1) (* b product))))
(exp-iter n 1))
;;; COUNTATOMS from section 2.2.2
(define (countatoms tree)
(cond ((null? tree) 0)
((atom? tree) 1)
(else (+ (countatoms (car tree))
(countatoms (cdr tree))))))
;;; A version of COUNTATOMS not shown earlier
(define (countatoms tree)
(define (count-iter tree n)
(cond ((null? tree) n)
((atom? tree) (1+ n))
(else (count-iter (cdr tree)
(count-iter (car tree) n)))))
(count-iter tree 0))
\f
;;; Section 5.1.5 -- Register-machine simulator
;;; Expansion of first GCD machine definition above
(define gcd
(build-model '(a b t)
'(test-b
(branch (zero? (fetch b)) gcd-done)
(assign t (remainder (fetch a) (fetch b)))
(assign a (fetch b))
(assign b (fetch t))
(goto test-b)
gcd-done)))
;;; Start of Register-machine simulator
;;; Constructing the machine model
(define (build-model registers controller)
(let ((machine (make-new-machine)))
(set-up-registers machine registers)
(set-up-controller machine controller)
machine))
(define (set-up-registers machine registers)
(mapc (lambda (register-name)
(make-machine-register machine register-name))
registers))
(define (mapc proc l)
(if (null? l)
'done
(sequence (proc (car l))
(mapc proc (cdr l)))))
(define (set-up-controller machine controller)
(build-instruction-list machine
(cons '*start* controller)))
(define (build-instruction-list machine op-list)
(if (null? op-list)
'()
(let ((rest-of-instructions
(build-instruction-list machine (cdr op-list))))
(if (label? (car op-list))
(sequence
(declare-label machine
(car op-list)
rest-of-instructions)
rest-of-instructions)
(cons (make-machine-instruction machine
(car op-list))
rest-of-instructions)))))
(define (label? expression)
(symbol? expression))
;;; Registers
(define (make-machine-register machine name)
(remote-define machine name (make-register name)))
(define (make-register name)
(define contents nil)
(define (get) contents)
(define (set value)
(set! contents value))
(define (dispatch message)
(cond ((eq? message 'get) (get))
((eq? message 'set) set)
(else (error "Unknown request -- REGISTER"
name
message))))
dispatch)
(define (get-contents register)
(register 'get))
(define (set-contents register value)
((register 'set) value))
;;; Labels
(define (declare-label machine label labeled-entry)
(let ((defined-labels (remote-get machine '*labels*)))
(if (memq label defined-labels)
(error "Multiply-defined label" label)
(sequence
(remote-define machine label labeled-entry)
(remote-set machine
'*labels*
(cons label defined-labels))))))
;;; The Stack
(define (make-stack)
(define 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 '()))
(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))
;;; Representation of machines as environments
(define (remote-get machine variable)
(eval variable machine))
(define (remote-set machine variable value)
(eval (list 'set! variable (list 'quote value))
machine))
(define (remote-define machine variable value)
(eval (list 'define variable (list 'quote value))
machine))
;;; Instructions as procedures
(define (make-machine-instruction machine exp)
(eval (list 'lambda '() exp) machine))
;;; Creating an initial machine (environment)
(define (make-new-machine)
(make-environment
(define *labels* '())
(define *the-stack* (make-stack))
(define (initialize-stack)
(*the-stack* 'initialize))
(define fetch get-contents)
(define *program-counter* '())
(define (execute sequence)
(set! *program-counter* sequence)
(if (null? *program-counter*)
'done
((car *program-counter*))))
(define (normal-next-instruction)
(execute (cdr *program-counter*)))
(define (assign register value)
(set-contents register value)
(normal-next-instruction))
(define (save reg)
(push *the-stack* (get-contents reg))
(normal-next-instruction))
(define (restore reg)
(set-contents reg (pop *the-stack*))
(normal-next-instruction))
(define (goto new-sequence)
(execute new-sequence))
(define (branch predicate alternate-next)
(if predicate
(goto alternate-next)
(normal-next-instruction)))
(define (perform operation)
(normal-next-instruction))
)) ;;end of MAKE-NEW-MACHINE
;;; External interface to a simulated machine
(define (remote-fetch machine register-name)
(get-contents (remote-get machine register-name)))
(define (remote-assign machine register-name value)
(set-contents (remote-get machine register-name) value)
'done)
(define (start machine)
(eval '(goto *start*) machine))
;;; The monitored stack
;;; (MAKE-STACK and INITIALIZE-STACK can be substituted for the versions above)
(define (make-stack)
(define s '())
(define number-pushes 0)
(define max-depth 0)
(define (push x)
(set! s (cons x s))
(set! number-pushes (1+ number-pushes))
(set! max-depth (max (length s) max-depth)))
(define (pop)
(if (null? s)
(error "Empty stack -- POP")
(let ((top (car s)))
(set! s (cdr s))
top)))
(define (initialize)
(set! s '())
(set! number-pushes 0)
(set! max-depth 0))
(define (print-statistics)
(print (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 (initialize-stack)
(*the-stack* 'print-statistics)
(*the-stack* 'initialize))
\f
;;; Section 5.2
eval-dispatch
(branch (self-evaluating? (fetch exp)) ev-self-eval)
(branch (quoted? (fetch exp)) ev-quote)
(branch (variable? (fetch exp)) ev-variable)
(branch (definition? (fetch exp)) ev-definition)
(branch (assignment? (fetch exp)) ev-assignment)
(branch (lambda? (fetch exp)) ev-lambda)
(branch (conditional? (fetch exp)) ev-cond)
(branch (no-args? (fetch exp)) ev-no-args)
(branch (application? (fetch exp)) ev-application)
(goto unknown-expression-type-error)
(define (no-args? exp)
(if (atom? exp)
nil
(null? (cdr exp))))
(define (application? exp)
(if (atom? exp)
nil
(not (null? (cdr exp)))))
ev-self-eval
(assign val (fetch exp))
(goto (fetch continue))
ev-quote
(assign val (text-of-quotation (fetch exp)))
(goto (fetch continue))
ev-variable
(assign val
(lookup-variable-value (fetch exp) (fetch env)))
(goto (fetch continue))
ev-lambda
(assign val (make-procedure (fetch exp) (fetch env)))
(goto (fetch continue))
ev-no-args
(assign exp (operator (fetch exp)))
(save continue)
(assign continue setup-no-arg-apply)
(goto eval-dispatch)
setup-no-arg-apply
(assign fun (fetch val))
(assign argl '())
(goto apply-dispatch)
ev-application
(assign unev (operands (fetch exp)))
(assign exp (operator (fetch exp)))
(save continue)
(save env)
(save unev)
(assign continue eval-args)
(goto eval-dispatch)
eval-args
(restore unev)
(restore env)
(assign fun (fetch val))
(save fun)
(assign argl '())
(goto eval-arg-loop)
(define (last-operand? args)
(null? (cdr args)))
eval-arg-loop
(save argl)
(assign exp (first-operand (fetch unev)))
(branch (last-operand? (fetch unev)) eval-last-arg)
(save env)
(save unev)
(assign continue accumulate-arg)
(goto eval-dispatch)
accumulate-arg
(restore unev)
(restore env)
(restore argl)
(assign argl (cons (fetch val) (fetch argl)))
(assign unev (rest-operands (fetch unev)))
(goto eval-arg-loop)
eval-last-arg
(assign continue accumulate-last-arg)
(goto eval-dispatch)
accumulate-last-arg
(restore argl)
(assign argl (cons (fetch val) (fetch argl)))
(restore fun)
(goto apply-dispatch)
apply-dispatch
(branch (primitive-procedure? (fetch fun)) primitive-apply)
(branch (compound-procedure? (fetch fun)) compound-apply)
(goto unknown-procedure-type-error)
(define (apply-primitive-procedure p args)
(apply (eval (primitive-id p) user-initial-environment)
(reverse args)))
primitive-apply
(assign val
(apply-primitive-procedure (fetch fun)
(fetch argl)))
(restore continue)
(goto (fetch continue))
compound-apply
(assign env (make-bindings (fetch fun) (fetch argl)))
(assign unev (procedure-body (fetch fun)))
(goto eval-sequence)
(define (make-bindings proc args)
(extend-binding-environment (parameters proc)
args
(procedure-environment proc)))
(define (extend-binding-environment vars args env)
(extend-environment vars (reverse args) env))
(define no-more-exps? null?)
eval-sequence
(assign exp (first-exp (fetch unev)))
(branch (last-exp? (fetch unev)) last-exp)
(save unev)
(save env)
(assign continue eval-sequence-continue)
(goto eval-dispatch)
eval-sequence-continue
(restore env)
(restore unev)
(assign unev (rest-exps (fetch unev)))
(goto eval-sequence)
last-exp
(restore continue)
(goto eval-dispatch)
;;; Non-tail-recursive version of EVAL-SEQUENCE
eval-sequence
(branch (no-more-exps? (fetch unev)) end-sequence) ;***
(assign exp (first-exp (fetch unev))) ;***
(save unev)
(save env)
(assign continue eval-sequence-continue)
(goto eval-dispatch)
eval-sequence-continue
(restore env)
(restore unev)
(assign unev (rest-exps (fetch unev)))
(goto eval-sequence)
end-sequence
(restore continue)
(goto (fetch continue)) ;***
(define (count n)
(print n)
(count (1+ n)))
ev-cond
(save continue)
(assign continue evcond-decide)
(assign unev (clauses (fetch exp)))
evcond-pred
(branch (no-clauses? (fetch unev)) evcond-return-nil)
(assign exp (first-clause (fetch unev)))
(branch (else-clause? (fetch exp)) evcond-else-clause)
(save env)
(save unev)
(assign exp (predicate (fetch exp)))
(goto eval-dispatch)
evcond-return-nil
(restore continue)
(assign val nil)
(goto (fetch continue))
evcond-decide
(restore unev)
(restore env)
(branch (true? (fetch val)) evcond-true-predicate)
(assign unev (rest-clauses (fetch unev)))
(goto evcond-pred)
evcond-true-predicate
(assign exp (first-clause (fetch unev)))
evcond-else-clause
(assign unev (actions (fetch exp)))
(goto eval-sequence)
ev-assignment
(assign unev (assignment-variable (fetch exp)))
(save unev)
(assign exp (assignment-value (fetch exp)))
(save env)
(save continue)
(assign continue ev-assignment-1)
(goto eval-dispatch)
ev-assignment-1
(restore continue)
(restore env)
(restore unev)
(perform (set-variable-value! (fetch unev)
(fetch val)
(fetch env)))
(goto (fetch continue))
ev-definition
(assign unev (definition-variable (fetch exp)))
(save unev)
(assign exp (definition-value (fetch exp)))
(save env)
(save continue)
(assign continue ev-definition-1)
(goto eval-dispatch)
ev-definition-1
(restore continue)
(restore env)
(restore unev)
(perform
(define-variable! (fetch unev) (fetch val) (fetch env)))
(assign val (fetch unev)) ;return as value
;the symbol being defined
(goto (fetch continue))
;;; Controller starts here
read-eval-print-loop
(perform (initialize-stack))
(perform (newline))
(perform (princ "EC-EVAL==> "))
(assign exp (read))
(assign env the-global-environment)
(assign continue print-result)
(goto eval-dispatch)
print-result
(perform (user-print (fetch val)))
(goto read-eval-print-loop)
unknown-procedure-type-error
(assign val 'unknown-procedure-type-error)
(goto signal-error)
unknown-expression-type-error
(assign val 'unknown-expression-type-error)
(goto signal-error)
signal-error
(perform (user-print (fetch val)))
(goto read-eval-print-loop)
(define the-global-environment (setup-environment))
(define-machine explicit-control-evaluator
(registers exp env val continue fun argl unev)
(controller
;;body of the controller as given in this section
))
(start explicit-control-evaluator)
;;; Exercise 5.20
(define (factorial n)
(define (iter product counter)
(cond ((> counter n) product)
(else (iter (* counter product)
(+ counter 1)))))
(iter 1 1))
;;; Exercise 5.21
(define (factorial n)
(cond ((= n 1) 1)
(else (* (factorial (- n 1)) n))))
;;; Exercise 5.22
(define (fib n)
(cond ((= n 0) 0)
((= n 1) 1)
(else (+ (fib (- n 1)) (fib (- n 2))))))
;;; Section 5.2.5 -- Lexical addressing
;;; from exercise 5.27
(let ((a 1))
(define (f x)
(define b (+ a x))
(define a 5)
(+ a b))
(f 10))
\f
;;; Section 5.3 -- Compilation
;;; Section 5.3.1
(define (compile-expression exp c-t-env target cont)
(cond ((self-evaluating? exp)
(compile-constant exp c-t-env target cont))
((quoted? exp)
(compile-constant (text-of-quotation exp)
c-t-env target cont))
((variable? exp)
(compile-variable-access exp c-t-env target cont))
((assignment? exp)
(compile-assignment exp c-t-env target cont))
((definition? exp)
(compile-definition exp c-t-env target cont))
((lambda? exp)
(compile-lambda exp c-t-env target cont))
((conditional? exp)
(compile-cond (clauses exp) c-t-env target cont))
((no-args? exp)
(compile-no-args exp c-t-env target cont))
((application? exp)
(compile-application exp c-t-env target cont))
(else
(error "Unknown expression type -- COMPILE" exp))))
(define (preserving reg seq1 seq2)
(if (and (needs-register seq2 reg)
(modifies-register seq1 reg))
(append-instruction-sequences
(wrap-save-restore seq1 reg)
seq2)
(append-instruction-sequences seq1 seq2)))
;;; Section 5.3.2
(define (compile-continuation continuation)
(cond ((eq? continuation 'return) (compile-return))
((eq? continuation 'next)
(empty-instruction-sequence))
(else (make-jump continuation))))
;;; Simple expressions
(define (compile-constant constant c-t-env target cont)
(append-instruction-sequences
(make-register-assignment target (make-constant constant))
(compile-continuation cont)))
(define (compile-variable-access var c-t-env target cont)
(append-instruction-sequences
(make-register-assignment target
(make-variable-access var
c-t-env))
(compile-continuation cont)))
;;; Procedure applications
(define (compile-application app c-t-env target cont)
(preserving
'env
(compile-expression (operator app) c-t-env 'fun 'next)
(preserving 'fun
(compile-operands (operands app) c-t-env)
(compile-call target cont))))
(define (compile-operands rands c-t-env)
(let ((first-operand-code
(compile-first-operand rands c-t-env)))
(if (last-operand? rands)
first-operand-code
(preserving
'env
first-operand-code
(compile-rest-operands (rest-operands rands)
c-t-env)))))
(define (compile-first-operand rands c-t-env)
(append-instruction-sequences
(compile-expression (first-operand rands)
c-t-env 'val 'next)
(make-register-assignment
'argl
(make-singleton-arglist (make-fetch 'val)))))
(define (compile-rest-operands rands c-t-env)
(let ((next-operand-code
(compile-next-operand rands c-t-env)))
(if (last-operand? rands)
next-operand-code
(preserving
'env
next-operand-code
(compile-rest-operands (rest-operands rands)
c-t-env)))))
(define (compile-next-operand rands c-t-env)
(preserving
'argl
(compile-expression (first-operand rands)
c-t-env 'val 'next)
(make-register-assignment
'argl
(make-add-to-arglist (make-fetch 'val)
(make-fetch 'argl)))))
(define (compile-no-args app c-t-env target cont)
(append-instruction-sequences
(compile-expression (operator app) c-t-env 'fun 'next)
(make-register-assignment 'argl (make-empty-arglist))
(compile-call target cont)))
(define (compile-call target cont)
(if (eq? target 'val)
(compile-call-result-in-val cont)
(append-instruction-sequences
(compile-call-result-in-val 'next)
(make-register-assignment target (make-fetch 'val))
(compile-continuation cont))))
(define (compile-call-result-in-val cont)
(cond ((eq? cont 'return)
(compile-call-return-to nil))
((eq? cont 'next)
(let ((after-call (make-new-label 'after-call)))
(append-instruction-sequences
(compile-call-return-to after-call)
(make-entry-point-designator after-call))))
(else
(compile-call-return-to cont))))
(define (compile-return)
(append-instruction-sequences
(make-restore 'continue)
(make-return-from-procedure)))
(define (compile-call-return-to return-entry)
(if (null? return-entry)
(make-transfer-to-procedure)
(append-instruction-sequences
(make-register-assignment 'continue return-entry)
(make-save 'continue)
(make-transfer-to-procedure))))
;;; Conditionals
(define (compile-cond clauses c-t-env target cont)
(if (eq? cont 'next)
(let ((end-of-cond (make-new-label 'cond-end)))
(append-instruction-sequences
(compile-clauses clauses c-t-env target end-of-cond)
(make-entry-point-designator end-of-cond)))
(compile-clauses clauses c-t-env target cont)))
(define (compile-clauses clauses c-t-env target cont)
(if (no-clauses? clauses)
(compile-constant nil c-t-env target cont)
(compile-a-clause (first-clause clauses)
(rest-clauses clauses)
c-t-env target cont)))
(define (compile-a-clause clause rest c-t-env target cont)
(let ((consequent (compile-sequence (actions clause)
c-t-env target cont)))
(if (else-clause? clause)
consequent
(let
((alternative (compile-clauses rest
c-t-env target cont))
(pred (compile-expression (predicate clause)
c-t-env 'val 'next))
(true-branch (make-new-label 'true-branch)))
(let ((alternative-and-consequent
(parallel-instruction-sequences
alternative
(append-instruction-sequences
(make-entry-point-designator true-branch)
consequent))))
(preserving
'env
pred
(append-instruction-sequences
(make-branch (make-test 'val) true-branch)
alternative-and-consequent)))))))
(define (compile-sequence seq c-t-env target cont)
(if (last-exp? seq)
(compile-expression (first-exp seq)
c-t-env target cont)
(preserving
'env
(compile-expression (first-exp seq) c-t-env nil 'next)
(compile-sequence (rest-exps seq) c-t-env target cont)
)))
;;; Assignments
(define (compile-assignment exp c-t-env target cont)
(let ((hold-value (if (null? target) 'val target)))
(preserving
'env
(compile-expression (assignment-value exp)
c-t-env hold-value 'next)
(append-instruction-sequences
(make-variable-assignment (assignment-variable exp)
c-t-env
(make-fetch hold-value))
(compile-continuation cont)))))
;;; Definitions
(define (compile-definition exp c-t-env target cont)
(let ((hold-value (if (null? target) 'val target))
(var (definition-variable exp)))
(preserving
'env
(compile-expression (definition-value exp)
c-t-env hold-value 'next)
(append-instruction-sequences
(make-variable-definition var
c-t-env
(make-fetch hold-value))
(make-register-assignment target (make-constant var))
(compile-continuation cont)))))
;;; Lambda expressions
(define (compile-lambda exp c-t-env target cont)
(if (eq? cont 'next)
(let ((after-lambda (make-new-label 'after-lambda)))
(append-instruction-sequences
(compile-lambda-2 exp c-t-env target after-lambda)
(make-entry-point-designator after-lambda)))
(compile-lambda-2 exp c-t-env target cont)))
(define (compile-lambda-2 exp c-t-env target cont)
(let ((proc-entry (make-new-label 'entry)))
(tack-on-instruction-sequence
(append-instruction-sequences
(make-register-assignment
target
(make-procedure-constructor proc-entry))
(compile-continuation cont))
(compile-lambda-body exp c-t-env proc-entry))))
(define (compile-lambda-body exp c-t-env proc-entry)
(append-instruction-sequences
(make-entry-point-designator proc-entry)
(make-environment-switch (lambda-parameters exp))
(compile-sequence
(lambda-body exp)
(extend-compile-time-env (lambda-parameters exp) c-t-env)
'val
'return)))
;;; New syntax procedures
(define (lambda-parameters exp) (cadr exp))
(define (lambda-body exp) (cddr exp))
;;; Section 5.3.3 -- compiler data structures
;;; Instruction sequences
(define (make-instruction-sequence needs modifies statements)
(list needs modifies statements))
(define (registers-needed s) (car s))
(define (registers-modified s) (cadr s))
(define (statements s) (caddr s))
(define (needs-register seq reg)
(element-of-set? reg (registers-needed seq)))
(define (modifies-register seq reg)
(element-of-set? reg (registers-modified seq)))
(define (make-instruction needed modified statement)
(make-instruction-sequence needed
modified
(list statement)))
(define (empty-instruction-sequence)
(make-instruction-sequence empty-set empty-set '()))
;;; Combining instruction sequences
(define (append-instruction-sequences . seqs)
(define (append-2-sequences seq1 seq2)
(make-instruction-sequence
(union-set (registers-needed seq1)
(difference-set (registers-needed seq2)
(registers-modified seq1)))
(union-set (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))
;;; Combiner used by Compile-lambda
(define (tack-on-instruction-sequence seq body-seq)
(append-instruction-sequences
seq
(make-instruction-sequence empty-set
empty-set
(statements body-seq))))
;;; Combiner used by Compile-cond
(define (parallel-instruction-sequences seq1 seq2)
(make-instruction-sequence
(union-set (registers-needed seq1)
(registers-needed seq2))
(union-set (registers-modified seq1)
(registers-modified seq2))
(append (statements seq1) (statements seq2))))
;;; Sets of registers
(define (union-set s1 s2)
(cond ((null? s1) s2)
((memq (car s1) s2) (union-set (cdr s1) s2))
(else (cons (car s1) (union-set (cdr s1) s2)))))
(define (difference-set s1 s2)
(cond ((null? s1) '())
((memq (car s1) s2) (difference-set (cdr s1) s2))
(else (cons (car s1) (difference-set (cdr s1) s2)))))
(define (element-of-set? x s) (memq x s))
(define (singleton x) (list x))
(define (make-set list-of-elements) list-of-elements)
(define empty-set '())
;;; Value specifiers
(define (make-val-spec registers-needed expression)
(list registers-needed expression))
(define (val-spec-registers-needed value)
(car value))
(define (val-spec-expression value)
(cadr value))
;;; Section 5.3.4 -- Primitive code generators
;;; Generators for any register machine
(define (make-constant c)
(make-val-spec empty-set (list 'quote c)))
(define (make-label symbol)
(make-val-spec empty-set symbol))
(define (make-new-label name)
(make-label (make-new-symbol name)))
(define (make-fetch reg)
(make-val-spec (singleton reg) (list 'fetch reg)))
(define (make-operation operation . inputs)
(make-val-spec
(union-all-sets (mapcar val-spec-registers-needed inputs))
(cons operation (mapcar val-spec-expression inputs))))
(define (union-all-sets sets)
(if (null? sets)
empty-set
(union-set (car sets) (union-all-sets (cdr sets)))))
(define (make-register-assignment reg val-spec)
(if (null? reg)
(empty-instruction-sequence)
(make-instruction
(val-spec-registers-needed val-spec)
(singleton reg)
(list 'assign reg (val-spec-expression val-spec)))))
(define (make-nonlocal-goto continuation cont-needs)
(make-goto continuation (make-set cont-needs) all))
(define all (make-set '(fun env val argl continue)))
(define (make-jump continuation)
(make-goto continuation empty-set empty-set))
(define (make-goto cont cont-needs cont-modifies)
(make-instruction
(union-set (val-spec-registers-needed cont) cont-needs)
cont-modifies
(list 'goto (val-spec-expression cont))))
(define (make-branch predicate true-branch)
(make-instruction
(union-set (val-spec-registers-needed predicate)
(val-spec-registers-needed true-branch))
empty-set
(list 'branch
(val-spec-expression predicate)
(val-spec-expression true-branch))))
(define (make-save reg)
(make-instruction (singleton reg)
empty-set
(list 'save reg)))
(define (make-restore reg)
(make-instruction empty-set
(singleton reg)
(list 'restore reg)))
(define (make-perform action)
(make-instruction
(val-spec-registers-needed action)
empty-set
(list 'perform (val-spec-expression action))))
(define (make-entry-point-designator label-val-spec)
(make-instruction empty-set
empty-set
(val-spec-expression label-val-spec)))
;;; The following is used by Preserving
(define (wrap-save-restore seq reg)
(make-instruction-sequence
(registers-needed seq)
(difference-set (registers-modified seq) (singleton reg))
(append (statements (make-save reg))
(statements seq)
(statements (make-restore reg)))))
;;; Generators for the evaluator machine
(define (make-variable-access var c-t-env)
(make-operation 'lookup-variable-value
(make-constant var)
(make-fetch 'env)))
(define (make-test reg)
(make-operation 'true? (make-fetch reg)))
(define (make-variable-assignment var c-t-env value)
(make-perform
(make-operation 'set-variable-value!
(make-constant var)
value
(make-fetch 'env))))
(define (make-variable-definition var c-t-env value)
(make-perform
(make-operation 'define-variable!
(make-constant var)
value
(make-fetch 'env))))
(define (make-procedure-constructor entry)
(make-operation 'make-compiled-procedure
entry
(make-fetch 'env)))
(define (make-environment-switch formals)
(append-instruction-sequences
(make-register-assignment
'env
(make-operation 'compiled-procedure-env
(make-fetch 'fun)))
(make-register-assignment
'env
(make-operation 'extend-binding-environment
(make-constant formals)
(make-fetch 'argl)
(make-fetch 'env)))))
(define (make-singleton-arglist first-arg-spec)
(make-operation 'cons first-arg-spec (make-constant '())))
(define (make-add-to-arglist next-arg-spec rest-args-spec)
(make-operation 'cons next-arg-spec rest-args-spec))
(define (make-empty-arglist)
(make-constant '()))
(define (make-transfer-to-procedure)
(make-nonlocal-goto (make-label 'apply-dispatch)
'(fun argl)))
(define (make-return-from-procedure)
(make-nonlocal-goto (make-fetch 'continue)
'(val)))
;;; Section 5.3.5 -- sample compilation
(compile-expression
'(define (factorial n)
(cond ((= n 1) 1)
(else (* (factorial (- n 1)) n))))
initial-c-t-env
'val
'next)
;;; Exercise 5.30
(define (factorial-alt n)
(cond ((= n 1) 1)
(else (* n (factorial-alt (- n 1))))))
;;; Exercise 5.31
(define (factorial-iter n)
(define (iter product counter)
(cond ((> counter n) product)
(else (iter (* counter product) (+ counter 1)))))
(iter 1 1))
\f
;;; Section 5.3.6 -- Compiler/evaluator interface
apply-dispatch
(branch (primitive-procedure? (fetch fun)) primitive-apply)
(branch (compound-procedure? (fetch fun)) compound-apply)
(branch (compiled-procedure? (fetch fun)) compiled-apply)
(goto unknown-procedure-type-error)
compiled-apply
(assign val (compiled-procedure-entry (fetch fun)))
(goto (fetch val))
(define (make-compiled-procedure entry env)
(list 'compiled-procedure entry env))
(define (compiled-procedure? proc)
(if (atom? proc)
nil
(eq? (car proc) 'compiled-procedure)))
(define (compiled-procedure-entry proc)
(cadr proc))
(define (compiled-procedure-env proc)
(caddr proc))
(define (compile-and-go expression)
(remote-assign
explicit-control-evaluator
'val
(build-instruction-list explicit-control-evaluator
(compile expression)))
(eval '(goto external-entry)
explicit-control-evaluator))
external-entry
(perform (initialize-stack))
(assign env the-global-environment)
(assign continue print-result)
(save continue)
(goto (fetch val))
(define (user-print object)}}}
(cond ((compound-procedure? object)
(print (list 'compound-procedure
(parameters object)
(procedure-body object)
'[procedure-env])))
((compiled-procedure? object) ;new clause
(print '[compiled-procedure]))
(else (print object))))
(define (compile expression)
(statements (compile-expression expression
initial-c-t-env
'val
'return)))
\f
;;; Section 5.3.7 -- Lexical addressing
(let ((x 3) (y 4))
(lambda (a b c d e)
(let ((y (* a b x))
(z (+ c d x)))
(* x y z))))
((lambda (x y)
(lambda (a b c d e)
((lambda (y z) (* x y z))
(* a b x)
(+ c d x))))
3
4)
(define (extend-compile-time-env params c-t-env)
(cons params c-t-env))
;;; Exercise 5.39
((lambda (n)
((lambda (fact-iter)
(fact-iter fact-iter 1 1))
(lambda (f-i product counter)
(cond ((> counter n) product)
(else (f-i f-i
(* counter product)
(+ counter 1)))))))
4)
\f
;;; Section 5.4.2 -- Stop-and-copy garbage collector
begin-garbage-collection
(assign free 0)
(assign scan 0)
(assign old (fetch root))
(assign relocate-continue reassign-root)
(goto relocate-old-result-in-new)
reassign-root
(assign root (fetch new))
(goto gc-loop)
gc-loop
(branch (= (fetch scan) (fetch free)) gc-flip)
(assign old (vector-ref (fetch new-cars) (fetch scan)))
(assign relocate-continue update-car)
(goto relocate-old-result-in-new)
update-car
(perform
(vector-set! (fetch new-cars) (fetch scan) (fetch new)))
(assign old (vector-ref (fetch new-cdrs) (fetch scan)))
(assign relocate-continue update-cdr)
(goto relocate-old-result-in-new)
update-cdr
(perform
(vector-set! (fetch new-cdrs) (fetch scan) (fetch new)))
(assign scan (1+ (fetch scan)))
(goto gc-loop)
relocate-old-result-in-new
(branch (pointer-to-pair? (fetch old)) pair)
(assign new (fetch old))
(goto (fetch relocate-continue))
pair
(assign oldcr (vector-ref (fetch the-cars) (fetch old)))
(branch (broken-heart? (fetch oldcr)) already-moved)
(assign new (fetch free)) ;new location for pair
(assign free (1+ (fetch free))) ;update free pointer
;;Copy the car and cdr to new memory.
(perform
(vector-set! (fetch new-cars) (fetch new) (fetch oldcr)))
(assign oldcr (vector-ref (fetch the-cdrs) (fetch old)))
(perform
(vector-set! (fetch new-cdrs) (fetch new) (fetch oldcr)))
;;Construct the broken heart.
(perform
(vector-set! (fetch the-cars) (fetch old) broken-heart))
(perform
(vector-set! (fetch the-cdrs) (fetch old) (fetch new)))
(goto (fetch relocate-continue))
already-moved
(assign new (vector-ref (fetch the-cdrs) (fetch old)))
(goto (fetch relocate-continue))
gc-flip
(assign temp (fetch the-cdrs))
(assign the-cdrs (fetch new-cdrs))
(assign new-cdrs (fetch temp))
(assign temp (fetch the-cars))
(assign the-cars (fetch new-cars))
(assign new-cars (fetch temp))