SICP演習問題5.13
とりゃっとちょっと言ってみた.
今回の問題は簡単?だった.
変更点
- make-machine
- make-assign
- make-save
- make-primitive-procedure
方針としては
- make-machine変数の数を減らす
- {make-assign, make-save, make-primitive}を実行するときにそのレジスタが作られているかチェックし,なければ作成してから実行する
これをやれば,他の命令では,レジスタが存在しないはずはないので,この3つの関数にチェックする部分を追加する.追加するものはまったく同じ.
(define (make-machine ops controller-text) (let ((machine (make-new-machine))) ((machine 'install-operations) ops) ((machine 'install-instruction-sequence) (assemble controller-text machine)) machine)) (define (make-assign instruction machine labels operations pc) (let* ((reg-name (assign-reg-name instruction)) (target (get-register machine reg-name)) (value-exp (assign-value-exp instruction))) (if (not target) (begin ((machine 'allocate-register) reg-name) (set! target (get-register machine reg-name)))) (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 (make-save instruction machine stack pc) (let* ((reg-name (stack-instruction-reg-name instruction)) (reg (get-register machine reg-name))) (if (not reg) (begin ((machine 'allocate-register) reg-name) (set! reg (get-register machine reg-name)))) (lambda () (push stack (get-contents reg)) (advance-pc pc)) )) (define (make-primitive-exp exp machine labels) (cond [(constant-exp? exp) (let ((constant-value (constant-exp-value exp))) (lambda () constant-value))] [(label-exp? exp) (let ((instructions (lookup-label labels (label-exp-label exp)))) (lambda () instructions))] [(register-exp? exp) (let* ((reg-name (register-exp-reg exp)) (reg (get-register machine reg-name))) (if (not reg) (begin ((machine 'allocate-register) reg-name) (set! reg (get-register machine reg-name)))) (lambda () (get-contents reg)))] [else (error "Unknown expression type -- ASSEMBLE" exp)]) )
fibを実行する
(define fib-machine (make-machine ; '(continue val n) (list (list '< <) (list '= =) (list '- -) (list '+ +) (list 'print print)) '(controller (assign continue (label fib-done)) fib-loop (test (op <) (reg n) (const 2)) (branch (label immediate-answer)) ;; set up to compute Fib(n-1) (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 print) (reg n)) ;; set up to compute Fib(n-2) (assign n (op -) (reg n) (const 2)) (assign continue (label afterfib-n-2)) (save val) (goto (label fib-loop)) afterfib-n-2 (assign n (reg val)) (restore val) ; (restore n) (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! fib-machine 'n 3) (start fib-machine) (get-register-contents fib-machine 'val)
gosh> (set-register-contents! fib-machine 'n 10) done gosh> (start fib-machine) done gosh> (get-register-contents fib-machine 'val) 55
追記
では,
;;; make-new-machine の内部定義手続き lookup-register を register ;;; が見つからなかったら作るよう変更する。 (define (lookup-register name) (let ((val (assoc name register-table))) (if val (cadr val) (begin (allocate-register name) (lookup-register name)))))
確かに....これならいろいろなところに追加しなくていいから簡単です.