diff options
author | Ben Burwell <bburwell1@gmail.com> | 2013-04-11 00:03:50 -0400 |
---|---|---|
committer | Ben Burwell <bburwell1@gmail.com> | 2013-04-11 00:03:50 -0400 |
commit | 5b05b64a2a658c0f7d4eb5b09fa342c7375a776e (patch) | |
tree | bad4537081da8b969084cff6880e36418f13a97d /hw08.scm |
Init
Diffstat (limited to 'hw08.scm')
-rw-r--r-- | hw08.scm | 394 |
1 files changed, 394 insertions, 0 deletions
diff --git a/hw08.scm b/hw08.scm new file mode 100644 index 0000000..fe329f2 --- /dev/null +++ b/hw08.scm @@ -0,0 +1,394 @@ +#lang eopl + +; 3.9 INTERPRETER +; - the interpreter consists of several components +; - SCANNER - converts characters to tokens +; - PARSER - converts tokens to abstract syntax trees +; - ENVIRONMENT - maps identifiers to values +; - EVALUATOR - converts abstract syntax trees to values/results +; - this interpreter supports: +; - (3.1) basic functionality +; - whitespace & comments (skipped) +; - integers & built-in defined constants +; - 3 binary primitive operations - add, sub, mult +; - 2 unary primitive operations - incr, decr +; - (3.3) conditionals - if-then-else +; - (3.4) local bindings - let +; - (3.5) procedures - proc, app-exp +; - (3.6) recursion - letrec +; - (3.7) variable assignment - set +; - (3.9) statements - assign, print, compound, if, while, block +; +; THINGS DO DO (save as 3.9a) + +; ------------------------------------------------------------ +; scanner specification + +(define scanner-spec + '( + (whitespace (whitespace) skip) + (comment ("%" (arbno (not #\newline))) skip) + (identifier (letter (arbno (or letter digit "?"))) make-symbol) + (number (digit (arbno digit)) make-number) )) + +; ------------------------------------------------------------ +; grammar specification + +(define grammar + '( + ; (3.1) program + (program (statement) a-program) + + ; (3.9) statements + (statement (identifier "=" expression) + assign-statement) + (statement ("print" "(" expression ")") + print-statement) + (statement ("{" (separated-list statement ";") "}") + compound-statement) + (statement ("if" expression statement statement) + if-statement) + (statement ("while" expression "do" statement) + while-statement) + (statement ("var" (separated-list identifier ",") ";" statement) + block-statement) + + ; (3.1) expressions + (expression (number) lit-exp) + (expression (identifier) var-exp) + (expression (primitive "(" (separated-list expression ",") ")") + primapp-exp) + + ; (3.3) conditional evaluation + (expression ("if" expression "then" expression "else" expression) + if-exp) + ; (3.4) local binding + (expression ("let" (arbno identifier "=" expression) "in" expression) + let-exp) + + ; (3.5) procedure definition & application + (expression ("proc" "(" (separated-list identifier ",") ")" expression) + proc-exp) + (expression ("(" expression (arbno expression) ")") + app-exp) + + ; (3.6) recursion + (expression ("letrec" + (arbno identifier "(" (separated-list identifier ",") ")" + "=" expression) + "in" expression) + letrec-exp) + + ; (3.7) variable assignment + (expression ("set" identifier "=" expression) + varassign-exp) + + ; (3.7 HW) sequential expressions + (expression ("begin" expression (arbno ";" expression) "end") + begin-exp) + + ; (3.1) primitives + (primitive ("+") add-prim) + (primitive ("-") subtract-prim) + (primitive ("*") mult-prim) + (primitive ("add1") incr-prim) + (primitive ("sub1") decr-prim) + ; (3.3) primitives + (primitive ("equal?") equal-prim) + (primitive ("zero?") zero-prim) + (primitive ("greater?") greater-prim) + (primitive ("less?") less-prim) + )) + +; ------------------------------------------------------------ +; define datatypes before defining interpreter + +(sllgen:make-define-datatypes scanner-spec grammar) +(define dump-datatypes + (lambda () (sllgen:list-define-datatypes scanner-spec grammar))) + +; ------------------------------------------------------------ +; booleans + +(define truth 1) +(define falsity 0) + +(define true-value? (lambda (x) (not (zero? x)))) + +; ------------------------------------------------------------ +; environments + +(define init-env + (lambda () (extend-env '(stdout) '(*uninitialized*) (empty-env)) )) + +(define-datatype environment environment? + (empty-env-record) + (extended-env-record + (syms (list-of symbol?)) + (vec vector?) ; can use this for anything + (env environment?) )) + +(define empty-env (lambda () (empty-env-record))) + +(define extend-env + (lambda (syms vals env) (extended-env-record syms (list->vector vals) env))) + +(define extend-env-recursively + (lambda (proc-names idss bodies old-env) + (let ((len (length proc-names))) + (let ((vec (make-vector len))) + (let ((env (extended-env-record proc-names vec old-env))) + (for-each + (lambda (pos ids body) + (vector-set! vec pos (closure ids body env))) + (iota len) + idss + bodies) + env))))) + +(define apply-env-ref + (lambda (env sym) + (cases environment env + (empty-env-record () + (eopl:error 'apply-env "no association for symbol ~s" sym)) + (extended-env-record (syms vals env) + (let ((position (env-find-position sym syms))) + (if (number? position) (a-ref position vals) (apply-env-ref env sym))))))) + +(define apply-env + (lambda (env sym) (deref (apply-env-ref env sym)))) + +(define env-find-position + (lambda (sym los) (list-find-position sym los))) + +(define list-find-position + (lambda (sym los) (list-index (lambda (sym1) (eqv? sym1 sym)) los))) + +(define list-index + (lambda (pred ls) + (cond + ((null? ls) #f) + ((pred (car ls)) 0) + (else (let ((list-index-r (list-index pred (cdr ls)))) + (if (number? list-index-r) (+ list-index-r 1) #f)))))) + +(define iota + (lambda ( n ) (do ((n n (- n 1)) (x '() (cons (- n 1) x))) ((zero? n) x)))) + +; ------------------------------------------------------------ +; evaluator + +; evaluator for root of abstract syntax tree +(define execute-program + (lambda (pgm) + (cases program pgm + (a-program (statement) + (execute-statement statement (init-env)) )))) + +; (3.9) statement evaluator +(define execute-statement + (lambda (stmt env) + (cases statement stmt + + (assign-statement (id exp) + (setref! + (apply-env-ref env id) + (eval-expression exp env) )) + + (print-statement (exp) + (write (eval-expression exp env)) (newline) ) + + (compound-statement (statements) + (for-each + (lambda (statement) (execute-statement statement env)) + statements) ) + + (if-statement (exp true-statement false-statement) + (if (true-value? (eval-expression exp env)) + (execute-statement true-statement env) + (execute-statement false-statement env) )) + + ; alternate "named" LET syntax + (while-statement (exp statement) (while-loop exp statement env)) + + (block-statement (ids statement) + (execute-statement statement + (extend-env ids (map (lambda (id) 0) ids) env) )) + ))) + +(define while-loop + (lambda (exp stmt env) + (if (true-value? exp) + (lambda () (execute-statement stmt env) (while-loop exp stmt env)) + (#f)))) + +; expression evaluator +(define eval-expression + (lambda (exp env) + (cases expression exp + (lit-exp (datum) datum) + (var-exp (id) (apply-env env id)) + + (primapp-exp (prim rands) + (let ((args (eval-rands rands env))) + (apply-primitive prim args))) + + ; (3.3) conditional evaluation + (if-exp (test-exp true-exp false-exp) + (if (true-value? (eval-expression test-exp env)) + (eval-expression true-exp env) + (eval-expression false-exp env) )) + + ; (3.4) local binding + (let-exp (ids rands body) + (let ((args (eval-rands rands env))) + (eval-expression body (extend-env ids args env)))) + + ; (3.5) procedure definition + (proc-exp (ids body) (closure ids body env)) + + ; (3.5) procedure application + (app-exp (rator rands) + (let ((proc (eval-expression rator env)) + (args (eval-rands rands env)) ) + (if (procval? proc) + (apply-procval proc args) + (eopl:error 'eval-expression + "attempt to apply non-procedure ~s" + proc)))) + + ; (3.6) recursion + (letrec-exp (proc-names idss bodies letrec-body) + (eval-expression letrec-body + (extend-env-recursively proc-names idss bodies env))) + + ; (3.7) variable assignment + (varassign-exp (id rhs-exp) + (begin (setref! + (apply-env-ref env id) + (eval-expression rhs-exp env)) + 1)) + + ; (3.7) sequential expressions + (begin-exp (exp1 exps) + (letrec + ((loop (lambda (acc exps) + (if (null? exps) acc + (loop (eval-expression (car exps) env) + (cdr exps)))))) + (loop (eval-expression exp1 env) exps))) + ))) + +; (3.4) evaluate operands +(define eval-rands + (lambda (rands env) (map (lambda (x) (eval-rand x env)) rands))) +(define eval-rand + (lambda (rand env) (eval-expression rand env))) + +; (3.1) apply primitive operations +(define apply-primitive + (lambda (prim args) + (define (check arity) + (if (not (= arity (length args))) + (eopl:error 'apply-primitive + "wrong number of arguments to primitive ~s" + prim))) + (cases primitive prim + (add-prim () (check 2) (+ (car args) (cadr args))) + (subtract-prim () (check 2) (- (car args) (cadr args))) + (mult-prim () (check 2) (* (car args) (cadr args))) + (incr-prim () (check 1) (+ (car args) 1)) + (decr-prim () (check 1) (- (car args) 1)) + (equal-prim () (check 2) (if (= (car args) (cadr args)) truth falsity)) + (zero-prim () (check 1) (if (zero? (car args)) truth falsity)) + (greater-prim () (check 2) (if (> (car args) (cadr args)) truth falsity)) + (less-prim () (check 2) (if (< (car args) (cadr args)) truth falsity)) + ))) + +; ------------------------------------------------------------ +; procedures (3.5) + +(define-datatype procval procval? + (closure + (ids (list-of symbol?)) ; formal parameters + (body expression?) ; procedure body + (env environment?))) ; closure (calling environment) + +(define apply-procval + (lambda (proc args) + (cases procval proc + (closure (ids body env) + (if (= (length ids) (length args)) + (eval-expression body (extend-env ids args env)) + (eopl:error 'apply-procval + "wrong number of arguments to procedure ~s" + ids)))))) + +; ------------------------------------------------------------ +; references - for variable assignment (3.7) + +(define-datatype reference reference? + (a-ref + (position integer?) + (vec vector?) )) + +(define primitive-deref + (lambda (ref) + (cases reference ref + (a-ref (pos vec) + (vector-ref vec pos) )))) + +(define primitive-setref! + (lambda (ref value) + (cases reference ref + (a-ref (pos vec) + (vector-set! vec pos value))))) + +(define deref (lambda (ref) (primitive-deref ref))) +(define setref! (lambda (ref value) (primitive-setref! ref value))) + +; ------------------------------------------------------------ +; interpreter + +; scanner only, and parser only +(define scan + (sllgen:make-string-scanner scanner-spec grammar)) +(define scan&parse + (sllgen:make-string-parser scanner-spec grammar)) +(define read-dump + (sllgen:make-rep-loop "--> " (lambda (tree) tree) + (sllgen:make-stream-parser scanner-spec grammar))) + +(define scan&parse&eval + (lambda (s) (execute-program (scan&parse s))) ) + +(define read-eval-print + (sllgen:make-rep-loop "--> " execute-program + (sllgen:make-stream-parser scanner-spec grammar))) + +; ------------------------------------------------------------ +; tests + +(define test-3.1a "add1(2)") +; ignores extra parameters +(define test-3.1b "add1(2,3)") +(define test-3.1c "+(3,4,5)") +; more tests +(define test-3.1d "+(add1(2),-(6,4))") +(define test-3.1e "*(2,+(3,sub1(4)))") +(define test-3.3a "if -(3,+(1,2)) then 2 else 3") +(define test-3.4a "let x = 5 y = 6 in +(x,y)") + +(define test3.5a "print(let f=proc(y,z) +(y,-(z,5)) in (f 2 28))") +(define test3.5b "print((proc (x) +(x,2) 4))") +(define test3.5c "print(let x=5 in let f=proc(y,z) +(y,-(z,x)) x=28 in (f 2 x))") + +(define test3.6a "print(letrec fact(x)=if zero?(x) then 1 else *(x,(fact sub1(x))) +in (fact 6))") +(define test3.6b "print(letrec even(x)=if zero?(x) then 1 else (odd sub1(x)) +odd(x)=if zero?(x) then 0 else (even sub1(x)) +in (odd 13))") + +(define test3.9a "var x,y; {x=3; y=4; print(+(x,y))}") +(define test3.9b "var x,y,z; {x=3; y=4; z=0; +while x do {z=+(z,y); x=sub1(x)}; print(z)}")
\ No newline at end of file |