← back to programming

Explicit-Control Evaluator

Abelson & Sussman · 1996 · SICP §5.4

The metacircular evaluator from Ch.14, compiled down to register machine instructions. Makes explicit what the high-level interpreter hides: stack saves, register assignments, goto dispatch.

eval-dispatch (expression type?) self-eval number? variable symbol? application pair? return val lookup env apply proc the evaluator from Ch.14, compiled to register machine dispatch

The dispatcher: eval-dispatch

The evaluator’s core is a dispatch loop. It reads the expression type and jumps to the matching handler. In the metacircular evaluator this was a cond inside eval. Here it’s explicit: test the tag, branch to a label.

Scheme

Evaluating simple expressions

Self-evaluating expressions (numbers, strings) go straight to the val register. Variables require an environment lookup. Quoted expressions strip the quote tag and return the datum. No stack needed. These are leaves of the expression tree.

Scheme

Evaluating combinations: the operand loop

Combinations require evaluating the operator and each operand, then applying. The explicit-control evaluator must save registers before recursing into subexpressions. The operand loop pushes each evaluated argument onto a list (argl), building the argument list one element at a time.

Scheme

Sequence evaluation and tail recursion

A tail call is a call in return position: nothing left to do after it returns. The explicit-control evaluator recognizes this and skips the save of the continuation register. No save means the stack doesn’t grow. Scheme guarantees tail-call optimization because the evaluator’s structure makes it free.

Scheme

Conditionals and assignments

Conditionals evaluate the predicate, then branch to the consequent or alternative. The explicit-control evaluator saves the environment and unevaluated branches on the stack before evaluating the predicate. Assignments use set-variable-value! to mutate the environment. This is the only place the evaluator writes to the environment frame.

Scheme

Notation reference

Register Machine / SICP Python Meaning
eval-dispatcheval()Main dispatch loop
(save continue)stack.append(return_addr)Save return address
(restore continue)return_addr = stack.pop()Restore return address
ev-if / ev-assignmentvisit_If / visit_AssignHandler labels (like AST visitor methods)
arglargs = []Accumulator for evaluated operands
tail position → no save(not optimized in CPython)Tail-call optimization

Translation notes

The explicit-control evaluator bridges the high-level metacircular evaluator (Ch.14) and real machine code. Every implicit operation — function calls, argument evaluation order, stack management — becomes a visible instruction. CPython’s ceval.c works the same way: a giant switch statement dispatching on bytecode opcode, with an explicit value stack. Tail-call optimization falls out of the evaluator’s structure, not a compiler trick: if the evaluator doesn’t push a frame, the stack doesn’t grow.

Neighbors

Other reading pages

  • SICP Ch.14 — the metacircular evaluator this chapter compiles down

Foundations (Wikipedia)

Ready for the real thing? Read SICP §5.4.