As with the metacircular evaluator, special forms are handled by
selectively evaluating fragments of the expression. For an `if`
expression, we must evaluate the predicate and decide, based on the
value of predicate, whether to evaluate the consequent or the
alternative.

Before evaluating the predicate, we save the `if` expression
itself so that we can later extract the consequent or alternative. We
also save the environment, which we will need later in order to
evaluate the consequent or the alternative, and we save `
continue`, which we will need later in order to return to the
evaluation of the expression that is waiting for the value of the `
if`.

ev-if (save exp); save expression for later(save env) (save continue) (assign continue (label ev-if-decide)) (assign exp (op if-predicate) (reg exp)) (goto (label eval-dispatch)); evaluate the predicate

When we return from evaluating the predicate, we test whether it was
true or false and, depending on the result, place either the
consequent or the alternative in `exp` before going to `
eval-dispatch`. Notice that restoring `env` and `continue`
here sets up `eval-dispatch` to have the correct environment and
to continue at the right place to receive the value of the `if`
expression.

ev-if-decide (restore continue) (restore env) (restore exp) (test (op true?) (reg val)) (branch (label ev-if-consequent))ev-if-alternative (assign exp (op if-alternative) (reg exp)) (goto (label eval-dispatch)) ev-if-consequent (assign exp (op if-consequent) (reg exp)) (goto (label eval-dispatch))

Assignments and definitions

Assignments are handled by `ev-assignment`, which is reached from
`eval-dispatch` with the assignment expression in `exp`. The code at `
ev-assignment` first evaluates the value part of the expression and
then installs the new value in the environment. `
Set-variable-value!` is assumed to be available as a machine
operation.

ev-assignment (assign unev (op assignment-variable) (reg exp)) (save unev); save variable for later(assign exp (op assignment-value) (reg exp)) (save env) (save continue) (assign continue (label ev-assignment-1)) (goto (label eval-dispatch)); evaluate the assignment valueev-assignment-1 (restore continue) (restore env) (restore unev) (perform (op set-variable-value!) (reg unev) (reg val) (reg env)) (assign val (const ok)) (goto (reg continue))

Definitions are handled in a similar way:

ev-definition (assign unev (op definition-variable) (reg exp)) (save unev); save variable for later(assign exp (op definition-value) (reg exp)) (save env) (save continue) (assign continue (label ev-definition-1)) (goto (label eval-dispatch)); evaluate the definition valueev-definition-1 (restore continue) (restore env) (restore unev) (perform (op define-variable!) (reg unev) (reg val) (reg env)) (assign val (const ok)) (goto (reg continue))

**Exercise.**
Extend the evaluator to handle derived expressions such as `cond`,
`let`, and so on (section ).
You may ``cheat'' and assume that the syntax
transformers such as `cond->if` are available as machine
operations.^{}

**Exercise.**
Implement `cond` as a new basic special form without
reducing it to `if`. You will have to construct a loop that tests
the predicates of successive `cond` clauses until you find one
that is true, and then use `ev-sequence` to evaluate the actions
of the clause.

**Exercise.**
Modify the evaluator so that it uses normal-order evaluation,
based on the lazy evaluator of section .