The assembler transforms the sequence of controller expressions for a machine
into a corresponding list of machine instructions, each with its execution
procedure. Overall, the assembler is much like the evaluators we studied in
Chapter 4—there is an input language (in this case, the
register-machine language) and we must perform an appropriate action for each
type of expression in the language.
汇编器将机器的控制器表达式序列转换为对应的机器指令表,其中每条指令都附有相应的执行过程。总体而言,汇编器与我们在第 4 章研究过的求值器十分相似——都有一种输入语言(这里是寄存器机器语言),并且必须对语言中的每种表达式类型执行恰当的动作。
The technique of producing an execution procedure for each instruction is just
what we used in 4.1.7 to speed up the evaluator by separating
analysis from runtime execution. As we saw in Chapter 4, much useful
analysis of Scheme expressions could be performed without knowing the actual
values of variables. Here, analogously, much useful analysis of
register-machine-language expressions can be performed without knowing the
actual contents of machine registers. For example, we can replace references
to registers by pointers to the register objects, and we can replace references
to labels by pointers to the place in the instruction sequence that the label
designates.
为每条指令生成执行过程的技术,正是我们在 4.1.7 节中为加速求值器而采用的技术——通过将分析与运行时执行分离来实现。如同我们在第 4 章所见,对 Scheme 表达式的许多有用分析都可以在不知道变量实际值的情况下完成。与此类似,对寄存器机器语言表达式的许多有用分析也可以在不知道机器寄存器实际内容的情况下完成。例如,我们可以将对寄存器的引用替换为指向寄存器对象的指针,将对标号 (labels) 的引用替换为指向该标号所指定的指令序列位置的指针。
Before it can generate the instruction execution procedures, the assembler must
know what all the labels refer to, so it begins by scanning the controller text
to separate the labels from the instructions. As it scans the text, it
constructs both a list of instructions and a table that associates each label
with a pointer into that list. Then the assembler augments the instruction
list by inserting the execution procedure for each instruction.
在生成指令执行过程之前,汇编器必须知道所有标号所引用的位置,因此它首先扫描控制器文本,将标号与指令分离。在扫描文本的过程中,它同时构造一个指令表和一个将每个标号与该表中某一指针相关联的表格。之后,汇编器通过为每条指令插入执行过程来扩充这个指令表。
The assemble procedure is the main entry to the assembler. It takes the
controller text and the machine model as arguments and returns the instruction
sequence to be stored in the model. Assemble calls
extract-labels to build the initial instruction list and label table
from the supplied controller text. The second argument to
extract-labels is a procedure to be called to process these results:
This procedure uses update-insts! to generate the instruction execution
procedures and insert them into the instruction list, and returns the modified
list.
过程 `assemble` 是汇编器的主入口。它以控制器文本和机器模型为参数,返回将存入模型的指令序列。`assemble` 调用 `extract-labels`,根据所提供的控制器文本构建初始指令表和标号表。`extract-labels` 的第二个参数是一个用于处理这些结果的过程:该过程调用 `update-insts!` 生成指令执行过程并将其插入指令表,然后返回修改后的指令表。
Extract-labels takes as arguments a list text (the sequence of
controller instruction expressions) and a receive procedure.
Receive will be called with two values: (1) a list insts of
instruction data structures, each containing an instruction from text;
and (2) a table called labels, which associates each label from
text with the position in the list insts that the label
designates.
`extract-labels` 以一个表 `text`(控制器指令表达式的序列)和一个接收过程 `receive` 作为参数。`receive` 将被以两个值调用:(1)由指令数据结构组成的表 `insts`,其中每个元素包含来自 `text` 的一条指令;(2)一个称为 `labels` 的表格,它将 `text` 中的每个标号与其在 `insts` 表中所指定位置相关联。
Extract-labels works by sequentially scanning the elements of the
text and accumulating the insts and the labels. If an
element is a symbol (and thus a label) an appropriate entry is added to the
labels table. Otherwise the element is accumulated onto the
insts list.
`extract-labels` 通过顺序扫描 `text` 的各个元素来工作,逐步积累 `insts` 和 `labels`。若某个元素是符号(因而是标号),则向 `labels` 表中添加一个相应的条目;否则,该元素被积累到 `insts` 表中。
Update-insts! modifies the instruction list, which initially contains
only the text of the instructions, to include the corresponding execution
procedures:
`update-insts!` 修改指令表——该表最初只包含指令文本——以插入对应的执行过程:
The machine instruction data structure simply pairs the instruction text with
the corresponding execution procedure. The execution procedure is not yet
available when extract-labels constructs the instruction, and is
inserted later by update-insts!.
机器指令数据结构将指令文本与相应的执行过程简单地配对在一起。执行过程在 `extract-labels` 构造指令时尚不可用,由 `update-insts!` 在之后插入。
The instruction text is not used by our simulator, but it is handy to keep
around for debugging (see Exercise 5.16).
Elements of the label table are pairs:
指令文本在我们的模拟器中并不使用,但保留它便于调试(见练习 5.16)。标号表的元素是序对:
Entries will be looked up in the table with
表中的条目将通过以下方式查找:
(define (assemble controller-text machine)
(extract-labels controller-text
(lambda (insts labels)
(update-insts! insts labels machine)
insts))) (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)
(receive
insts
(cons
(make-label-entry
next-inst
insts)
labels))
(receive
(cons (make-instruction
next-inst)
insts)
labels))))))) (define (update-insts! insts labels machine)
(let ((pc (get-register machine 'pc))
(flag (get-register machine 'flag))
(stack (machine 'stack))
(ops (machine 'operations)))
(for-each
(lambda (inst)
(set-instruction-execution-proc!
inst
(make-execution-procedure
(instruction-text inst)
labels
machine
pc
flag
stack
ops)))
insts))) (define (make-instruction text)
(cons text '()))
(define (instruction-text inst) (car inst))
(define (instruction-execution-proc inst)
(cdr inst))
(define (set-instruction-execution-proc!
inst
proc)
(set-cdr! inst proc)) (define (make-label-entry label-name insts)
(cons label-name insts)) (define (lookup-label labels label-name)
(let ((val (assoc label-name labels)))
(if val
(cdr val)
(error "Undefined label: ASSEMBLE"
label-name))))