Project 2: Decaf Parser
Due: Sunday, March 3, 2013 at 11:59pm

Description

The lexer from Project 1 must return appropriate token types for each terminal in the language.

The parser that you are creating for Project 2 should encode the grammar rules of Decaf as specified below.

The semantic actions of the parser should construct an AST.

Decaf Grammar

x     (in bold) means that x is a terminal

x             means x is a nonterminal.

<x>        means zero or one occurrence of x, i.e., x is optional

x*           means zero or more occurrences of x

x+           means one or more occurrences of x

x+,        a comma-separated list of one or more x’s (commas appear only between x’s)

|             separates production alternatives

 

Program       ::=    Decl+

Decl          ::=    VariableDecl | FunctionDecl | ClassDecl | InterfaceDecl

VariableDecl  ::=    Variable ;

Variable      ::=    Type ident

Type          ::=    int | double | bool | string | ident | Type [ ]

FunctionDecl ::=    Type ident ( Formals ) StmtBlock |

void ident ( Formals ) StmtBlock

Formals       ::=    Variable+, | ε

ClassDecl     ::=    class ident < extends ident> <implements ident+,> { Field* }

Field         ::=    VariableDecl | FunctionDecl

InterfaceDecl::=     interface ident { Prototype* }

Prototype     ::=    Type ident ( Formals ) ; | void ident ( Formals ) ;

StmtBlock     ::=    { VariableDecl* Stmt* }

Stmt          ::=    <Expr>; | IfStmt | WhileStmt | ForStmt | BreakStmt |

ReturnStmt | PrintStmt | StmtBlock

IfStmt        ::=    if ( Expr ) Stmt <else Stmt>

WhileStmt     ::=    while ( Expr ) Stmt

ForStmt       ::=    for ( <Expr>; <Expr> ; <Expr> ) Stmt

ReturnStmt    ::=    return <Expr> ;

BreakStmt     ::=    break ;

PrintStmt     ::=    Print ( Expr+, ) ;

Expr          ::=    LValue = Expr | Constant | LValue | this | Call | ( Expr ) |

Expr + Expr | Expr - Expr | Expr * Expr | Expr / Expr |

Expr % Expr | - Expr | Expr < Expr | Expr <= Expr |

Expr > Expr | Expr >= Expr | Expr == Expr | Expr != Expr |

Expr && Expr | Expr || Expr | !Expr | ReadInteger ( ) |

ReadLine ( ) | New ( ident ) | NewArray ( Expr , Type )

LValue        ::=    ident | Expr . ident | Expr [ Expr ]

Call          ::=    ident ( Actuals ) | Expr . ident ( Actuals )

Actuals       ::=    Expr+, | ε

Constant      ::=    intConstant | doubleConstant | boolConstant |

stringConstant | null

Operators

Precedence from highest to lowest:

[ .         array indexing and field selection

! -         unary minus, logical not

* / %       multiply, divide, mod

+ -         addition, subtraction

< <= > >=   relational

== !=       equality

&&          logical and

||          logical or

=           assignment

 

All binary arithmetic operators and both binary logical operators are left-associative. Assignment and the relational operators do not associate (i.e. you cannot chain a sequence of these operators that are at the same precedence level: a < b >= c should not parse, however a < b == c is okay). Parentheses may be used to override the precedence and/or associativity.

Abstract Syntax Tree

Each terminal and nonterminal that conveys meaning (that is, punctuation excluded) should have a node type that can be combined into an AST. For instance, an IfStatementNode should have an Expression node and a Statement node as children. You may wish to have another child that is the else Statement node, which could be NULL.

Nodes representing terminals with values (integers, strings, identifiers) should have the value of the token in them. You will also want space for the line and column numbers for the error handing in the next part of the project, although you can wait until then to add it.

Have the semantic actions of your parser build an AST with a Program node as a root. Nodes should be a class hierarchy in Java and structs (possibly with a type enumeration instead of different struct names). You will then need to write a traversal of the AST that does the following.

Pretty Printer

After the parser returns the completed AST, turn the AST back into nicely formatted Decaf code. Use tab indentation and spaces around each operator, value, and identifier. This means that the input and output of your parser are identical except for whitespace and comments (which were discarded in the lexer and are not available to the parser).

Requirements

·         Use JavaCUP or bison to implement a parser and construct an AST

·         For this project, you may assume valid Decaf programs. Your next project will focus on finding and reporting lexing, parsing, and type checking errors.

Submission

By the deadline, you need to submit:

1.       Your JFlex or flex file containing your lexer

2.       Your JavaCUP or bison file containing your parser

3.       Your Java or C files containing main() and any auxiliary files you have used for your AST

4.       A pretty printer that traverses your AST

5.       A Makefile to build it all

6.       A README text file describing how to run it

7.       3 or more valid Decaf programs of your own creation to test your parser on.

Create a zip file of the above files and copy to

/afs/cs.pitt.edu/usr/jmisurda/submit/2210