Write a meta circular interpreter for the core of Proto. In
particular, it must handle a simplified version of proto including:
SPECIAL FORMS
QUOTE (QUOTE ,value)
IF (IF ,test ,then ,else)
SEQ (SEQ ,@forms)
FUN (FUN ,sig ,@body)
LET (LET ((,name ,value) ...) ,@body)
LOC (LOC ((,name (,name ...) ,@body) ...) ,@body)
LAB (LAB ,name ,@body)
FIN (FIN ,protected-form ,@cleanup-forms)
DV (DV ,name ,value)
SET (SET ,name ,value)
CALLS
call (,form ,@args)
LITERALS
literal ,value
You can use the full language of Proto (as defined in Proto's doc) in
writing the interpreter. The source for the runtime libraries is also
available on our course website. You can also use the following
implementation of environments:
(dv )
(dv (isa ))
(slot (env-next ))
(slot (env-frame ) (isa ))
(dv $empty-env (isa ))
(dm env-define-binding! ((env ) (name ) (value ))
(set (elt (env-frame env) name) value))
(dm env-extend! ((env ) (names ) (values ) => )
(let ((new-env (isa (set env-next env))))
(do2 (fun (name value) (set (elt (env-frame new-env) name) value))
names values)
new-env))
(dm env-binding-value ((env ) (name ) => )
(if (== env $empty-env)
nul
(let ((value (elt (env-frame env) name)))
(if (== value nul)
(env-binding-value (env-next env) name)
value))))
(dm env-binding-value-setter ((value ) (env ) (name ))
(if (== env $empty-env)
nul
(if (== (elt (env-frame env) name) nul)
(set (env-binding-value (env-next env) name) value)
(set (elt (env-frame env) name) value))))
and the following functions for picking apart sexpressions:
(dm sexpr-if-test ((exp ) => )
(2nd exp))
(dm sexpr-if-then ((exp ) => )
(3rd exp))
(dm sexpr-if-else ((exp ) => )
(if (empty? (tail (tail (tail exp))))
#f
(head (tail (tail (tail exp))))))
(dm sexpr-begin-actions (begin-exp => )
(tail begin-exp))
(dm sexpr-variable-name ((exp ) => )
(1st exp))
(dm sexpr-variable-name (exp => )
exp)
(dm sexpr-definition-variable ((defn ) => )
(2nd defn))
(dm sexpr-definition-value (defn => )
(3rd defn))
(dm sexpr-assignment-variable ((assn ) => )
(2nd assn))
(dm sexpr-assignment-value ((assn ) => )
(3rd assn))
(dm sexpr-let-bound-variables ((let-exp ) => )
(map head (2nd let-exp)))
(dm sexpr-let-values ((let-exp ) => )
(map 2nd (2nd let-exp)))
(dv $sexpr-begin-tag 'seq)
(dm sexpr-last-exp? ((seq ) => )
(empty? (tail seq)))
(dm sexpr-first-exp ((seq ) => )
(head seq))
(dm sexpr-rest-exps ((seq ) => )
(tail seq))
(dm sexpr-let-values ((let-exp ) => )
(map 2nd (2nd let-exp)))
(dm sexpr-let-body ((let-exp ) => )
(tail (tail let-exp)))
(dv $sexpr-method-tag 'fun)
(dm sexpr-make-begin ((exp ) => )
(pair $sexpr-begin-tag exp))
(dm sexpr-lab-name ((exp ) => )
(2nd exp))
(dm sexpr-lab-body ((exp ) => )
(tail (tail exp)))
(dm sexpr-fin-protected-form ((exp ) => )
(2nd exp))
(dm sexpr-fin-cleanup-forms ((exp ) => )
(tail (tail exp)))
(dm sexpr-function-parameters (defn => )
(3rd defn))
(dm sexpr-function-body (defn => )
(tail (tail (tail defn))))
Your interpreter should also preseed its base environment with the
following primitives: pair, head, tail, empty?, +, -, <, =, and ==.
These primitives should be available to programs fed to your
interpreter.
Name your eval function evol in order to avoid collision with the
built-in eval function.
Your interpreter should be able to correctly reproduce these input
output pairs:
1
=> 1
#t
=> #t
#f
=> #f
'()
=> ()
'(1)
=> (1)
'1
=> 1
(IF #t 1 2)
=> 1
(IF #f 1 2)
=> 2
(IF 0 1 2)
=> 1
(SEQ)
=> #f
(SEQ 1)
=> 1
(SEQ 1 2)
=> 2
(+ 1 2)
=> 3
(- 1 2)
=> -1
(> 1 2)
=> #f
(= 1 1)
=> #t
(LET ((x 1)) x)
=> 1
(LET ((x 1) (y x)) y)
=> 1
(LET ((x 0)) (SET x 1) x)
=> 1
(LAB ret 1)
=> 1
(LAB ret (ret 1) 2)
=> 1
(FIN 1 2 3)
=> 1
(LET ((x 0)) (LAB ret (FIN (ret 2) (SET x 1))) x)
=> 1
(DV x 1)
=> #f
(SEQ (DV x 1) x)
=> 1
(SEQ (DV x 0) (SET x 1) x)
=> 1
((FUN () 1))
=> 1
((FUN (x) x) 1)
=> 1
((FUN (x y) (+ x y)) 1 2)
=> 3
(LOC ((f (x) x)) (f 1))
=> 1
(LOC ((f (x) (g x)) (g (y) y)) (f 1))
=> 1
(LOC ((f (x) (if (< x 2) x (* x (f (- x 1)))))) (f 5))
=> 120
(SEQ (DV c (FUN (x) (if (empty? x) x (pair (+ (head x) 1) (c (tail x))))))
(c '(1 2 3)))
=> (2 3 4)
Feel free to ask questions by email at oodl-fac@ai.mit.edu or by
stopping by our office at room 802 the AI Lab (NE-43).
There will probably be bugs in this early version of Proto so please
bear with us and definitely let us know what problems you run into.
Keep checking the web site:
http://www.ai.mit.edu/projects/dynlangs/oodl-course/spring01/
for new versions of Proto and its documentation as we fix bugs and
fill out the documentation.
This assignment is due Thursday 22FEB01 before class. Please email it
to us at: oodl-fac@ai.mit.edu.