CS536 Programming Assignment 3

Due by Oct 25, 2021 at 11pm.

Overview

For this assignment you will use the parser-generator Java Cup to write a parser for the b language. The parser will find syntax errors and, for syntactically correct programs, it will build an abstract-syntax tree (AST) representation of the program. You will also write methods to unparse the AST built by your parser and an input file to test your parser. A main program, P3.java, that calls the parser and then the unparser is provided for you to use. You will be graded on the correctness of your parser and your unparse methods and on how thoroughly your input file tests the parser. In particular, you should write an input file that causes the action associated with every grammar rule in your Java CUP specification to be executed at least once.

Specifications

Getting Started

Skeleton files on which you should build are in the following zip file:

p3.zip contains all files below.

Here is a link to the Java CUP reference manual. There is also a link in the "Tools" section of the "Quick Links" menu on the course website.

Operator Precedences and Associativities

The b grammar in the file b.grammar is ambiguous; it does not uniquely define the precedences and associativities of the arithmetic, relational, equality, and logical operators. You will need to add appropriate precedence and associativity declarations to your Java CUP specification.

Note that the same token (MINUS) is used for both the unary and binary minus operator, and that they have different precedences; however, the b grammar has been written so that the unary minus operator has the correct (highest) precedence; therefore, you can declare MINUS to have the precedence appropriate for the binary minus operator.

Java Cup will print a message telling you how many conflicts it found in your grammar. If the number is not zero, it means that your grammar is still ambiguous and the parser is unlikely to work correctly. Do not ignore this! Go back and fix your specification so that your grammar is not ambiguous.

Building an Abstract-Syntax Tree

To make your parser build an abstract-syntax tree, you must add new productions, declarations, and actions to b.cup. You will need to decide, for each nonterminal that you add, what type its associated value should have. Then you must add the appropriate nonterminal declaration to the specification. For most nonterminals, the value will either be some kind of tree node (a subclass of ASTnode) or a LinkedList of some kind of node (use the information in ast.java to guide your decision). Note that you cannot use parameterized types for the types of nonterminals; so if the translation of a nonterminal is a LinkedList of some kind of node, you will have to declare its type as just plain LinkedList.

You must also add actions to each new grammar production that you add to b.cup. Make sure that each action ends by assigning an appropriate value to RESULT. Note that the parser will return a Symbol whose value field contains the value assigned to RESULT in the production for the root nonterminal (nonterminal program).

Unparsing

To test your parser, you must write the unparse methods for the subclasses of ASTnode (in the file ast.java). When the unparse method of the root node of the program's abstract-syntax tree is called, it should print a nicely formatted version of the program (this is called unparsing the abstract-syntax tree). The output produced by calling unparse should be the same as the input to the parser except that:

  1. There will be no comments in the output.
  2. The output will be "pretty printed" (newlines and indentation will be used to make the program readable); and
  3. Expressions will be fully parenthesized to reflect the order of evaluation.

For example, if the input program includes:

if (b == -1) { x = 4+3*5-y; while (c) { y = y*2+x; } } else { x = 0; }

the output of unparse should be something like the following:

if ((b == (-1))) {
    x = ((4 + (3 * 5)) - y);
    while (c) {
        y = ((y * 2) + x);
    }
}
else {
    x = 0;
}

To make grading easier, put open curly braces on the same line as the preceding code and put closing curly braces on a line with no other code (as in the example above). Put the first statement in the body of an if or while on the line following the open curly brace. Whitespace within a line is up to you (as long as it looks reasonable).

Note: Trying to unparse a tree will help you determine whether you have built the tree correctly in the first place. Besides looking at the output of your unparser, you should try using it as the input to your parser; if it doesn't parse, you've made a mistake either in how you built your abstract-syntax tree or in how you've written your unparser.

It is a good idea to work incrementally (see Suggestions for How to Work on This Assignment below for more detailed suggestions):

Modifying ast.java (IMPORTANT)

We will test your program by using our unparse methods on your abstract-syntax trees and by using your unparse methods on our abstract-syntax trees. To make this work, you will need to:

  1. Modify ast.java only by filling in the bodies of the unparse methods (and you must fill in all of the method bodies).
  2. Make sure that no field is null (i.e., when you call the constructor of a class with a LinkedList argument, that argument should never be null). The only two exceptions to these are ReturnStmtNode and CallExpNode; it is OK to make the ExpNode field of a ReturnStmtNode null (when no value is returned), likewise for the ExpListNode field of a CallExpNode (when the call has no arguments). Thus, you shouldn't be checking to see if a field is null or not, other than in these two nodes.
  3. Follow the convention that the mySize field of a VarDeclNode has the value VarDeclNode.NOT_STRUCT if the type of the declared variable is a non-struct type.

Testing

Part of your task will be to write an input file called test.b that thoroughly tests your parser and your unparser. You should be sure to include code that corresponds to every grammar rule in the file b.grammar.

Note that since you are to provide only one input file, test.b should contain no syntax errors (you should also test your parser on some bad inputs, but don't hand those in).

You will probably find it helpful to use comments in test.b to explain what aspects of the parser are being tested, but your testing grade will depend only on how thoroughly the file tests the parser.

Suggestions for How to Work on This Assignment

This assignment involves three main tasks:

  1. Writing the parser specification (b.cup).
  2. Writing the unparse methods for the AST nodes (in ast.java).
  3. Writing an input file (test.b) to test your implementation.

If you work with a partner, it is a good idea to share responsibility for all tasks to ensure that both partners understand all aspects of the assignment.

I suggest that you proceed as follows, testing your parser after each change (if you are working alone, I still suggest that you follow the basic steps outlined below, just do them all yourself):

If you worked alone on the previous program and are now working with a partner, see programming assignment 2 for more suggestions on how to work in pairs.

Handing in

Please read the following handing in instructions carefully. You will need to submit all the files in the entire working folder as a compressed zip file as given below.

lastname.firstname.lastname.firstname.P3.zip
+---+ deps/
+---+ ast.java
+---+ b.cup
+---+ b.grammar
+---+ b.jlex
+---+ ErrMsg.java
+---+ Makefile
+---+ P3.java
+---+ test.b
+---+ lastname.firstname.lastname.firstname.P3.pdf

Please ensure that you do not include any extra sub-directories.

If you are working in a pair, have only one member submit the program. Include both persons' name as given above. Also, mention the teammate's name as a comment while submitting the assignment on canvas.

If you are working by yourself, submit the program with only your name in the zip and pdf files.

Grading criteria

General information on program grading criteria can be found on the Assignments page).

For more advice on Java programming style, see Code Conventions for the Java Programming Language. See also the style and commenting standards used in CS 302 and CS 367.