読者です 読者をやめる 読者になる 読者になる

(wat-aro)

無職から有職者にランクアップしました

SICP 問題 5.17

scheme SICP

トレースログにラベルネームをつける.
 
extract-labelsでlabelを見つけた時に('label labe-name)の形でinsts, labels両方に登録する.
make-new-machineでtracing-labelを作り,そこに現在のラベルを登録する.
*1の実行形式はそのまま(advanced-pc pc)でpcをすすめるだけ.
後はexecuteを調整する

(define (extract-labels text receive)
  (if (null? text)
      (receive '() '())
      (extract-labels
       (cdr text)
       (lambda (insts labels)
         (let ((next-inst (car text)))
           (if (symbol? next-inst)
               (if (assoc next-inst labels)
                   (error
                    "The same label name is used to indicate two different location "
                    label-name)
                   ;; ここでlabelは('label . next-inst)の形でinstsに登録
                   (let ((insts (cons (list (list 'label next-inst)) insts)))
                     (receive insts
                         (cons (make-label-entry next-inst insts)
                               labels))))
               (receive (cons (make-instruction next-inst)
                              insts)
                   labels)))))))

(define (make-new-machine)
  (let ((pc (make-register 'pc))
        (flag (make-register 'flag))
        (stack (make-stack))
        (the-instruction-sequence '())
        (the-instruction-counter 0)
        (tracing-flag (lambda (inst) #f))
        (tracing-label 'global))
    (let ((the-ops
           (list (list 'initialize-stack
                       (lambda () (stack 'initialize)))
                 (list 'print-stack-statistics
                       (lambda () (stack 'print-statistics)))))
          (register-table
           (list (list 'pc pc) (list 'flag flag))))
      (define (allocate-register name)
        (if (assoc name register-table)
            (error "Multiply defined rgister: " name)
            (set! register-table
                  (cons (list name (make-register name))
                        register-table)))
        'register-allocated)
      (define (lookup-register name)
        (let ((val (assoc name register-table)))
          (if val
              (cadr val)
              (error "Unknown register: " name))))
      (define (execute trace)
        (let ((insts (get-contents pc)))
          (cond ((null? insts) 'done)
                (else
                 ((instruction-execution-proc (car insts)))
                 (cond ((label-exp? (caar insts))
                        (set! tracing-label (cdaar insts)))
                       (else (set! the-instruction-counter (+ 1 the-instruction-counter))
                             (trace (caar insts))))
                 (execute trace)))))
      (define (trace-on)
        (set! tracing-flag (lambda (inst)
                             (display tracing-label)
                             (display " : ")
                             (display inst) (newline)))
        'trace-on)
      (define (trace-off)
        (set! tracing-flag (lambda (inst) #f))
        'trace-off)
      (define (initialize-counter)
        (set! instruction-counter 0))
      (define (dispatch message)
        (cond ((eq? message 'start)
               (set-contents! pc the-instruction-sequence)
               (execute tracing-flag))
              ((eq? message 'install-instruction-sequence)
               (lambda (seq) (set! the-instruction-sequence seq)))
              ((eq? message 'allocate-register) allocate-register)
              ((eq? message 'get-register) lookup-register)
              ((eq? message 'install-operations)
               (lambda (ops) (set! the-ops (append the-ops ops))))
              ((eq? message 'stack) stack)
              ((eq? message 'operations) the-ops)
              ((eq? message 'get-counter) the-instruction-counter)
              ((eq? message 'initilize-counter) (initilize-counter))
              ((eq? message 'trace-on) (trace-on))
              ((eq? message 'trace-off) (trace-off))
              (else (error "Unknown request -- MACHINE" message))))
      dispatch)))

(define (make-execution-procedure inst labels machine
                                  pc flag stack ops)
  (cond ((eq? (car inst) 'assign)
         (make-assign inst machine labels ops pc))
        ((eq? (car inst) 'test)
         (make-test inst machine labels ops flag pc))
        ((eq? (car inst) 'branch)
         (make-branch inst machine labels flag pc))
        ((eq? (car inst) 'goto)
         (make-goto inst machine labels pc))
        ((eq? (car inst) 'save)
         (make-save inst machine stack pc))
        ((eq? (car inst) 'restore)
         (make-restore inst machine stack pc))
        ((eq? (car inst) 'perform)
         (make-perform inst machine labels ops pc))
        ((eq? (car inst) 'label)
         (lambda () (advance-pc pc)))
        (else (error "Unknown instruction type -- ASSEMBLE" inst))))

test

(define fib-machine
  (make-machine
   '(n val continue)
   (list (list '< <) (list '- -) (list '+ +))
   '(start
     (assign continue (label fib-done))
     fib-loop
     (test (op <) (reg n) (const 2))
     (branch (label immediate-answer))
     (save continue)
     (assign continue (label afterfib-n-1))
     (save n)
     (assign n (op -) (reg n) (const 1))
     (goto (label fib-loop))
     afterfib-n-1
     (restore n)
     (assign n (op -) (reg n) (const 2))
     (assign continue (label afterfib-n-2))
     (save val)
     (goto (label fib-loop))
     afterfib-n-2
     (assign n (reg val))
     (restore val)
     (restore continue)
     (assign val
             (op +) (reg val) (reg n))
     (goto (reg continue))
     immediate-answer
     (assign val (reg n))
     (goto (reg continue))
     fib-done
     (assign n (op print-stack-statistics)))))

gosh> (set-register-contents! fib-machine 'n 3)
done
gosh> (fib-machine 'trace-on)
trace-on
gosh> (start fib-machine)
(start) : (assign continue (label fib-done))
(fib-loop) : (test (op <) (reg n) (const 2))
(fib-loop) : (branch (label immediate-answer))
(fib-loop) : (save continue)
(fib-loop) : (assign continue (label afterfib-n-1))
(fib-loop) : (save n)
(fib-loop) : (assign n (op -) (reg n) (const 1))
(fib-loop) : (goto (label fib-loop))
(fib-loop) : (test (op <) (reg n) (const 2))
(fib-loop) : (branch (label immediate-answer))
(fib-loop) : (save continue)
(fib-loop) : (assign continue (label afterfib-n-1))
(fib-loop) : (save n)
(fib-loop) : (assign n (op -) (reg n) (const 1))
(fib-loop) : (goto (label fib-loop))
(fib-loop) : (test (op <) (reg n) (const 2))
(fib-loop) : (branch (label immediate-answer))
(immediate-answer) : (assign val (reg n))
(immediate-answer) : (goto (reg continue))
(afterfib-n-1) : (restore n)
(afterfib-n-1) : (assign n (op -) (reg n) (const 2))
(afterfib-n-1) : (assign continue (label afterfib-n-2))
(afterfib-n-1) : (save val)
(afterfib-n-1) : (goto (label fib-loop))
(fib-loop) : (test (op <) (reg n) (const 2))
(fib-loop) : (branch (label immediate-answer))
(immediate-answer) : (assign val (reg n))
(immediate-answer) : (goto (reg continue))
(afterfib-n-2) : (assign n (reg val))
(afterfib-n-2) : (restore val)
(afterfib-n-2) : (restore continue)
(afterfib-n-2) : (assign val (op +) (reg val) (reg n))
(afterfib-n-2) : (goto (reg continue))
(afterfib-n-1) : (restore n)
(afterfib-n-1) : (assign n (op -) (reg n) (const 2))
(afterfib-n-1) : (assign continue (label afterfib-n-2))
(afterfib-n-1) : (save val)
(afterfib-n-1) : (goto (label fib-loop))
(fib-loop) : (test (op <) (reg n) (const 2))
(fib-loop) : (branch (label immediate-answer))
(immediate-answer) : (assign val (reg n))
(immediate-answer) : (goto (reg continue))
(afterfib-n-2) : (assign n (reg val))
(afterfib-n-2) : (restore val)
(afterfib-n-2) : (restore continue)
(afterfib-n-2) : (assign val (op +) (reg val) (reg n))
(afterfib-n-2) : (goto (reg continue))

(total-pushes = 6 maximum-depth = 4)(fib-done) : (assign n (op print-stack-statistics))
done

*1:'label label-name