use logger for logging + fix bug in stringFirst

This commit is contained in:
ChUrl
2020-12-07 23:33:28 +01:00
parent aba8a51db2
commit ea4cf84c41
2 changed files with 74 additions and 21 deletions

View File

@ -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;
}
}

View File

@ -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<String, Set<String>> initFirst() {
@ -47,6 +50,8 @@ public class LL1GrammarAnalyzer {
final Predicate<String[]> 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<String, Set<String>> initFollow() {
final Map<String, Set<String>> 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<Map.Entry<String, String>, 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<String> 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());