From a94802b5713b4a0ba6038bf8fff10d95569c5720 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C5=A1per=20Dobrovoljc?= Date: Fri, 21 Mar 2025 15:28:24 +0100 Subject: [PATCH] Finished SynAn without good errors --- .idea/inspectionProfiles/Project_Default.xml | 7 + .idea/misc.xml | 8 + generate.py | 53 +++ grammar.txt | 50 ++- pns.iml | 6 + prg/pass.pins | 35 ++ prg/test.pins | 2 - src/pins25/common/Token.java | 277 ++++++++---- src/pins25/phase/SynAn.java | 423 ++++++++++++++++--- 9 files changed, 688 insertions(+), 173 deletions(-) create mode 100644 generate.py create mode 100644 prg/pass.pins diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 581c216..4e7a66a 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -1,6 +1,8 @@ \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 687f0c0..ea683db 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,12 @@ + + + + + diff --git a/generate.py b/generate.py new file mode 100644 index 0000000..4d5ab82 --- /dev/null +++ b/generate.py @@ -0,0 +1,53 @@ +from collections import defaultdict + +data = open('./grammar.txt').read().split() + +productions = defaultdict(lambda: []) + + +def recurse(prod): + prods = [] + if prod not in productions.keys(): + prods.append(prod) + else: + for p in productions[prod]: + if len(p): + prods += recurse(p[0]) + + return prods + + +while len(data): + name = data.pop(0) + data.pop(0) # -> + + symbols = [] + while True: + symbol = data.pop(0) + if symbol == '.': + productions[name].append(symbols) + break + if symbol == '|': + productions[name].append(symbols) + symbols = [] + continue + symbols.append(symbol) + +for prod, defs in productions.items(): + func = f"""private void {prod}() {{ + Token token = lexAn.peekToken(); + switch(token.symbol()) {{ +""" + for d in defs: + for r in recurse(d[0]): + func += f" case {r}:\n" + + func += f' System.out.println("{prod} -> {defs}");' + + for d2 in d: + if d2.isupper(): + func += f"check({d2});" + + func += """ } +}""" + print(func) diff --git a/grammar.txt b/grammar.txt index 920531b..b9e804d 100644 --- a/grammar.txt +++ b/grammar.txt @@ -1,48 +1,54 @@ program -> definition restdefs . restdefs -> definition restdefs | . -definition -> fun IDENTIFIER LPAREN parameters RPAREN funcassign . +definition -> FUN IDENTIFIER LPAREN parameters RPAREN funcassign . funcassign -> ASSIGN statements | . -definition -> var IDENTIFIER ASSING initializers . +definition -> VAR IDENTIFIER ASSIGN initializers . parameters -> IDENTIFIER restparams | . -restparams -> COMMA parameters | . +restparams -> COMMA IDENTIFIER restparams | . statements -> statement reststmts . -reststmts -> COMMA statements | . +reststmts -> COMMA statement reststmts | . statement -> expression exprassign . exprassign -> ASSIGN expression | . -statement -> if expression then statements elsestmt end . -elsestmt -> else statements | . +statement -> IF expression THEN statements elsestmt END . +elsestmt -> ELSE statements | . -statement -> while expression do statements end . +statement -> WHILE expression DO statements END . -statement -> let definition reststmtdefs in statements end . +statement -> LET definition reststmtdefs IN statements END . reststmtdefs -> definition reststmtdefs | . expression -> conjexpr restdisj . -restdisj -> OR expression | . +restdisj -> OR conjexpr restdisj | . conjexpr -> cmpexpr restconj . -restconj -> AND conjexpr | . +restconj -> AND cmpexpr restconj | . cmpexpr -> addexpr restcmp . -restcmp -> cmpop cmpexpr | . -cmpop -> EQ | NEQ | LTH | GTH | LEQ | GEQ . +restcmp -> EQU addexpr + | NEQ addexpr + | LTH addexpr + | GTH addexpr + | LEQ addexpr + | GEQ addexpr + | . addexpr -> multexpr restadd . -restadd -> addop addexpr | . -addop -> ADD | SUB . +restadd -> ADD multexpr restadd + | SUB multexpr restadd | . multexpr -> prefixexpr restmult . -restmult -> multop multexpr | . -multop -> MUL | DIV | MOD . +restmult -> MUL prefixexpr restmult + | DIV prefixexpr restmult + | MOD prefixexpr restmult + | . -prefixexpr -> prefixop postfixexpr . -prefixop -> NOT prefixop | ADD prefixop | SUB prefixop | PTR prefixop | . +prefixexpr -> NOT prefixexpr | ADD prefixexpr | SUB prefixexpr | PTR prefixexpr | postfixexpr . postfixexpr -> primary postfixop . postfixop -> PTR postfixop | . @@ -51,12 +57,12 @@ primary -> const | LPAREN expression RPAREN | IDENTIFIER exprargs . exprargs -> LPAREN arguments RPAREN | . arguments -> expression restargs | . -restargs -> COMMA restargs | . +restargs -> COMMA expression restargs | . initializers -> initializer restinits | . -restinits -> COMMA initializers | . +restinits -> COMMA initializer restinits | . -initializer -> INTCONST intconstmul | CHARCONST | STRINGCONST . -intconstmul -> MUL const | . +initializer -> INTCONST intconstmult | CHARCONST | STRINGCONST . +intconstmult -> MUL const | . const -> INTCONST | CHARCONST | STRINGCONST . \ No newline at end of file diff --git a/pns.iml b/pns.iml index c90834f..7f55ad5 100644 --- a/pns.iml +++ b/pns.iml @@ -1,5 +1,10 @@ + + + + + @@ -7,5 +12,6 @@ + \ No newline at end of file diff --git a/prg/pass.pins b/prg/pass.pins new file mode 100644 index 0000000..459fe2c --- /dev/null +++ b/prg/pass.pins @@ -0,0 +1,35 @@ +fun noarg() +fun onearg(a) +fun multargs(a, b) +fun funcassign(a) = + a = 1 + +var a = 1 +var b = 'a' +var c = "test" +var e = 'a', "test", 4 +var f = 1 * 3 +var g = 1 * 'a' +var h = 4 * "aaa" + +fun a() = + 1, 'a', "a", + a, neki(a, 1, 'a', "a"), + a^, a^^, + +a, -a, !a, ^a, +-!^a, + a * b, a / b, a % b, a * b / c % d, + a + b, a - b, + a == b, a != b, a < b, a > b, a <= b, a >= b, + a && b, a && b && c, + a || b, a || b || c, + (1), (a + b), (a - (!(1) * 2)), + a + 1 = b - 1, + if a then b end, + if a == 3 then b = 1, !c end, + if !a then b else a = 3 * a end, + if a then b else a, b end, + while a <= 10 do a + 1 end, + while a <= 10 do a + 1, ^c end, + let fun a(b, c) in !b end, + let fun a(b, c) var e = 'o' in !b end, + let fun a(b, c) in !b, 4 end diff --git a/prg/test.pins b/prg/test.pins index 4fbe95f..e69de29 100644 --- a/prg/test.pins +++ b/prg/test.pins @@ -1,2 +0,0 @@ -fun test(a, b,,) = - var c = 0 \ No newline at end of file diff --git a/src/pins25/common/Token.java b/src/pins25/common/Token.java index 8735449..d30b890 100644 --- a/src/pins25/common/Token.java +++ b/src/pins25/common/Token.java @@ -1,98 +1,205 @@ package pins25.common; +import java.util.HashMap; + /** * Leksikalni simbol. - * + * * @param location Lokacija simbola v izvornem programu. * @param symbol Vrsta simbola. * @param lexeme Znakovna predstavitev simbola. */ public record Token(Report.Location location, Symbol symbol, String lexeme) implements Report.Locatable { - /** - * Vrste leksikalnih simbolov. - */ - public enum Symbol { - /** Konec datoteke. */ - EOF, - /** Stevilo. */ - INTCONST, - /** Znak. */ - CHARCONST, - /** Niz znakov. */ - STRINGCONST, - /** Ime. */ - IDENTIFIER, - /** Kljucna beseda {@code fun}. */ - FUN, - /** Kljucna beseda {@code var}. */ - VAR, - /** Kljucna beseda {@code if}. */ - IF, - /** Kljucna beseda {@code then}. */ - THEN, - /** Kljucna beseda {@code else}. */ - ELSE, - /** Kljucna beseda {@code while}. */ - WHILE, - /** Kljucna beseda {@code do}. */ - DO, - /** Kljucna beseda {@code let}. */ - LET, - /** Kljucna beseda {@code in}. */ - IN, - /** Kljucna beseda {@code end}. */ - END, - /** Simbol {@code =}. */ - ASSIGN, - /** Simbol {@code ,}. */ - COMMA, - /** Simbol {@code &&}. */ - AND, - /** Simbol {@code ||}. */ - OR, - /** Simbol {@code !}. */ - NOT, - /** Simbol {@code ==}. */ - EQU, - /** Simbol {@code !=}. */ - NEQ, - /** Simbol {@code >}. */ - GTH, - /** Simbol {@code <}. */ - LTH, - /** Simbol {@code >=}. */ - GEQ, - /** Simbol {@code <=}. */ - LEQ, - /** Simbol {@code +}. */ - ADD, - /** Simbol {@code -}. */ - SUB, - /** Simbol {@code *}. */ - MUL, - /** Simbol {@code /}. */ - DIV, - /** Simbol {@code %}. */ - MOD, - /** Simbol {@code ^}. */ - PTR, - /** Simbol {@code (}. */ - LPAREN, - /** Simbol {@code )}. */ - RPAREN, - } + /** + * Vrste leksikalnih simbolov. + */ + public enum Symbol { + /** + * Konec datoteke. + */ + EOF, + /** + * Stevilo. + */ + INTCONST, + /** + * Znak. + */ + CHARCONST, + /** + * Niz znakov. + */ + STRINGCONST, + /** + * Ime. + */ + IDENTIFIER, + /** + * Kljucna beseda {@code fun}. + */ + FUN, + /** + * Kljucna beseda {@code var}. + */ + VAR, + /** + * Kljucna beseda {@code if}. + */ + IF, + /** + * Kljucna beseda {@code then}. + */ + THEN, + /** + * Kljucna beseda {@code else}. + */ + ELSE, + /** + * Kljucna beseda {@code while}. + */ + WHILE, + /** + * Kljucna beseda {@code do}. + */ + DO, + /** + * Kljucna beseda {@code let}. + */ + LET, + /** + * Kljucna beseda {@code in}. + */ + IN, + /** + * Kljucna beseda {@code end}. + */ + END, + /** + * Simbol {@code =}. + */ + ASSIGN, + /** + * Simbol {@code ,}. + */ + COMMA, + /** + * Simbol {@code &&}. + */ + AND, + /** + * Simbol {@code ||}. + */ + OR, + /** + * Simbol {@code !}. + */ + NOT, + /** + * Simbol {@code ==}. + */ + EQU, + /** + * Simbol {@code !=}. + */ + NEQ, + /** + * Simbol {@code >}. + */ + GTH, + /** + * Simbol {@code <}. + */ + LTH, + /** + * Simbol {@code >=}. + */ + GEQ, + /** + * Simbol {@code <=}. + */ + LEQ, + /** + * Simbol {@code +}. + */ + ADD, + /** + * Simbol {@code -}. + */ + SUB, + /** + * Simbol {@code *}. + */ + MUL, + /** + * Simbol {@code /}. + */ + DIV, + /** + * Simbol {@code %}. + */ + MOD, + /** + * Simbol {@code ^}. + */ + PTR, + /** + * Simbol {@code (}. + */ + LPAREN, + /** + * Simbol {@code )}. + */ + RPAREN; - @Override - public String toString() { - String lexeme = switch (symbol) { - case INTCONST -> "(" + this.lexeme + ")"; - case CHARCONST -> "(" + this.lexeme + ")"; - case STRINGCONST -> "(" + this.lexeme + ")"; - case IDENTIFIER -> "(" + this.lexeme + ")"; - default -> ""; - }; - return location + " " + symbol + lexeme; - } + public String prettyPrint() { + return switch (this) { + case INTCONST -> "integer constant"; + case CHARCONST -> "character constant"; + case STRINGCONST -> "string constant"; + case IDENTIFIER -> "identifier"; + case FUN -> "'fun'"; + case VAR -> "'var'"; + case IF -> "'if'"; + case THEN -> "'then'"; + case ELSE -> "'else'"; + case WHILE -> "'while'"; + case DO -> "'do'"; + case LET -> "'let'"; + case IN -> "'in'"; + case END -> "'end'"; + case ASSIGN -> "'='"; + case COMMA -> "','"; + case AND -> "'&&'"; + case OR -> "'||'"; + case NOT -> "'!'"; + case EQU -> "'=='"; + case NEQ -> "'!='"; + case GTH -> "'>'"; + case LTH -> "'<'"; + case GEQ -> "'>='"; + case LEQ -> "'<='"; + case ADD -> "'+'"; + case SUB -> "'-'"; + case MUL -> "'*'"; + case DIV -> "'/'"; + case MOD -> "'%'"; + case PTR -> "'^'"; + case LPAREN -> "'('"; + case RPAREN -> "')'"; + default -> this.toString(); + }; + } + } + + + @Override + public String toString() { + String lexeme = switch (symbol) { + case INTCONST, IDENTIFIER, CHARCONST, STRINGCONST -> "(" + this.lexeme + ")"; + default -> ""; + }; + return location + " " + symbol + lexeme; + } } \ No newline at end of file diff --git a/src/pins25/phase/SynAn.java b/src/pins25/phase/SynAn.java index 8eca340..6955e36 100644 --- a/src/pins25/phase/SynAn.java +++ b/src/pins25/phase/SynAn.java @@ -38,7 +38,7 @@ public class SynAn implements AutoCloseable { 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 + "."); + throw new Report.Error(token, "Unexpected symbol '" + token.lexeme() + "', expected " + symbol.prettyPrint() + "."); return token; } @@ -54,21 +54,26 @@ public class SynAn implements AutoCloseable { } 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 Token.Symbol.FUN: + case FUN: + System.out.println("definition -> FUN IDENTIFIER LPAREN parameters RPAREN funcassign"); check(Token.Symbol.FUN); check(Token.Symbol.IDENTIFIER); check(Token.Symbol.LPAREN); @@ -77,7 +82,8 @@ public class SynAn implements AutoCloseable { parseFunctionAssignment(); break; - case Token.Symbol.VAR: + case VAR: + System.out.println("definition -> VAR IDENTIFIER ASSIGN initializers"); check(Token.Symbol.VAR); check(Token.Symbol.IDENTIFIER); check(Token.Symbol.ASSIGN); @@ -91,78 +97,80 @@ public class SynAn implements AutoCloseable { private void parseFunctionAssignment() { Token token = lexAn.peekToken(); - switch (token.symbol()) { - case Token.Symbol.FUN: - case Token.Symbol.VAR: - case Token.Symbol.IN: - case Token.Symbol.EOF: - break; - - case Token.Symbol.ASSIGN: - check(Token.Symbol.ASSIGN); - parseStatements(); - break; - - default: - throw new Report.Error(token, "Unexpected symbol '" + token.lexeme() + "', expected ASSIGN."); + 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(); - switch (token.symbol()) { - case Token.Symbol.IDENTIFIER: - check(Token.Symbol.IDENTIFIER); - parseRestParameters(); - break; - - case Token.Symbol.RPAREN: - break; - - default: - throw new Report.Error(token, "Unexpected symbol '" + token.lexeme() + "', expected IDENTIFIER or RPAREN."); + 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(); - switch (token.symbol()) { - case Token.Symbol.RPAREN: - break; - - case Token.Symbol.COMMA: - check(Token.Symbol.COMMA); - check(Token.Symbol.IDENTIFIER); - parseRestParameters(); - break; - - default: - throw new Report.Error(token, "Unexpected symbol '" + token.lexeme() + "', expected ')' or ','."); + 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 Token.Symbol.IDENTIFIER: - case Token.Symbol.LPAREN: - case Token.Symbol.ADD: - case Token.Symbol.SUB: - case Token.Symbol.NOT: - case Token.Symbol.PTR: - case Token.Symbol.INTCONST: - case Token.Symbol.CHARCONST: - case Token.Symbol.STRINGCONST: - parseExpression(); - parseExpressionAssign(); - break; - - case Token.Symbol.IF: + case IF: + System.out.println("statement -> if expression then statements elsestmt end"); check(Token.Symbol.IF); parseExpression(); check(Token.Symbol.THEN); @@ -171,7 +179,8 @@ public class SynAn implements AutoCloseable { check(Token.Symbol.END); break; - case Token.Symbol.WHILE: + case WHILE: + System.out.println("statement -> while expression do statements end"); check(Token.Symbol.WHILE); parseExpression(); check(Token.Symbol.DO); @@ -179,7 +188,8 @@ public class SynAn implements AutoCloseable { check(Token.Symbol.END); break; - case Token.Symbol.LET: + case LET: + System.out.println("statement -> let definition reststmtdefs in statements end"); check(Token.Symbol.LET); parseDefinition(); parseRestStatementDefinitions(); @@ -187,33 +197,318 @@ public class SynAn implements AutoCloseable { parseStatements(); check(Token.Symbol.END); break; - } - } - private void parseRestStatements() { - if (lexAn.peekToken().symbol() == Token.Symbol.COMMA) { - check(Token.Symbol.COMMA); - parseStatements(); + 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 parseExpressionAssign() { + 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 parseElseStatement() { + 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 --- /**