Exercise 5.23. Extend the evaluator to handle derived expressions such as cond, let, and so on (section 4.1.2). You may ``cheat'' and assume that the syntax transformers such as cond->if are available as machine operations. ———————————————————————————————————————————————————————————————————————— eval-dispatch will need to be extended for each new derived expression: eval-dispatch (test (op self-evaluating?) (reg exp)) (branch (label ev-self-eval)) (test (op variable?) (reg exp)) (branch (label ev-variable)) (test (op quoted?) (reg exp)) (branch (label ev-quoted)) (test (op assignment?) (reg exp)) (branch (label ev-assignment)) (test (op definition?) (reg exp)) (branch (label ev-definition)) (test (op if?) (reg exp)) (branch (label ev-if)) (test (op lambda?) (reg exp)) (branch (label ev-lambda)) (test (op begin?) (reg exp)) (branch (label ev-begin)) (test (op application?) (reg exp)) (branch (label ev-application)) + (test (op cond?) (reg exp)) + (branch (label ev-cond)) + (test (op let?) (reg exp)) + (branch (label ev-let)) (goto (label unknown-expression-type)) Given that the syntax transformations are available, the implementations are straightforward: eval-cond (assign exp (op cond->if) (reg exp)) (goto (label ev-if)) eval-let (assign exp (op let->lambda-application) (reg exp)) (goto (label ev-application)) We simply replace the expression with one that the interpreter can handle natively, and then continue as if the program had contained that expression instead. As mentioned in the footnote, a source-to-source transformer written in Scheme could perform this operation before evaluating programs, in which case the interpreter would never see derived forms.