// Copyright 2012- Bill Campbell, Swami Iyer and Bahar Akbal-Delibas // Edited by Steven Carr for CS451 Compilers+ // Last Edited: March 27th 2024 /** * This is the input file to JavaCC for generating a scanner and a parser for j--. From the * specification in this file, JavaCC generates, among other files, a JavaCCParser.java program * (the parser) and a JavaCCParserTokenManager.java program (the scanner). */ PARSER_BEGIN(JavaCCParser) package jminusminus; import java.util.ArrayList; /** * Parser generated by JavaCC. It parses a j-- compilation unit (program file), taking tokens from * the scanner (also generated by JavaCC), and produces an abstract syntax tree (AST) for it. */ class JavaCCParser { // Whether a parser error has been found. private boolean errorHasOccurred; // Name of the file that is parsed. private String fileName; /** * Sets the name of the file being parsed. * * @param fileName name of the file being parsed. */ public void fileName(String fileName) { this.fileName = fileName; } /** * Returns {@code true} if a parser error has occurred up to now, and {@code false} otherwise. * * @return {@code true} if a parser error has occurred up to now, and {@code false} otherwise. */ public boolean errorHasOccurred() { return errorHasOccurred; } // Pulls out and returns the ambiguous part of a name. private AmbiguousName ambiguousPart(TypeName name) { String qualifiedName = name.toString(); int i = qualifiedName.lastIndexOf('.'); return i == -1 ? null : new AmbiguousName(name.line(), qualifiedName.substring(0, i)); } // Reports a syntax error. private void reportParserError(String message, Object... args) { errorHasOccurred = true; System.err.printf("%s:%d: error: ", fileName, token.beginLine); System.err.printf(message, args); System.err.println(); } // Recover from the parser error that occurred by skipping to any of the specified tokens. // Current error recovery mechanism is rather simple-minded and is based on skipping all the // tokens until a SEMI or an EOF is encountered. This scheme can be enhanced by passing in the // FOLLOW-SET of the non-terminal at hand. private void recoverFromError(int[] skipTo, ParseException e) { // Get the possible expected tokens. StringBuffer expected = new StringBuffer(); for (int i = 0; i < e.expectedTokenSequences.length; i++) { for (int j = 0; j < e.expectedTokenSequences[i].length; j++) { expected.append("\n"); expected.append(" "); expected.append(tokenImage[e.expectedTokenSequences[i][j]]); expected.append("..."); } } // Print error message. if (e.expectedTokenSequences.length == 1) { reportParserError("\"%s\" found where %s sought", getToken(1), expected); } else { reportParserError("\"%s\" found where one of %s sought", getToken(1), expected); } // Recover. boolean loop = true; do { token = getNextToken(); for (int i = 0; i < skipTo.length; i++) { if (token.kind == skipTo[i]) { loop = false; break; } } } while(loop); } } PARSER_END(JavaCCParser) ///////////////////////////////////////////////////////// // The j-- lexical grammar starts here // ///////////////////////////////////////////////////////// // Whitespace -- ignored SKIP: { " " | "\t" | "\n" | "\r" | "\f" } // Single line comment -- ignored SKIP: { : IN_SINGLE_LINE_COMMENT } SKIP: { : DEFAULT } SKIP: { } // Multi line comment -- ignored -> Added for project4 SKIP: { : IN_MULTILINE_COMMENT } SKIP: { } SKIP: { : DEFAULT } // Reserved words // Added for project4: break, case, catch, continue, default, do, // double, finally, for, implements, interface, long // switch, throw, throws, try TOKEN: { | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | } // Separators TOKEN: { | | | | | | | | } // Operators // Added for project4: ?, :, ~, !=, /, /=, -=, *=, %, %=, // >>, >>=, >>>, >>>=, >=, <<, <<=, <, ^, ^=, // |, |=, ||, &, &= TOKEN: { | | >"> | >="> | | | | | | ="> | "> | | | | | >>"> | >>="> | | | | | | | | | | | | "_" | "$" )*> | <#LETTER: [ "a"-"z", "A"-"Z" ]> | <#DIGIT: [ "0"-"9" ]> } // Literals // Added for project4: long and double literals TOKEN: { ( )*> | ( "l" | "L" )> | > | | "." ( )? ( )? ( )? | "." ( )? ( )? | ( )? | ( )? > | | ~[ "'", "\\" ] ) "'"> | | ~[ "\"", "\\" ] )* "\""> | <#ESC: "\\" [ "n", "t", "b", "r", "f", "\\", "'", "\"" ]> } // For anything else, we return an ERROR token. Without this definition the TokenManager will throw // an Error when a lexical error occurs, making it impossible to recover from it. So we define this // ERROR token. TOKEN: { } ///////////////////////////////////////////////////////// // The j-- syntactic grammar starts here // ///////////////////////////////////////////////////////// /** * Parses a compilation unit (a program file) and returns an AST for it. * *
 *   compilationUnit ::= [ PACKAGE qualifiedIdentifier SEMI ]
 *                       { IMPORT  qualifiedIdentifier SEMI }
 *                       { typeDeclaration }
 *                       EOF
 * 
