CS 214: Programming Languages
Spring 2009

Home|Syllabus|Schedule
<<|>>|ANTLR API|CITkit API|PolyD API|EasyMock API

String (and Integers)
Interpreters, Iteration 4

User Story

User Story #4: Interpreter evaluates a string.

A Hobbes program can be a single string in double quotes. The interpreter prints the value of the string without the quotes.

Examples:

"This is a string"

and

"So is this!!!"

They evaluate to This is a string and So it this!!!, respectively.

You need to do this in addition to interpreting an integer.

The procedural solution is a bit tricky because input strings will be written like "hello", complete with the double quotes. The ASTs that you get back from the parser will still have the double quotes, and you'll have to handle them. (The object-oriented solution uses the TIR builder, a step beyond the parser, and the TIR builder takes off the double quotes for you.)

The object-oriented solution is easy. You'll change one word in your existing code (and write a couple of tests). Don't worry: the object-oriented solution will be more interesting in the next iteration.

Procedural Solution

Compare and contrast with the existing createIntegerAST(String).

Your procedural solution receives an AST, and it's supposed to return a String result. You can easily build STRING ASTs:

Create a new method createStringAST(String) which returns a new ANTLR AST of type HobbesParser.STRING.

This will allow you to easily create assertions for STRING ASTs.

Create a new test method shouldInterpretStrings(). Compile, and green bar.

You can't written any assertions yet, so the code should still green bar.

Here's an assertion:

assertEquals("abc123", myInterpreter.interpret(createStringAST("\"abc123\"")));

Note the double quotes around the actual string. Your interpreter has to strip these double quotes away.

Add this assertion to the test method, write two more, compile, and red bar.

You should get a complaint about the double quotes. What you already have for the interpret(Tree) method should return something for a STRING, except for those double quotes.

So turn your attention to ProceduralInterpreter#interpret(Tree). Just returning the text of the AST is correct for an INTEGER, and you do not want to lose this. However, you have to do something different for a STRING.

This is an integer value being compared for equality. This is why C included the switch statement. It doesn't explain why Java has it, except for procedural demonstrations like this.

You need to make a decision based on the type of the AST. With a procedural approach, the right way to do this is to get the AST's type from the AST itself. Not too surprisingly, ANTLR gives us a getType() method for Trees. This returns an int which can be compared against constants that ANTLR defined in the grammar: HobbesParser.INTEGER and HobbesParser.STRING.

So I could write code like this if I just needed some feedback:

switch (tree.getType()) {
case HobbesParser.INTEGER:
  return "this is an integer";
case HobbesParser.STRING:
  return "this is a string";
default:
  throw new IllegalArgumentException(tree.getType() + " is unrecognized");
}

Based on the type of the AST (in tree, of type Tree), I decide which feedback message to return. If I need to do more work for one or the other, I just add more code for that case. The throw clause is helpful for debugging purposes. (Hopefully, you never need it, but if it ever gets triggered, it can save you a lot of time debugging.)

Use a switch statement in interpret(Tree) to decide between INTEGER and STRING as in the code above. Use the old body of the method for the INTEGER case. Do not write anything for the STRING case yet. Do include a default case as above. Compile, and different red bar.

You should get the thrown exception causing the red bar. (The old integer tests should still pass!) If you look at the stack trace in the exception report from JUnit, you should be able to track the problem from the specific assertion that failed all the way back to the specific line of code that threw the exception. So you know where to fix the problem!

Add a case for STRING. Start with just returning the text from the tree unchanged. Compile, and original red bar.

The fix is to do some string manipulation. The String class has methods length() and substring(start, end) which you'll find handy. It won't be pretty.

Complete the STRING case. Compile, and green bar.

Try your procedural driver!

Write a couple Hobbes programs, and run the procedural driver over them.

Object-Oriented Solution

The object-oriented solution turns out to be really easy.

@Test
public void shouldInterpretStrings() {
        assertEquals("foo", myInterpreter.interpret(new StringETIR("foo")));
}

Add this test method to OOHobbesInterpterTest. Compile fails.

The compile fails because OOHobbesInterpreter#interpret(IntegerETIR) takes an IntegerETIR as an argument. You're giving it a StringETIR here. This being an object-oriented solution, you should imagine that the solution involves inheritance. Both IntegerETIR and StringETIR implement an interface named ExpressionTIR.

Change interpret(IntegerETIR) to be interpret(ExpressionTIR). Compile, and green bar!

It turns out, in this case, that you could go as high as Object for this parameter's type because the only method you're calling is Object#toString(). And that method has been overridden in the ways you want for both IntegerETIR and StringETIR.

Add two more assertions to shouldInterpretStrings(). Compile, and green bar.

Run your object-oriented driver over string programs, too.

At first, the driver will fail, but you can fix this by removing the (IntegerETIR) cast.