Homework 10
Extending Boom, A Little Language for Arithmetic
Due: Friday, May 2, at 11:59 PM
Introduction
This assignment extends Boom, our little language for doing arithmetic, and the interpreter and other tools that process programs written in the language. The new version of the language supports local variables.
Before going any farther, read the updated Boom language specification. It defines the language, in particular the extensions, and talks about some of the Racket you can use to implement your solution.
Code and Files
For this assignment, you will extend the Boom interpreter to handle local variables, including the syntax procedures that define the new expressions, the pre-processor, and the evaluator. You will organize your code in the same way as you did for Homework 9.
Here are a few changes specific to this assignment:
-
Make a copy of the
boom-hw09/
directory from Homework 9, which will contain all your files for the project. Name the copyboom-hw10/
. Modify and extend these files for the project. -
Put the abstract data type you implement for
Problem 1 in a new file name
datatypes.rkt
. It will contain the data types we implement for our language-processing programs. (There will be at least one more datatype soon.) -
Put the
(go-boom)
function you write for Problem 5 in theinterpreter.rkt
file. -
Make sure to update the
provide
clause in each file to include the new public functions you write.
We will extend the Boom language and interpreter again on the next homework assignment. Please comment your source code so that you and I can easily find the pieces relevant to this assignment.
A Data Abstraction for Environments
In order to support local variables, our interpreter needs a way to map names onto values. To provide this behavior, we need an abstract data type called an environment. The environment ADT is an example of a finite function.
This data type consists of four operations:
-
the ability to create an empty set of bindings with
(make-bindings)
, -
the ability to bind a variable to a value with
(bind var val existing-bindings)
, -
the ability to look up the value of a variable with
(look-up var existing-bindings)
, and -
the ability to check whether a variable is defined in an
environment, with
(var-exists? var existing-bindings)
.
The var-exists?
function is an addition to the
interface of finite functions we studied in class. It enables
us to determine whether an environment contains a particular
variable, without ever having to look up a non-existent variable
and cause an error.
Problems
-
Implement the environment ADT as a finite function using
association lists.
An association list is a list of name/value pairs, such as:((foo . 2) (bar . 5) (baz . 15))
For example:
> (make-bindings) () > (bind 'foo 2 (make-bindings)) ((foo . 2)) > (bind 'bar 5 (bind 'foo 2 (make-bindings))) ((bar . 5) (foo . 2)) > (define env (bind 'bar 5 (bind 'foo 2 (make-bindings)))) > (look-up 'foo env) 2 > (var-exists? 'bif env) #f > (look-up 'bif env) environment: undefined variable -- baz
You may write your own recursive code to implement the
look-up
function, or you may use the Racket's primitiveassoc
function. -
Define the syntax procedures for variable references and
let/in
expressions.
For each of the new expression types, define a type predicate, a constructor, and the corresponding access procedures.Be sure to extend the general type predicate
boom-exp?
(or whatever you named it) to recognize the new types of expression, too.Note: we do not need accessors to retrieve the symbols
let
,=
, orin
. They are keywords, not values provided by the programmer. -
Extend
(preprocess sugared-exp)
to handle variable references andlet/in
expressions.
Both of the new types of expression are core features of Boom, sopreprocess
needs only to de-sugar the sub-expressions of a variable declaration: the body and the variable's value.For example:
> (preprocess 'two) 'two > (preprocess '(let z = (x @ y) in (- z))) '(let z = ((x + y) / 2) in (- z)) > (preprocess '(let square = (sq x) in (let average = (square @ x) in (average << 2)))) '(let square = (x * x) in (let average = ((square + x) / 2) in (average * (10 ^ 2))))
-
Extend
(eval-exp exp)
to handle variable references andlet/in
expressions.
eval-exp
returns the value ofexp
, which now may be or contain the new kinds of expression, as specified by the language's semantics.eval-exp
must now maintain its own environment and look up the value of a variable references in the environment. Haveeval-exp
do the following:- create an initial environment in which to evaluate its argument. This environment should contain the primitive values of Boom
- pass the initial environment, along with the pre-processed version of its argument, to the helper function that actually evaluates an expression in a given environment
A
let/in
expression creates a new variable, which must be added to the environment before its body is evaluated. The helper will pass the extended environment on its recursive call to evaluate thelet/in
expression's body.For example:
> (eval-exp 'two) 2 > (eval-exp '(let z = (two * ten) in (- z))) -20 > (eval-exp '(let square = (sq ten) in (let half = (square / 2) in (half + (4 * 12))))) 98
-
Define a function
(go-boom)
that opens a REPL for your Boom interpreter.
Have the eval step in your REPL call youreval-exp
function. Feel free to use the ideas from the reading on imperative programming, but customize the REPL so that it is unmistakably yours! This is an opportunity to put a bit of your own personality into the language.go-boom
should validate the input before callingeval-exp
. If the user enters an illegal expression, that is, anything that is not a legal Boom program, the REPL should not cause an error. Instead, have it write an error message to the screen and let the user enter another expression.
Deliverables
By the due time and date, use the course submission system to submit the following files electronically:
syntax-procs.rkt
interpreter.rkt
datatypes.rkt
tests.rkt
utilities.rkt
(optional)
Be sure that your submission follows the submission requirements. As always, use the specified names for your files. This enables the auto-grader to find and run your code.