use logger for logging + fix bug in stringFirst
This commit is contained in:
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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());
|
||||
|
||||
Reference in New Issue
Block a user