|CIT 594 Bugs
Interpeter, part 1
Spring 2008, David Matuszek
Given a program in the Bugs language, you now can create an AST (Abstract Syntax Tree) for it. The next step is to interpret the AST, so that your Bugs program "does something."
In this assignment you will write the first half of the interpreter. (The next assignment will be to complete the interpreter.) We will leave three things for later: Implementing function calls, displaying the bugs' actions on the screen, and coordinating the actions of multiple bugs.
Now might be a very good time to review The Bugs Language.
Name your Bug interpreter class
Two fundamental methods are needed:
public double evaluate(Tree<Token> tree), for parts of the tree (mostly, expressions) that need to return a value, and
public void interpret(Tree<Token> tree), for parts of the tree (such as statements) that do not return a value.
interpretwith the root node of a Bug (the AST representing a
<bug definition>. To interpret this node, you interpret each of its five children, as follows:
nameof the Bug in an instance variable.
loopnode will walk its children repeatedly). Some nodes, such as an assignment node, may cause certain children to be
evaluated, rather than
interpreted, and it will be obvious when to do this.
Note: Although the interpretation proceeds top down, starting at theFor keeping track of variables and their values, write the following two methods:
Bugroot, you will need to write the methods by starting at the bottom and working your way up (just as you did in the
Parser), so that you can test as you go. Of course, full JUnit testing is required.
void store(String variable, double value)is used to perform the assignment
double fetch(String variable)is used to retrieve the current value of
variable. (If there is no such variable, throw some kind of
HashMap<String, Double>to keep track of the values of variables. However, there are three variables that need to be treated specially:
angle. These do not go into the HashMap, but are instance variables of the Bug class, for reasons that should become clear when we implement functions. Make sure that
fetchhandle these three variables correctly.
These are more-or-less in the order given in the Bugs Grammar, not in the order you need to write them. Remember, bottom up!
Interpreterclass, not in a
Bugobject. The constructor should take as arguments the Bug's name, the Bug's AST, and a reference to the
Interpreterthat created the Bug. Save each Bug in a
HashMap<String, Bug>, using the Bug's name as key.
HashMap<String, Double>to store the
vardeclarations (with initial values of 0.0).
HashMap<String, Tree<Token>>to store the function definitions.
Bugclass should have an instance variable
HashMap<String, Tree<Token>> functions
functionnode as the value. (Actually interpreting the function will be done by a
storeeach named variable, with an initial value of zero.
expressionchild, and "move" this Bug forward (its
angletells what direction it is facing) by that amount, by setting new values of
y. You will need a small amount of trigonometry to determine the new values of
y; get help from a classmate if necessary. Part 2. The Bug is supposed to draw a line as it moves (unless its color is set to none). Create a Command object that specifies the color and endpoints of the line, and save it in a list. Notify the Interpreter that this bug has performed an action.
expressionchildren, and set
yto these two values, respectively. Part 2. The Bug is supposed to draw a line as it moves (unless its color is set to none). Create a Command object that specifies the color and endpoints of the line, and save it in a list. Notify the Interpreter that this bug has performed an action.
expressionchild, and add this amount to this Bug's
angle. If necessary, adjust the value to be between 0.0 and 360.0, inclusive. (Maintain full accuracy--do not use int values!). Part 2. Notify the Interpreter that this bug has performed an action.
expressionchild, and set this Bug's
angleto the new value. If necessary, adjust the value to be between 0.0 and 360.0, inclusive. (Maintain full accuracy--do not use int values!). Part 2. Notify the Interpreter that this bug has performed an action.
storethe result of the evaluation into the variable name.
block) repeatedly. The loop ends when an
exit ifstatement in the block is interpreted. You can do it by setting and clearing a
booleanvariable, to be checked by
casechild, in order, until one returns "true"--then stop. (It seems strange to evaluate a case clause, rather than interpreting it, but this is an easy way to implement the switch statement.) Remember, "false" is any number between -0.001 and +0.001, and "true" is any number that isn't false.
java.awt.Colorvalue (there is no shortcut to doing this, you just need a big
ifstatement), and store the result in this Bug's
colorinstance variable. Throw some kind of
RuntimeExceptionif the name isn't a legal color.
HashMap<String,Double>, and put each formal parameter (under the
varnode into it. Push this HashMap onto this Bug's stack of HashMaps.
returnstatement, evaluate its expression, store the result in an instance variable, pop the HashMap off this Bug's stack of HashMaps, and return from interpreting the
returnstatement, treat it as a
ifstatement), and return
0.0for "false." Remember, two numbers are "equal" if they are within 0.001 of each other.
interpret, not one huge test method for each. For example,
testAssignmentStatement, or whatever). Remember that JUnit 4 tests can be named whatever you like.
void, you need to test it by its effect. That means that pretty much everything you interpret should set the values of some variables, so you can
fetchthose variables and see if they were set correctly.
Zip the complete project and submit it via Blackboard by midnight Tuesday, April 15.