* * @return an AST for a compilation unit. */ public JCompilationUnit compilationUnit(): { int line = 0; TypeName packageName = null; TypeName anImport = null; ArrayList imports = new ArrayList(); JAST aTypeDeclaration = null; ArrayList typeDeclarations = new ArrayList(); } { try { [ { line = token.beginLine; } packageName = qualifiedIdentifier() ] ( { line = line == 0 ? token.beginLine : line; } anImport = qualifiedIdentifier() { imports.add(anImport); } )* ( aTypeDeclaration = typeDeclaration() { line = line == 0 ? aTypeDeclaration.line() : line; typeDeclarations.add(aTypeDeclaration); } )* { line = line == 0 ? token.beginLine : line; } } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return new JCompilationUnit(fileName, line, packageName, imports, typeDeclarations); } } /** * Parses and returns a qualified identifier. * *
 *   qualifiedIdentifier ::= IDENTIFIER { DOT IDENTIFIER }
 * 
* * @return a qualified identifier. */ private TypeName qualifiedIdentifier(): { int line = 0; String qualifiedIdentifier = ""; } { try { { line = token.beginLine; qualifiedIdentifier = token.image; } ( // Lookahead added to suppress JavaCC warnings. LOOKAHEAD( ) { qualifiedIdentifier += "." + token.image; } )* } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return new TypeName(line, qualifiedIdentifier); } } /** * Parses a type declaration and returns an AST for it. * *
 *   typeDeclaration ::= modifiers classDeclaration
 * 
* * @return an AST for a type declaration. */ private JAST typeDeclaration(): { ArrayList mods = null; JAST classDeclaration = null; } { try { mods = modifiers() classDeclaration = classDeclaration(mods) } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return classDeclaration; } } /** * Parses and returns a list of modifiers. * *
 *   modifiers ::= { ABSTRACT | PRIVATE | PROTECTED | PUBLIC | STATIC }
 * 
* * @return a list of modifiers. */ private ArrayList modifiers(): { ArrayList mods = new ArrayList(); boolean scannedPUBLIC = false; boolean scannedPROTECTED = false; boolean scannedPRIVATE = false; boolean scannedSTATIC = false; boolean scannedABSTRACT = false; } { try { ( { mods.add("abstract"); if (scannedABSTRACT) { reportParserError("Repeated modifier: abstract"); } scannedABSTRACT = true; } | { mods.add("private"); if (scannedPRIVATE) { reportParserError("Repeated modifier: private"); } if (scannedPUBLIC || scannedPROTECTED) { reportParserError("Access conflict in modifiers"); } scannedPRIVATE = true; } | { mods.add("protected"); if (scannedPROTECTED) { reportParserError("Repeated modifier: protected"); } if (scannedPUBLIC || scannedPRIVATE) { reportParserError("Access conflict in modifiers"); } scannedPROTECTED = true; } | { mods.add("public"); if (scannedPUBLIC) { reportParserError("Repeated modifier: public"); } if (scannedPROTECTED || scannedPRIVATE) { reportParserError("Access conflict in modifiers"); } scannedPUBLIC = true; } | { mods.add("static"); if (scannedSTATIC) { reportParserError("Repeated modifier: static"); } scannedSTATIC = true; } )* } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return mods; } } /** * Parses a class declaration and returns an AST for it. * *
 *   classDeclaration ::= CLASS IDENTIFIER [ EXTENDS qualifiedIdentifier ] classBody
 * 
* * @param mods the class modifiers. * @return an AST for a class declaration. */ private JClassDeclaration classDeclaration(ArrayList mods): { int line = 0; String name = ""; Type superClass = Type.OBJECT; ArrayList classBody = null; } { try { { line = token.beginLine; } { name = token.image; } [ superClass = qualifiedIdentifier() ] classBody = classBody() } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return new JClassDeclaration(line, mods, name, superClass, null, classBody); } } /** * Parses a class body and returns a list of members in the body. * *
 *   classBody ::= LCURLY { modifiers memberDecl } RCURLY
 * 
* * @return a list of members in the class body. */ private ArrayList classBody(): { ArrayList mods = null; JMember aMember = null; ArrayList members = new ArrayList(); } { try { ( mods = modifiers() aMember = memberDecl(mods) { members.add(aMember); } )* } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return members; } } /** * Parses a member declaration and returns an AST for it. * * Added THROWS for project4 *
 *   memberDecl ::= IDENTIFIER formalParameters [ THROWS qualifiedIdentifier { COMMA qualifiedIdentifier } ] block
 *                | ( VOID | type ) IDENTIFIER formalParameters
                        [ THROWS qualifiedIdentifier { COMMA qualifiedIdentifier } ] ( block | SEMI )
 *                | type variableDeclarators SEMI
 * 
* * @param mods the class member modifiers. * @return an AST for a member declaration. */ private JMember memberDecl(ArrayList mods): { int line = 0; Type type = null; String name = ""; ArrayList params = null; JBlock body = null; ArrayList variableDeclarators = null; JMember memberDecl = null; ArrayList exceptions = null; TypeName qualifiedID = null; } { try { LOOKAHEAD( ) ( { line = token.beginLine; name = token.image; } params = formalParameters() [ { exceptions = new ArrayList(); } qualifiedID = qualifiedIdentifier() { exceptions.add(qualifiedID); } ( qualifiedID = qualifiedIdentifier() { exceptions.add(qualifiedID); } )* ] body = block() { memberDecl = new JConstructorDeclaration(line, mods, name, params, exceptions, body); } ) | LOOKAHEAD(( | type()) ) ( ( { type = Type.VOID; } | type = type() ) { line = token.beginLine; } { name = token.image; } params = formalParameters() [ { exceptions = new ArrayList(); } qualifiedID = qualifiedIdentifier() { exceptions.add(qualifiedID); } ( qualifiedID = qualifiedIdentifier() { exceptions.add(qualifiedID); } )* ] ( body = block() | ) { memberDecl = new JMethodDeclaration(line, mods, name, type, params, exceptions, body); } ) | ( type = type() { line = token.beginLine; } variableDeclarators = variableDeclarators(type) { memberDecl = new JFieldDeclaration(line, mods, variableDeclarators); } ) } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return memberDecl; } } /** * Parses a block and returns an AST for it. * *
 *   block ::= LCURLY { blockStatement } RCURLY
 * 
* * @return an AST for a block. */ private JBlock block(): { int line = 0; JStatement aStatement = null; ArrayList statements = new ArrayList(); } { try { { line = token.beginLine; } ( aStatement = blockStatement() { statements.add(aStatement); } )* } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return new JBlock(line, statements); } } /** * Parses a block statement and returns an AST for it. * *
 *   blockStatement ::= localVariableDeclarationStatement
 *                    | statement
 * 
* * @return an AST for a block statement. */ private JStatement blockStatement(): { JStatement statement = null; } { try { LOOKAHEAD(type() ) statement = localVariableDeclarationStatement() | statement = statement() } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return statement; } } /** * Parses a statement and returns an AST for it. * Added for project4: Do statement, For statement, Break Statement, Switch Statement, Throw Statement * *
 *   statement ::= block
 *               | BREAK SEMI
 *               | CONTINUE SEMI
 *               | DO statement WHILE parExpression SEMI
 *               | FOR LPAREN [ forInit ] SEMI [ expression ] SEMI [ forUpdate ] RPAREN statement
 *               | IF parExpression statement [ ELSE statement ]
 *               | RETURN [ expression ] SEMI
 *               | SEMI
 *               | SWITCH parExpression LCURLY { switchBlockStatementGroup } RCURLY
 *               | THROW expression SEMI
 *               | WHILE parExpression statement
 *               | statementExpression SEMI
 * 
* * @return an AST for a statement. */ private JStatement statement(): { int line = 0; JStatement statement = null; JExpression test = null; JStatement consequent = null; JStatement alternate = null; JStatement body = null; JExpression expr = null; ArrayList inits = null; ArrayList updates = null; ArrayList switchBlockStmtGroup = null; SwitchStatementGroup switchStmtGrp = null; JBlock tryBlock = null; ArrayList params = null; ArrayList catchBlocks = null; JBlock cBlock = null; JFormalParameter parameter = null; JBlock finallyBlock = null; } { try { statement = block() | { line = token.beginLine; } { statement = new JBreakStatement(line); } | { line = token.beginLine; } { statement = new JContinueStatement(line); } | { line = token.beginLine; } body = statement() test = parExpression() { statement = new JDoStatement(line, body, test); } | { line = token.beginLine; } ( [ inits = forInit() ] [ expr = expression() ] [ updates = forUpdate() ] body = statement() ) { statement = new JForStatement(line, inits, expr, updates, body); } | { line = token.beginLine; } test = parExpression() consequent = statement() // Even without the lookahead below, which is added to suppress JavaCC warnings, dangling // if-else problem is resolved by binding the alternate to the closest consequent. [ LOOKAHEAD() alternate = statement() ] { statement = new JIfStatement(line, test, consequent, alternate); } | { line = token.beginLine; } [ expr = expression() ] { statement = new JReturnStatement(line, expr); } | { line = token.beginLine; statement = new JEmptyStatement( line ); } | { line = token.beginLine; switchBlockStmtGroup = new ArrayList(); } test = parExpression() ( switchStmtGrp = switchBlockStatementGroup() { switchBlockStmtGroup.add(switchStmtGrp); } )* { statement = new JSwitchStatement(line, test, switchBlockStmtGroup); } | { line = token.beginLine; } expr = expression() { statement = new JThrowStatement(line, expr); } | { line = token.beginLine; params = new ArrayList(); catchBlocks = new ArrayList(); } tryBlock = block() ( parameter = formalParameter() { params.add(parameter); } cBlock = block() { catchBlocks.add(cBlock); } )* [ finallyBlock = block() { return new JTryStatement(line, tryBlock, params, catchBlocks, finallyBlock); } ] { statement = new JTryStatement(line, tryBlock, params, catchBlocks, null); } | { line = token.beginLine; } test = parExpression() body = statement() { statement = new JWhileStatement(line, test, body); } | // Must be a statementExpression. statement = statementExpression() } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return statement; } } /** * Parses and returns a list of formal parameters. * *
 *   formalParameters ::= LPAREN [ formalParameter { COMMA  formalParameter } ] RPAREN
 * 
* * @return a list of formal parameters. */ private ArrayList formalParameters(): { ArrayList parameters = new ArrayList(); JFormalParameter aParameter = null; } { try { [ aParameter = formalParameter() { parameters.add(aParameter); } ( aParameter = formalParameter() { parameters.add(aParameter); } )* ] } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return parameters; } } /** * Parses a formal parameter and returns an AST for it. * *
 *   formalParameter ::= type IDENTIFIER
 * 
* * @return an AST for a formal parameter. */ private JFormalParameter formalParameter(): { int line = 0; Type type = null; String name = ""; } { try { type = type() { line = token.beginLine; } { name = token.image; } } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return new JFormalParameter(line, name, type); } } /** * Parses a parenthesized expression and returns an AST for it. * *
 *   parExpression ::= LPAREN expression RPAREN
 * 
* * @return an AST for a parenthesized expression. */ private JExpression parExpression(): { JExpression expr = null; } { try { expr = expression() } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return expr; } } /** * Added for project4 * Parses the initializations for a for loop. * *
 *   forInit ::= statementExpression { COMMA statementExpression }
 *             | type variableDeclarators
 * 
* * @return a list of initialization statements. */ private ArrayList forInit(): { int line = 0; ArrayList init = new ArrayList(); ArrayList vdecls = null; JStatement expr = null; Type type = null; } { try { LOOKAHEAD(statementExpression()) expr = statementExpression() { init.add(expr); } ( expr = statementExpression() { init.add(expr); } )* | ( type = type() vdecls = variableDeclarators(type) { line = token.beginLine; init.add(new JVariableDeclaration(line, vdecls)); } ) } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return init; } } /** * Added for project4 * Parses the update expressions for a for loop. * *
 *   forUpdate ::= statementExpression { COMMA statementExpression }
 * 
* * @return a list of update statements. */ private ArrayList forUpdate(): { ArrayList updates = new ArrayList(); JStatement expr = null; } { try { expr = statementExpression() { updates.add(expr); } ( expr = statementExpression() { updates.add(expr); } )* } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return updates; } } /** * Added for project4 * Parses a switch block statement group. * *
 *   switchBlockStatementGroup ::= switchLabel { switchLabel } { blockStatement }
 * 
* * @return an object that contains the labels and block statements. */ private SwitchStatementGroup switchBlockStatementGroup(): { ArrayList switchLabels = new ArrayList(); ArrayList blockStatements = new ArrayList(); JExpression swLabel = null; JStatement blockSt = null; } { try { swLabel = switchLabel() { switchLabels.add(swLabel); } ( swLabel = switchLabel() { switchLabels.add(swLabel); } | swLabel = switchLabel() { switchLabels.add(swLabel); } )* ( blockSt = blockStatement() { blockStatements.add(blockSt); } )* } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return new SwitchStatementGroup(switchLabels, blockStatements); } } /** * Added for project4 * Parses a switch label. * *
  *   switchLabel ::= CASE expression COLON
  *                 | DEFLT COLON
  * 
* * @return the expression for the case label or null for the default label. */ private JExpression switchLabel(): { JExpression expr = null; } { try { expr = expression() | } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return expr; } } /** * Parses a local variable declaration statement and returns an AST for it. * *
 *   localVariableDeclarationStatement ::= type variableDeclarators SEMI
 * 
* * @return an AST for a local variable declaration statement. */ private JVariableDeclaration localVariableDeclarationStatement(): { int line = 0; Type type = null; ArrayList vdecls = null; } { try { type = type() { line = token.beginLine; } vdecls = variableDeclarators(type) } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return new JVariableDeclaration(line, vdecls); } } /** * Parses and returns a list of variable declarators. * *
 *   variableDeclarators ::= variableDeclarator { COMMA variableDeclarator }
 * 
* * @param type type of the variables. * @return a list of variable declarators. */ private ArrayList variableDeclarators(Type type): { JVariableDeclarator aVariableDeclarator = null; ArrayList variableDeclarators = new ArrayList(); } { try { aVariableDeclarator = variableDeclarator(type) { variableDeclarators.add(aVariableDeclarator); } ( aVariableDeclarator = variableDeclarator(type) { variableDeclarators.add(aVariableDeclarator); } )* } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return variableDeclarators; } } /** * Parses a variable declarator and returns an AST for it. * *
 *   variableDeclarator ::= IDENTIFIER [ ASSIGN variableInitializer ]
 * 
* * @param type type of the variable. * @return an AST for a variable declarator. */ private JVariableDeclarator variableDeclarator(Type type): { int line = 0; JExpression initial = null; String name = ""; } { try { { line = token.beginLine; name = token.image; } [ initial = variableInitializer(type) ] } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return new JVariableDeclarator(line, name, type, initial); } } /** * Parses a variable initializer and returns an AST for it. * *
 *   variableInitializer ::= arrayInitializer | expression
 * 
* * @param type type of the variable. * @return an AST for a variable initializer. */ private JExpression variableInitializer(Type type): { JExpression initializer = null; } { try { initializer = arrayInitializer(type) | initializer = expression() } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return initializer; } } /** * Parses an array initializer and returns an AST for it. * *
 *   arrayInitializer ::= LCURLY [variableInitializer {COMMA variableInitializer} [COMMA]] RCURLY
 * 
* * @param type type of the array. * @return an AST for an array initializer. */ private JArrayInitializer arrayInitializer(Type type): { int line = 0; ArrayList initials = new ArrayList(); JExpression anInitializer = null; } { try { { line = token.beginLine; } [ anInitializer = variableInitializer(type.componentType()) { initials.add(anInitializer); } ( anInitializer = variableInitializer(type.componentType()) { initials.add(anInitializer); } )* ] } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return new JArrayInitializer(line, type, initials); } } /** * Parses and returns a list of arguments. * *
 *   arguments ::= LPAREN [ expression { COMMA expression } ] RPAREN
 * 
* * @return a list of arguments. */ private ArrayList arguments(): { ArrayList args = new ArrayList(); JExpression anExpression = null; } { try { [ anExpression = expression() { args.add(anExpression); } ( anExpression = expression() { args.add(anExpression); } )* ] } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return args; } } /** * Parses and returns a type. * *
 *   type ::= referenceType | basicType
 * 
* * @return a type. */ private Type type(): { Type type = null; } { try { LOOKAHEAD( | basicType() ) type = referenceType() | type = basicType() } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return type; } } /** * Parses and returns a basic type. * Added long and double basic types for project4 * *
 *   basicType ::= BOOLEAN | CHAR | DOUBLE | INT | LONG
 * 
* * @return a basic type. */ private Type basicType(): { Type type = Type.ANY; } { try { { type = Type.BOOLEAN; } | { type = Type.CHAR; } | { type = Type.DOUBLE; } | { type = Type.INT; } | { type = Type.LONG; } } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { if (type == Type.ANY) { reportParserError("Type sought where %s found", token.image); } return type; } } /** * Parses and returns a reference type. * *
 *   referenceType ::= basicType LBRACK RBRACK { LBRACK RBRACK }
 *                   | qualifiedIdentifier { LBRACK RBRACK }
 * 
* * @return a reference type. */ private Type referenceType(): { Type type = Type.ANY; } { try { type = basicType() { type = new ArrayTypeName(type); } ( { type = new ArrayTypeName(type); } )* | type = qualifiedIdentifier() ( { type = new ArrayTypeName(type); } )* } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return type; } } /** * Parses a statement expression and returns an AST for it. * *
 *   statementExpression ::= expression
 * 
* * @return an AST for a statement expression. */ private JStatement statementExpression(): { int line = 0; JExpression expr = null; } { try { expr = expression() { line = expr.line(); if (expr instanceof JAssignment || expr instanceof JPreIncrementOp || expr instanceof JPreDecrementOp || expr instanceof JPostIncrementOp || expr instanceof JPostDecrementOp || expr instanceof JMessageExpression || expr instanceof JSuperConstruction || expr instanceof JThisConstruction || expr instanceof JNewOp || expr instanceof JNewArrayOp) { // So as not to save on stack. expr.isStatementExpression = true; } else { reportParserError("Invalid statement expression; it does not have a side-effect"); } } } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return new JStatementExpression( line, expr ); } } /** * Parses an expression and returns an AST for it. * *
 *   expression ::= assignmentExpression
 * 
* * @return an AST for an expression. */ private JExpression expression(): { JExpression expr = null; } { try { expr = assignmentExpression() } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return expr; } } /** * Parses an assignment expression and returns an AST for it. * Added for project4: , , , , , , * , , , * *
 *   assignmentExpression ::= conditionalAndExpression
 *                                [ ( ASSIGN | PLUS_ASSIGN ) assignmentExpression ]
 * 
* * @return an AST for an assignment expression. */ private JExpression assignmentExpression(): { int line = 0; JExpression lhs = null, rhs = null; } { try { lhs = conditionalExpression() { line = lhs.line(); } [ rhs = assignmentExpression() { lhs = new JALeftShiftAssignOp(line, lhs, rhs); } | rhs = assignmentExpression() { lhs = new JAndAssignOp(line, lhs, rhs); } | rhs = assignmentExpression() { lhs = new JARightShiftAssignOp(line, lhs, rhs); } | rhs = assignmentExpression() { lhs = new JAssignOp(line, lhs, rhs); } | rhs = assignmentExpression() { lhs = new JDivAssignOp(line, lhs, rhs); } | rhs = assignmentExpression() { lhs = new JLRightShiftAssignOp(line, lhs, rhs); } | rhs = assignmentExpression() { lhs = new JMinusAssignOp(line, lhs, rhs); } | rhs = assignmentExpression() { lhs = new JOrAssignOp(line, lhs, rhs); } | rhs = assignmentExpression() { lhs = new JPlusAssignOp(line, lhs, rhs); } | rhs = assignmentExpression() { lhs = new JRemAssignOp(line, lhs, rhs); } | rhs = assignmentExpression() { lhs = new JStarAssignOp(line, lhs, rhs); } | rhs = assignmentExpression() { lhs = new JXorAssignOp(line, lhs, rhs); } ] } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return lhs; } } /** * Added for project4 * Parses a conditional expression and return an AST for it. * *
 *   conditionalExpression ::= conditionalOrExpression [ QUESTION expression COLON conditionalExpression ]
 * 
* * @return an AST for a conditional expression. */ private JExpression conditionalExpression(): { int line = 0; JExpression expr = null, thenPart = null, elsePart = null; } { try { expr = conditionalOrExpression() { line = expr.line(); } [ thenPart = expression() elsePart = conditionalExpression() { expr = new JConditionalExpression(line, expr, thenPart, elsePart); } ] } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return expr; } } /** * Added for project4 * Parses a conditional-or expression and returns an AST for it. * *
 *   conditionalOrExpression ::= conditionalAndExpression { LOR conditionalAndExpression }
 * 
* * @return an AST for a conditional-and expression. */ private JExpression conditionalOrExpression(): { int line = 0; JExpression lhs = null, rhs = null; } { try { lhs = conditionalAndExpression() { line = lhs.line(); } ( rhs = conditionalAndExpression() { lhs = new JLogicalOrOp(line, lhs, rhs); } )* } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return lhs; } } /** * Parses a conditional-and expression and returns an AST for it. * *
 *   conditionalAndExpression ::= inclusiveOrExpression { LAND inclusiveOrExpression }
 * 
* * @return an AST for a conditional-and expression. */ private JExpression conditionalAndExpression(): { int line = 0; JExpression lhs = null, rhs = null; } { try { lhs = inclusiveOrExpression() { line = lhs.line(); } ( rhs = inclusiveOrExpression() { lhs = new JLogicalAndOp(line, lhs, rhs); } )* } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return lhs; } } /** * Added for project4 * Parses an inclusive-or expression and returns an AST for it. * *
*   inclusiveOrExpression ::= exclusiveOrExpression { OR exclusiveOrExpression }
* 
* * @return an AST for an inclusive-or expression. */ private JExpression inclusiveOrExpression(): { int line = 0; JExpression lhs = null, rhs = null; } { try { lhs = exclusiveOrExpression() { line = lhs.line(); } ( rhs = exclusiveOrExpression() { lhs = new JOrOp(line, lhs, rhs); } )* } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return lhs; } } /** * Added for project4 * Parses an exclusive-or expression and returns an AST for it. * *
 *   exclusiveOrExpression ::= andExpression { XOR andExpression }
 * 
* * @return an AST for a exclusive-or expression. */ private JExpression exclusiveOrExpression(): { int line = 0; JExpression lhs = null, rhs = null; } { try { lhs = andExpression() { line = lhs.line(); } ( rhs = andExpression() { lhs = new JXorOp(line, lhs, rhs); } )* } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return lhs; } } /** * Added for project4 * Parses an and expression and returns an AST for it. * *
 *   andExpression ::= equalityExpression { AND equalityExpression }
 * 
* * @return an AST for an and expression. */ private JExpression andExpression(): { int line = 0; JExpression lhs = null, rhs = null; } { try { lhs = equalityExpression() { line = lhs.line(); } ( rhs = equalityExpression() { lhs = new JAndOp(line, lhs, rhs); } )* } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return lhs; } } /** * Parses an equality expression and returns an AST for it. * Added for project4: * *
 *   equalityExpression ::= relationalExpression { EQUAL relationalExpression }
 * 
* * @return an AST for an equality expression. */ private JExpression equalityExpression(): { int line = 0; JExpression lhs = null, rhs = null; } { try { lhs = relationalExpression() { line = lhs.line(); } ( rhs = relationalExpression() { lhs = new JEqualOp(line, lhs, rhs); } | rhs = relationalExpression() { lhs = new JNotEqualOp(line, lhs, rhs); } )* } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return lhs; } } /** * Parses a relational expression and returns an AST for it. * *
 *   relationalExpression ::= shiftExpression [ ( GT | LE ) shiftExpression | INSTANCEOF referenceType ]
 * 
* * @return an AST for a relational expression. */ private JExpression relationalExpression(): { int line = 0; JExpression lhs = null, rhs = null; Type type = null; } { try { lhs = shiftExpression() { line = lhs.line(); } [ rhs = shiftExpression() { lhs = new JGreaterEqualOp(line, lhs, rhs); } | rhs = shiftExpression() { lhs = new JGreaterThanOp(line, lhs, rhs); } | rhs = shiftExpression() { lhs = new JLessEqualOp(line, lhs, rhs); } | rhs = shiftExpression() { lhs = new JLessThanOp(line, lhs, rhs); } | type = referenceType() { lhs = new JInstanceOfOp(line, lhs, type); } ] } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return lhs; } } /** * Added for project4 * Parses a shift expression and returns an AST for it. * *
 *   shiftExpression ::= additiveExpression { ( ALSHIFT | ARSHIFT | LRSHIFT ) additiveExpression }
 * 
* * @return an AST for a shift expression. */ private JExpression shiftExpression(): { int line = 0; JExpression lhs = null, rhs = null; } { try { lhs = additiveExpression() { line = lhs.line(); } ( rhs = additiveExpression() { lhs = new JALeftShiftOp(line, lhs, rhs); } | rhs = additiveExpression() { lhs = new JARightShiftOp(line, lhs, rhs); } | rhs = additiveExpression() { lhs = new JLRightShiftOp(line, lhs, rhs); } )* } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return lhs; } } /** * Parses an additive expression and returns an AST for it. * *
 *   additiveExpression ::= multiplicativeExpression { ( MINUS | PLUS ) multiplicativeExpression }
 * 
* * @return an AST for an additive expression. */ private JExpression additiveExpression(): { int line = 0; JExpression lhs = null, rhs = null; } { try { lhs = multiplicativeExpression() { line = lhs.line(); } ( rhs = multiplicativeExpression() { lhs = new JSubtractOp(line, lhs, rhs); } | rhs = multiplicativeExpression() { lhs = new JPlusOp(line, lhs, rhs); } )* } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return lhs; } } /** * Parses a multiplicative expression and returns an AST for it. * Added for project4:
, * *
 *   multiplicativeExpression ::= unaryExpression { STAR unaryExpression }
 * 
* * @return an AST for a multiplicative expression. */ private JExpression multiplicativeExpression(): { int line = 0; JExpression lhs = null, rhs = null; } { try { lhs = unaryExpression() { line = lhs.line(); } (
rhs = unaryExpression() { lhs = new JDivideOp(line, lhs, rhs); } | rhs = unaryExpression() { lhs = new JRemainderOp(line, lhs, rhs); } | rhs = unaryExpression() { lhs = new JMultiplyOp(line, lhs, rhs); } )* } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return lhs; } } /** * Parses an unary expression and returns an AST for it. * *
 *   unaryExpression ::= INC unaryExpression
 *                     | MINUS unaryExpression
 *                     | simpleUnaryExpression
 * 
* * @return an AST for an unary expression. */ private JExpression unaryExpression(): { int line = 0; JExpression expr = null, unaryExpr = null; } { try { { line = token.beginLine; } unaryExpr = unaryExpression() { expr = new JPreDecrementOp(line, unaryExpr); } | { line = token.beginLine; } unaryExpr = unaryExpression() { expr = new JPreIncrementOp(line, unaryExpr); } | { line = token.beginLine; } unaryExpr = unaryExpression() { expr = new JNegateOp(line, unaryExpr); } | { line = token.beginLine; } unaryExpr = unaryExpression() { expr = new JUnaryPlusOp(line, unaryExpr); } | expr = simpleUnaryExpression() } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return expr; } } /** * Parses a simple unary expression and returns an AST for it. * *
 *   simpleUnaryExpression ::= LNOT unaryExpression
 *                           | LPAREN basicType RPAREN unaryExpression
 *                           | LPAREN referenceType RPAREN simpleUnaryExpression
 *                           | postfixExpression
 * 
* * @return an AST for a simple unary expression. */ private JExpression simpleUnaryExpression(): { int line = 0; Type type = null; JExpression expr = null, unaryExpr = null, simpleUnaryExpr = null; } { try { { line = token.beginLine; } unaryExpr = unaryExpression() { expr = new JLogicalNotOp(line, unaryExpr); } | { line = token.beginLine; } unaryExpr = unaryExpression() { expr = new JComplementOp(line, unaryExpr); } | LOOKAHEAD( basicType() ) { line = token.beginLine; } type = basicType() unaryExpr = unaryExpression() { expr = new JCastOp(line, type, unaryExpr); } | LOOKAHEAD( referenceType() ) { line = token.beginLine; } type = referenceType() simpleUnaryExpr = simpleUnaryExpression() { expr = new JCastOp(line, type, simpleUnaryExpr); } | expr = postfixExpression() } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return expr ; } } /** * Parses a postfix expression and returns an AST for it. * *
 *   postfixExpression ::= primary { selector } { DEC }
 * 
* * @return an AST for a postfix expression. */ private JExpression postfixExpression(): { int line = 0; JExpression primaryExpr = null; } { try { primaryExpr = primary() { line = primaryExpr.line(); } ( primaryExpr = selector(primaryExpr) )* ( { primaryExpr = new JPostDecrementOp(line, primaryExpr); } | { primaryExpr = new JPostIncrementOp(line, primaryExpr); } )* } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return primaryExpr; } } /** * Parses a selector and returns an AST for it. * *
 *   selector ::= DOT qualifiedIdentifier [ arguments ]
 *              | LBRACK expression RBRACK
 * 
* * @param target the target expression for this selector. * @return an AST for a selector. */ private JExpression selector(JExpression target): { int line = 0; ArrayList args = null; TypeName id = null; JExpression expr = null; } { try { { line = token.beginLine; } id = qualifiedIdentifier() { expr = new JFieldSelection(line, ambiguousPart(id), target, id.simpleName()); } [ args = arguments() { expr = new JMessageExpression(line, target, ambiguousPart(id), id.simpleName(), args); } ] | { line = token.beginLine; } { expr = new JArrayExpression(line, target, expression()); } } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return expr; } } /** * Parses a primary expression and returns an AST for it. * *
 *   primary ::= parExpression
 *             | NEW creator
 *             | THIS [ arguments ]
 *             | SUPER ( arguments | DOT IDENTIFIER [ arguments ] )
 *             | qualifiedIdentifier [ arguments ]
 *             | literal
 * 
* * @return an AST for a primary expression. */ private JExpression primary(): { int line = 0; String name = ""; JExpression expr = null; JExpression newTarget = null; ArrayList args = null; TypeName id = null; } { try { expr = parExpression() | expr = creator() | { line = token.beginLine; expr = new JThis(line); } [ args = arguments() { expr = new JThisConstruction(line, args); } ] | { line = token.beginLine; } ( args = arguments() { expr = new JSuperConstruction(line, args); } | { name = token.image; newTarget = new JSuper(line); expr = new JFieldSelection(line, newTarget, name); } [ args = arguments() { expr = new JMessageExpression(line, newTarget, null, name, args); } ] ) | // Language is ambiguous here. JavaCC is unable to choose between qualifiedIdentifier and // selector. Semantic analysis will sort it out. id = qualifiedIdentifier() { line = id.line(); if (ambiguousPart(id) == null) { expr = new JVariable(line, id.simpleName()); } else { expr = new JFieldSelection(line, ambiguousPart(id), null, id.simpleName()); } } [ args = arguments() { expr = new JMessageExpression(line, null, ambiguousPart(id), id.simpleName(), args); } ] | expr = literal() } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return expr; } } /** * Parses a creator and returns an AST for it. * *
 *   creator ::= ( basicType | qualifiedIdentifier )
 *                   ( arguments
 *                   | LBRACK RBRACK { LBRACK RBRACK } [ arrayInitializer ]
 *                   | newArrayDeclarator
 *                   )
 * 
* * @return an AST for a creator. */ private JExpression creator(): { int line = 0; Type type = null; ArrayList args = null; ArrayList dims = null; JArrayInitializer init = null; JExpression expr = null; Type expected = null; } { try { ( type = basicType() | type = qualifiedIdentifier() ) { line = token.beginLine; expected = type; } ( args = arguments() { expr = new JNewOp(line, type, args); } | LOOKAHEAD( ) { expected = new ArrayTypeName(expected); } ( LOOKAHEAD( ) { expected = new ArrayTypeName(expected); } )* [ expr = arrayInitializer(expected) ] | expr = newArrayDeclarator(type) ) } catch (ParseException e) { expr = new JWildExpression(token.beginLine); recoverFromError(new int[] { SEMI, EOF }, e); } { return expr; } } /** * Parses a new array declarator and returns an AST for it. * *
 *   newArrayDeclarator ::= LBRACK expression RBRACK { LBRACK expression RBRACK } { LBRACK RBRACK }
 * 
* * @param line line in which the declarator occurred. * @param type type of the array. * @return an AST for a new array declarator. */ private JNewArrayOp newArrayDeclarator(Type type): { int line = 0; ArrayList dimensions = new ArrayList(); JExpression expr = null; } { try { { line = token.beginLine; } expr = expression() { dimensions.add(expr); type = new ArrayTypeName(type); } ( LOOKAHEAD( expression() ) expr = expression() { dimensions.add(expr); type = new ArrayTypeName(type); } )* ( LOOKAHEAD( ) { type = new ArrayTypeName(type); } )* } catch (ParseException e) { recoverFromError(new int[] { SEMI, EOF }, e); } { return new JNewArrayOp(line, type, dimensions); } } /** * Parses a literal and returns an AST for it. * Added DOUBLE_LITERAL and LONG_LITERAL for project4 * *
 *   literal ::= CHAR_LITERAL | DOUBLE_LITERAL | FALSE | INT_LITERAL | LONG_LITERAL | NULL | STRING_LITERAL | TRUE
 * 
* * @return an AST for a literal. */ private JExpression literal(): { JExpression expr = null; } { try { { expr = new JLiteralChar(token.beginLine, token.image); } | { expr = new JLiteralDouble(token.beginLine, token.image); } | { expr = new JLiteralBoolean(token.beginLine, token.image); } | { expr = new JLiteralInt(token.beginLine, token.image); } | { expr = new JLiteralLong(token.beginLine, token.image); } | { expr = new JLiteralNull(token.beginLine); } | { expr = new JLiteralString(token.beginLine, token.image); } | { expr = new JLiteralBoolean(token.beginLine, token.image); } } catch (ParseException e) { expr = new JWildExpression(token.beginLine); recoverFromError(new int[] { SEMI, EOF }, e); } { return expr; } }