class SyntaxException extends Exception { public SyntaxException(String s) { super(s); } } /* ========================================================================= */ /** * Recognizer uses a Lexer, sequentially reading its tokens, and recognizing * the Decaf grammar. */ class Recognizer { private Lexer L; /* ------------------------------------------------------------------------- */ public Recognizer(Lexer l) { L = l; } /* ------------------------------------------------------------------------- */ private SyntaxException syntacticError(String whatWeExpected) { return new SyntaxException("Expected " + whatWeExpected + " instead of `" + L.token.spelling + "'; " + L.token.range + "."); } /* ------------------------------------------------------------------------- */ private void match(int expectedType) throws SyntaxException, LexicalException { if (L.token.type == expectedType) L.advance(); else throw syntacticError(Token.spellingOf(expectedType)); } private void matchIt() throws SyntaxException, LexicalException { L.advance(); } /* ------------------------------------------------------------------------- */ // Expressions. /* ------------------------------------------------------------------------- */ private void recognizeIdentifier() throws SyntaxException, LexicalException { match(Token.ID); } private void recognizeNumber() throws SyntaxException, LexicalException { match(Token.NUM); } /* ------------------------------------------------------------------------- */ /* *** There are six methods you have to fill in here, corresponding exactly to the left-hand side of the productions in the Decaf grammar that describe expressions. */ /* ------------------------------------------------------------------------- */ private void recognizeConditionalAndExpr() throws SyntaxException, LexicalException { // *** Fill this in. } /* ------------------------------------------------------------------------- */ private void recognizeExpression() throws SyntaxException, LexicalException { recognizeConditionalAndExpr(); while (L.token.type == Token.OR) { matchIt(); recognizeConditionalAndExpr(); } } /* ------------------------------------------------------------------------- */ // Statements. /* ------------------------------------------------------------------------- */ /* *** There are five methods you have to fill in here, corresponding exactly to the left-hand side of the productions in the Decaf grammar that describe statements. */ /* ------------------------------------------------------------------------- */ private void recognizeBlock() throws LexicalException, SyntaxException { match(Token.LBRACE); while (L.token.type != Token.RBRACE) recognizeStatement(); match(Token.RBRACE); } /* ------------------------------------------------------------------------- */ private void recognizeStatement() throws LexicalException, SyntaxException { switch (L.token.type) { case Token.LBRACE: recognizeBlock(); break; case Token.INT : break; // *** Fill this in. case Token.IF : break; // *** Fill this in. case Token.WHILE : break; // *** Fill this in. case Token.RETURN: break; // *** Fill this in. case Token.ID : break; // *** Fill this in. default: throw syntacticError("statement"); } } /* ------------------------------------------------------------------------- */ // High-level program structures. /* ------------------------------------------------------------------------- */ private void recognizeFormalParam() throws SyntaxException, LexicalException { // *** Fill this in. } // Here's an example where it's good that the follow set is disjoint from the first set! // Also a good example of how to do lists with separators. private void recognizeFormalParams() throws SyntaxException, LexicalException { // *** Fill this in. } /* ------------------------------------------------------------------------- */ private void recognizeType() throws SyntaxException, LexicalException { match(Token.INT); // For nocaf, only kind of type we recognize. // for decaf you have to add the boolean type. } /* ------------------------------------------------------------------------- */ // Here's a standard form for recognizing lists. private void recognizeMethodDecl() throws SyntaxException, LexicalException { match(Token.STATIC); recognizeType(); match(Token.ID); match(Token.LPAREN); recognizeFormalParams(); match(Token.RPAREN); recognizeBlock(); } private void recognizeMethodDecls() throws SyntaxException, LexicalException { while (L.token.type != Token.RBRACE) recognizeMethodDecl(); } /* ------------------------------------------------------------------------- */ public void recognizeClassDeclaration() throws SyntaxException, LexicalException { match(Token.CLASS); match(Token.ID); match(Token.LBRACE); recognizeMethodDecls(); match(Token.RBRACE); match(Token.EOT); } } // end class /* ========================================================================= */ /** * Parser uses a Lexer, sequentially reading its tokens, and building * a tree for a Decaf class declaration. */ class Parser { private Lexer L; /* ------------------------------------------------------------------------- */ public Parser(Lexer l) { L = l; } /* ------------------------------------------------------------------------- */ private SyntaxException syntacticError(String whatWeExpected) { return new SyntaxException("Expected " + whatWeExpected + " instead of `" + L.token.spelling + "'; " + L.token.range + "."); } /* ------------------------------------------------------------------------- */ private void match(int expectedType) throws SyntaxException, LexicalException { if (L.token.type == expectedType) L.advance(); else throw syntacticError(Token.spellingOf(expectedType)); } private void matchIt() throws SyntaxException, LexicalException { L.advance(); } /* ------------------------------------------------------------------------- */ // Expressions. /* ------------------------------------------------------------------------- */ private Id parseIdentifier() throws SyntaxException, LexicalException { String spelling = L.token.spelling.toString(); match(Token.ID); return new Id(spelling); } /* ------------------------------------------------------------------------- */ private Num parseNumber() throws SyntaxException, LexicalException { String spelling = L.token.spelling.toString(); match(Token.NUM); return new Num(spelling); } /* *** You have to add a method for parsing boolean literals "true" and "false" */ /* ------------------------------------------------------------------------- */ /* *** There are six methods you have to fill in here, corresponding exactly to the left-hand side of the productions in the Decaf grammar that describe expressions. */ /* ------------------------------------------------------------------------- */ private Expression parseConditionalAndExpr() throws SyntaxException, LexicalException { return null; // *** Fill this in. Very similar to parseExpression. } /* ------------------------------------------------------------------------- */ private Expression parseExpression() throws SyntaxException, LexicalException { Expression left = parseConditionalAndExpr(); // Subtyping! while (L.token.type == Token.OR) { matchIt(); Expression right = parseConditionalAndExpr(); left = new ConditionalExpr(Token.OR, left, right); } return left; } /* ------------------------------------------------------------------------- */ // Statements. /* ------------------------------------------------------------------------- */ /* *** There are five methods you have to fill in here, corresponding exactly to the left-hand side of the productions in the Decaf grammar that describe statements. */ /* ------------------------------------------------------------------------- */ private Statements parseStatements() throws LexicalException, SyntaxException { Statements ss = new Statements(); while (L.token.type != Token.RBRACE) ss.append(parseStatement()); return ss; } private Block parseBlock() throws LexicalException, SyntaxException { match(Token.LBRACE); Statements ss = parseStatements(); match(Token.RBRACE); return new Block(ss); } /* ------------------------------------------------------------------------- */ private Statement parseStatement() throws LexicalException, SyntaxException { switch (L.token.type) { case Token.LBRACE: return parseBlock(); case Token.INT : return null; // *** Fill this in. case Token.IF : return null; // *** Fill this in. case Token.WHILE : return null; // *** Fill this in. case Token.RETURN: return null; // *** Fill this in. case Token.ID : return null; // *** Fill this in. default: throw syntacticError("statement"); } } /* ------------------------------------------------------------------------- */ // High-level program structures. /* ------------------------------------------------------------------------- */ private FormalParam parseFormalParam() throws SyntaxException, LexicalException { return null; // *** Fill this in. } // Here's an example where it's good that the follow set is disjoint from the first set! // Also an example of how to do lists WITH separators. Note that separated lists // lend themselves better to iteration than to recursion. private FormalParams parseFormalParams() throws SyntaxException, LexicalException { return new FormalParams(); // *** Fill this in. } /* ------------------------------------------------------------------------- */ private Id parseType() throws SyntaxException, LexicalException { match(Token.INT); return new Id("int"); } /* ------------------------------------------------------------------------- */ private MethodDecl parseMethodDecl() throws SyntaxException, LexicalException { match(Token.STATIC); Id typeName = parseType(); Id name = parseIdentifier(); match(Token.LPAREN); FormalParams params = parseFormalParams(); match(Token.RPAREN); Block body = parseBlock(); return new MethodDecl(typeName, name, params, body); } // Here's an example where it's good that the follow set is disjoint from the first set! private MethodDecls parseMethodDecls() throws SyntaxException, LexicalException { MethodDecls mds = new MethodDecls(); while (L.token.type != Token.RBRACE) mds.append(parseMethodDecl()); return mds; } /* ------------------------------------------------------------------------- */ public ClassDecl parseClassDecl() throws SyntaxException, LexicalException { match(Token.CLASS); Id name = parseIdentifier(); match(Token.LBRACE); MethodDecls mds = parseMethodDecls(); match(Token.RBRACE); match(Token.EOT); return new ClassDecl(name, mds); } }