5.16 Exercise 5.16

To add instruction tracing, we can instrument the internal execute procedure in the machine to output instructions before executing them. I think this is better than instrumenting the instruction procedures themselves because the changes to allow instruction tracing are guaranteed to stay isolated here. It also seems right to me to separate the actual operations that each instruction performs from a machine-level concern like instruction tracing.

The exercise doesn’t specify how the instructions ought to be displayed, so we’re going to do the simple thing and print the forms literally with no extra formatting applied. The displayln helper function I wrote awhile ago will make this almost completely trivial. It’s also trivial to add commands to turn instruction tracing on and off.

In make-new-machine, we modify the following segments. The rest has been omitted for clarity.

(let ((pc (make-register 'pc))
      (flag (make-register 'flag))
      (stack (make-stack))
      (the-instruction-sequence '())
      (instruction-set '())
      (entry-points '())
      (stack-registers '())
      (assign-sources '())
      (instruction-count 0)
      (tracing-instructions #f))
  ...
 
  (define (execute)
    (let ((insts (get-contents pc)))
      (if (null? insts)
          'done
          (begin
            (set! instruction-count (+ instruction-count 1))
            (if tracing-instructions
              (display-instruction (car insts)))
            ((instruction-execution-proc (car insts)))
            (execute)))))
  ...
 
  (define (dispatch message)
    (cond ...
      ((eq? message 'trace-on)
       (lambda () (set! tracing-instructions #t)))
      ((eq? message 'trace-off)
       (lambda () (set! tracing-instructions #f))))))

To support this, we use a few helper functions:

(define (trace-on machine)
  ((machine 'trace-on)))
(define (trace-off machine)
  ((machine 'trace-off)))
 
(define (display-instruction inst)
  (displayln (car inst)))

And with that, we’re all done:

> (set-register-contents! recursive-exponentiation-machine 'b 2)

'done

 

> (set-register-contents! recursive-exponentiation-machine 'n 2)

'done

 

> (trace-on recursive-exponentiation-machine)

 

> (start recursive-exponentiation-machine)

(perform (op initialize-instruction-count))

(assign continue (label expt-done))

(test (op =) (reg n) (const 0))

(branch (label base-case))

(save continue)

(assign n (op -) (reg n) (const 1))

(save n)

(assign continue (label after-expt))

(goto (label expt-loop))

(test (op =) (reg n) (const 0))

(branch (label base-case))

(save continue)

(assign n (op -) (reg n) (const 1))

(save n)

(assign continue (label after-expt))

(goto (label expt-loop))

(test (op =) (reg n) (const 0))

(branch (label base-case))

(assign val (const 1))

(goto (reg continue))

(restore n)

(restore continue)

(assign val (op *) (reg b) (reg val))

(goto (reg continue))

(restore n)

(restore continue)

(assign val (op *) (reg b) (reg val))

(goto (reg continue))

(perform (op print-instruction-count))

instruction-count = 28

'done

 

> (get-register-contents recursive-exponentiation-machine 'val)

4

 

> (set-register-contents! recursive-exponentiation-machine 'b 2)

'done

 

> (set-register-contents! recursive-exponentiation-machine 'n 2)

'done

 

> (trace-off recursive-exponentiation-machine)

 

> (start recursive-exponentiation-machine)

instruction-count = 28

'done

 

> (get-register-contents recursive-exponentiation-machine 'val)

4