SICP 読み (269) 5.2 レジスタ計算機での計算
この節のゴールはデバッガらしい。breakpoint 設定しちゃってます。
問題 5.17
直前ラベルを印字しなさい、との事。これはムズい。label な情報は assemble の時にそれぞれの手続きの中に隠蔽されちゃってる訳で、これを印字するにはどうしたものか、容量の少ない脳をイタめた夕方だった訳です。
で、出てきた順にアイデアを列挙。基本的には insts なリストの car 部に命令なテキストと一緒にラベルを格納しよう、という事になっております。
- update-insts! の中でなんとかする (具体的には for-each の後又は中)
- labels を先頭から見てって云々。ケツから処理できたらシアワセ
- make-label-entry (extract-labels で呼ばれています) の中で云々
- extra-labels の中の label な処理の中でなんたら
ってコトで、とりあえず試験から作って下から順に動作確認。動いた瞬間検討は止める予定ッス。(を
(use gauche.test) (add-load-path ".") (load "ch5-regsim") (test-start "5.17") (test-section "assemble") (let ((m (make-new-machine))) (for-each (lambda (register-name) ((m 'allocate-register) register-name)) '(n continue val)) ((m 'install-operations) (list (list '= =) (list '- -) (list '* *))) (let ((insts (assemble '(controller (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) m))) (test* "(car (car (car insts)))" 'controller (car (car (car insts)))) (test* "(cdr (car (car insts)))" '(assign continue (label fact-done)) (cdr (car (car insts)))) (test* "(car (car (cadr insts)))" 'fact-loop (car (car (cadr insts)))) ) ) (test-end)
とりあえず上記で様子を見て、大丈夫そうなら試験追加とゆー事で。
extract-labels で
extract-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 "Dup label entry -- ASSEMBLE" next-inst) (receive insts ; (cons (make-label-entry next-inst ;; 5.17 ; insts) ;; 5.17 (cons (make-label-entry next-inst ;; 5.17 (add-label-name ;; 5.17 next-inst ;; 5.17 insts)) ;; 5.17 labels))) (receive (cons (make-instruction next-inst) insts) labels))))))) (define (add-label-name label insts) (for-each (lambda (inst) (set-car! inst (cons label (instruction-text inst)))) insts) insts)
上記の試験にパスしない。
$ gosh test-5.17.scm Testing 5.17 ... <assemble>--------------------------------------------------------------------- test (car (car (car insts))), expects controller ==> ok test (cdr (car (car insts))), expects (assign continue (label fact-done)) ==> ok test (car (car (cadr insts))), expects fact-loop ==> ERROR: GOT controller failed. discrepancies found. Errors are: test (car (car (cadr insts))): expects fact-loop => got controller $
ケツから処理してるハズなんですが何故だ、と言いつつカブセてる可能性に気付く。add-label-name を
(define (add-label-name label insts) (for-each (lambda (inst) (if (null? (car (car inst))) (set-car! inst (cons label (instruction-text inst))))) insts) insts)
のようにしたら 3 つの試験にはパス。
$ gosh test-5.17.scm Testing 5.17 ... <assemble>--------------------------------------------------------------------- test (car (car (car insts))), expects controller ==> ok test (cdr (car (car insts))), expects (assign continue (label fact-done)) ==> ok test (car (car (cadr insts))), expects fact-loop ==> ok passed. $
で、どう試験したものか、と言いつつ短気を起こして (以下略
$ gosh gosh> (add-load-path ".") ("." "/usr/share/gauche/site/lib" "/usr/share/gauche/0.8.8/lib") gosh> (load "ch5-regsim") #t gosh> (define m (make-machine '(n continue val) (list (list '= =) (list '- -) (list '* *)) '(controller (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))) m gosh> (m 'trace-on) #t gosh> (set-register-contents! m 'n 1) done gosh> (m 'start) (controller assign continue (label fact-done)) (fact-loop test (op =) (reg n) (const 1)) (fact-loop branch (label base-case)) (base-case assign val (const 1)) (base-case goto (reg continue)) done gosh> (set-register-contents! m 'n 2) done gosh> (m 'start) (controller assign continue (label fact-done)) (fact-loop test (op =) (reg n) (const 1)) (fact-loop branch (label base-case)) (fact-loop save continue) (fact-loop save n) (fact-loop assign n (op -) (reg n) (const 1)) (fact-loop assign continue (label after-fact)) (fact-loop goto (label fact-loop)) (fact-loop test (op =) (reg n) (const 1)) (fact-loop branch (label base-case)) (base-case assign val (const 1)) (base-case goto (reg continue)) (after-fact restore n) (after-fact restore continue) (after-fact assign val (op *) (reg n) (reg val)) (after-fact goto (reg continue)) done gosh>
もう少し追試します。なんとなくイケてるっぽくはあるのですが。
追記
以下の修正もしてますが、エントリに盛り込むのを忘れとりました (汗
(define (make-instruction text) (cons (cons '() text) '())) (define (instruction-text inst) (cdr (car inst)))
さらに追記
make-new-machine 方面の修正ログも載せていない。とりあえず一部のみ以下に。
(define (execute) (let ((insts (get-contents pc))) (if (null? insts) 'done (begin (if trace ;; 5.16 (begin ;; 5.16 ; (display (instruction-text (car insts))) ;; 5.16 (display (car (car insts))) ;; 5.17 (newline))) ;; 5.16 ((instruction-execution-proc (car insts))) (set! inst-ctr (+ inst-ctr 1)) ;; 5.15 (execute)))))
うーん。イタい。しかも出力微妙だし。