SICP 読み (310) 5.5 翻訳系

直前エントリでは (= n 1) を compile-application に吸わせて proc-code にセットされるリスト

'((env) (proc)
  ((assign proc
	   (op lookup-variable-value)
	   (const =)
	   (reg env))))

が取得できたトコまでだった。
次は operand-codes にセットされるリストを

(map (lambda (operand) (compile operand 'proc 'next))
     (operands exp))

で取得するあたり。(= n 1) の operands は (n 1) なのでそれぞれの要素について map の中の lambda がナニ。最初は (compile n 'val 'next) になります。
これは compile-variable な手続きが適用。compile-variable では最初に instruction-sequence が作成される。

'((env) (proc) ((assign val (op lookup-variable-value) (const n) (reg env))))

で、これを next な linkage と共に end-with-linkage に。この中では上記の式と

'(() () ())

な instruction-sequence を (continue) を引数に preserving する。preserving では基本的に seq1 の modifies-register と seq2 の needs-register に preserving に渡したレジスタリストの要素が合致したら、それは save/restore の対象となる、と判断している。当たり前と言えば当たり前か。しかしまだ needs なソレをどうやって判断しているのか、が微妙。ちょっと前節に遡って見直す必要はあるな。
で、save/restore なソレの用意ができれば、append-instruction する訳ですか。append-instruction についてはもう少し複雑なソレが出てくるまでは態度保留。
1 の評価は略すとして map が出してくる最終的なリストは以下か。

'(((env) (proc) ((assign val (op lookup-variable-value) (const n) (reg env))))
  ((env) (proc) ((assign val (const 1)))))

ここから未知の領域に突入ですな。まず以下の式

(preserving '(proc continue)
	    (construct-arglist operand-codes)
	    (compile-procedure-call target linkage))

ええと、ここは eval-if の p-code を取得する手続きの中なんで、target は val で linkage は next になっている模様。ちなみに operand-codes は上記のリストです。

construct-arglist

一旦 operand-codes を reverse して、ケツにあった引数と

'((val) (argl) ((assign argl (op list) (reg val))))

を append-instruction している。これは良く見てみた方が良さげ。以下のような形になるのか

(append-instruction-sequences
 '((env) (proc) ((assign val (const 1))))
 '((val) (argl) ((assign argl (op list) (reg val)))))

append の動作を見るには良い例になってくれれば良いですが。この例で言うと append の引数の seqs は以下か

'(((env) (proc) ((assign val (const 1))))
  ((val) (argl) ((assign argl (op list) (reg val)))))

上記のリストの御機嫌を伺ってみます。

gosh> (define  l '(((env) (proc) ((assign val (const 1))))
  ((val) (argl) ((assign argl (op list) (reg val))))))
l
gosh> (car l)
((env) (proc) ((assign val (const 1))))
gosh> (cdr l)
(((val) (argl) ((assign argl (op list) (reg val)))))
gosh> (cdr (cdr l))
()
gosh> 

最初に評価されるのは

(append-2-sequences
 ((val) (argl) ((assign argl (op list) (reg val))))
 (() () ()))

になる。これはそのまま

'((val) (argl) ((assign argl (op list) (reg val))))

が戻る。ので一つ上に行って

(append-2-sequences
 '((env) (proc) ((assign val (const 1))))
 '((val) (argl) ((assign argl (op list) (reg val)))))

になってここからがある意味本番。まず make-instruction-sequence に渡される最初の引数は

(list-union '(env)
	    (list-difference '(val) '(proc)))

になる。上記の list-difference は '(val) を戻すので上記の list-union は '(env val) を戻す形になるはず。うーん。あるいは二番目の引数は

(list-union '(proc) '(argl))

なので単純に '(proc argl) になるのか。最終的に append-instruction が戻すのは

'((env val) (proc argl) ((assign val (const 1)) (assign argl (op list) (reg val))))

になるんでしょうか。ええとこれが construct-arglist の中の code-to-get-last-arg にセットされるリストになる、という事にしておきます。これでようやく中身の手続きに移ることになりますでしょうか。

          (if (null? (cdr operand-codes))
              code-to-get-last-arg
              (preserving '(env)
               code-to-get-last-arg
               (code-to-get-rest-args
                (cdr operand-codes))))))))

むむ。上記の if の consequent なソレは引数が一つの場合のナニ。今回のケイスは二つですので alternative な式が評価されるはず。まず、code-to-get-rest-args を確認してみる必要あり。

code-to-get-rest-args

この手続きは基本的には残りの operand-codes の要素について

(assign argl (op cons) (reg val) (reg argl))

な手続きをケツに preserving でくっつけながら、それぞれを preserving でくっつけていく手続き、と言えば良いのでしょうか。今回の例で言うと

(preserving '(argl)
	    '((env) (proc) ((assign val (op lookup-variable-value) (const n) (reg env))))
	    '((val argl) (argl) ((assign argl (op cons) (reg val) (reg argl)))))

になるか。まだ preserving なソレが一目ではない。
見てみると、

(and (needs-register? seq2 first-reg)
     (modifies-register? seq1 first-reg))

な条件を満たすソレはありませんので、単純に append される模様。append された結果としては

'((env val argl) (proc argl)
  ((assign val (op lookup-variable-value) (const n) (reg env))
   (assign argl (op cons) (reg val) (reg argl))))

になりますでしょうか。本当でしょうか (を
で、上記と preserving されたナニが construct-arglist になるんだな。

(preserving '(env)
	    '((env val) (proc argl) 
	      ((assign val (const 1)) 
	       (assign argl (op list) (reg val))))
	    '((env val argl) (proc argl)
	      ((assign val (op lookup-variable-value) (const n) (reg env))
	       (assign argl (op cons) (reg val) (reg argl)))))

これはこれは。env は save/restore されませんので単純に (??) append される

(append-2-sequences
 '((env val) (proc argl) 
	      ((assign val (const 1)) 
	       (assign argl (op list) (reg val))))
 '((env val argl) (proc argl)
	      ((assign val (op lookup-variable-value) (const n) (reg env))
	       (assign argl (op cons) (reg val) (reg argl)))))

まず (env val) + ((env val argl) - (proc argl)) は (env val) ですな。第二引数は略で良いとして (単純に重複を除いた和集合) 以下ッスか??

'((env val) (proc argl)
  ((assign val (const 1)) 
   (assign argl (op list) (reg val))
   (assign val (op lookup-variable-value) (const n) (reg env))
   (assign argl (op cons) (reg val) (reg argl))))

上記が construct-arglist の戻りと信じたい。次の compile-procedure-call の引数って何だったかも記憶の外。

compile-procedure-call

これは何だ。そろそろ限界かも。って apply-dispatch なのか。まだ if の条件式を評価する途中なのか。まだまだ先は長い。