SICP問題5.18-5.19
GWがあったのと、その後遺症で脳が機能を縮退していたせいもあり、だいぶ間があいてしまいましたが、つづきです。
いっぱいなおしすぎてるんで、もうわけわかりません。
ソースおいとくので、そっちみてください。
5.18のレジスタのトレースについては、いままでやってきたのをレジスタに適用するだけです。トレースをON/OFFするのは、別途set-register-trace-onとset-register-trace-offを用意してます。
5.19はいよいよ本命のブレークポイントを導入する問題。
ラベルとラベルからの距離をいれることでその位置にブレークポイントを設定し、pcがそこに到達すると、その命令を実行する直前に処理を停止させる。
5.17でinstructionにラベルをいれるのが個人的に非常に気に入ったので、ブレークポイントの設定はリストにして保持するのではなく、ラベルからの距離と一緒にinstructionにいれてしまうことにしました。
(define (make-instruction text)
; テキスト、命令、直前のラベル、ラベルからの距離、ブレイクポイント
(list text '() '() '() false)); instructionにラベルとラベルからの距離の情報を記憶させる
(define (set-label-to-instructions! insts label)
(define (iter insts count)
(if (or (null? insts) (instruction-have-label? (car insts)))
insts
(cons (set-instruction-label-info! (car insts) label count)
(iter (cdr insts) (+ count 1)))))
(iter insts 1))
そして、(set-breakpoint machine label n)としたときにえっちらおっちらinstructionを検索して、ラベルと距離が一致するところにブレークポイントを設定します。
; ブレークポイントを設定する
(define (set-breakpoint-switch label n switch)
; pcを頭から走査し、ラベルと距離が一致したらセット
; 見つからない場合はエラーにする。
(define (iter insts)
(if (null? insts)
(error "Not find label -- MACHINE" label n)
(let ((inst (car insts)))
(if (and (eq? (instruction-label inst) label)
(eq? (instruction-label-count inst) n))
(set-instruction-breakpoint! inst switch)
(iter (cdr insts))))))
(iter the-instruction-sequence)
'done)
; ブレークポイントON用
(define (set-breakpoint label n)
(set-breakpoint-switch label n true))
; ブレークポイントCANCEL用
(define (cancel-breakpoint label n)
(set-breakpoint-switch label n false))
executeでは実行直前にinstructionがブレークポイント設定されているかどうかを判定し
、設定されていたら何もせずに終わります。このとき、pcの中身は実行しようとしていた命令のままです。
(define (execute)
(let ((insts (get-contents pc)))
(if (null? insts)
'done
(begin
; 命令計数
(advance-instruction-count)
; 命令トレース
(print-instruction-trace (car insts)); ブレークポイントが設定されていない場合のみexecuteする
; このときpcは実行直前の状態になってるはずなので
; この状態で再度executeすれば続きから実行できるはず
(if (not (instruction-breakpoint (car insts)))
(begin
((instruction-execution-proc (car insts)))
(execute))
(begin
(print-breakpoint (car insts))
'stop))))))
このままexecuteをもう一回やっても同じようにとまってしまうので、proceed-machineはpcの最初の命令をブレークポイントを無視して実行し、つづきはexecuteにまかせると言う形をとります。
; 再開
(define (proceed)
; とまっている箇所をブレークポイントを無視して実行し
; executeを呼びだす。
(let ((insts (get-contents pc)))
(if (null? insts)
'done
(begin
; 命令計数
(advance-instruction-count)
; 命令トレース
(print-instruction-trace (car insts))
((instruction-execution-proc (car insts)))
(execute)))))
なんか無駄が多いような気がしますが。
cancel-all-breakpointはinstructionを全部なめて片っ端からoffにしていくだけです。
ソース
| 固定リンク | コメント (0) | トラックバック (0)

最近のコメント