From ea4cf84c41acc5249c4ff94f993147e853363d0d Mon Sep 17 00:00:00 2001 From: ChUrl Date: Mon, 7 Dec 2020 23:33:28 +0100 Subject: [PATCH] use logger for logging + fix bug in stringFirst --- src/main/java/parser/LL1Parser.java | 13 ++- .../parser/grammar/LL1GrammarAnalyzer.java | 82 +++++++++++++++---- 2 files changed, 74 insertions(+), 21 deletions(-) diff --git a/src/main/java/parser/LL1Parser.java b/src/main/java/parser/LL1Parser.java index c542d3b..217e056 100644 --- a/src/main/java/parser/LL1Parser.java +++ b/src/main/java/parser/LL1Parser.java @@ -11,6 +11,8 @@ import java.util.ArrayDeque; import java.util.Deque; import java.util.List; +import static util.tools.Logger.log; + public class LL1Parser { private final ILL1ParsingTable parsetable; @@ -35,7 +37,9 @@ public class LL1Parser { stack.push(root); int inputPosition = 0; - System.out.println("\nParsing " + token + ":"); + + log("\nParsing:"); + log("Input: " + token + "\n"); // Parsing while (!stack.isEmpty()) { @@ -76,8 +80,7 @@ public class LL1Parser { // Wenn das Nichtterminal auf dem Stack durch (s)eine Produktion ersetzt werden kann // Hier wird auch der AST aufgebaut - System.out.println(top + " -> " + prod); - + log("Used: " + top + " -> " + prod); Node pop = stack.pop(); final String[] split = prod.split(" "); @@ -89,7 +92,9 @@ public class LL1Parser { } } - System.out.println("\n" + tree); + log("\nParsed AST:\n" + tree); + log("-".repeat(100) + "\n"); + return true; } } diff --git a/src/main/java/parser/grammar/LL1GrammarAnalyzer.java b/src/main/java/parser/grammar/LL1GrammarAnalyzer.java index 3df2c31..706b774 100644 --- a/src/main/java/parser/grammar/LL1GrammarAnalyzer.java +++ b/src/main/java/parser/grammar/LL1GrammarAnalyzer.java @@ -13,6 +13,10 @@ import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; +import static util.tools.Logger.log; +import static util.tools.Logger.logIfTrue; +import static util.tools.Logger.logNullable; + public class LL1GrammarAnalyzer { private final Grammar grammar; @@ -25,15 +29,14 @@ public class LL1GrammarAnalyzer { public LL1GrammarAnalyzer(Grammar grammar) { this.grammar = grammar; + log("-".repeat(100)); + log("Analyzing Grammar:\n"); + // Es muss zwingend in der Reihenfolge [Nullable < First < Follow < Table] initialisiert werden this.first = this.initFirst(); this.follow = this.initFollow(); this.table = this.initParseTable(); - - // System.out.println("First:\n" + this.first); - // System.out.println("Follow:\n" + this.follow); - System.out.println("LL-Table:\n" + this.table); } private Map> initFirst() { @@ -47,6 +50,8 @@ public class LL1GrammarAnalyzer { final Predicate allNullable = split -> split.length == 0 || Arrays.stream(split).allMatch(nullable); + log("First Initialisieren:"); + // Initialisieren for (String nterm : this.grammar.getNonterminals()) { firstOut.put(nterm, new HashSet<>()); @@ -90,13 +95,19 @@ public class LL1GrammarAnalyzer { .filter(sym -> !sym.equals(this.grammar.getEpsilonSymbol())) .collect(Collectors.toSet()); - change = change || firstOut.get(leftside).addAll(firstYiNoEps); + boolean changeNow = firstOut.get(leftside).addAll(firstYiNoEps); + change = change || changeNow; + + logIfTrue(changeNow, "First: Added " + firstYiNoEps + " to " + leftside + " (All before are nullable)"); } if (i == split.length - 1 && allNullable.test(split)) { // 2. (b) If epsilon is in first(Y1) ... first(Yk), then add epsilon to first(X). - change = change || firstOut.get(leftside).add(this.grammar.getEpsilonSymbol()); + boolean changeNow = firstOut.get(leftside).add(this.grammar.getEpsilonSymbol()); + change = change || changeNow; + + logIfTrue(changeNow, "First: Added " + this.grammar.getEpsilonSymbol() + " to " + leftside + " (All are nullable)"); } } } @@ -104,18 +115,26 @@ public class LL1GrammarAnalyzer { if (rightside.equals(this.grammar.getEpsilonSymbol())) { // 3. If X -> epsilon is a production, then add epsilon to first(X). - change = change || firstOut.get(leftside).add(this.grammar.getEpsilonSymbol()); + boolean changeNow = firstOut.get(leftside).add(this.grammar.getEpsilonSymbol()); + change = change || changeNow; + + logIfTrue(changeNow, "First: Added " + this.grammar.getEpsilonSymbol() + " to " + leftside + " (X -> EPS exists)"); } } } } while (change); + log("\n" + firstOut); + log("-".repeat(100) + "\n"); + return firstOut; } private Map> initFollow() { final Map> followOut = new HashMap<>(); + log("Follow Initialisieren:"); + // Initialisieren for (String nterm : this.grammar.getNonterminals()) { followOut.put(nterm, new HashSet<>()); @@ -158,7 +177,10 @@ public class LL1GrammarAnalyzer { .filter(sym -> !sym.equals(this.grammar.getEpsilonSymbol())) .collect(Collectors.toSet()); - change = change || followOut.get(split[i - 1]).addAll(firstXkNoEps); + boolean changeNow = followOut.get(split[i - 1]).addAll(firstXkNoEps); + change = change || changeNow; + + logIfTrue(changeNow, "Follow: Added " + firstXkNoEps + " to " + split[i - 1] + " (Dazwischen nullable)"); } } @@ -168,26 +190,37 @@ public class LL1GrammarAnalyzer { if (this.allNullable(sub)) { - change = change || followOut.get(split[i - 1]).addAll(followOut.get(leftside)); + boolean changeNow = followOut.get(split[i - 1]).addAll(followOut.get(leftside)); + change = change || changeNow; + + logIfTrue(changeNow, "Follow: Added " + leftside + " to " + split[i - 1] + " (Dahinter nullable)"); } } if (this.grammar.getNonterminals().contains(split[split.length - 1])) { // 3. (a) If there is a production A -> aB, then everything in follow(A) is in follow(B). - change = change || followOut.get(split[split.length - 1]).addAll(followOut.get(leftside)); + boolean changeNow = followOut.get(split[split.length - 1]).addAll(followOut.get(leftside)); + change = change || changeNow; + + logIfTrue(changeNow, "Follow: Added " + followOut.get(leftside) + " to " + split[split.length - 1] + " (Ende der Regel)"); } } } } while (change); + log("\n" + followOut); + log("-".repeat(100) + "\n"); + return followOut; } private ILL1ParsingTable initParseTable() { Map, String> tableOut = new HashMap<>(); + log("Parsetable Aufstellen:"); + for (String leftside : this.grammar.getLeftSides()) { for (String rightside : this.grammar.getRightsides(leftside)) { @@ -198,13 +231,17 @@ public class LL1GrammarAnalyzer { for (String sym : firstRightside) { // 1. For each terminal t in first(a), add A -> a to table[A, t] - tableOut.put(new AbstractMap.SimpleEntry<>(leftside, sym), rightside); + String prev = tableOut.put(new AbstractMap.SimpleEntry<>(leftside, sym), rightside); + + log("Add " + rightside + " to cell (" + leftside + ", " + sym + ") (" + sym + " in first of " + rightside + ")"); + logNullable("Overwritten " + prev + "!\n"); } final Set followLeftside = this.follow(leftside); - System.out.println(leftside + " -> " + rightside); - System.out.println("First: " + firstRightside); + // log(leftside + " -> " + rightside); + // log("First: " + firstRightside); + // log("Follow: " + followLeftside + "\n"); if (firstRightside.contains(this.grammar.getEpsilonSymbol())) { // 2. If epsilon in first(a), then... @@ -212,19 +249,30 @@ public class LL1GrammarAnalyzer { for (String sym : followLeftside) { // ...for each terminal b in follow(A), add A -> a to table[A, b]. - tableOut.put(new AbstractMap.SimpleEntry<>(leftside, sym), rightside); + String prev = tableOut.put(new AbstractMap.SimpleEntry<>(leftside, sym), rightside); + + log("Add " + rightside + " to cell (" + leftside + ", " + sym + ") (" + sym + " in follow of " + leftside + ")"); + logNullable("Overwritten " + prev + "!\n"); } if (followLeftside.contains("$")) { // If epsilon is in first(a) and $ is in follow(A), add A -> a to table[A, $]. - tableOut.put(new AbstractMap.SimpleEntry<>(leftside, "$"), rightside); + String prev = tableOut.put(new AbstractMap.SimpleEntry<>(leftside, "$"), rightside); + + log("Add " + rightside + " to cell (" + leftside + ", $) (epsilon in first of " + rightside + " and $ in follow of " + leftside + ")"); + logNullable("Overwritten " + prev + "!\n"); } } } } - return new LL1ParsingTable(this.grammar, tableOut); + final LL1ParsingTable table = new LL1ParsingTable(this.grammar, tableOut); + + log("\n" + table); + log("-".repeat(100) + "\n"); + + return table; } @@ -277,7 +325,7 @@ public class LL1GrammarAnalyzer { firstOut.addAll(firstXiNoEps); - if (i == split.length - 1) { + if (i == split.length - 1 && this.allNullable(split)) { // Finally, add epsilon to first(X1 X2 ... Xn) if, for all i, epsilon is in first(Xi). firstOut.add(this.grammar.getEpsilonSymbol());