package pins25.phase; import pins25.common.*; import java.util.Objects; /** * Sintaksni analizator. */ public class SynAn implements AutoCloseable { /** * Leksikalni analizator. */ private final LexAn lexAn; /** * Ustvari nov sintaksni analizator. * * @param srcFileName Ime izvorne datoteke. */ public SynAn(final String srcFileName) { this.lexAn = new LexAn(srcFileName); } @Override public void close() { lexAn.close(); } /** * Prevzame leksikalni analizator od leksikalnega analizatorja in preveri, ali * je prave vrste. * * @param symbol Pričakovana vrsta leksikalnega simbola. * @return Prevzeti leksikalni simbol. */ private Token check(Token.Symbol symbol) { final Token token = lexAn.takeToken(); if (token.symbol() != symbol) throw new Report.Error(token, "Unexpected symbol '" + token.lexeme() + "', expected " + symbol.prettyPrint() + "."); return token; } /** * Opravi sintaksno analizo. */ public void parse() { parseProgram(); if (lexAn.peekToken().symbol() != Token.Symbol.EOF) Report.warning(lexAn.peekToken(), "Unexpected text '" + lexAn.peekToken().lexeme() + "...' at the end of the program."); } private void parseProgram() { System.out.println("program -> definition restdefs"); parseDefinition(); parseRestDefinitions(); } private void parseRestDefinitions() { if (lexAn.peekToken().symbol() != Token.Symbol.EOF) { System.out.println("restdefs -> definition restdefs"); parseDefinition(); parseRestDefinitions(); } else { System.out.println("restdefs -> ε"); } } private void parseDefinition() { Token token = lexAn.peekToken(); switch (token.symbol()) { case FUN: System.out.println("definition -> FUN IDENTIFIER LPAREN parameters RPAREN funcassign"); check(Token.Symbol.FUN); check(Token.Symbol.IDENTIFIER); check(Token.Symbol.LPAREN); parseParameters(); check(Token.Symbol.RPAREN); parseFunctionAssignment(); break; case VAR: System.out.println("definition -> VAR IDENTIFIER ASSIGN initializers"); check(Token.Symbol.VAR); check(Token.Symbol.IDENTIFIER); check(Token.Symbol.ASSIGN); parseInitializers(); break; default: throw new Report.Error(token, "Unexpected symbol '" + token.lexeme() + "', expected FUN or VAR."); } } private void parseFunctionAssignment() { Token token = lexAn.peekToken(); if (token.symbol() == Token.Symbol.ASSIGN) { System.out.println("funcassign -> ASSIGN statements"); check(Token.Symbol.ASSIGN); parseStatements(); } else { System.out.println("funcassign -> ε"); } } private void parseParameters() { Token token = lexAn.peekToken(); if (token.symbol() == Token.Symbol.IDENTIFIER) { System.out.println("parameters -> IDENTIFIER restparams"); check(Token.Symbol.IDENTIFIER); parseRestParameters(); } else { System.out.println("parameters -> ε"); } } private void parseRestParameters() { Token token = lexAn.peekToken(); if (token.symbol() == Token.Symbol.COMMA) { System.out.println("restparams -> COMMA IDENTIFIER restparams"); check(Token.Symbol.COMMA); check(Token.Symbol.IDENTIFIER); parseRestParameters(); } else { System.out.println("restparams -> ε"); } } private void parseStatements() { System.out.println("statements -> statement reststmts"); parseStatement(); parseRestStatements(); } private void parseExpressionAssign() { if (lexAn.peekToken().symbol() == Token.Symbol.ASSIGN) { System.out.println("exprassign -> ASSIGN expression"); check(Token.Symbol.ASSIGN); parseExpression(); } else { System.out.println("exprassign -> ε"); } } private void parseElseStatement() { if (lexAn.peekToken().symbol() == Token.Symbol.ELSE) { System.out.println("elsestmt -> ELSE statements"); check(Token.Symbol.ELSE); parseStatements(); } else { System.out.println("elsestmt -> ε"); } } private void parseRestStatements() { if (lexAn.peekToken().symbol() == Token.Symbol.COMMA) { System.out.println("reststmts -> COMMA statement reststmts"); check(Token.Symbol.COMMA); parseStatement(); parseRestStatements(); } else { System.out.println("reststmts -> ε"); } } private void parseStatement() { Token token = lexAn.peekToken(); switch (token.symbol()) { case IF: System.out.println("statement -> if expression then statements elsestmt end"); check(Token.Symbol.IF); parseExpression(); check(Token.Symbol.THEN); parseStatements(); parseElseStatement(); check(Token.Symbol.END); break; case WHILE: System.out.println("statement -> while expression do statements end"); check(Token.Symbol.WHILE); parseExpression(); check(Token.Symbol.DO); parseStatements(); check(Token.Symbol.END); break; case LET: System.out.println("statement -> let definition reststmtdefs in statements end"); check(Token.Symbol.LET); parseDefinition(); parseRestStatementDefinitions(); check(Token.Symbol.IN); parseStatements(); check(Token.Symbol.END); break; default: System.out.println("statement -> expression exprassign"); parseExpression(); parseExpressionAssign(); } } private void parseRestStatementDefinitions() { switch (lexAn.peekToken().symbol()) { case IN: System.out.println("reststmtdefs -> ε"); break; case FUN: case VAR: System.out.println("reststmtdefs -> definition reststmtdefs"); parseDefinition(); parseRestStatementDefinitions(); break; } } private void parseInitializers() { switch (lexAn.peekToken().symbol()) { case INTCONST: case CHARCONST: case STRINGCONST: System.out.println("initializers -> initializer restinits"); parseInitializer(); parseRestInitializers(); break; default: System.out.println("initializers -> ε"); break; } } private void parseInitializer() { Token token = lexAn.peekToken(); switch (token.symbol()) { case INTCONST: System.out.println("initializer -> INTCONST intconstmult"); check(Token.Symbol.INTCONST); parseIntegerConstantMultiplier(); break; case CHARCONST: System.out.println("initializer -> CHARCONST"); check(Token.Symbol.CHARCONST); break; case STRINGCONST: System.out.println("initializer -> STRINGCONST"); check(Token.Symbol.STRINGCONST); break; default: throw new Report.Error(token, "Unexpected symbol '" + token.lexeme() + "', expected integer, character or string constant."); } } private void parseRestInitializers() { Token token = lexAn.peekToken(); if (token.symbol() == Token.Symbol.COMMA) { System.out.println("restinits -> COMMA initializer restinits"); check(Token.Symbol.COMMA); parseInitializer(); parseRestInitializers(); } else { System.out.println("restinits -> ε"); } } private void parseIntegerConstantMultiplier() { Token token = lexAn.peekToken(); if (token.symbol() == Token.Symbol.MUL) { System.out.println("intconstmult -> MUL const"); check(Token.Symbol.MUL); parseConstant(); } else { System.out.println("intconstmult -> ε"); } } private void parseConstant() { Token token = lexAn.peekToken(); switch (token.symbol()) { case INTCONST: System.out.println("const -> INTCONST"); check(Token.Symbol.INTCONST); break; case CHARCONST: System.out.println("const -> CHARCONST"); check(Token.Symbol.CHARCONST); break; case STRINGCONST: System.out.println("const -> STRINGCONST"); check(Token.Symbol.STRINGCONST); break; default: throw new Report.Error(token, "Unexpected symbol '" + token.lexeme() + "', expected integer, character or string constant."); } } private void parseExpression() { System.out.println("expression -> conjexpr restdisj"); parseConjunctionExpression(); parseRestDisjunctions(); } private void parseRestDisjunctions() { if (lexAn.peekToken().symbol() == Token.Symbol.OR) { System.out.println("restdisj -> OR conjexpr restdisj"); check(Token.Symbol.OR); parseConjunctionExpression(); parseRestDisjunctions(); } } private void parseConjunctionExpression() { System.out.println("conjexpr -> cmpexpr restconj"); parseComparisonExpression(); parseRestConjunctionExpressions(); } private void parseRestConjunctionExpressions() { if (lexAn.peekToken().symbol() == Token.Symbol.AND) { System.out.println("restconj -> AND cmpexpr restconj"); check(Token.Symbol.AND); parseComparisonExpression(); parseRestConjunctionExpressions(); } else { System.out.println("restconj -> ε"); } } private void parseComparisonExpression() { System.out.println("cmpexpr -> addexpr restcmp"); parseAdditionExpression(); parseRestComparisons(); } private void parseRestComparisons() { Token token = lexAn.peekToken(); switch (token.symbol()) { case EQU: case NEQ: case LTH: case GTH: case LEQ: case GEQ: System.out.printf("restcmp -> %s addexpr\n", token.symbol()); check(token.symbol()); parseAdditionExpression(); break; default: System.out.println("restcmp -> ε"); break; } } private void parseAdditionExpression() { System.out.println("addexpr -> multexpr restadd"); parseMultiplicationExpression(); parseRestAdditions(); } private void parseRestAdditions() { Token token = lexAn.peekToken(); switch (token.symbol()) { case ADD: case SUB: System.out.printf("restadd -> %s multexpr restadd\n", token.symbol()); check(token.symbol()); parseMultiplicationExpression(); parseRestAdditions(); break; default: System.out.println("restadd -> ε"); break; } } private void parseMultiplicationExpression() { System.out.println("multexpr -> prefixexpr restmult"); parsePrefixExpression(); parseRestMultiplicationExpressions(); } private void parseRestMultiplicationExpressions() { Token token = lexAn.peekToken(); switch (token.symbol()) { case MUL: case DIV: case MOD: System.out.printf("restmult -> %s prefixexpr restmult\n", token.symbol()); check(token.symbol()); parsePrefixExpression(); parseRestMultiplicationExpressions(); break; default: System.out.println("restmult -> ε"); break; } } private void parsePrefixExpression() { Token token = lexAn.peekToken(); switch (token.symbol()) { case ADD: case SUB: case NOT: case PTR: System.out.printf("prefixexpr -> %s prefixexpr\n", token.symbol()); check(token.symbol()); parsePrefixExpression(); break; default: System.out.println("prefixexpr -> postfixexpr"); parsePostfixExpression(); break; } } private void parsePostfixExpression() { System.out.println("postfixexpr -> primary postfixop"); parsePrimary(); parsePostfixOperator(); } private void parsePostfixOperator() { if (lexAn.peekToken().symbol() == Token.Symbol.PTR) { System.out.println("postfixop -> PTR postfixop"); check(Token.Symbol.PTR); parsePostfixOperator(); } else { System.out.println("postfixop -> ε"); } } private void parsePrimary() { Token token = lexAn.peekToken(); switch (token.symbol()) { case IDENTIFIER: System.out.println("primary -> IDENTIFIER exprargs"); check(Token.Symbol.IDENTIFIER); parseExpressionArguments(); break; case LPAREN: System.out.println("primary -> LPAREN expression RPAREN"); check(Token.Symbol.LPAREN); parseExpression(); check(Token.Symbol.RPAREN); break; case INTCONST: case CHARCONST: case STRINGCONST: System.out.println("primary -> const"); parseConstant(); break; default: throw new Report.Error(token, "Unexpected symbol '" + token.lexeme() + "', expected identifier, constant or '('."); } } private void parseExpressionArguments() { if (lexAn.peekToken().symbol() == Token.Symbol.LPAREN) { System.out.println("exprargs -> LPAREN arguments RPAREN"); check(Token.Symbol.LPAREN); parseArguments(); check(Token.Symbol.RPAREN); } else { System.out.println("exprargs -> ε"); } } private void parseArguments() { Token token = lexAn.peekToken(); if (token.symbol() == Token.Symbol.RPAREN) { System.out.println("arguments -> ε"); } else { System.out.println("arguments -> expression restargs"); parseExpression(); parseRestArguments(); } } private void parseRestArguments() { if (lexAn.peekToken().symbol() == Token.Symbol.COMMA) { System.out.println("restargs -> COMMA restargs"); check(Token.Symbol.COMMA); parseExpression(); parseRestArguments(); } else { System.out.println("restargs -> ε"); } } // --- ZAGON --- /** * Zagon sintaksnega analizatorja kot samostojnega programa. * * @param cmdLineArgs Argumenti v ukazni vrstici. */ public static void main(final String[] cmdLineArgs) { System.out.println("This is PINS'25 compiler (syntax analysis):"); try { if (cmdLineArgs.length == 0) throw new Report.Error("No source file specified in the command line."); if (cmdLineArgs.length > 1) Report.warning("Unused arguments in the command line."); try (SynAn synAn = new SynAn(cmdLineArgs[0])) { synAn.parse(); } // Upajmo, da kdaj pridemo to te tocke. // A zavedajmo se sledecega: // 1. Prevod je zaradi napak v programu lahko napacen :-o // 2. Izvorni program se zdalec ni tisto, kar je programer hotel, da bi bil ;-) Report.info("Done."); } catch (Report.Error error) { // Izpis opisa napake. System.err.println(error.getMessage()); System.exit(1); } } }