5.8 Exercise 5.8
Consider the following program with an ambiguous label:
start (goto (label here)) here (assign a (const 3)) (goto (label there)) here (assign a (const 4)) (goto (label there)) there
We can see in extract-labels that new labels are prepended to the list of existing labels. However, the instructions are iterated through in reverse order – the fact that extract-labels calls (extract-labels (cdr text) ...) is a tell-tale clue of this. This means that the first declaration of the here label will be first in the list. Since lookup-label uses assoc, it will therefore return the first instance of the here label in code.
We can verify this by simulation:
(define broken-machine (make-machine '(a) '() '(start (goto (label here)) here (assign a (const 3)) (goto (label there)) here (assign a (const 4)) (goto (label there)) there)))
> (start broken-machine ) |
'done |
> (get-register-contents broken-machine 'a) |
3 |
We can fix this by forcing extract-labels to verify that a label with a given name doesn’t already exist in the list of labels. It’s not very efficient, but assoc will do the job here with minimal changes:
(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 "Duplicate label -- ASSEMBLE" next-inst) (receive insts (cons (make-label-entry next-inst insts) labels))) (receive (cons (make-instruction next-inst) insts) labels)))))))