diff --git a/ex-5_31-xx.scm b/ex-5_31-xx.scm index 2a51196..6441cde 100644 --- a/ex-5_31-xx.scm +++ b/ex-5_31-xx.scm @@ -74,7 +74,7 @@ ev-appl-did-operator-no-restore (display (car xs) port) (display "\n" port) (write-list-to-port (cdr xs) port)))) - (if #f ; #t means write to file; #f means don't write to file + (if #t ; #t means write to file; #f means don't write to file (let* ((compile-result (compile code target linkage)) (assembly-insts (statements compile-result)) (port (open-output-file file-name))) @@ -391,13 +391,6 @@ ev-appl-did-operator-no-restore (display "\nex-5.38 - optimize-procedure-application\n") -; a. The open-coded primitives, unlike the special forms, all need their -; operands evaluated. Write a code generator spread-arguments for use by all -; the open-coding code generators. Spread-arguments should take an operand list -; and compile the given operands targeted to successive argument registers. -; Note that an operand may contain a call to an open-coded primitive, so -; argument registers will have to be preserved during operand evaluation. - (define (spread-arguments operand-list) (define (compile-operands operand-list operand-number) (cond @@ -414,33 +407,45 @@ ev-appl-did-operator-no-restore (compile-operands (cdr operand-list) (+ operand-number 1)))) (else (error "Only two arg registers supported -- SPREAD-ARGUMENTS")))) - (let ((operand-codes (compile-operands operand-list 1))) operand-codes)) -(define (display-lines xs) - (define (display-line x) - (display x) (newline)) - (map display-line xs)) +(define (primitive-procedure? exp) + (define primitive-procedures '(= * - +)) + (and (pair? exp) + (= (length exp) 3) ;; only support two args for now + (memq (car exp) primitive-procedures) + )) -(display-lines (third (spread-arguments '(1 1)))) -(newline) +(define (compile-primitive-call op target linkage) + (end-with-linkage linkage + (make-instruction-sequence + '(arg1 arg2) + `(,target) + `((assign ,target (op ,op) (reg arg1) (reg arg2)))))) -(display "b. CONTINUE HERE\n") +(define (compile-primitive exp target linkage) + (let ((proc-code (compile-primitive-call (operator exp) target linkage)) + (operand-codes (spread-arguments (operands exp)))) + (preserving '(env continue) + operand-codes + proc-code))) -; b. For each of the primitive procedures =, *, -, and +, write a code -; generator that takes a combination with that operator, together with a target -; and a linkage descriptor, and produces code to spread the arguments into the -; registers and then perform the operation targeted to the given target with -; the given linkage. You need only handle expressions with two operands. Make -; compile dispatch to these code generators. +(compile-to-file + '(define (factorial n) + (if (= n 1) + 1 + (* (factorial (- n 1)) n))) + 'val 'next "factorial-opt.sicp-asm") -; c. Try your new compiler on the factorial example. Compare the resulting -; code with the result produced without open coding. +; c. The optimization saves 39 instructions +; λ symposium sicp → λ git master* → wc -l factorial.sicp-asm factorial-opt.sicp-asm +; 79 factorial.sicp-asm +; 40 factorial-opt.sicp-asm +; 119 total -; d. Extend your code generators for + and * so that they can handle -; expressions with arbitrary numbers of operands. An expression with more than -; two operands will have to be compiled into a sequence of operations, each -; with only two inputs. +(display "[answered]\n") (display "\nex-5.39\n") + +(display "\nex-5.40\n") diff --git a/misc/ch5-compiler.scm b/misc/ch5-compiler.scm index c27c010..d2dd2c7 100644 --- a/misc/ch5-compiler.scm +++ b/misc/ch5-compiler.scm @@ -34,6 +34,8 @@ target linkage)) ((cond? exp) (compile (cond->if exp) target linkage)) + ((primitive-procedure? exp) + (compile-primitive exp target linkage)) ((application? exp) (compile-application exp target linkage)) (else @@ -46,6 +48,8 @@ (define (empty-instruction-sequence) (make-instruction-sequence '() '() '())) +;; Implemented in 5.38. +(define (primitive-procedure? exp) #f) ;;;SECTION 5.5.2