The assembler calls make-execution-procedure to generate the execution
procedure for an instruction. Like the analyze procedure in the
evaluator of 4.1.7, this dispatches on the type of instruction to
generate the appropriate execution procedure.
汇编器调用 `make-execution-procedure` 为每条指令生成执行过程。与 4.1.7 节求值器中的 `analyze` 过程类似,它按指令类型进行分派,生成相应的执行过程。
For each type of instruction in the register-machine language, there is a
generator that builds an appropriate execution procedure. The details of these
procedures determine both the syntax and meaning of the individual instructions
in the register-machine language. We use data abstraction to isolate the
detailed syntax of register-machine expressions from the general execution
mechanism, as we did for evaluators in 4.1.2, by using syntax
procedures to extract and classify the parts of an instruction.
Subheading: Assign instructions
The make-assign procedure handles assign instructions:
对于寄存器机器语言中的每种指令类型,都有一个生成器负责构建适当的执行过程。这些过程的细节同时决定了寄存器机器语言中各条指令的语法与语义。我们采用数据抽象将寄存器机器表达式的具体语法与通用执行机制相隔离,正如在 4.1.2 节中对求值器所做的那样——通过语法过程来提取并归类指令的各个部分。
子标题:`assign` 指令
过程 `make-assign` 处理 `assign` 指令:
Make-assign extracts the target register name (the second element of the
instruction) and the value expression (the rest of the list that forms the
instruction) from the assign instruction using the selectors
`make-assign` 使用选择函数从 `assign` 指令中提取目标寄存器名(指令的第二个元素)和值表达式(构成指令的表中的其余部分):
The register name is looked up with get-register to produce the target
register object. The value expression is passed to make-operation-exp
if the value is the result of an operation, and to make-primitive-exp
otherwise. These procedures (shown below) parse the value expression and
produce an execution procedure for the value. This is a procedure of no
arguments, called value-proc, which will be evaluated during the
simulation to produce the actual value to be assigned to the register. Notice
that the work of looking up the register name and parsing the value expression
is performed just once, at assembly time, not every time the instruction is
simulated. This saving of work is the reason we use execution procedures, and
corresponds directly to the saving in work we obtained by separating program
analysis from execution in the evaluator of 4.1.7.
寄存器名通过 `get-register` 查找,得到目标寄存器对象。若值是某个操作的结果,值表达式被传给 `make-operation-exp`;否则传给 `make-primitive-exp`。这两个过程(如下所示)解析值表达式并产生相应的值执行过程。该执行过程是一个无参过程,称为 `value-proc`,在模拟期间被求值以产生实际的赋值。注意,查找寄存器名和解析值表达式的工作仅在汇编时执行一次,而不是每次模拟指令时都执行。节省这部分工作正是我们使用执行过程的原因,这与 4.1.7 节中通过将程序分析与执行分离所获得的节省直接对应。
The result returned by make-assign is the execution procedure for the
assign instruction. When this procedure is called (by the machine
model’s execute procedure), it sets the contents of the target register
to the result obtained by executing value-proc. Then it advances the
pc to the next instruction by running the procedure
`make-assign` 返回的结果是 `assign` 指令的执行过程。当该过程被调用时(由机器模型的 `execute` 过程调用),它将目标寄存器的内容设置为执行 `value-proc` 所得的结果,然后通过运行以下过程将 `pc` 推进到下一条指令:
Advance-pc is the normal termination for all instructions except
branch and goto.
Subheading: Test, branch, and goto instructions
`advance-pc` 是除 `branch` 和 `goto` 以外所有指令的正常终止方式。
子标题:`test`、`branch` 与 `goto` 指令
Make-test handles test instructions in a similar way. It
extracts the expression that specifies the condition to be tested and generates
an execution procedure for it. At simulation time, the procedure for the
condition is called, the result is assigned to the flag register, and
the pc is advanced:
`make-test` 以类似方式处理 `test` 指令。它提取指定被测条件的表达式,并为其生成执行过程。在模拟时,条件过程被调用,结果赋给 `flag` 寄存器,然后推进 `pc`:
The execution procedure for a branch instruction checks the contents of
the flag register and either sets the contents of the pc to the
branch destination (if the branch is taken) or else just advances the pc
(if the branch is not taken). Notice that the indicated destination in a
branch instruction must be a label, and the make-branch procedure
enforces this. Notice also that the label is looked up at assembly time, not
each time the branch instruction is simulated.
`branch` 指令的执行过程检查 `flag` 寄存器的内容,若分支成立则将 `pc` 的内容设为分支目标,否则只是推进 `pc`。注意,`branch` 指令中指定的目标必须是一个标号,`make-branch` 过程强制执行这一约束。还应注意,标号的查找在汇编时完成,而不是每次模拟 `branch` 指令时才查找。
A goto instruction is similar to a branch, except that the destination
may be specified either as a label or as a register, and there is no condition
to check—the pc is always set to the new destination.
`goto` 指令与 `branch` 类似,不同之处在于目标既可以是标号也可以是寄存器,且无需检查任何条件——`pc` 总是被设置为新的目标。
Subheading: Other instructions
子标题:其他指令
The stack instructions save and restore simply use the stack with
the designated register and advance the pc:
栈指令 `save` 和 `restore` 只是对指定寄存器使用栈,并推进 `pc`:
The final instruction type, handled by make-perform, generates an
execution procedure for the action to be performed. At simulation time, the
action procedure is executed and the pc advanced.
最后一种指令类型由 `make-perform` 处理,它为待执行的动作生成执行过程。在模拟时,动作过程被执行,然后推进 `pc`。
Subheading: Execution procedures for subexpressions
子标题:子表达式的执行过程
The value of a reg, label, or const expression may be
needed for assignment to a register (make-assign) or for input to an
operation (make-operation-exp, below). The following procedure
generates execution procedures to produce values for these expressions during
the simulation:
`reg`、`label` 或 `const` 表达式的值可能用于赋值给寄存器(`make-assign`)或作为操作的输入(`make-operation-exp`,见下文)。以下过程生成执行过程,在模拟期间产生这些表达式的值:
The syntax of reg, label, and const expressions is
determined by
`reg`、`label` 和 `const` 表达式的语法由以下过程确定:
Assign, perform, and test instructions may include the
application of a machine operation (specified by an op expression) to
some operands (specified by reg and const expressions). The
following procedure produces an execution procedure for an “operation
expression”—a list containing the operation and operand expressions from the
instruction:
`assign`、`perform` 和 `test` 指令中可以包含将某个机器操作(由 `op` 表达式指定)应用于若干运算对象(由 `reg` 和 `const` 表达式指定)的调用。以下过程为"操作表达式 (operation expression)"——一个包含操作及指令中运算对象表达式的表——产生执行过程:
The syntax of operation expressions is determined by
操作表达式的语法由以下过程确定:
Observe that the treatment of operation expressions is very much like the
treatment of procedure applications by the analyze-application procedure
in the evaluator of 4.1.7 in that we generate an execution
procedure for each operand. At simulation time, we call the operand procedures
and apply the Scheme procedure that simulates the operation to the resulting
values. The simulation procedure is found by looking up the operation name in
the operation table for the machine:
请注意,对操作表达式的处理与 4.1.7 节求值器中 `analyze-application` 过程处理过程应用的方式非常相似——我们同样为每个运算对象生成执行过程。在模拟时,我们调用各运算对象过程,并将模拟该操作的 Scheme 过程应用于所得的各个值。模拟过程通过在机器的操作表中查找操作名称来找到:
(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))
(else (error "Unknown instruction
type: ASSEMBLE"
inst)))) (define (make-assign
inst machine labels operations pc)
(let ((target
(get-register
machine
(assign-reg-name inst)))
(value-exp (assign-value-exp inst)))
(let ((value-proc
(if (operation-exp? value-exp)
(make-operation-exp
value-exp
machine
labels
operations)
(make-primitive-exp
(car value-exp)
machine
labels))))
(lambda () ; execution procedure
; for assign
(set-contents! target (value-proc))
(advance-pc pc))))) (define (assign-reg-name assign-instruction)
(cadr assign-instruction))
(define (assign-value-exp assign-instruction)
(cddr assign-instruction)) (define (advance-pc pc)
(set-contents! pc (cdr (get-contents pc)))) (define
(make-test
inst machine labels operations flag pc)
(let ((condition (test-condition inst)))
(if (operation-exp? condition)
(let ((condition-proc
(make-operation-exp
condition
machine
labels
operations)))
(lambda ()
(set-contents!
flag (condition-proc))
(advance-pc pc)))
(error "Bad TEST instruction:
ASSEMBLE" inst))))
(define (test-condition test-instruction)
(cdr test-instruction)) (define
(make-branch
inst machine labels flag pc)
(let ((dest (branch-dest inst)))
(if (label-exp? dest)
(let ((insts
(lookup-label
labels
(label-exp-label dest))))
(lambda ()
(if (get-contents flag)
(set-contents! pc insts)
(advance-pc pc))))
(error "Bad BRANCH instruction:
ASSEMBLE"
inst))))
(define (branch-dest branch-instruction)
(cadr branch-instruction)) (define (make-goto inst machine labels pc)
(let ((dest (goto-dest inst)))
(cond ((label-exp? dest)
(let ((insts
(lookup-label
labels
(label-exp-label dest))))
(lambda ()
(set-contents! pc insts))))
((register-exp? dest)
(let ((reg
(get-register
machine
(register-exp-reg dest))))
(lambda ()
(set-contents!
pc
(get-contents reg)))))
(else (error "Bad GOTO instruction:
ASSEMBLE"
inst)))))
(define (goto-dest goto-instruction)
(cadr goto-instruction)) (define (make-save inst machine stack pc)
(let ((reg (get-register
machine
(stack-inst-reg-name inst))))
(lambda ()
(push stack (get-contents reg))
(advance-pc pc))))
(define (make-restore inst machine stack pc)
(let ((reg (get-register
machine
(stack-inst-reg-name inst))))
(lambda ()
(set-contents! reg (pop stack))
(advance-pc pc))))
(define (stack-inst-reg-name
stack-instruction)
(cadr stack-instruction)) (define (make-perform
inst machine labels operations pc)
(let ((action (perform-action inst)))
(if (operation-exp? action)
(let ((action-proc
(make-operation-exp
action
machine
labels
operations)))
(lambda ()
(action-proc)
(advance-pc pc)))
(error "Bad PERFORM instruction:
ASSEMBLE"
inst))))
(define (perform-action inst) (cdr inst)) (define (make-primitive-exp exp machine labels)
(cond ((constant-exp? exp)
(let ((c (constant-exp-value exp)))
(lambda () c)))
((label-exp? exp)
(let ((insts
(lookup-label
labels
(label-exp-label exp))))
(lambda () insts)))
((register-exp? exp)
(let ((r (get-register
machine
(register-exp-reg exp))))
(lambda () (get-contents r))))
(else (error "Unknown expression type:
ASSEMBLE"
exp)))) (define (register-exp? exp)
(tagged-list? exp 'reg))
(define (register-exp-reg exp)
(cadr exp))
(define (constant-exp? exp)
(tagged-list? exp 'const))
(define (constant-exp-value exp)
(cadr exp))
(define (label-exp? exp)
(tagged-list? exp 'label))
(define (label-exp-label exp)
(cadr exp)) (define (make-operation-exp
exp machine labels operations)
(let ((op (lookup-prim
(operation-exp-op exp)
operations))
(aprocs
(map (lambda (e)
(make-primitive-exp
e machine labels))
(operation-exp-operands exp))))
(lambda () (apply op (map (lambda (p) (p))
aprocs))))) (define (operation-exp? exp)
(and (pair? exp)
(tagged-list? (car exp) 'op)))
(define (operation-exp-op operation-exp)
(cadr (car operation-exp)))
(define (operation-exp-operands operation-exp)
(cdr operation-exp)) (define (lookup-prim symbol operations)
(let ((val (assoc symbol operations)))
(if val
(cadr val)
(error "Unknown operation: ASSEMBLE"
symbol))))