/var/log/messages

debugging with sixth sense

SICP5

金曜に実装を写経して正常動作を確認後、make-machine 以降のナニを纏めたのですが scrach buffer に残したままになってて OSX がフリーズしました。見事に消失。

記録としては自分用に有益なので再度エントリを起こすことにしました。

起点としては make-machine が何をしているか、という事で

  • vm なオブジェクトを生成
  • 引数で渡されたリストな名前のレジスタなオブジェクトを生成して vm に設定
  • 引数で渡されたリストのリストで primitive な命令を登録して vm に設定
  • 引数で渡された命令のリストから命令列を生成して vm に設定
  • vm なオブジェクトを戻す

になっているのですが、命令列を生成する assemble 手続きを掘削します。

assemble 手続き

実装としては extract-labels を呼びだしているだけ、なのですが引数として渡しているのは例えば gcd-machine の例であれば以下のリストです。

'(test-b
  (test (op =) (reg b) (const 0))
  (branch (label gcd-done))
  (assign t (op rem) (reg a) (reg b))
  (assign a (reg b))
  (assign b (reg t))
  (goto (label test-b))
  gcd-done)))

あと、最初に渡されるのが以下な手続きオブジェクトになります。これは一番最後に apply されます。

(lambda (insts labels)
  (update-insts! insts labels machine)
  insts)))

ので、ここでは一旦スルー。

extract-labels 手続き

引数として命令リストと手続きオブジェクトが渡されます。

この手続き、命令リストの car について

  • symbol? ならラベルと理解してラベルな引数リストに追加
  • symbol? でなければ命令と理解して命令な引数リストに追加

します。また、引数リストに追加する時に

  • ラベルの場合はラベル文字列とそれ以降の命令リスト
  • 命令の場合は (対象となる命令) という形のリスト

を作ります。命令の場合はリスト、って書いてますが正確には

(対象となる命令 . ())

で、後程 cdr に命令の実行手続き、という書き方の手続きオブジェクトが格納されます。

extract-labels 手続きのポイントとしては

  • 命令リストの car を取り出しつつ
  • 取り出した car に対する手続きを設定しつつ
  • 命令リストの末端まで同様の処理をして
  • 命令リストの末端に到達した時点で設定された手続きを apply しつつ
  • 最後にそれらの手続きで作られたリストについて update-insts! して
  • update-insts! が変更した何かを戻す

という形になっている、はず。

これを前提に掘削してみます。

update-insts! 手続き

! 付いてるので void でありつつ二番目の引数更新、になる模様。基本的には insts なリストについて for-each で数えあげつつ

 (lambda (inst)
   (set-instruction-execution-proc!
inst
(make-execution-procedure
 (instruction-text inst) labels machine pc flag stack ops)))

な手続きを、という形。先に書いた通り、inst として渡れるのは

(対象となる命令 . ())

というリストです。基本的にはこのリストに対して make-execution-procedure の戻りを set-cdr! する形です。

make-execution-procedure は基本的に引数を取らない手続きオブジェクトを戻します (これって何って名前が付いてたのだったか忘れた)。

最終的に

assemble 手続きから戻される命令リストは最終的に ‘start で以下な形で動きはじめます。

   (set-contents! pc the-instruction-sequence)
   (execute))

pc レジスタに assemble から戻されたリストを設定して execute を apply しています。execute の定義は以下になってて

  (define (execute)
(let ((insts (get-contents pc)))
  (if (null? insts)
      'done
      (begin
    ((instruction-execution-proc (car insts)))
    (execute)))))

リストから順に取り出しては cdr を取得して apply しては execute しています。基本的に apply される lambda な手続きの中で pc を先にすすめる形になっているのでこれだけで動作するはず。

終わりに

なんか消えさったテキストはもっと色々な情報が盛り込まれていたはずなんですが、スデに何だったのかとか忘却の彼方。

あと、make-execution-procedure から呼び出されている手続きも確認な必要あるはずなのですが、とりあえずスルー。

5.4 ではこの vm というかシミュレータが評価できる命令で scheme の評価機を作ります。そして 5.5 では scheme の命令なリストをこの vm というかシミュレータが評価できる命令列に翻訳する翻訳系を実装して解釈系と接合する模様。

実は 5 章はきちんと理解できていないのがトラウマになってて、何故かこの時期にリトライを思いついてしまっている次第です。どうなるか。

Comments