(module interp (lib "eopl.ss" "eopl") (require "drscheme-init.scm") (require "lang.scm") (require "data-structures.scm") (require "environments.scm") (require "store.scm") (provide value-of-program value-of instrument-let instrument-newref) ;;;;;;;;;;;;;;;; switches for instrument-let ;;;;;;;;;;;;;;;; (define instrument-let (make-parameter #f)) ;; say (instrument-let #t) to turn instrumentation on. ;; (instrument-let #f) to turn it off again. ;;;;;;;;;;;;;;;; the interpreter ;;;;;;;;;;;;;;;; ;; value-of-program : program -> expval (define value-of-program (lambda (pgm) (initialize-store!) ; new for explicit refs. (cases program pgm (a-program (exp1) (value-of exp1 (init-env)))))) ;; value-of : expression * environment -> expval (define value-of (lambda (exp env) (cases expression exp (const-exp (num) (num-val num)) (var-exp (var) (apply-env env var)) ; Order of evaluation matters here, hence the let*. (diff-exp (exp1 exp2) (let* ((val1 (value-of exp1 env)) (val2 (value-of exp2 env))) (let ((num1 (expval->num val1)) (num2 (expval->num val2))) (num-val (- num1 num2))))) (zero?-exp (exp1) (let ((val1 (value-of exp1 env))) (let ((num1 (expval->num val1))) (if (zero? num1) (bool-val #t) (bool-val #f))))) (if-exp (exp1 exp2 exp3) (let ((val1 (value-of exp1 env))) (if (expval->bool val1) (value-of exp2 env) (value-of exp3 env)))) (let-exp (var exp1 body) (let ((val1 (value-of exp1 env))) (value-of body (extend-env var val1 env)))) (proc-exp (var body) (proc-val (procedure var body env))) ; Order of evaluation matters here, hence the let*. (call-exp (rator rand) (let* ((proc (expval->proc (value-of rator env))) (arg (value-of rand env))) (apply-procedure proc arg))) (letrec-exp (p-names b-vars p-bodies letrec-body) (value-of letrec-body (extend-env-rec* p-names b-vars p-bodies env))) ; Order of evaluation matters here. (begin-exp (exp1 exps) (letrec ((value-of-begins (lambda (e1 es) (let ((v1 (value-of e1 env))) (if (null? es) v1 (value-of-begins (car es) (cdr es))))))) (value-of-begins exp1 exps))) (newref-exp (exp1) (let ((v1 (value-of exp1 env))) (ref-val (newref v1)))) (deref-exp (exp1) (let ((v1 (value-of exp1 env))) (let ((ref1 (expval->ref v1))) (deref ref1)))) ; Order of evaluation matters here, hence the nested let. (setref-exp (exp1 exp2) (let ((ref (expval->ref (value-of exp1 env)))) (let ((v2 (value-of exp2 env))) (begin (setref! ref v2) (num-val 23))))) ))) ;; apply-procedure : procedure * expval -> expval ;; apply-procedure : procedure * expval -> expval ;; (define apply-procedure ;; (lambda (proc1 arg) ;; (cases proc proc1 ;; (procedure (bvar body saved-env) ;; (value-of body (extend-env bvar arg saved-env)))))) (define apply-procedure (lambda (proc1 arg) (cases proc proc1 (procedure (var body saved-env) (let ((r arg)) (let ((new-env (extend-env var r saved-env))) (if (instrument-let) (begin (eopl:printf "entering body of proc ~s with env =~%" var) (pretty-print (env->list new-env)) (eopl:printf "store =~%") (pretty-print (store->list (get-store-as-list))) (eopl:printf "~%"))) (value-of body new-env))))))) ;; store->list : (list expval) -> (list num displayable-expvals) (define store->list (lambda (sto) (letrec ((store->list-inner ;; convert sto to list as if its car was location n (lambda (sto n) (if (null? sto) '() (cons (list n (expval->printable (car sto))) (store->list-inner (cdr sto) (+ n 1))))))) (store->list-inner sto 0)))) )