Exercise 5.47. This section described how to modify the explicit-control evaluator so that interpreted code can call compiled procedures. Show how to modify the compiler so that compiled procedures can call not only primitive procedures and compiled procedures, but interpreted procedures as well. This requires modifying compile-procedure-call to handle the case of compound (interpreted) procedures. Be sure to handle all the same target and linkage combinations as in compile-proc-appl. To do the actual procedure application, the code needs to jump to the evaluator's compound-apply entry point. This label cannot be directly referenced in object code (since the assembler requires that all labels referenced by the code it is assembling be defined there), so we will add a register called compapp to the evaluator machine to hold this entry point, and add an instruction to initialize it: (assign compapp (label compound-apply)) (branch (label external-entry)) ; branches if flag is set read-eval-print-loop ... To test your code, start by defining a procedure f that calls a procedure g. Use compile-and-go to compile the definition of f and start the evaluator. Now, typing at the evaluator, define g and try to call f. ———————————————————————————————————————————————————————————————————————— Code is in 5.47-compiler.scm. $ scheme --load load-eceval-compiler.scm 1 ]=> (load "5.47-compiler.scm") 1 ]=> (compile-and-go '(define (f x) (g (g x)))) ;;; EC-Eval input: (define (g x) (* x x)) ;;; EC-Eval input: (f 3) ;;; EC-Eval value: 81 The changes made to the compiler involved splitting compile-proc-appl into two procedures compile-proc-appl-comp and compile-proc-appl-interp for compiled and interpreted procedures. The existing compile-proc-appl was modified to take the chunk of code that differs between the two cases as an argument. --- ch5-compiler.scm 2001-06-21 12:54:32.000000000 -0600 +++ 5.47-compiler.scm 2010-06-27 15:57:43.000000000 -0600 @@ -245,17 +245,24 @@ (define (compile-procedure-call target linkage) (let ((primitive-branch (make-label 'primitive-branch)) (compiled-branch (make-label 'compiled-branch)) + (interpreted-branch (make-label 'interpreted-branch)) (after-call (make-label 'after-call))) (let ((compiled-linkage (if (eq? linkage 'next) after-call linkage))) (append-instruction-sequences (make-instruction-sequence '(proc) '() `((test (op primitive-procedure?) (reg proc)) - (branch (label ,primitive-branch)))) + (branch (label ,primitive-branch)) + (test (op compound-procedure?) (reg proc)) + (branch (label ,interpreted-branch)))) (parallel-instruction-sequences - (append-instruction-sequences - compiled-branch - (compile-proc-appl target compiled-linkage)) + (parallel-instruction-sequences + (append-instruction-sequences + compiled-branch + (compile-proc-appl-comp target compiled-linkage)) + (append-instruction-sequences + interpreted-branch + (compile-proc-appl-interp target compiled-linkage))) (append-instruction-sequences primitive-branch (end-with-linkage linkage @@ -268,30 +275,35 @@ after-call)))) ;;;applying compiled procedures +(define (compile-proc-appl-comp target linkage) + (compile-proc-appl target linkage + '((assign val (op compiled-procedure-entry) + (reg proc)) + (goto (reg val))))) + +;;;applying interpreted procedures +(define (compile-proc-appl-interp target linkage) + (compile-proc-appl target linkage + '((save continue) ;; necessary because of how the ec-eval handles procedure application + (goto (reg compapp))))) -(define (compile-proc-appl target linkage) +(define (compile-proc-appl target linkage entry-jump) (cond ((and (eq? target 'val) (not (eq? linkage 'return))) (make-instruction-sequence '(proc) all-regs `((assign continue (label ,linkage)) - (assign val (op compiled-procedure-entry) - (reg proc)) - (goto (reg val))))) + ,@entry-jump))) ((and (not (eq? target 'val)) (not (eq? linkage 'return))) (let ((proc-return (make-label 'proc-return))) (make-instruction-sequence '(proc) all-regs `((assign continue (label ,proc-return)) - (assign val (op compiled-procedure-entry) - (reg proc)) - (goto (reg val)) + ,@entry-jump ,proc-return (assign ,target (reg val)) (goto (label ,linkage)))))) ((and (eq? target 'val) (eq? linkage 'return)) (make-instruction-sequence '(proc continue) all-regs - '((assign val (op compiled-procedure-entry) - (reg proc)) - (goto (reg val))))) + entry-jump)) ((and (not (eq? target 'val)) (eq? linkage 'return)) (error "return linkage, target not val -- COMPILE" target))))