← 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 right 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: it skips the save of the continuation register. No save means the stack doesn’t grow. This is why Scheme guarantees tail-call optimization — 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 — 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 is the bridge between 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 is structurally the same: a giant switch statement dispatching on bytecode opcode, with an explicit value stack. Tail-call optimization is a property 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.