SICP 読み (293) 5.4 積極制御評価器

手動評価器を再起動。(291) の続きから、という事で以下に停止するまでのナニを再掲。
ええと、評価するソレは以下で。

;;; EC-Eval input:
(define (factorial n)
  (define (iter product counter)
    (if (> counter n)
        product
        (iter (* counter product)
              (+ counter 1))))
  (iter 1 1))

(total-pushes = 3 maximum-depth = 3)
;;; EC-Eval value:
ok

;;; EC-Eval input:
(factorial 1)

(total-pushes = 64 maximum-depth = 10)
;;; EC-Eval value:
1

;;; EC-Eval input:

あと、factorial を define するナニは略で (factorial 1) の評価から

  • eval-dispach で application 認定
    • continue (最初なので print-result が格納) を save
    • env (factorial を手続きに束縛している the-global-environment が格納) を save
    • unev に operands を格納して save
    • exp に operator、cont に ev-appl-did-operator をセット
  • eval-dispatch で variable 認定 (ev-variable に jmp)
    • val に lookup した式をセット
    • continue (ev-appl-did-operator) に jmp
    • unev、env の順で restore (cont は最後限定じゃないとマズい)
    • algl に空リスト、proc に val をセット
    • 引数ナシだったら jmp しますが、引数は一つある
    • proc を save
    • argl も save
    • exp に unev (引数リスト) の最初の要素をセット
    • unev に残りがないので ev-appl-last-arg に jmp
    • continue に ev-appl-accum-last-arg をセット
    • この時点で stack には argl, proc, continue が格納されている
  • exp は 1 なので eval-dispatch で self-evaluating 認定
    • val に 1 セットして continue (ev-appl-accum-last-arg) に jmp
    • argl を restore
    • argl に val を追加
    • proc を restore して apply-dispatch に jmp
    • proc の中身は compound 認定なので compound-apply に jmp
    • unev に procedure-parameter をセット
    • env に procedure-environment (これは define した時点の環境) をセット
    • env 拡張 uenv と argl を使って n に 1 を束縛
    • unev に procedure-body をセット
    • ev-sequence に jmp
    • この時点の stack は continue (最初のヤツ) のみな模様
    • exp に取り出される最初の式は define な式
    • uenv と env が save
    • continue に ev-sequence-continue がセットされて eval-dispatch に jmp
  • eval-dispatch では definition 認定
    • unev に definition-variable な iter がセットされて save
    • exp に lambda にされた手続き本体がセット
    • env と continue が save される (この時点で最大深さ 6)
    • continue に ev-definition-1 がセット
  • eval-dispatch では lambda 認定
    • unev に lambda なパラメータがセット
    • exp に手続き本体がセット
    • make-procedure な戻りが val にセット
    • continue (ev-definition-1) に jmp
    • continue と env と unev が restore
    • iter (unev) を eval した手続き (val) に束縛 (define-variable!)
    • val に OK をセットして continue (ev-sequence-continue) に jmp
    • env と unev が restore
    • unev に (cdr unev) がセット (unev は ((iter 1 1)) になる)
    • ev-sequence に jmp
    • この時点での最大深さは 6 で、save の回数は 10 回 ?? あと stack は最初の continue のみが格納されてる状態
    • exp に (iter 1 1) がセット
    • last-exp? は #t になるので ev-sequence-last-exp に jmp
    • continue が restore されて print-result が格納
  • eval-dispatch では application 認定 (ある意味ここがスタート地点)
    • continue と env が save
    • unev に operands (1 1) がセット
    • unev が save
    • exp に operator (iter) がセット
    • continue に ev-appl-did-operator がセット
  • eval-dispatch では variable 認定
    • val に手続きセット
    • continue (ev-appl-did-operator) へ jmp
    • unev と env が restore
    • argl に空リストがセット
    • proc に val をセット
    • unev は null ではないので proc を save
    • argl も save
    • exp に unev の最初の要素 (1) がセット
    • unev の cdr は null ではないので env と unev が save
    • continue に ev-appl-accumulate-arg がセット
  • eval-dispatch では self-evaluating 認定
    • val に 1 がセットされて continue (ev-appl-accumulate-arg) に jmp
    • unev、env、argl が restore
    • argl に val (1) を追加
    • unev に (cdr unev) がセット
    • ev-appl-operand-loop に jmp
    • argl が save
    • exp に unev の最初の要素 (1) がセット
    • unev の cdr は null なんで ev-appl-last-arg に jmp
    • continue に ev-appl-accum-last-arg をセット
  • eval-dispatch では self-evaluating 認定
    • val に 1 がセットされて continue (ev-appl-accum-last-arg) に jmp
    • argl を restore
    • argl に val (1) を追加
    • proc を restore (!!)
    • apply-dispatch に jmp
    • save 18 回で最大深さは 6 回 (前のナニからここまで最大深さは 5 回)、この時点で stack にあるのは最初の continue なのか
  • apply-dispatch では compound 認定
    • unev に procedure-parameters (product operator) をセット
    • env に procedure-environment をセット
    • env に extend-environment なソレ (product は 1 で operator は 1) をセット
    • unev に 手続きをセットして ev-sequence に jmp
    • exp に unev の先頭リストをセット (if 一発)
    • last-exp なので ev-sequence-last-exp に jmp
    • continue を restore (最初の continue が pop されて stack は空)
  • eval-dispatch で if 認定

多分このあたりが末尾再帰のキモなんだろうな、と言いつつオワ。次回からは続きで勘弁して頂いて最後に纏める方向で勘弁して下さひ。