SICP 読み (358) 5.5 翻訳系

なんと言えば良いか分かりませんが、この最後の 5.5 節はあまりきちんと読めていない気がします。コードも allcode なソレに頼りきってたりしますし。

とりあえず 47 と 48 のまとめ

ええと、(357) なエントリにおいて手続きの入口では (って書き方で良いのかなぁ

  • 解釈系では継続が stack のてっぺんにある
  • 翻訳系では継続が continue にある

という相違があるので例えば翻訳系から解釈系の手続きを呼び出す時には、これを吸収してあげる必要がある模様。ただ、(355) なエントリではこれを解釈系側で処理しているために、解釈系で define された手続きから解釈系で define された手続きが呼び出されるケイスにおいて不具合が生じる。
基本的には compound-branch な手続き中で continue は save されるべきと思われる。

  compiled-branch10 
  (assign val (op compiled-procedure-entry) (reg proc)) 
  (goto (reg val)) 
  compound-branch11 
;; このあたりで (save continue) されるべき
  (assign val (reg compapp)) 
  (goto (reg val)) 
  primitive-branch9 
  (assign val (op apply-primitive-procedure) (reg proc) (reg argl)) 
  #2=(goto (reg continue)) 
  after-call12 
  after-lambda8 

次の 5.48 は解釈系で何度も翻訳系を呼び出したい、という事で解釈系の基本手続きを拡張する必要がある。その拡張された基本手続きから compile および assemble を行なう組込み手続きを呼び出して戻されたものに goto すれば良い。

問題 5.47

というソレを踏まえてリトライ。てーか、proc と next な組み合わせの時にどうなるか、が自信ない。修正対象だったのは以下の手続きです (ch5-compiler.scm)

(define (compile-procedure-call target linkage)
  (let ((primitive-branch (make-label 'primitive-branch))
        (compiled-branch (make-label 'compiled-branch))
        (compound-branch (make-label 'compound-branch)) ;; add
        (after-call (make-label 'after-call)))
    (let ((compiled-linkage
           (if (eq? linkage 'next) after-call linkage)))
      (append-instruction-sequences
       (make-instruction-sequence '(proc) '()
        `((test (op primitive-procedure?) (reg proc))
          (branch (label ,primitive-branch))))
       (make-instruction-sequence '(proc) '()           ;; add
        `((test (op compound-procedure?) (reg proc))    ;; add
          (branch (label ,compound-branch))))           ;; add
       (parallel-instruction-sequences
        (append-instruction-sequences
         compiled-branch
         (compile-proc-appl target compiled-linkage))
        (parallel-instruction-sequences                    ;; add
         (append-instruction-sequences                     ;; add
          compound-branch                                  ;; add
          (compound-proc-appl target compiled-linkage))    ;; add
         (append-instruction-sequences
          primitive-branch
          (end-with-linkage linkage
                            (make-instruction-sequence '(proc argl)
                             (list target)
                             `((assign ,target
                                       (op apply-primitive-procedure)
                                       (reg proc)
                                       (reg argl)))))))
        ) ;; add
       after-call))))

;;;applying compound procedures

(define (compound-proc-appl target linkage)
  (cond ((and (eq? target 'val) (not (eq? linkage 'return)))
         (make-instruction-sequence '(proc) all-regs
           `((assign continue (label ,linkage))
	     (save continue)
             (assign val (reg compapp))
             (goto (reg val)))))
        ((and (not (eq? target 'val))
              (not (eq? linkage 'return)))
         (let ((proc-return (make-label 'proc-return)))
           (make-instruction-sequence '(proc) all-regs
            `((assign continue (label ,proc-return))
	      (save continue)
              (assign val (reg compapp))
              (goto (reg val))
              ,proc-return
              (assign ,target (reg val))
              (goto (label ,linkage))))))
        ((and (eq? target 'val) (eq? linkage 'return))
         (make-instruction-sequence '(proc continue) all-regs
          '((assign val (reg compapp))
	    (save continue)
            (goto (reg val)))))
        ((and (not (eq? target 'val)) (eq? linkage 'return))
         (error "return linkage, target not val -- COMPILE"
                target))))

target が val で linkage が return 以外のケイスについては試験してません。(を
とりあえず動作しているのは翻訳された手続きから解釈系で定義された手続きを呼び出すような以下のケイスのみ

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

;;; EC-Eval input:
(define (g n) (* 3 n))

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

;;; EC-Eval input:
(f 3)

(total-pushes = 14 maximum-depth = 5)
;;; EC-Eval value:
9

;;; EC-Eval input:

問題 5.48

基本的には(357) なエントリの考え方で良いはず。ch5-eceval-compiler.scm についてまず以下の手続きを定義し

(define (compile->assemble exp)
  (assemble (statements (compile (cadr exp) 'val 'return)) eceval))
(define (compile-and-run? exp)
  (tagged-list? exp 'compile-and-run))

これらを eceval-operation に追加

(define eceval-operations
  (list
   ;; 5.48
   (list 'compile->assemble compile-assemble)
   (list 'compile-and-run? compile-and-run)

   ;;primitive Scheme operations
   (list 'read read)			;used by eceval

eval-dispatch に以下を挿入

;; 5.48
  (test (op compile-and-run?) (reg exp))
  (branch (label ev-compile-and-run))
;; 5.48
  (test (op application?) (reg exp))
  (branch (label ev-application))
  (goto (label unknown-expression-type))

あとは ev-compile-and-run な手続きを追加

ev-compile-and-run
  (assign val (op compie->assemble) (reg exp))
  (assign continue (label print-result))
  (goto (reg val))

これで動作確認したら

*** ERROR: Unbound variable factorial
Stack Trace:
_______________________________________
  0  (map (lambda (p) (p)) aprocs)
        At line 385 of "./ch5-regsim.scm"
  1  value-proc

  2  (set-contents! target (value-proc))
        At line 258 of "./ch5-regsim.scm"
  3  (instruction-execution-proc (car insts))
        At line 139 of "./ch5-regsim.scm"

って叱られた (鬱
問題解決してないじゃん。でもあっちでは動いたはずなんだけどなぁ。とりあえずログは残ってるってコトで明日確認する事にしてもう寝る。