Chapter 5: Problem 38
Our compiler is clever about avoiding unnecessary stack operations, but it is not clever at all when it comes to compiling calls to the primitive procedures of the language in terms of the primitive operations supplied by the machine. For example, consider how much code is compiled to compute \((+a 1):\) The code sets up an argument list in argl, puts the primitive addition procedure (which it finds by looking up the symbol + in the environment) into proc, and tests whether the procedure is primitive or compound. The compiler always generates code to perform the test, as well as code for primitive and compound branches (only one of which will be executed). We have not shown the part of the controller that implements primitives, but we presume that these instructions make use of primitive arithmetic operations in the machine's data paths. Consider how much less code would be generated if the compiler could open-code primitives-that is, if it could generate code to directly use these primitive machine operations. The expression (+ a 1) might be compiled into something as simple as \({ }^{43}\) (assign val (op lookup-variable-value) (const a) (reg env)) (assign val (op +) (reg val) (const 1)) In this exercise we will extend our compiler to support open coding of selected primitives. Special-purpose code will be generated for calls to these primitive ;; construct the procedure and skip over code for the procedure body (assign val (op make-compiled-procedure) (label entry2) (reg env)) (goto (label after-lambda1)) entry2 ;calls to factorial will enter here (assign env (op compiled-procedure-env) (reg proc)) (assign env (op extend-environment) (const (n)) (reg argl) (reg env)) begin actual procedure body (save continue) (save env) ;; compute (=n 1) (assign proc (op lookup-variable-value) (const =) (reg env)) (assign val (const 1)) (assign argl (op list) (reg val)) (assign val (op lookup-variable-value) (const n) (reg env)) (assign argl (op cons) (reg val) (reg argl)) (test (op primitive-procedure?) (reg proc)) (branch (label primitive-branch17)) compiled-branch16 (assign continue (label after-calli5)) (assign val (op compiled-procedure-entry) (reg proc)) (goto (reg val)) primitive-branch17 (assign val (op apply-primitive-procedure) (reg proc) (reg argl)) after-callis ; val now contains result of \((=\mathrm{n} 1)\) (restore env) (restore continue) (test (op false?) (reg val)) (branch (label false-branch4)) true-branch5 ; return 1 (assign val (const 1)) (goto (reg continue)) false-branch4 ;; compute and return (* (factorial (- n 1)) n) (assign proc (op lookup-variable-value) (const *) (reg env)) (save continue) (save proc) ; save* procedure (assign val (op lookup-variable-value) (const n) (reg env)) (assign argl (op list) (reg val)) (save argl) ; save partial argument list for * ;; compute (factorial (- n 1)), which is the other argument for* (assign proc (op lookup-variable-value) (const factorial) (reg env)) (save proc) ; save factorial procedure
Short Answer
Step by step solution
Key Concepts
These are the key concepts you need to understand to accurately answer the question.