In section 5.1 we saw how to transform simple Scheme JavaScript programs into descriptions of register machines. We will now perform this transformation on a more complex program, the metacircular evaluator of sections 4.1.1–4.1.4, which shows how the behavior of a Scheme JavaScript interpreter can be described in terms of the procedures eval functions evaluate and apply. The explicit-control evaluator that we develop in this section shows how the underlying procedure-calling function-calling and argument-passing mechanisms used in the evaluation process can be described in terms of operations on registers and stacks. In addition, the explicit-control evaluator can serve as an implementation of a Scheme JavaScript interpreter, written in a language that is very similar to the native machine language of conventional computers. The evaluator can be executed by the register-machine simulator of section 5.2. Alternatively, it can be used as a starting point for building a machine-language implementation of a Scheme JavaScript evaluator, or even a special-purpose machine for evaluating Scheme expressions. JavaScript programs. Figure 5.21 shows such a hardware implementation: a silicon chip that acts as an evaluator for Scheme. Scheme, the language used in place of JavaScript in the original edition of this book. The chip designers started with the data-path and controller specifications for a register machine similar to the evaluator described in this section and used design automation programs to construct the integrated-circuit layout.[1]
In designing the explicit-control evaluator, we must specify the operations to be used in our register machine. We described the metacircular evaluator in terms of abstract syntax, using procedures functions such as quoted? is_literal and make-procedure. make_function. In implementing the register machine, we could expand these procedures functions into sequences of elementary list-structure memory operations, and implement these operations on our register machine. However, this would make our evaluator very long, obscuring the basic structure with details. To clarify the presentation, we will include as primitive operations of the register machine the syntax procedures functions given in section 4.1.2 and the procedures functions for representing environments and other runtime data given in sections 4.1.3 and 4.1.4. In order to completely specify an evaluator that could be programmed in a low-level machine language or implemented in hardware, we would replace these operations by more elementary operations, using the list-structure implementation we described in section 5.3.
Our Scheme JavaScript evaluator register machine includes a stack and seven registers: exp, comp, env, val, continue, proc, fun, argl, and unev. Exp The comp register is used to hold the expression component to be evaluated, and env contains the environment in which the evaluation is to be performed. At the end of an evaluation, val contains the value obtained by evaluating the expressioncomponent in the designated environment. The continue register is used to implement recursion, as explained in section 5.1.4. (The evaluator needs to call itself recursively, since evaluating an expressiona component requires evaluating its subexpressions.subcomponents.) The registers proc, fun, argl, and unev are used in evaluating function applications.
We will not provide a data-path diagram to show how the registers and operations of the evaluator are connected, nor will we give the complete list of machine operations. These are implicit in the evaluator's controller, which will be presented in detail.