CIT 594 Errata #1 for Bugs Grammar (and Code)
Spring 2008, David Matuszek


Since I make up a different language each time I teach CIT594, it is inevitable that there will be corrections as we go along. This is the first such set of corrections. Don't let the size of this page worry you--the corrections are actually pretty minor.

I have made these corrections to the Bugs Grammar file and the relevant source code files. Hence, if you look at the files online, these corrections should already be there.
As you write the Recognizer methods, you will find yourself writing a lot of similar code. Some of this is inevitable, since you have to capture all the definitions in the grammar, and they are all BNF. However, you can save yourself a lot of typing if you can invent some helper methods that let you abbreviate in a typical method. This is even more true in the RecognizerTest class.

The isFactor() method needs to be updated to allow a function call as a factor. This was in the grammar but not in the code.

In addition, I said in The "Bugs" Language that a Bug could access the variables of another Bug, with dot notation. However, I forgot to add this to the grammar. That, too, goes into the isFactor() method.
Was:
<factor> ::= <function call>
           | <variable>
           | <NUMBER>
           | "(" <expression> ")"
Now:
<factor> ::= <variable> "." <variable>
           | <function call>
           | <variable>
           | <NUMBER>
           | "(" <expression> ")"
It is tempting to support function calls by adding if (isFunctionCall()) return true; as the first line of the isFactor() method. If you can figure out why this doesn't work, you have a pretty good understanding of recursive descent!

In addition, a Factor should be an Expression enclosed in parentheses, not just an ArithmeticExpression enclosed in parentheses.
Was:
public boolean isFactor() {
    if (isVariable());
    if (number()) return true;
    if (symbol("(")) {
        if (!isArithmeticExpression()) error("Error in parenthesized expression");
        if (!symbol(")")) error("Unclosed parenthetical expression");
        return true;
   }
   return false;
}
Now:
public boolean isFactor() {
    if (isVariable()) {
        if (symbol(".")) {  // reference to another Bug
if (name()) return true;
else error("Incorrect use of dot notation");
} else if (isParameterList()) return true; // function call else return true; // just a variable }
if (number()) return true; if (symbol("(")) { if (!isExpression()) error("Error in parenthesized expression"); if (!symbol(")")) error("Unclosed parenthetical expression"); return true; } return false; }

I upgraded the Tokenizer to distinguish between keywords and other names, and then I added several color names to the list of keywords, but I missed the following:

Was:
<color statement> ::= "color" <NAME> <eol>
Now:
<color statement> ::= "color" <KEYWORD> <eol>

Since <parameter list> is defined appropriately, the definition of <do statement> can be simplified. This doesn't change what is accepted by the grammar.

Was:
<do statement> ::= "do" <variable> [ "(" <expression> { "," <expression> } ")" ] <eol>
Now:
<do statement> ::= "do" <variable> [ <parameter list> ] <eol>

I made isParameterList() private, then found an error in it. So I made it public and wrote a test for it.

Was:
private boolean isParameterList() {
    if (!symbol("(")) return false;
    if (isExpression()) {
        while (symbol(",")) {
            if (!isExpression()) error("No expression after ','");
        }
        if (!symbol(")")) error("Parameter list doesn't end with ')'");
    }
    return true;
}
Now:
public boolean isParameterList() {
    if (!symbol("(")) return false;
    if (isExpression()) {
        while (symbol(",")) {
            if (!isExpression()) error("No expression after ','");
        }
    }
    if (!symbol(")")) error("Parameter list doesn't end with ')'");
    return true;
}
Test:
@Test
public void testIsParameterList() {
    Recognizer r = new Recognizer("() $");
    assertTrue(r.isParameterList()); followedBy(r, "$");
    r = new Recognizer("(5) $");
    assertTrue(r.isParameterList()); followedBy(r, "$");
    r = new Recognizer("(bar, x+3) $");
    assertTrue(r.isParameterList()); followedBy(r, "$");
}

The <moveto action> is supposed to move this Bug to the specified x, y location, hence it needs two numbers, not just one.

Was:
<moveto action> ::= "moveto" <expression> <eol>
Now:
<moveto action> ::= "moveto" <expression> "," <expression> <eol>