CIT 594 Assignment 8: Interpreter Notes
CIT 594, Spring 2005

This is just a random collection of observations about the Robot interpreter. There are no new requirements here.


In Assignment 4 you wrote a program to evaluate expressions. This was a pretty complicated program because you went directly from strings to values, so you had to handle tokenizing, operator precedence, and parentheses. None of that is necessary in the present assignment, because your parser has already constructed trees of exactly the right shape. This time around, evaluating expressions is much, much simpler.

Here's what you do. The root of an expression will be a number, a name, the keyword distance, or an operator (+, -, *, /, %). If it's a number, you're done. If it's a name, look up its value in some hash table. If it's the keyword distance, ask the robot for a value. If it's an operator, recursively evaluate the two operands, then apply the operator to get the result.


In the assignment I had:

void interpret(Tree command)
Given the root of a Tree representing a program or a command, interpret the program or command (that is, do what it says to do).

and a little later I had:

else if ("while".equals(command)) {
    while (evaluateCondition(child[0])) {
        interpret(child[1]);
     }
}

This is inconsistent--in the first case I'm using command as a Tree, and in the second case I'm using it as a String. My code actually looks (approximately) like:

private void interpret(Tree node) {
    if (node == null) return;
    Token token = (Token) node.value;
    String command = getString(node);
    if ...
    ...
    else if ("while".equals(command)) {
    while (evaluateCondition(child[0])) {
        interpret(child[1]);
    }
    ...
}

Procedure definitions are indicated by the keyword to. Procedure calls are indicated by the keyword do.

Your Interpreter should interpret the "main" program (the part before the procedures). Interpret a procedure if and only if it is called from the main program or from another procedure.

This is just like methods in Java. Methods are only executed when and if they are called, and not for any other reason.


Methods are your friends. Any time you find you are doing something complicated, write a method to do it for you, and give the method a meaningful name. This will make your code much easier to read.


Avoid long, complicated expressions. Expressions with one dot are okay; two dots is questionable; and more than two is just too complicated.

Consider:

String procedureName = ((String)((Token)procedure.getChildren()[0].
                       getChildren()[0].getValue())).getValue();
and compare this to:
Tree headerNode = procedure.getChildren()[0];
Tree procedureNameNode = headerNode.getChildren()[0];
Token nameToken = (Token)procedureNameNode.getValue();
String procedureName = (String)nameToken.getValue();

I claim the second is easier to understand. And most certainly, if you get a NullPointerException, you'll get a lot more information about what value was null if you use the second form.

Likewise, don't do this:

private void interpret(Tree node) {

    if ("program".equals(getString((Token)node.getValue()))) {...}
    if ("block".equals(getString((Token)node.getValue()))) {...}
    if ("forward".equals(getString((Token)node.getValue()))) {...}
...
when you can do this:
private void interpret(Tree node) {
    Token token = (Token)node.getValue();
    String command = getString(node);


    if ("program".equals(command)) {...}
    if ("block".equals(command)) {...}
    if ("forward".equals(command)) {...}
...

Here's a simple little test program for your robot, and the results that my DummyRobot prints out. This isn't a complete test, but it should get you started.

forward 5
turn left
turn right
turn around
take apple
drop orange
repeat 3 {
    forward 1
}
set x 3
if x = 3 {
    drop apple
}
if x = 3 {
    drop apple
}
else {
    drop pear
}
if x = 5 {
    drop pomegranite
}
else {
    drop apple
}
while x > 0 {
    back 1
    set x x - 1
}
set x 2
do foo 4 5*x
back x
stop
to foo w v
    while x < w {
        turn right
        set w w - 1
    }
    turn left
    forward w
    forward x
    set x 17
end
Moving forward 5.
Turning left.
Turning right.
Turning around.
Taking apple.
Dropping orange.
Moving forward 1.
Moving forward 1.
Moving forward 1.
Dropping apple.
Dropping apple.
Dropping apple.
Moving back 1.
Moving back 1.
Moving back 1.
Turning right.
Turning right.
Turning left.
Moving forward 2.
Moving forward 2.
Moving back 17.
Interpreter stopped.