;; eval-cc5.scm ;; registerizing k, val (calling it acc* now), env, exp, and rands ;; registers (define k* 'nobinding) (define acc* 'nobinding) ; was val (define env* 'nobinding) (define exp* 'nobinding) (define rands* 'nobinding) ;; rest (define *k-trace* #f) (define k-trace (lambda () (for-each display '("Kontinuation tracing enabled." #\newline)) (set! *k-trace* #t))) (define stop-k-trace (lambda () (for-each display '("Kontinuation tracing disabled." #\newline)) (set! *k-trace* #f))) (define show-k-trace (lambda (k) (if *k-trace* (begin (display (vector-ref k 0)) ; name (newline))))) ; (run ; '((lambda (n) ; ((lambda (!) ; (! n !)) ; (lambda (n bang) ; (if (zero? n) ; 1 ; (* n (bang (- n 1) bang)))))) ; 5)) ; ; This generates 135 calls to apply-k. (load "record.ss") (define-record lit (datum)) (define-record varref (var)) (define-record lambda (formals body)) (define-record app (rator rands)) (define-record if (test-exp then-exp else-exp)) (define-record letcc (var exp)) (define-record extended-env (formals args env)) (define-record closure (formals body env)) (define-record continuation-closure (kont)) ; NEW (define-record primitive (sym)) ;; This is used to add a single var (and a single arg) to the env. (define make-extended-env/1 (lambda (var arg env) (make-extended-env (list var) (list arg) env))) ;; records for continuations (define-record post-test-k (then-exp else-exp env k)) (define-record post-rator-k (rands env k)) (define-record post-rands-k (proc k)) (define-record post-rest-rands-k (a k)) (define-record post-first-rands-k (rands env k)) (define-record final-k (jumpout)) ; (define apply-k cons) ; the old version (define apply-k (lambda () (cons k* acc*))) (define apply-k* (lambda () (show-k-trace k*) (variant-case k* (final-k (jumpout) (jumpout acc*)) (post-test-k (then-exp else-exp env k) (if (zero? acc*) (begin (set! k* k) (set! env* env) (set! exp* else-exp) (eval-exp)) (begin (set! k* k) (set! env* env) (set! exp* then-exp) (eval-exp)))) (post-rator-k (rands env k) (set! k* (make-post-rands-k acc* k)) (set! env* env) (set! rands* rands) (eval-rands)) (post-rands-k (proc k) (set! k* k) (apply-closure proc acc*)) (post-rest-rands-k (a k) (set! k* k) (set! acc* (cons a acc*)) (apply-k)) (post-first-rands-k (rands env k) (set! k* (make-post-rest-rands-k acc* k)) (set! env* env) (set! rands* (cdr rands)) (eval-rands)) (else (error 'apply-k "Not a valid continuation: ~s" k*))))) ;; This is a major hack! We really shouldn't use scheme's ;; "apply", but instead have a giant case statement which switches on ;; sym and has in it the code for applying all the primitive ;; functions. (define apply-primitive (lambda (sym args) (case sym ((zero?) (let ((x (apply (eval sym) args))) (if x 1 0))) (else (apply (eval sym) args))))) (define find-lexical-address-ONE (lambda (e cenv) (letrec ((find-lexical-address (lambda (cenv) (cond ((eq? (car cenv) e) 0) (else (+ 1 (find-lexical-address (cdr cenv)))))))) (find-lexical-address cenv)))) (define little-lookup (lambda (item item-list match-list) (list-ref match-list (find-lexical-address-ONE item item-list)))) (define apply-env (lambda (sym) (variant-case env* (extended-env (formals args env) (if (memq sym formals) (begin (set! k* k*) (set! acc* (little-lookup sym formals args)) (apply-k)) (begin (set! k* k*) (set! env* env) (apply-env sym)))) (else (set! k* k*) (set! acc* (global-table sym)) (apply-k))))) (define apply-closure (lambda (proc args) (variant-case proc (closure (formals body env) (set! k* k*) (set! env* (make-extended-env formals args env)) (set! exp* body) (eval-exp)) (primitive (sym) (set! k* k*) (set! acc* (apply-primitive sym args)) (apply-k)) (continuation-closure (kont) (set! k* kont) (set! acc* (car args)) (apply-k)) (else (error 'apply-closure "Invalid closure type: ~s" proc))))) (define global-table (let ((apply* (make-primitive '*)) (apply+ (make-primitive '+)) (apply-cons (make-primitive 'cons)) (apply-car (make-primitive 'car)) (apply-cdr (make-primitive 'cdr)) (apply-zero? (make-primitive 'zero?)) (apply- (make-primitive '-))) (lambda (sym) (case sym ((cons) apply-cons) ((car) apply-car) ((cdr) apply-cdr) ((zero?) apply-zero?) ((X) 10) ((V) 5) ((D) 500) ((C) 100) ((I) 1) ((M) 1000) ((*) apply*) ((+) apply+) ((-) apply-) (else (error 'global-table "unbound variable: ~s" sym)))))) (define eval-rands (lambda () (cond ((null? rands*) (set! k* k*) (set! acc* '()) (apply-k)) (else (set! k* (make-post-first-rands-k rands* env* k*)) (set! env* env*) (set! exp* (car rands*)) (eval-exp))))) (define eval-exp (letrec ((eval-exp (lambda () (variant-case exp* (lit (datum) (set! k* k*) (set! acc* datum) (apply-k)) (varref (var) (set! k* k*) (set! env* env*) (apply-env var)) (if (test-exp then-exp else-exp) (set! k* (make-post-test-k then-exp else-exp env* k*)) (set! env* env*) (set! exp* test-exp) (eval-exp)) (app (rator rands) (set! k* (make-post-rator-k rands env* k*)) (set! env* env*) (set! exp* rator) (eval-exp)) (letcc (var exp) (set! k* k*) (set! env* (make-extended-env/1 var (make-continuation-closure k*) env*)) (set! exp* exp) (eval-exp)) (lambda (formals body) (set! k* k*) (set! acc* (make-closure formals body env*)) (apply-k)) )))) (lambda () (set! k* k*) (set! env* env*) (set! exp* exp*) (eval-exp)))) ;; run is for testing ;; (it parses the exp and also supplies the global table as an arg to ;; eval-exp) (define run (letrec ((parse-exp (lambda (e) (cond ((number? e) (make-lit e)) ((atom? e) (make-varref e)) ((and (list? e) ; a cheap hack (eq? (car e) 'lambda)) (make-lambda (cadr e) ; formals (parse-exp (caddr e)))) ; body ((and (list? e) ; a cheap hack (eq? (car e) 'letcc)) (make-letcc (cadr e) ; var (parse-exp (caddr e)))) ; exp ((and (list? e) ; a cheap hack (eq? (car e) 'if)) (make-if (parse-exp (cadr e)) ; test exp (parse-exp (caddr e)) ; then exp (parse-exp (cadddr e)))) ; else exp (else ; else application (make-app (parse-exp (car e)) ; operator (map parse-exp (cdr e)))))))) (lambda (unparsed-expression) (letrec ((loop (lambda (pr) (loop (begin (set! k* (car pr)) (set! acc* (cdr pr)) (apply-k*)))))) (letcc escape-to-scheme (loop (begin (set! k* (make-final-k escape-to-scheme)) (set! env* global-table) (set! exp* (parse-exp unparsed-expression)) (eval-exp))))))))