λ5.2節
問題 5.7
問題 5.8
問題 5.9
問題 5.10
問題 5.11
問題 5.12
問題 5.13
問題 5.14
問題 5.15
問題 5.16
問題 5.17
問題 5.18
問題 5.19
レジスタ計算機シミュレータ
デバッグ支援レジスタ計算機シミュレータ
レジスタ計算機シミュレータ
;;レジスタ計算機シミュレータ p.308
(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))
;;レジスタ p.308
(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))
;;スタック p.308
;; p.308のmake-stackをスタック使用統計監視用make-stackで置き換えた p.318
(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 (pop stack)
(stack 'pop))
(define (push stack value)
((stack 'push) value))
;;基本計算機 p.309
(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 (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)))
(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)))
;;アセンブラ p.310
(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))))
;;命令の実行手続きの生成 p.313
(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))))
;;assign命令 p.313
(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 ()
(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))))
;;test, branchおよびgoto命令 p.314
(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))
;;その他の命令 p.315
(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))
;;部分式の実行手続き p.315
(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))))
;;抽象構文用手続き p.218
(define (tagged-list? exp tag)
(if (pair? exp)
(eq? (car exp) tag)
false))
(load "regmacheceval2.sch")
デバッグ支援レジスタ計算機シミュレータ
(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*) (trace-flag '())) ;;ex5.18
(define (dispatch message)
(cond ((eq? message 'get) contents)
((eq? message 'set)
(lambda (value)
(if trace-flag ;ex5.18
(begin (newline) (display "register name:") (display name)
(newline) (display "old content:") (display contents)
(newline) (display "new content:") (display value)))
(set! contents value)))
((eq? message 'trace-on) (set! trace-flag #t)) ;ex5.18
((eq? message 'trace-off) (set! trace-falg '())) ;ex5.18
(else
(error "Unknown request -- REGISTER" message))))
dispatch))
(define (get-contents register)
(register 'get))
(define (set-contents! register value)
((register 'set) value))
;; スタック使用統計監視用make-stack
(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 (pop stack)
(stack 'pop))
(define (push stack value)
((stack 'push) value))
(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 (get-db machine) ;ex5.12
(machine 'get-db))
(define (reset-inst-count machine) ;ex5.15
(machine 'reset-inst-count))
(define (get-inst-count machine) ;ex5.15
(machine 'get-inst-count))
(define (set-register-trace! machine register-name) ;ex5.18
(set-trace (get-register machine register-name)))
(define (reset-register-trace! machine register-name) ;ex5.18
(reset-trace (get-register machine register-name)))
(define (set-trace register) ;ex5.18
(register 'trace-on))
(define (reset-trace register) ;ex5.18
(register 'trace-off))
(define (set-breakpoint machine label n) ;ex5.19
((machine 'set-breakpoint) label n))
(define (cancel-breakpoint machine label n) ;ex5.19
((machine 'cancel-breakpoint) label n))
(define (cancel-all-breakpoints machine) ;ex5.19
(machine 'cancel-all-breakpoints))
(define (proceed-machine machine) ;ex5.19
(machine 'proceed-machine))
(define (make-new-machine)
(let ((pc (make-register 'pc))
(flag (make-register 'flag))
(stack (make-stack))
(the-instruction-sequence '())
(the-labels '()) ;ex5.19
(trace-flag '()) ;ex5.16
(inst-count 0) ;ex5.15
(db '())) ;ex5.12
(let ((the-ops
(list (list 'initialize-stack
(lambda () (stack 'initialize)))
(list 'print-stack-statistics
(lambda () (stack 'print-statistics)))
(list 'trace-on ;ex5.16
(lambda () (set! trace-flag #t)))
(list 'trace-off ;ex5.16
(lambda () (set! trace-flag '())))))
(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 (init-db)
(set! db (map (lambda (x) (list x))
(list 'assign 'test 'branch 'goto 'save 'restore 'perform
'label-reg 'save-reg 'restore-reg 'source)))
'done)
(define (execute)
(let ((insts (get-contents pc)))
(if (null? insts)
'done
(if (pair? (caaar insts)) (cdaaar insts) ;ex5.19
(begin
(if trace-flag
(cond ((eq? (caaar insts) 'label)
(newline) (display (cadaar insts)) (display ":"))
(else (newline) (display (caar insts)))))
(if (not (eq? (caaar insts) 'label))
(set! inst-count (+ inst-count 1)))
((instruction-execution-proc (car insts)))
(execute))))))
(define (set-breakpoint label n) ;ex5.19 設定
(let ((insts (lookup-label the-labels label))
(breakpoint-id (list 'breakpoint label n)))
(define (insert-breakpoint insts n) ;設定の下請け ループ
(cond ((null? insts) (error "breakpoint too far -- SETBREAKPOINT" n))
((eq? (caaar insts) 'label) (insert-breakpoint (cdr insts) n))
((> n 0) (insert-breakpoint (cdr insts) (- n 1)))
(else (set-car! (caar insts)
(cons (caaar insts) breakpoint-id)))))
(insert-breakpoint insts n)
'done))
(define (cancel-breakpoint label n) ;ex5.19 削除
(let ((insts (lookup-label the-labels label)))
(define (remove-breakpoint insts n) ;削除の下請け ループ
(cond ((null? insts)
(error "breakpoint too far -- CANCELBREAKPOINT" n))
((eq? (caaar insts) 'label) (remove-breakpoint (cdr insts) n))
((> n 0) (remove-breakpoint (cdr insts) (- n 1)))
((pair? (caaar insts))
(set-car! (caar insts) (caaaar insts)))))
(remove-breakpoint insts n)
'done))
(define (reset insts) ;ex5.19 ブレークポイント全部削除
(if (pair? insts)
(begin
(if (pair? (caaar insts))
(set-car! (caar insts) (caaaar insts)))
(reset (cdr insts)))
'done))
(define (dispatch message)
(cond ((eq? message 'start)
(set-contents! pc the-instruction-sequence)
(execute))
((eq? message 'init-db) (init-db)) ;ex5.12
((eq? message 'get-db) db) ;ex5.12
((eq? message 'install-instruction-sequence)
(lambda (seq) (set! the-instruction-sequence (car seq))
(set! the-labels (cdr seq)))) ;ex5.19
((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)
((eq? message 'get-inst-count) inst-count) ;ex5.15
((eq? message 'reset-inst-count) (set! inst-count 0) 'ok);ex5.15
((eq? message 'set-breakpoint) ;ex5.19
(lambda (label n) (set-breakpoint label n)))
((eq? message 'cancel-breakpoint) ;ex5.19
(lambda (label n) (cancel-breakpoint label n)))
((eq? message 'cancel-all-breakpoints) ;ex5.19
(reset the-instruction-sequence))
((eq? message 'proceed-machine) ;ex5.19
((instruction-execution-proc (car (get-contents pc))))
(execute))
(else (error "Unknown request -- MACHINE" message))))
(init-db) ;ex5.12 databaseの初期化
dispatch)))
;;assembly program
(define (assemble controller-text machine)
(extract-labels controller-text
(lambda (insts labels)
(update-insts! insts labels machine)
(cons insts labels)))) ;ex5.19
(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)
(let ((insts (cons (list (list 'label next-inst)) insts)));;ex5.17
(receive insts
(cons (make-label-entry next-inst
insts)
labels)))
(receive (cons (make-instruction next-inst)
insts)
labels)))))))
(define (insert! value record)
(if (not (member value (cdr record)))
(set-cdr! record (cons value (cdr record)))))
(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))
((eq? (car inst) 'label) ;;ex5.17
(lambda () (advance-pc 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)))
(insert! inst (assoc 'assign (machine 'get-db)))
(let ((reg (assign-reg-name inst))
(val (assign-value-exp inst))
(record (assoc 'source (machine 'get-db))))
;(newline) (display record)
(if (assoc reg (cdr record))
(insert! val (assoc reg (cdr record)))
(set-cdr! record (cons (list reg val) (cdr record)))))
(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 ()
(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)))
(insert! inst (assoc 'test (machine 'get-db)))
(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)))
(insert! inst (assoc 'branch (machine 'get-db)))
(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)))
(insert! inst (assoc 'goto (machine 'get-db)))
(cond ((label-exp? dest)
(let ((insts
(lookup-label labels
(label-exp-label dest))))
(lambda () (set-contents! pc insts))))
((register-exp? dest)
(insert! (register-exp-reg dest)
(assoc 'label-reg (machine 'get-db)))
(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))))
(insert! inst (assoc 'save (machine 'get-db)))
(insert! (stack-inst-reg-name inst)
(assoc 'save-reg (machine 'get-db)))
(lambda ()
; (display (list 'push reg)) (newline)
(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))))
(insert! inst (assoc 'restore (machine 'get-db)))
(insert! (stack-inst-reg-name inst)
(assoc 'restore-reg (machine 'get-db)))
(lambda ()
; (display (list 'pop reg)) (newline)
(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)))
(insert! inst (assoc 'perform (machine 'get-db)))
(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))))
(define (tagged-list? exp tag)
(if (pair? exp)
(eq? (car exp) tag)
false))
問題 5.7
;再帰版
(define expt-machine
(make-machine
'(b n val continue)
(list (list '- -) (list '* *) (list '= =))
'((assign continue (label expt-done))
expt-loop
(assign val (const 1))
(test (op =) (reg n) (const 0))
(branch (label return))
(save continue)
(assign continue (label after-expt))
(assign n (op -) (reg n) (const 1))
(goto (label expt-loop))
after-expt
(restore continue)
(assign val (op *) (reg b) (reg val))
(goto (reg continue))
return
(assign val (const 1))
(goto (reg continue))
expt-done)))
(set-register-contents! expt-machine 'b 2)
(set-register-contents! expt-machine 'n 8)
(start expt-machine)
(get-register-contents expt-machine 'val)
;反復版
(define expt-machine
(make-machine
'(b n counter product)
(list (list '- -) (list '* *) (list '= =))
'((assign counter (reg n))
(assign product (const 1))
expt-loop
(test (op =) (reg counter) (const 0))
(branch (label expt-done))
(assign counter (op -) (reg counter) (const 1))
(assign product (op *) (reg b) (reg product))
(goto (label expt-loop))
expt-done)))
(set-register-contents! expt-machine 'b 2)
(set-register-contents! expt-machine 'n 8)
(start expt-machine)
(get-register-contents expt-machine 'product)
問題 5.8
(define ex5.8machine
(make-machine
'(a)
'()
'(start
(goto (label here))
here
(assign a (const 3))
(goto (label there))
here
(assign a (const 4))
(goto (label there))
there)))
(start ex5.8machine)
(get-register-contents ex5.8machine 'a)
; 実行してみると -> 3
; labelをlabelsに追加するときに,すでに存在していたらエラーとする.
; 以下のように修正する.
(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)
(if (assoc next-inst labels)
(error "The same label name used --- ASSEMBLE"
next-inst)
(receive insts
(cons (make-label-entry next-inst
insts)
labels)))
(receive (cons (make-instruction next-inst)
insts)
labels)))))))
;上のプログラムを実行してみると,
;The same label name used --- ASSEMBLE here
問題 5.9
make-assign (p.313)をみると,演算子なしの代入でmake-primitive-expを使い,
演算子があるときはmake-operation-expを呼ぶ.このmake-operation-exp(p.316)
はまたmake-primitive-expを使っている.
make-primitive-expでlabelが見つかるが,演算から呼ばれたときはlabelは使えない
ようにすればよい.
たとえば
(define ex5.9machine
(make-machine
'()
(list (list '= =))
'(start
(test (op =) (label start) (label start)))))
は通過する.
そこで次のように修正する.
(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 '#t))))
(lambda ()
(set-contents! target (value-proc))
(advance-pc pc)))))
(define (make-primitive-exp exp machine labels use)
(cond ((constant-exp? exp)
(let ((c (constant-exp-value exp)))
(lambda () c)))
((label-exp? exp)
(if use
(let ((insts
(lookup-label labels
(label-exp-label exp))))
(lambda () insts))
(error "Label used in operation --- ASSEMBLE" exp)))
((register-exp? exp)
(let ((r (get-register machine
(register-exp-reg exp))))
(lambda () (get-contents r))))
(else
(error "Unknown expression type -- ASSEMBLE" 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)))))
;これで上のプログラムを実行すると
;Label used in operation --- ASSEMBLE (label start)
問題 5.11
a.
afterfib-n-2
の下の2行
(assign n (reg val))
(restore val)
を
(restore n)
に変える.
Fib(n-1) Fib(n-2)は反対のレジスタに入るが結果は同じになる.
問題 5.12
make-new-machine の変数に db (database) を追加
dbを読むインターフェース手続き
(define (get-db machine)
(machine 'get-db))
dbを初期化する手続き make-new-machineの内部
(define (init-db)
(set! db (map (lambda (x) (list x))
(list 'assign 'test 'branch 'goto 'save 'restore 'perform
'label-reg 'save-reg 'restore-reg 'source)))
'done)
二つのメッセージを追加
((eq? message 'init-db) (init-db))
((eq? message 'get-db) db)
初期化を起動
(init-db)
dbに新規追加する手続き
(define (insert! value record)
(if (not (member value (cdr record)))
(set-cdr! record (cons value (cdr record)))))
make-assocの中
(insert! inst (assoc 'assign (machine 'get-db)))
(let ((reg (assign-reg-name inst))
(val (assign-value-exp inst))
(record (assoc 'source (machine 'get-db))))
(if (assoc reg (cdr record))
(insert! val (assoc reg (cdr record)))
(set-cdr! record (cons (list reg val) (cdr record)))))
make-test
(insert! inst (assoc 'test (machine 'get-db)))
make-branch
(insert! inst (assoc 'branch (machine 'get-db)))
make-goto
(insert! inst (assoc 'goto (machine 'get-db)))
(insert! (register-exp-reg dest)
(assoc 'label-reg (machine 'get-db)))
make-save
(insert! inst (assoc 'save (machine 'get-db)))
(insert! (stack-inst-reg-name inst)
(assoc 'save-reg (machine 'get-db)))
make-restore
(insert! inst (assoc 'restore (machine 'get-db)))
(insert! (stack-inst-reg-name inst)
(assoc 'restore-reg (machine 'get-db)))
make-perform
(insert! inst (assoc 'perform (machine 'get-db)))
を追加する
fibonacci-machineを定義し (get-db 'fibonacci-machine)を実行すると
((assign
(assign val (reg n))
(assign val (op +) (reg val) (reg n))
(assign n (reg val))
(assign continue (label afterfib-n-2))
(assign n (op -) (reg n) (const 2))
(assign n (op -) (reg n) (const 1))
(assign continue (label afterfib-n-1))
(assign continue (label fib-done)))
(test
(test (op <) (reg n) (const 2)))
(branch
(branch (label immediate-answer)))
(goto
(goto (reg continue))
(goto (label fib-loop)))
(save
(save val)
(save n)
(save continue))
(restore
(restore val)
(restore continue)
(restore n))
(perform)
(label-reg continue)
(save-reg val n continue)
(restore-reg val continue n)
(source
(val ((reg n)) ((op +) (reg val) (reg n)))
(n ((reg val)) ((op -) (reg n) (const 2)) ((op -) (reg n) (const 1)))
(continue ((label afterfib-n-2)) ((label afterfib-n-1)) ((label fib-done)))))
が得られる.
問題 5.14
まず階乗計算機を定義し
(define fact-machine
(make-machine
'(continue n val)
(list (list '= =) (list '- -) (list '* *))
'((perform (op initialize-stack))
(assign continue (label fact-done))
fact-loop
(test (op =) (reg n) (const 1))
(branch (label base-case))
(save continue)
(save n)
(assign n (op -) (reg n) (const 1))
(assign continue (label after-fact))
(goto (label fact-loop))
after-fact
(restore n)
(restore continue)
(assign val (op *) (reg n) (reg val))
(goto (reg continue))
base-case
(assign val (const 1))
(goto (reg continue))
fact-done
(perform (op print-stack-statistics)))))
スタックをテストするプログラムを書き
(define (stack-test n)
(newline)(display "n = ") (display n)
(set-register-contents! fact-machine 'n n)
(start fact-machine)
(newline)(display (get-register-contents fact-machine 'val)))
(stack-test 1)
(stack-test 2)
(stack-test 3)
(stack-test 4)
(stack-test 5)
(stack-test 6)
(stack-test 7)
(stack-test 8)
(stack-test 9)
(stack-test 10)
でテストする.実行結果
n = 1
(total-pushes = 0 maximum-depth = 0)
1
n = 2
(total-pushes = 2 maximum-depth = 2)
2
n = 3
(total-pushes = 4 maximum-depth = 4)
6
n = 4
(total-pushes = 6 maximum-depth = 6)
24
n = 5
(total-pushes = 8 maximum-depth = 8)
120
n = 6
(total-pushes = 10 maximum-depth = 10)
720
n = 7
(total-pushes = 12 maximum-depth = 12)
5040
n = 8
(total-pushes = 14 maximum-depth = 14)
40320
n = 9
(total-pushes = 16 maximum-depth = 16)
362880
n = 10
(total-pushes = 18 maximum-depth = 18)
3628800 -- done
Unspecified return value
問題 5.15
make-new-machineの変数にinst-countを用意する
(execute)の中でinst-countを増やす
(set! inst-count (+ inst-count 1))
インターフェース
(define (reset-inst-count machine)
(machine 'reset-inst-count))
(define (get-inst-count machine)
(machine 'get-inst-count))
メッセージ処理
((eq? message 'get-inst-count) inst-count)
((eq? message 'reset-inst-count) (set! inst-count 0) 'ok)
fibonacci-machineを実行してみる
;Value: fibonacci-machine
1 ]=> (set-register-contents! fibonacci-machine 'n 10)
;Value: done
1 ]=> (start fibonacci-machine)
;Value: done
1 ]=> (get-inst-count fibonacci-machine)
;Value: 2029
1 ]=> (get-register-contents fibonacci-machine 'val)
;Value: 55
問題 5.16
make-new-machineの中に
(define trace-flag '())
を追加し
executeの中でトレースする
(if trace-flag
(begin (newline) (display (caar insts))))
(perform (op trace-on)) でトレース開始
(perform (op trace-off)) でトレース終了
(define fibonacci-machine
(make-machine
'(continue n val)
(list (list '< <) (list '- -) (list '+ +))
;; (list 'trace-on trace-on) (list 'trace-off trace-off)) ;;opを追加
;; 演算子のリストにtrace-on, trace-offはいらない, make-new-machineで定義済み
'(
(assign continue (label fib-done))
fib-loop
(test (op <) (reg n) (const 2))
(branch (label immediate-answer))
(save continue)
(assign continue (label afterfib-n-1))
(save n)
(assign n (op -) (reg n) (const 1))
(goto (label fib-loop))
afterfib-n-1
(restore n)
(perform (op trace-on)) ;; trace-on
(restore continue)
(assign n (op -) (reg n) (const 2))
(save continue)
(assign continue (label afterfib-n-2))
(save val)
(goto (label fib-loop))
afterfib-n-2
(assign n (reg val))
(restore val)
(perform (op trace-off))
(restore continue)
(assign val (op +) (reg val) (reg n))
(goto (reg continue))
immediate-answer
(assign val (reg n))
(goto (reg continue))
fib-done)))
(set-register-contents! fibonacci-machine 'n 2)
(start fibonacci-machine)
(get-register-contents fibonacci-machine 'val)
n=2で実行してみる
(assign continue (label fib-done))
(test (op <) (reg n) (const 2))
(branch (label immediate-answer))
(save continue)
(assign continue (label afterfib-n-1))
(save n)
(assign n (op -) (reg n) (const 1))
(goto (label fib-loop))
(test (op <) (reg n) (const 2))
(branch (label immediate-answer))
(assign val (reg n))
(goto (reg continue))
(restore n)
(restore continue)
(assign n (op -) (reg n) (const 2))
(save continue)
(assign continue (label afterfib-n-2))
(save val)
(goto (label fib-loop))
(test (op <) (reg n) (const 2))
(branch (label immediate-answer))
(assign val (reg n))
(goto (reg continue))
(assign n (reg val))
(restore val)
(restore continue)
(assign val (op +) (reg val) (reg n))
(goto (reg continue)) -- done
;Value: 1
問題 5.17
ラベルが現れたらextract-labelsでinstの前に ((label