; Tail-recursive Scheme interpreter ; Uses: startup scmhelp.lsp ; Based on Abelson & Sussman, chapter 5. ; The most glaring omissions are error-checking, set!, begin, and call/cc. (define next '*) (define exp '*) (define env '*) (define proc '*) (define rands '*) (define args '*) (define value '*) (define cont '*) (define read-eval-print-loop (lambda () (while (begin (write '>) (not (eq? the-eof-object (set! exp (read))))) (set! exp (macroexpand exp)) (set! env init-env) (set! cont (lambda () 'halt)) (set! next eval-exp) (run) (print value)))) (define run (lambda () (while (not (eq? (next) 'halt))))) (define goto (lambda (procedure) (set! next procedure))) (define return (lambda (val) (set! value val) (set! next cont))) (define eval-exp (lambda () (if (atom? exp) (return (if (symbol? exp) (lookup-variable exp env) exp)) (let ((handler (get (car exp) 'evaluator))) (if handler (handler) (begin ; procedure call (push cont) ; this eventually is popped by apply-proc (push env) (push (cdr exp)) ; save the operands (set! exp (car exp)) ; evaluate the operator (set! cont eval-rands) (goto eval-exp))))))) (define eval-rands (lambda () (set! rands (pop)) (set! env (pop)) (set! args '()) (push value) ; save the procedure (goto rands-loop))) (define rands-loop (lambda () (if (null? rands) (begin (set! args (reverse! args)) (set! proc (pop)) (goto apply-proc)) (begin (set! exp (car rands)) (push env) (push args) (push (cdr rands)) (set! cont add-arg) (goto eval-exp))))) (define add-arg (lambda () (set! rands (pop)) (set! args (cons value (pop))) (set! env (pop)) (goto rands-loop))) (put 'quote 'evaluator (lambda () (return (cadr exp)))) (put 'lambda 'evaluator (lambda () (return (make-closure exp env)))) (put 'if 'evaluator (lambda () (push cont) (push env) (push exp) (set! cont decide) (set! exp (test-exp exp)) (goto eval-exp))) (define decide (lambda () (set! exp (pop)) (set! env (pop)) (set! cont (pop)) (set! exp (if value (then-exp exp) (else-exp exp))) (goto eval-exp))) (put 'define 'evaluator (lambda () (push cont) (push env) (push (cadr exp)) ; save the variable being defined (set! exp (caddr exp)) ; evaluate the defining expression (set! cont do-definition) (goto eval-exp))) (define do-definition (lambda () (set! exp (pop)) (set! env (pop)) (set! cont (pop)) (define-variable-value exp value env) (return exp))) (define apply-proc (lambda () (set! cont (pop)) (if (primitive? proc) (return (apply proc args)) (begin (set! exp (closure-body proc)) (set! env (extend-env (closure-formals proc) args (closure-env proc))) (goto eval-exp))))) ; Stack operations (define stack '()) (define push (lambda (x) (set! stack (cons x stack)))) (define pop (lambda () (let ((result (car stack))) (set! stack (cdr stack)) result))) ; Here we go (define init-env (extend-env '() '() '())) (read-eval-print-loop)