
In your textbook so far, you've seen a discussion of expressed and denoted values.
Expressed values: values that can be returned from expressions. By definition, eval-expression
returns expressed values.
Denoted values: what are bound to variables in environments.
These sets of values, plus other parts that go into the way we store data for our language make up what is called a data model.
In the models we've used so far, the set of expressed values and the set of denoted values are the same. When we first built the interpreter, we had only numbers:
Expressed Values = Number Denoted Values = Expressed Values
When you added lists in a previous homework assignment, these became new expressed values:
Expressed Values = Number + List Denoted Values = Expressed Values
When we added functions, they too became new expressed values:
Expressed Values = Number + List + Procval Denoted Values = Expressed Values
Let's now add variable assignment to our language. (We'll come back to the data model idea in a moment.)
The BNF for variable assignment in ELL is
<expression> = set <identifier> = <expression>
To add it, we add the following line to our grammatical specification:
(expression ("set" identifier "=" expression) varassign-exp)
Here's a simple assignment expression:
set x = add1(x)
We can sequence assignments using let expressions:
let z = 20 in let temp = set z = 19 in z
This might seem strange, but let expressions are the only way
we have to cause sequencing until we add an expression-sequencing construct
(like begin) to our language. (You'll add this in HW-23.)
Here's how to read this let expression:
Let the variable "z" be 20 in evaluating the following expression: Let the variable "temp" be the result of setting "z" to 19 in the following expression: Evaluate z
When we evaluate z, even though it was initialized to be 20, it has been assigned (changed) to be 19.
Here's the abstract syntax generated by SLLGEN for variable assignment:
(varassign-exp (id symbol?) (rhs-exp expression?))
Here's what we'd like to do for a variable assignment:
rhs-exp. rhs-exp into where the identifier stores its value. So, how do we "find out where the indentifier stores its value"? How do we even represent that? To do this, we need to change our data model.
Expressed Values = Number + List + Procval Denoted Values = Ref (Expressed Values)
The change is that variables are now bound conceptually to references to expressed value, not expressed values themselves.
Going back to the steps we identified earlier for the desired behavior, we can rewrite these steps in terms of the data model:
rhs-exp to get its expressed value.Since our values are stored in Scheme vectors, we can build a reference type that points to
a particular vector and contains an index into that vector.
(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 val) (cases reference ref (a-ref (pos vec) (vector-set! vec pos val))))) (define deref (lambda (ref) (primitive-deref ref))) (define setref! (lambda (ref val) (primitive-setref! ref val)))
Let's also add a new function apply-env-ref to our environment implementation that returns a reference to where
the variable is stored. (Our current apply-env returns the expressed value--we want the denoted value.)
(define apply-env-ref (lambda (env sym) (cases environment env (empty-env-record () (eopl:error 'apply-env-ref "No binding for ~s" sym)) (extended-env-record (syms vals env) (let ((pos (rib-find-position sym syms))) (if (number? pos) (a-ref pos vals) (apply-env-ref env sym)))))))
Now that we have the necessary machinery in place for references and getting references to stored variables, implementing assignment is easy:
(define eval-expression (lambda (exp env) (cases expression exp (lit-exp (datum) datum) (var-exp (id) (apply-env env id)) (varassign-exp (id rhs-exp) (begin (setref! (apply-env-ref env id) (eval-expression rhs-exp env)) 1)) ... )))
Notice that we call apply-env-ref to get a reference to the id,
then we evaluate the right-hand side of the assignment (rhs-exp),
then we use setref! to change the referenced location to contain the new expressed value.
Remember that this new assignment expression is an expression, not a statement, so it needs to return a value. What value? This implementation always returns "1" for the result of an assignment. We could change the implementation to return the expressed value assigned to the variable:
(define eval-expression (lambda (exp env) (cases expression exp (lit-exp (datum) datum) (var-exp (id) (apply-env env id)) (varassign-exp (id rhs-exp) (let ((val (eval-expression rhs-exp env))) (setref! (apply-env-ref env id) val) val)) ... )))
The complete interpreter for Lecture 20.

Last updated at 9:54 am on Friday, August 27, 2004.