status messages + better error messages

This commit is contained in:
ChUrl
2020-12-14 16:04:33 +01:00
parent 1987e6532d
commit 2ef7cefedc
5 changed files with 48 additions and 15 deletions

View File

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

View File

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

View File

@ -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)

View File

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

View File

@ -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.");
} }