1. What makes a grammar ambiguous?

  2. What is the difference between operator precedence and operator associativity?

  3. Can the following grammar be parsed by a top-down parser (i.e., is it LL(1))? Why or why not?
    G -> S $$
    S -> A M | A
    M -> S
    A -> a E | b A A | a
    E -> a B | B A
    B -> b E | a B B | b 
    
  4. For the following grammar, list the a) non-terminal symbols, and b) terminal symbols.

  5. For each non-terminal in the above grammar for declarations, list:

    1. The First set
    2. The Follow set

    For each production in the above grammar for declarations, list

    1. The Predict set for that production

  6. Can the above grammar for declarations be parsed by a top-down parser (i.e., is it LL(1))? Why or why not?

  7. Re-write the above declarations grammar so that it is not left recursive. You only need to re-write the left recursive production.

  8. Extend the prefix expression tree parser that you wrote in the previous assignment so that it builds expression trees for each of the expressions input by the user. As in the previous assignment, name your Antlr grammar Prefix.g and place it in a package named formula. You should modify the expression tree classes that either you or I wrote in previous assignments to construct your expression trees.

    You should still use an interactive interpreter that reads lines one at a time. Instead of having your code parse the input it should now call your Antlr parser to parse the input. Your Antlr parser should build an expression tree as it recognizes productions and then store the expression tree in an appropriate instance variable in your expression tree class.

    You will need to create a new instance of your parser for each line of input since the parser wants to read to the end of the input in order to fully recognize a string. To get the parser and lexer to read from your string instead of from stdin you will need to pass an instance of a StringReader class to your lexer. Here is an example of how your interactive interpreter might look (you will need to insert this method into a driver class):

    void execute() {
            java.util.Scanner input = new java.util.Scanner(System.in);
            PrefixParser expParser;
            PrefixLexer lex;
            Exp tree; // My top-level class for expression trees was
                           // called Exp
    
            while (true) {
                try {
                    System.out.print(">>> ");
                    // 1. Read a line of input, wrap it in a StringReader object, and
                    //    wrap the StringReader object in an ANTLRReaderStream object.
                    // 2. Finally create a lexer for that one line of input.
                    // 3. Note that nextLine() removes the newline character so we
                    //    must add it back so that our parser can determine when
                    //    an expression has legitimately ended
                    lex = new PrefixLexer(new ANTLRReaderStream(new StringReader(input.nextLine() + "\n")));
                    CommonTokenStream tokens = new CommonTokenStream(lex);
                    // Parse the one line of input and return an expression tree
                    expParser = new PrefixParser(tokens);
    
                    // my grammar had pgm as the start non-terminal
                    tree = expParser.pgm(); 
    
                    // Evaluate the expression tree
                    System.out.printf("%3.2f\n", tree.eval());
                } catch (RecognitionException e) {
                    e.printStackTrace();
                } catch (java.util.NoSuchElementException e) { break; }
                catch (Exception e) {System.out.println(e);}
            }
        }
    

    When you have completed this exercise your code should be much simpler than it was when you hand-parsed each statement.

    Hints

    1. You will need to move the declaration for the hash table you use to store variables and their values to ExpressionTree from your parser. The reason is that if you keep it in your parser, each new instantiation of the parser will create a new hash table, rather than use the pre-existing hash table. You should declare the hash table as static in ExpressionTree, so that all of your classes can access it.
    2. Your stmt non-terminal should return an Exp object and you should create an AssignNode class (or some comparably named class that is consistent with your naming nomenclature) that is a subclass of Exp to handle assignment statements.

What to Submit

You should submit a jar file named hw6.jar that contains the following files:

  1. A file named hw6.txt or hw6.pdf with your solutions to problems 1-7,
  2. Your Prefix.g grammar file
  3. Your java source and class files
  4. A manifest.txt file that contains the following two lines:
    Main-Class: Your Problem 8 Driver Class Name
    Class-Path: /usr/share/java/antlr3.jar
    
We want to be able to type "java hw6.jar" and have it execute your prefix expression interpreter.