status messages + better error messages
This commit is contained in:
@ -12,6 +12,7 @@ import java.nio.file.Path;
|
|||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import static util.Logger.log;
|
import static util.Logger.log;
|
||||||
|
|
||||||
@ -33,7 +34,7 @@ public class StupsParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public AST parse(List<? extends Token> token, Vocabulary voc) {
|
public AST parse(List<? extends Token> token, Vocabulary voc) {
|
||||||
ASTNode root = new ASTNode(this.parsetable.getStartSymbol());
|
ASTNode root = new ASTNode(this.parsetable.getStartSymbol(), 0);
|
||||||
AST tree = new AST(root);
|
AST tree = new AST(root);
|
||||||
Deque<ASTNode> stack = new ArrayDeque<>();
|
Deque<ASTNode> stack = new ArrayDeque<>();
|
||||||
stack.push(root);
|
stack.push(root);
|
||||||
@ -48,6 +49,7 @@ public class StupsParser {
|
|||||||
final String top = stack.peek().getName();
|
final String top = stack.peek().getName();
|
||||||
|
|
||||||
final String currentTokenSym;
|
final String currentTokenSym;
|
||||||
|
int currentLine = 0;
|
||||||
if (inputPosition >= token.size()) {
|
if (inputPosition >= token.size()) {
|
||||||
// Wenn auf dem Stack mehr Nichtterminale liegen als Terminale in der Eingabe vorhanden sind
|
// Wenn auf dem Stack mehr Nichtterminale liegen als Terminale in der Eingabe vorhanden sind
|
||||||
// Die Eingabe wurde komplett konsumiert
|
// Die Eingabe wurde komplett konsumiert
|
||||||
@ -57,6 +59,7 @@ public class StupsParser {
|
|||||||
// Es sind noch Eingabesymbole vorhanden
|
// Es sind noch Eingabesymbole vorhanden
|
||||||
|
|
||||||
currentTokenSym = voc.getSymbolicName(token.get(inputPosition).getType());
|
currentTokenSym = voc.getSymbolicName(token.get(inputPosition).getType());
|
||||||
|
currentLine = token.get(inputPosition).getLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
final String prod = this.parsetable.get(top, currentTokenSym);
|
final String prod = this.parsetable.get(top, currentTokenSym);
|
||||||
@ -73,13 +76,15 @@ public class StupsParser {
|
|||||||
} else if (this.parsetable.getTerminals().contains(top)) {
|
} else if (this.parsetable.getTerminals().contains(top)) {
|
||||||
// Wenn das Terminal auf dem Stack nicht mit der aktuellen Eingabe übereinstimmt
|
// Wenn das Terminal auf dem Stack nicht mit der aktuellen Eingabe übereinstimmt
|
||||||
|
|
||||||
System.out.println("Syntaxfehler.");
|
System.out.println("\nLine " + currentLine + " Syntaxerror: Expected " + top + " but found " + currentTokenSym);
|
||||||
|
this.printSourceLine(currentLine, token);
|
||||||
|
|
||||||
throw new ParseException("Invalid terminal on stack: " + top, tree);
|
throw new ParseException("Invalid terminal on stack: " + top, tree);
|
||||||
} else if (prod == null) {
|
} else if (prod == null) {
|
||||||
// Wenn es für das aktuelle Terminal und das Nichtterminal auf dem Stack keine Regel gibt
|
// Wenn es für das aktuelle Terminal und das Nichtterminal auf dem Stack keine Regel gibt
|
||||||
|
|
||||||
System.out.println("Syntaxfehler.");
|
System.out.println("\nLine " + currentLine + " Syntaxerror: Didn't expect " + currentTokenSym);
|
||||||
|
this.printSourceLine(currentLine, token);
|
||||||
|
|
||||||
throw new ParseException("No prod. for nonterminal " + top + ", terminal " + currentTokenSym, tree);
|
throw new ParseException("No prod. for nonterminal " + top + ", terminal " + currentTokenSym, tree);
|
||||||
} else {
|
} else {
|
||||||
@ -92,7 +97,7 @@ public class StupsParser {
|
|||||||
final String[] split = prod.split(" ");
|
final String[] split = prod.split(" ");
|
||||||
|
|
||||||
for (int i = split.length - 1; i >= 0; i--) {
|
for (int i = split.length - 1; i >= 0; i--) {
|
||||||
ASTNode ASTNode = new ASTNode(split[i]);
|
ASTNode node = new ASTNode(split[i], currentLine);
|
||||||
|
|
||||||
if (inputPosition + i < token.size()) {
|
if (inputPosition + i < token.size()) {
|
||||||
// Die Schleife geht in der Eingabe weiter
|
// Die Schleife geht in der Eingabe weiter
|
||||||
@ -100,12 +105,12 @@ public class StupsParser {
|
|||||||
|
|
||||||
// Die Token mit semantischem Inhalt auswählen
|
// Die Token mit semantischem Inhalt auswählen
|
||||||
if ("IDENTIFIER".equals(split[i]) || split[i].endsWith("_LIT")) {
|
if ("IDENTIFIER".equals(split[i]) || split[i].endsWith("_LIT")) {
|
||||||
ASTNode.setValue(currentTok.getText());
|
node.setValue(currentTok.getText());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stack.push(ASTNode);
|
stack.push(node);
|
||||||
pop.addChild(ASTNode);
|
pop.addChild(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,6 +118,17 @@ public class StupsParser {
|
|||||||
log("\nParsed AST:\n" + tree);
|
log("\nParsed AST:\n" + tree);
|
||||||
log("-".repeat(100) + "\n");
|
log("-".repeat(100) + "\n");
|
||||||
|
|
||||||
|
System.out.println("- Parsing successful.");
|
||||||
|
|
||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void printSourceLine(int line, List<? extends Token> token) {
|
||||||
|
Optional<String> srcLine = token.stream()
|
||||||
|
.filter(tok -> tok.getLine() == line)
|
||||||
|
.map(Token::getText)
|
||||||
|
.reduce((s1, s2) -> s1 + " " + s2);
|
||||||
|
|
||||||
|
srcLine.ifPresent(s -> System.out.println(" :: " + s));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,6 +51,8 @@ public final class ASTBalancer {
|
|||||||
|
|
||||||
log(tree.toString());
|
log(tree.toString());
|
||||||
log("-".repeat(100));
|
log("-".repeat(100));
|
||||||
|
|
||||||
|
System.out.println("- Tree balancing successful.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Baum spiegeln, damit höhere Ebenen links sind und EXPR vorwärts laufen
|
// Baum spiegeln, damit höhere Ebenen links sind und EXPR vorwärts laufen
|
||||||
@ -106,7 +108,7 @@ public final class ASTBalancer {
|
|||||||
return false; // Braucht keine weitere Rotation
|
return false; // Braucht keine weitere Rotation
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTNode insertLeft = new ASTNode(root.getName());
|
ASTNode insertLeft = new ASTNode(root.getName(), root.getLine());
|
||||||
insertLeft.setValue(right.getValue()); // Operation wird linksvererbt
|
insertLeft.setValue(right.getValue()); // Operation wird linksvererbt
|
||||||
insertLeft.setChildren(left, right.getChildren().get(0));
|
insertLeft.setChildren(left, right.getChildren().get(0));
|
||||||
|
|
||||||
@ -171,7 +173,7 @@ public final class ASTBalancer {
|
|||||||
|
|
||||||
log("Right-Rotating " + root.getName() + ": " + root.getValue());
|
log("Right-Rotating " + root.getName() + ": " + root.getValue());
|
||||||
|
|
||||||
ASTNode insertRight = new ASTNode(root.getName());
|
ASTNode insertRight = new ASTNode(root.getName(), root.getLine());
|
||||||
insertRight.setValue(root.getValue());
|
insertRight.setValue(root.getValue());
|
||||||
insertRight.setChildren(left.getChildren().get(1), right);
|
insertRight.setChildren(left.getChildren().get(1), right);
|
||||||
|
|
||||||
|
|||||||
@ -33,6 +33,8 @@ public final class ASTCompacter {
|
|||||||
log(tree.toString());
|
log(tree.toString());
|
||||||
log("\nCleaned Tree: " + removed + " nodes removed.");
|
log("\nCleaned Tree: " + removed + " nodes removed.");
|
||||||
log("-".repeat(100));
|
log("-".repeat(100));
|
||||||
|
|
||||||
|
System.out.println("- Tree compression successful.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Entfernt [compact]-able Nodes (Reicht Werte nach oben)
|
// Entfernt [compact]-able Nodes (Reicht Werte nach oben)
|
||||||
|
|||||||
@ -35,6 +35,8 @@ public class GrammarAnalyzer {
|
|||||||
this.follow = this.initFollow();
|
this.follow = this.initFollow();
|
||||||
|
|
||||||
this.table = this.initParseTable();
|
this.table = this.initParseTable();
|
||||||
|
|
||||||
|
System.out.println("\n- Grammar analysis successful.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, Set<String>> initFirst() {
|
private Map<String, Set<String>> initFirst() {
|
||||||
@ -280,11 +282,6 @@ public class GrammarAnalyzer {
|
|||||||
|| this.first.get(sym).contains(this.grammar.getEpsilonSymbol());
|
|| this.first.get(sym).contains(this.grammar.getEpsilonSymbol());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean allNullable(String rightside) {
|
|
||||||
return rightside.isBlank()
|
|
||||||
|| Arrays.stream(rightside.split(" ")).allMatch(this::nullable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean allNullable(String[] split) {
|
public boolean allNullable(String[] split) {
|
||||||
return split.length == 0
|
return split.length == 0
|
||||||
|| Arrays.stream(split).allMatch(this::nullable);
|
|| Arrays.stream(split).allMatch(this::nullable);
|
||||||
|
|||||||
@ -25,6 +25,8 @@ public final class TypeChecker {
|
|||||||
log("Typevalidation:");
|
log("Typevalidation:");
|
||||||
validate(tree.getRoot(), table, nodeTable);
|
validate(tree.getRoot(), table, nodeTable);
|
||||||
log("-".repeat(100));
|
log("-".repeat(100));
|
||||||
|
|
||||||
|
System.out.println("- Typechecking successful.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void validate(ASTNode root, SymbolTable table, Map<ASTNode, String> nodeTable) {
|
private static void validate(ASTNode root, SymbolTable table, Map<ASTNode, String> nodeTable) {
|
||||||
@ -69,6 +71,8 @@ public final class TypeChecker {
|
|||||||
log("Validating Assignment: " + identifierType + ": " + identifier + " = " + literalType);
|
log("Validating Assignment: " + identifierType + ": " + identifier + " = " + literalType);
|
||||||
|
|
||||||
if (!literalType.equals(identifierType)) {
|
if (!literalType.equals(identifierType)) {
|
||||||
|
System.out.println("Line " + root.getLine() + " Typeerror: Can't assign [" + literalNode.getValue() + "] to [" + identifier + "]: " + identifierType);
|
||||||
|
|
||||||
throw new AssignmentTypeMismatchException("Trying to assign " + literalType + " to a " + identifierType + " variable.");
|
throw new AssignmentTypeMismatchException("Trying to assign " + literalType + " to a " + identifierType + " variable.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,14 +83,24 @@ public final class TypeChecker {
|
|||||||
|
|
||||||
log("Validating Expression: " + root.getValue());
|
log("Validating Expression: " + root.getValue());
|
||||||
|
|
||||||
if (root.getChildren().size() != 1 && "NOT".equals(op)) {
|
if (!root.hasChildren()) {
|
||||||
|
// Keine Kinder
|
||||||
|
|
||||||
|
System.out.println("Line " + root.getLine() + " Operatorerror: Can't use [" + op + "] without arguments");
|
||||||
|
|
||||||
|
throw new OperatorUsageException("Versuche Operator " + op + " ohne Argumente aufzurufen.");
|
||||||
|
} else if (root.getChildren().size() != 1 && "NOT".equals(op)) {
|
||||||
// Unärer Operator mit != 1 Child
|
// Unärer Operator mit != 1 Child
|
||||||
// SUB, ADD müssen nicht geprüft werden, da diese doppelt belegt sind mit ihrem binären Gegenstück
|
// SUB, ADD müssen nicht geprüft werden, da diese doppelt belegt sind mit ihrem binären Gegenstück
|
||||||
|
|
||||||
|
System.out.println("Line " + root.getLine() + " Operatorerror: Can't use [" + op + "] with more than 1 argument");
|
||||||
|
|
||||||
throw new OperatorUsageException("Versuche unären Operator " + op + " mit mehreren Argument aufzurufen.");
|
throw new OperatorUsageException("Versuche unären Operator " + op + " mit mehreren Argument aufzurufen.");
|
||||||
} else if (root.getChildren().size() == 1 && !unary.contains(op)) {
|
} else if (root.getChildren().size() == 1 && !unary.contains(op)) {
|
||||||
// Binärer Operator mit 1 Child
|
// Binärer Operator mit 1 Child
|
||||||
|
|
||||||
|
System.out.println("Line " + root.getLine() + " Operatorerror: Can't use [" + op + "] with only 1 argument");
|
||||||
|
|
||||||
throw new OperatorUsageException("Versuche binären Operator " + op + " mit einem Argument aufzurufen.");
|
throw new OperatorUsageException("Versuche binären Operator " + op + " mit einem Argument aufzurufen.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,6 +114,8 @@ public final class TypeChecker {
|
|||||||
// Child returned Typ, welcher nicht im SymbolTable als Argumenttyp steht
|
// Child returned Typ, welcher nicht im SymbolTable als Argumenttyp steht
|
||||||
// Der NodeTable enthält auch Literale, diese müssen also nicht einzeln behandelt werden
|
// Der NodeTable enthält auch Literale, diese müssen also nicht einzeln behandelt werden
|
||||||
|
|
||||||
|
System.out.println("Line " + root.getLine() + " Typeerror: Can't use [" + op + "] with argument of type [" + nodeTable.get(child) + "]");
|
||||||
|
|
||||||
throw new OperatorTypeMismatchException("Versuche Operator " + op + " mit Argument vom Typ " + nodeTable.get(child) + " aufzurufen.");
|
throw new OperatorTypeMismatchException("Versuche Operator " + op + " mit Argument vom Typ " + nodeTable.get(child) + " aufzurufen.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user