rework SyntaxTree (AST)
This commit is contained in:
@ -6,8 +6,8 @@ import lexer.StupsLexer;
|
||||
import org.antlr.v4.runtime.CharStreams;
|
||||
import org.antlr.v4.runtime.Lexer;
|
||||
import parser.StupsParser;
|
||||
import parser.ast.AST;
|
||||
import parser.ast.ASTNode;
|
||||
import parser.ast.SyntaxTree;
|
||||
import parser.ast.SyntaxTreeNode;
|
||||
import parser.grammar.Grammar;
|
||||
import typechecker.TypeChecker;
|
||||
import util.Logger;
|
||||
@ -122,10 +122,11 @@ public final class StupsCompiler {
|
||||
final StupsParser stupsParser = StupsParser.fromGrammar(grammar);
|
||||
|
||||
// Parsing + Typechecking of program
|
||||
final AST tree = stupsParser.parse(lexer.getAllTokens(), lexer.getVocabulary());
|
||||
tree.postprocess(grammar);
|
||||
final Map<ASTNode, String> nodeTable = TypeChecker.validate(tree);
|
||||
final SyntaxTree parseTree = stupsParser.parse(lexer.getAllTokens(), lexer.getVocabulary());
|
||||
|
||||
return FlowGraphGenerator.fromAST(tree, nodeTable, filename);
|
||||
final SyntaxTree abstractSyntaxTree = SyntaxTree.toAbstractSyntaxTree(parseTree, grammar);
|
||||
final Map<SyntaxTreeNode, String> nodeTable = TypeChecker.validate(abstractSyntaxTree);
|
||||
|
||||
return FlowGraphGenerator.fromAST(abstractSyntaxTree, nodeTable, filename);
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ package codegen;
|
||||
|
||||
import codegen.flowgraph.FlowGraph;
|
||||
import codegen.flowgraph.FlowGraphGenerator;
|
||||
import parser.ast.AST;
|
||||
import parser.ast.ASTNode;
|
||||
import parser.ast.SyntaxTree;
|
||||
import parser.ast.SyntaxTreeNode;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@ -11,7 +11,7 @@ public final class CodeGenerator {
|
||||
|
||||
private CodeGenerator() {}
|
||||
|
||||
public static String generateCode(AST tree, Map<ASTNode, String> nodeTypeMap, String source) {
|
||||
public static String generateCode(SyntaxTree tree, Map<SyntaxTreeNode, String> nodeTypeMap, String source) {
|
||||
final FlowGraphGenerator gen = FlowGraphGenerator.fromAST(tree, nodeTypeMap, source);
|
||||
final FlowGraph graph = gen.generateGraph();
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package codegen.analysis;
|
||||
|
||||
import parser.ast.ASTNode;
|
||||
import parser.ast.SyntaxTreeNode;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
@ -10,7 +10,7 @@ import java.util.Deque;
|
||||
*/
|
||||
public class StackModel {
|
||||
|
||||
private final Deque<ASTNode> stack;
|
||||
private final Deque<SyntaxTreeNode> stack;
|
||||
|
||||
/**
|
||||
* Speichert die maximale Stacktiefe während der Ausführung.
|
||||
@ -21,7 +21,7 @@ public class StackModel {
|
||||
this.stack = new ArrayDeque<>();
|
||||
}
|
||||
|
||||
public void push(ASTNode root) {
|
||||
public void push(SyntaxTreeNode root) {
|
||||
this.stack.push(root);
|
||||
this.updateMax();
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package codegen.analysis;
|
||||
|
||||
import parser.ast.AST;
|
||||
import parser.ast.ASTNode;
|
||||
import parser.ast.SyntaxTree;
|
||||
import parser.ast.SyntaxTreeNode;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@ -9,7 +9,7 @@ import static util.Logger.log;
|
||||
|
||||
/**
|
||||
* Ermittelt die maximal benötigte Stacktiefe für ein Programm.
|
||||
* Das Programm wird übergeben als {@link AST}.
|
||||
* Das Programm wird übergeben als {@link SyntaxTree}.
|
||||
*/
|
||||
public final class StackSizeAnalyzer {
|
||||
|
||||
@ -23,7 +23,7 @@ public final class StackSizeAnalyzer {
|
||||
|
||||
private StackSizeAnalyzer() {}
|
||||
|
||||
public static int runStackModel(AST tree) {
|
||||
public static int runStackModel(SyntaxTree tree) {
|
||||
log("\nDetermining required stack depth:");
|
||||
|
||||
final StackModel stack = new StackModel();
|
||||
@ -33,7 +33,7 @@ public final class StackSizeAnalyzer {
|
||||
return stack.getMax();
|
||||
}
|
||||
|
||||
private static void runStackModel(ASTNode root, StackModel stack) {
|
||||
private static void runStackModel(SyntaxTreeNode root, StackModel stack) {
|
||||
if (mod.contains(root.getName())) {
|
||||
switch (root.getName()) {
|
||||
case "assignment" -> assignment(root, stack);
|
||||
@ -43,7 +43,7 @@ public final class StackSizeAnalyzer {
|
||||
default -> throw new IllegalStateException("Unexpected value: " + root.getName());
|
||||
}
|
||||
} else {
|
||||
for (ASTNode child : root.getChildren()) {
|
||||
for (SyntaxTreeNode child : root.getChildren()) {
|
||||
runStackModel(child, stack);
|
||||
}
|
||||
}
|
||||
@ -51,17 +51,17 @@ public final class StackSizeAnalyzer {
|
||||
|
||||
// Simulate instructions
|
||||
|
||||
private static void literal(ASTNode root, StackModel stack) {
|
||||
private static void literal(SyntaxTreeNode root, StackModel stack) {
|
||||
stack.push(root);
|
||||
}
|
||||
|
||||
private static void assignment(ASTNode root, StackModel stack) {
|
||||
private static void assignment(SyntaxTreeNode root, StackModel stack) {
|
||||
runStackModel(root.getChildren().get(0), stack);
|
||||
|
||||
stack.pop();
|
||||
}
|
||||
|
||||
private static void println(ASTNode root, StackModel stack) {
|
||||
private static void println(SyntaxTreeNode root, StackModel stack) {
|
||||
stack.push(root); // Getstatic
|
||||
|
||||
runStackModel(root.getChildren().get(1).getChildren().get(1), stack);
|
||||
@ -70,7 +70,7 @@ public final class StackSizeAnalyzer {
|
||||
stack.pop(); // Argument
|
||||
}
|
||||
|
||||
private static void expr(ASTNode root, StackModel stack) {
|
||||
private static void expr(SyntaxTreeNode root, StackModel stack) {
|
||||
if (root.getChildren().size() == 2 && binaryOperators.contains(root.getValue())) {
|
||||
// Expression with binary operator
|
||||
|
||||
@ -85,7 +85,7 @@ public final class StackSizeAnalyzer {
|
||||
|
||||
runStackModel(root.getChildren().get(0), stack);
|
||||
|
||||
stack.push(new ASTNode("1 (XOR)", 0)); // 1 for xor
|
||||
stack.push(new SyntaxTreeNode("1 (XOR)", 0)); // 1 for xor
|
||||
stack.pop(); // xor
|
||||
stack.pop(); // xor
|
||||
stack.push(root); // result
|
||||
|
@ -1,6 +1,6 @@
|
||||
package codegen.flowgraph;
|
||||
|
||||
import parser.ast.AST;
|
||||
import parser.ast.SyntaxTree;
|
||||
import util.GraphvizCaller;
|
||||
import util.Logger;
|
||||
|
||||
@ -15,7 +15,7 @@ import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Die Graph-Repräsentation des Programm, erzeugt aus einem {@link AST}.
|
||||
* Die Graph-Repräsentation des Programm, erzeugt aus einem {@link SyntaxTree}.
|
||||
* Der Grundbaustein ist {@link FlowBasicBlock}, diese enthalten wiederum {@link FlowInstruction}.
|
||||
*/
|
||||
public class FlowGraph implements Iterable<FlowBasicBlock> {
|
||||
|
@ -2,8 +2,8 @@ package codegen.flowgraph;
|
||||
|
||||
import codegen.CodeGenerationException;
|
||||
import codegen.analysis.StackSizeAnalyzer;
|
||||
import parser.ast.AST;
|
||||
import parser.ast.ASTNode;
|
||||
import parser.ast.SyntaxTree;
|
||||
import parser.ast.SyntaxTreeNode;
|
||||
import typechecker.TypeChecker;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
@ -23,7 +23,7 @@ import static util.Logger.log;
|
||||
public final class FlowGraphGenerator {
|
||||
|
||||
/**
|
||||
* Mappt die {@link ASTNode}-Namen auf entsprechende Methoden für die Codeerzeugung.
|
||||
* Mappt die {@link SyntaxTreeNode}-Namen auf entsprechende Methoden für die Codeerzeugung.
|
||||
*/
|
||||
private static final Map<String, Method> methodMap;
|
||||
|
||||
@ -33,16 +33,16 @@ public final class FlowGraphGenerator {
|
||||
try {
|
||||
final Class<?> gen = FlowGraphGenerator.class;
|
||||
map = Map.ofEntries(
|
||||
entry("cond", gen.getDeclaredMethod("condNode", ASTNode.class)),
|
||||
entry("loop", gen.getDeclaredMethod("loopNode", ASTNode.class)),
|
||||
entry("assignment", gen.getDeclaredMethod("assignNode", ASTNode.class)),
|
||||
entry("expr", gen.getDeclaredMethod("exprNode", ASTNode.class)),
|
||||
entry("cond", gen.getDeclaredMethod("condNode", SyntaxTreeNode.class)),
|
||||
entry("loop", gen.getDeclaredMethod("loopNode", SyntaxTreeNode.class)),
|
||||
entry("assignment", gen.getDeclaredMethod("assignNode", SyntaxTreeNode.class)),
|
||||
entry("expr", gen.getDeclaredMethod("exprNode", SyntaxTreeNode.class)),
|
||||
// Leafs
|
||||
entry("INTEGER_LIT", gen.getDeclaredMethod("intStringLiteralNode", ASTNode.class)),
|
||||
entry("BOOLEAN_LIT", gen.getDeclaredMethod("boolLiteralNode", ASTNode.class)),
|
||||
entry("STRING_LIT", gen.getDeclaredMethod("intStringLiteralNode", ASTNode.class)),
|
||||
entry("IDENTIFIER", gen.getDeclaredMethod("identifierNode", ASTNode.class)),
|
||||
entry("print", gen.getDeclaredMethod("printlnNode", ASTNode.class))
|
||||
entry("INTEGER_LIT", gen.getDeclaredMethod("intStringLiteralNode", SyntaxTreeNode.class)),
|
||||
entry("BOOLEAN_LIT", gen.getDeclaredMethod("boolLiteralNode", SyntaxTreeNode.class)),
|
||||
entry("STRING_LIT", gen.getDeclaredMethod("intStringLiteralNode", SyntaxTreeNode.class)),
|
||||
entry("IDENTIFIER", gen.getDeclaredMethod("identifierNode", SyntaxTreeNode.class)),
|
||||
entry("print", gen.getDeclaredMethod("printlnNode", SyntaxTreeNode.class))
|
||||
);
|
||||
} catch (NoSuchMethodException e) {
|
||||
map = null;
|
||||
@ -51,13 +51,13 @@ public final class FlowGraphGenerator {
|
||||
methodMap = map;
|
||||
}
|
||||
|
||||
private final AST tree;
|
||||
private final SyntaxTree tree;
|
||||
|
||||
/**
|
||||
* Enthält den Rückgabetypen von jedem Expression-Node.
|
||||
* Wird erstellt im {@link TypeChecker}.
|
||||
*/
|
||||
private final Map<ASTNode, String> nodeTypeMap;
|
||||
private final Map<SyntaxTreeNode, String> nodeTypeMap;
|
||||
|
||||
/**
|
||||
* Enthält die Mappings vom Symbol/Variablennamen auf die Position in der JVM-Locals-Tabelle.
|
||||
@ -68,7 +68,7 @@ public final class FlowGraphGenerator {
|
||||
|
||||
private int labelCounter;
|
||||
|
||||
private FlowGraphGenerator(Map<String, Integer> varMap, AST tree, Map<ASTNode, String> nodeTypeMap, FlowGraph graph) {
|
||||
private FlowGraphGenerator(Map<String, Integer> varMap, SyntaxTree tree, Map<SyntaxTreeNode, String> nodeTypeMap, FlowGraph graph) {
|
||||
this.varMap = varMap;
|
||||
this.tree = tree;
|
||||
this.nodeTypeMap = nodeTypeMap;
|
||||
@ -78,7 +78,7 @@ public final class FlowGraphGenerator {
|
||||
/**
|
||||
* @param source Das Source-File, welches compiliert wird (Optionaler Jasmin-Parameter)
|
||||
*/
|
||||
public static FlowGraphGenerator fromAST(AST tree, Map<ASTNode, String> nodeTypeMap, String source) {
|
||||
public static FlowGraphGenerator fromAST(SyntaxTree tree, Map<SyntaxTreeNode, String> nodeTypeMap, String source) {
|
||||
if (tree.isEmpty()) {
|
||||
throw new CodeGenerationException("Empty File can't be compiled");
|
||||
}
|
||||
@ -89,17 +89,17 @@ public final class FlowGraphGenerator {
|
||||
return new FlowGraphGenerator(varMap, tree, nodeTypeMap, graph);
|
||||
}
|
||||
|
||||
private static Map<String, Integer> initVarMap(AST tree) {
|
||||
private static Map<String, Integer> initVarMap(SyntaxTree tree) {
|
||||
final Map<String, Integer> varMap = new HashMap<>();
|
||||
|
||||
final Deque<ASTNode> stack = new ArrayDeque<>();
|
||||
final Deque<SyntaxTreeNode> stack = new ArrayDeque<>();
|
||||
stack.push(tree.getRoot());
|
||||
|
||||
int currentVarNumber = 0;
|
||||
|
||||
// Assign variables to map: Symbol -> jasminLocalVarNr.
|
||||
while (!stack.isEmpty()) {
|
||||
final ASTNode current = stack.pop();
|
||||
final SyntaxTreeNode current = stack.pop();
|
||||
|
||||
if ("declaration".equals(current.getName())) {
|
||||
// New variables only come from declarations
|
||||
@ -117,7 +117,7 @@ public final class FlowGraphGenerator {
|
||||
return Collections.unmodifiableMap(varMap);
|
||||
}
|
||||
|
||||
private static FlowGraph initFlowGraph(AST tree, Map<String, Integer> varMap, String source) {
|
||||
private static FlowGraph initFlowGraph(SyntaxTree tree, Map<String, Integer> varMap, String source) {
|
||||
final String bytecodeVersion = "49.0";
|
||||
final String clazz = tree.getRoot().getChildren().get(1).getValue();
|
||||
final int stackSize = StackSizeAnalyzer.runStackModel(tree);
|
||||
@ -149,7 +149,7 @@ public final class FlowGraphGenerator {
|
||||
* Der Wurzelname wird über die methodMap einer Methode zugewiesen.
|
||||
* Diese wird aufgerufen und erzeugt den entsprechenden Teilbaum.
|
||||
*/
|
||||
private void generateNode(ASTNode root) {
|
||||
private void generateNode(SyntaxTreeNode root) {
|
||||
if (methodMap.containsKey(root.getName())) {
|
||||
try {
|
||||
methodMap.get(root.getName()).invoke(this, root);
|
||||
@ -164,7 +164,7 @@ public final class FlowGraphGenerator {
|
||||
/**
|
||||
* Erzeugt den Teilbaum für einen If-Knoten.
|
||||
*/
|
||||
private void condNode(ASTNode root) {
|
||||
private void condNode(SyntaxTreeNode root) {
|
||||
final int currentLabel = this.labelCounter;
|
||||
this.labelCounter++;
|
||||
|
||||
@ -193,7 +193,7 @@ public final class FlowGraphGenerator {
|
||||
/**
|
||||
* Erzeugt den Teilbaum für einen While-Knoten.
|
||||
*/
|
||||
private void loopNode(ASTNode root) {
|
||||
private void loopNode(SyntaxTreeNode root) {
|
||||
final int currentLabel = this.labelCounter;
|
||||
this.labelCounter++;
|
||||
|
||||
@ -218,7 +218,7 @@ public final class FlowGraphGenerator {
|
||||
* Erzeugt den Teilbaum für Assignment-Knoten.
|
||||
* Die JVM-Stacksize wird dabei um 1 verringert, da istore/astore 1 Argument konsumieren.
|
||||
*/
|
||||
private void assignNode(ASTNode root) { //! Stack - 1
|
||||
private void assignNode(SyntaxTreeNode root) { //! Stack - 1
|
||||
this.generateNode(root.getChildren().get(0));
|
||||
|
||||
final String type = this.nodeTypeMap.get(root.getChildren().get(0));
|
||||
@ -236,7 +236,7 @@ public final class FlowGraphGenerator {
|
||||
/**
|
||||
* Wählt die entsprechende Methode für mathematische oder logische Ausdrücke.
|
||||
*/
|
||||
private void exprNode(ASTNode root) {
|
||||
private void exprNode(SyntaxTreeNode root) {
|
||||
if ("INTEGER_TYPE".equals(this.nodeTypeMap.get(root))) {
|
||||
this.intExpr(root);
|
||||
} else if ("BOOLEAN_TYPE".equals(this.nodeTypeMap.get(root))) {
|
||||
@ -249,7 +249,7 @@ public final class FlowGraphGenerator {
|
||||
* Bei unären Operatoren bleibt die Stackgröße konstant (1 konsumiert, 1 Ergebnis),
|
||||
* bei binären Operatoren sinkt die Stackgröße um 1 (2 konsumiert, 1 Ergebnis).
|
||||
*/
|
||||
private void intExpr(ASTNode root) {
|
||||
private void intExpr(SyntaxTreeNode root) {
|
||||
String inst = "";
|
||||
|
||||
if (root.getChildren().size() == 1) { //! Stack + 0
|
||||
@ -288,7 +288,7 @@ public final class FlowGraphGenerator {
|
||||
* Bei unären Operatoren wächst der Stack temporär um 1 (NOT pusht eine 1 für xor),
|
||||
* bei binären Operatoren sinkt die Stackgröße um 1 (2 konsumiert, 1 Ergebnis).
|
||||
*/
|
||||
private void boolExpr(ASTNode node) {
|
||||
private void boolExpr(SyntaxTreeNode node) {
|
||||
if (node.getChildren().size() == 1) { //! Stack + 1
|
||||
// Unary operator
|
||||
|
||||
@ -358,14 +358,14 @@ public final class FlowGraphGenerator {
|
||||
|
||||
// Leafs
|
||||
|
||||
private void intStringLiteralNode(ASTNode node) { //! Stack + 1
|
||||
private void intStringLiteralNode(SyntaxTreeNode node) { //! Stack + 1
|
||||
log("intStringLiteral(): " + node.getName() + ": " + node.getValue() + " => ldc");
|
||||
|
||||
// bipush only pushes 1 byte as int
|
||||
this.graph.addInstruction("ldc", node.getValue());
|
||||
}
|
||||
|
||||
private void boolLiteralNode(ASTNode node) { //! Stack + 1
|
||||
private void boolLiteralNode(SyntaxTreeNode node) { //! Stack + 1
|
||||
log("booleanLiteral(): " + node.getName() + ": " + node.getValue() + " => ldc");
|
||||
|
||||
final String val = "true".equals(node.getValue()) ? "1" : "0";
|
||||
@ -373,7 +373,7 @@ public final class FlowGraphGenerator {
|
||||
this.graph.addInstruction("ldc", val);
|
||||
}
|
||||
|
||||
private void identifierNode(ASTNode node) { //! Stack + 1
|
||||
private void identifierNode(SyntaxTreeNode node) { //! Stack + 1
|
||||
final String type = this.nodeTypeMap.get(node);
|
||||
final String inst = switch (type) {
|
||||
case "INTEGER_TYPE", "BOOLEAN_TYPE" -> "iload";
|
||||
@ -386,10 +386,10 @@ public final class FlowGraphGenerator {
|
||||
this.graph.addInstruction(inst, this.varMap.get(node.getValue()).toString());
|
||||
}
|
||||
|
||||
private void printlnNode(ASTNode node) { //! Stack + 1
|
||||
private void printlnNode(SyntaxTreeNode node) { //! Stack + 1
|
||||
this.graph.addInstruction("getstatic", "java/lang/System/out", "Ljava/io/PrintStream;");
|
||||
|
||||
final ASTNode expr = node.getChildren().get(1).getChildren().get(1);
|
||||
final SyntaxTreeNode expr = node.getChildren().get(1).getChildren().get(1);
|
||||
final String type = switch (this.nodeTypeMap.get(expr)) {
|
||||
case "BOOLEAN_TYPE" -> "Z";
|
||||
case "INTEGER_TYPE" -> "I";
|
||||
|
@ -1,14 +1,14 @@
|
||||
package parser;
|
||||
|
||||
import parser.ast.AST;
|
||||
import parser.ast.SyntaxTree;
|
||||
|
||||
import static util.Logger.log;
|
||||
|
||||
public class ParseException extends RuntimeException {
|
||||
|
||||
public ParseException(String message, AST ast) {
|
||||
public ParseException(String message, SyntaxTree syntaxTree) {
|
||||
super("\n" + message);
|
||||
|
||||
log("\nAST at last state:\n" + ast);
|
||||
log("\nAST at last state:\n" + syntaxTree);
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ package parser;
|
||||
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.Vocabulary;
|
||||
import parser.ast.AST;
|
||||
import parser.ast.ASTNode;
|
||||
import parser.ast.SyntaxTree;
|
||||
import parser.ast.SyntaxTreeNode;
|
||||
import parser.grammar.Grammar;
|
||||
import parser.grammar.GrammarAnalyzer;
|
||||
|
||||
@ -37,11 +37,11 @@ public class StupsParser {
|
||||
srcLine.ifPresent(s -> System.out.println(" :: " + s));
|
||||
}
|
||||
|
||||
public AST parse(List<? extends Token> token, Vocabulary voc) {
|
||||
public SyntaxTree parse(List<? extends Token> token, Vocabulary voc) {
|
||||
System.out.println(" - Parsing program...");
|
||||
final ASTNode root = new ASTNode(this.parsetable.getStartSymbol(), 0);
|
||||
final AST tree = new AST(root);
|
||||
final Deque<ASTNode> stack = new ArrayDeque<>();
|
||||
final SyntaxTreeNode root = new SyntaxTreeNode(this.parsetable.getStartSymbol(), 0);
|
||||
final SyntaxTree tree = new SyntaxTree(root);
|
||||
final Deque<SyntaxTreeNode> stack = new ArrayDeque<>();
|
||||
stack.push(root);
|
||||
|
||||
int inputPosition = 0;
|
||||
@ -97,12 +97,12 @@ public class StupsParser {
|
||||
// Hier wird auch der AST aufgebaut
|
||||
|
||||
log("Used: " + top + " -> " + prod);
|
||||
final ASTNode pop = stack.pop();
|
||||
final SyntaxTreeNode pop = stack.pop();
|
||||
|
||||
final String[] split = prod.split(" ");
|
||||
|
||||
for (int i = split.length - 1; i >= 0; i--) {
|
||||
final ASTNode node = new ASTNode(split[i], currentLine);
|
||||
final SyntaxTreeNode node = new SyntaxTreeNode(split[i], currentLine);
|
||||
|
||||
if (inputPosition + i < token.size()) {
|
||||
// Die Schleife geht in der Eingabe weiter
|
||||
|
@ -1,57 +0,0 @@
|
||||
package parser.ast;
|
||||
|
||||
import parser.grammar.Grammar;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class AST {
|
||||
|
||||
private final ASTNode root;
|
||||
|
||||
public AST(ASTNode root) {
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
public ASTNode getRoot() {
|
||||
return this.root;
|
||||
}
|
||||
|
||||
public long size() {
|
||||
return this.root.size();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return this.root.isEmpty();
|
||||
}
|
||||
|
||||
public void postprocess(Grammar grammar) {
|
||||
ASTCompacter.clean(this, grammar);
|
||||
ASTBalancer.balance(this);
|
||||
System.out.println("Tree processing successful.");
|
||||
}
|
||||
|
||||
public AST deepCopy() {
|
||||
return new AST(this.root.deepCopy());
|
||||
}
|
||||
|
||||
// Overrides
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof AST) {
|
||||
return this.root.equals(((AST) obj).root);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.root.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.root);
|
||||
}
|
||||
}
|
@ -43,7 +43,7 @@ public final class ASTBalancer {
|
||||
|
||||
private ASTBalancer() {}
|
||||
|
||||
public static void balance(AST tree) {
|
||||
public static void balance(SyntaxTree tree) {
|
||||
flip(tree);
|
||||
leftPrecedence(tree);
|
||||
operatorPrecedence(tree);
|
||||
@ -56,26 +56,26 @@ public final class ASTBalancer {
|
||||
}
|
||||
|
||||
// Baum spiegeln, damit höhere Ebenen links sind und EXPR vorwärts laufen
|
||||
public static void flip(AST tree) {
|
||||
public static void flip(SyntaxTree tree) {
|
||||
log("Flipping tree for ltr evaluation");
|
||||
flip(tree.getRoot());
|
||||
}
|
||||
|
||||
private static void flip(ASTNode root) {
|
||||
for (ASTNode child : root.getChildren()) {
|
||||
private static void flip(SyntaxTreeNode root) {
|
||||
for (SyntaxTreeNode child : root.getChildren()) {
|
||||
flip(child);
|
||||
}
|
||||
|
||||
Collections.reverse(root.getChildren());
|
||||
}
|
||||
|
||||
public static void flipCommutativeExpr(AST tree) {
|
||||
public static void flipCommutativeExpr(SyntaxTree tree) {
|
||||
log("Flipping commutative expressions for stack efficiency");
|
||||
flipCommutativeExpr(tree.getRoot());
|
||||
}
|
||||
|
||||
private static void flipCommutativeExpr(ASTNode root) {
|
||||
for (ASTNode child : root.getChildren()) {
|
||||
private static void flipCommutativeExpr(SyntaxTreeNode root) {
|
||||
for (SyntaxTreeNode child : root.getChildren()) {
|
||||
flipCommutativeExpr(child);
|
||||
}
|
||||
|
||||
@ -92,18 +92,18 @@ public final class ASTBalancer {
|
||||
|
||||
// Führt Linksrotationen durch
|
||||
// Es werden EXPR-Nodes (2 Childs, 1 davon EXPR, Kein Wert) solange wie möglich linksrotiert
|
||||
public static void leftPrecedence(AST tree) {
|
||||
public static void leftPrecedence(SyntaxTree tree) {
|
||||
log("Left-rotating expressions for left-precedence");
|
||||
leftPrecedence(tree.getRoot());
|
||||
}
|
||||
|
||||
// Es wird solange rotiert bis die letzte "Rotation" durchgeführt wurde
|
||||
private static void leftPrecedence(ASTNode root) {
|
||||
for (ASTNode child : root.getChildren()) {
|
||||
private static void leftPrecedence(SyntaxTreeNode root) {
|
||||
for (SyntaxTreeNode child : root.getChildren()) {
|
||||
leftPrecedence(child);
|
||||
}
|
||||
|
||||
final ASTNode expr = getExpr(root);
|
||||
final SyntaxTreeNode expr = getExpr(root);
|
||||
|
||||
if (expr == null || root.getChildren().size() != 2 || !root.getValue().isEmpty()) {
|
||||
return;
|
||||
@ -117,12 +117,12 @@ public final class ASTBalancer {
|
||||
}
|
||||
|
||||
// Die Letzte Rotation ist keine richtige Rotation, dort wird false zurückgegeben
|
||||
private static boolean specialLeftRotate(ASTNode root) {
|
||||
private static boolean specialLeftRotate(SyntaxTreeNode root) {
|
||||
log("Special-Left-Rotation around " + root.getName());
|
||||
log(root.toString());
|
||||
|
||||
final ASTNode left = root.getChildren().get(0);
|
||||
final ASTNode right = root.getChildren().get(1);
|
||||
final SyntaxTreeNode left = root.getChildren().get(0);
|
||||
final SyntaxTreeNode right = root.getChildren().get(1);
|
||||
|
||||
// Verhindert Wurzel mit nur einem EXPR-Child (nach oben "hängende" Wurzel)
|
||||
if (endOfExpr(right)) {
|
||||
@ -132,7 +132,7 @@ public final class ASTBalancer {
|
||||
return false; // Braucht keine weitere Rotation
|
||||
}
|
||||
|
||||
final ASTNode insertLeft = new ASTNode(root.getName(), root.getLine());
|
||||
final SyntaxTreeNode insertLeft = new SyntaxTreeNode(root.getName(), root.getLine());
|
||||
insertLeft.setValue(right.getValue()); // Operation wird linksvererbt
|
||||
insertLeft.setChildren(left, right.getChildren().get(0));
|
||||
|
||||
@ -143,8 +143,8 @@ public final class ASTBalancer {
|
||||
}
|
||||
|
||||
// Findet die 1te (linkeste) expr
|
||||
private static ASTNode getExpr(ASTNode root) {
|
||||
for (ASTNode child : root.getChildren()) {
|
||||
private static SyntaxTreeNode getExpr(SyntaxTreeNode root) {
|
||||
for (SyntaxTreeNode child : root.getChildren()) {
|
||||
if ("expr".equals(child.getName())) {
|
||||
return child;
|
||||
}
|
||||
@ -153,11 +153,11 @@ public final class ASTBalancer {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean endOfExpr(ASTNode root) {
|
||||
private static boolean endOfExpr(SyntaxTreeNode root) {
|
||||
return root.getChildren().size() == 1;
|
||||
}
|
||||
|
||||
public static void operatorPrecedence(AST tree) {
|
||||
public static void operatorPrecedence(SyntaxTree tree) {
|
||||
log("Right-rotating expressions for operator-precedence");
|
||||
|
||||
boolean changed;
|
||||
@ -167,10 +167,10 @@ public final class ASTBalancer {
|
||||
} while (changed);
|
||||
}
|
||||
|
||||
public static boolean operatorPrecedence(ASTNode root) {
|
||||
public static boolean operatorPrecedence(SyntaxTreeNode root) {
|
||||
boolean changed = false;
|
||||
|
||||
for (ASTNode child : root.getChildren()) {
|
||||
for (SyntaxTreeNode child : root.getChildren()) {
|
||||
changed = changed || operatorPrecedence(child);
|
||||
|
||||
if (preceding(root, child)) {
|
||||
@ -182,7 +182,7 @@ public final class ASTBalancer {
|
||||
return changed;
|
||||
}
|
||||
|
||||
private static boolean preceding(ASTNode parent, ASTNode child) {
|
||||
private static boolean preceding(SyntaxTreeNode parent, SyntaxTreeNode child) {
|
||||
if (!"expr".equals(parent.getName()) || parent.getValue().isEmpty()
|
||||
|| !"expr".equals(child.getName()) || child.getValue().isEmpty()) {
|
||||
return false;
|
||||
@ -199,14 +199,14 @@ public final class ASTBalancer {
|
||||
}
|
||||
}
|
||||
|
||||
private static void simpleRightRotate(ASTNode root) {
|
||||
private static void simpleRightRotate(SyntaxTreeNode root) {
|
||||
log("Right-Rotation around " + root.getName() + ": " + root.getValue());
|
||||
log(root.toString());
|
||||
|
||||
final ASTNode left = root.getChildren().get(0);
|
||||
final ASTNode right = root.getChildren().get(1);
|
||||
final SyntaxTreeNode left = root.getChildren().get(0);
|
||||
final SyntaxTreeNode right = root.getChildren().get(1);
|
||||
|
||||
final ASTNode insertRight = new ASTNode(root.getName(), root.getLine());
|
||||
final SyntaxTreeNode insertRight = new SyntaxTreeNode(root.getName(), root.getLine());
|
||||
insertRight.setValue(root.getValue());
|
||||
insertRight.setChildren(left.getChildren().get(1), right);
|
||||
|
||||
|
@ -11,7 +11,7 @@ public final class ASTCompacter {
|
||||
|
||||
private ASTCompacter() {}
|
||||
|
||||
public static void clean(AST tree, Grammar grammar) {
|
||||
public static void clean(SyntaxTree tree, Grammar grammar) {
|
||||
deleteChildren(tree, grammar);
|
||||
deleteIfEmpty(tree, grammar);
|
||||
promote(tree, grammar);
|
||||
@ -26,15 +26,15 @@ public final class ASTCompacter {
|
||||
}
|
||||
|
||||
// Entfernt [promote]-able Nodes (Reicht Werte nach oben)
|
||||
public static void promote(AST tree, Grammar grammar) {
|
||||
public static void promote(SyntaxTree tree, Grammar grammar) {
|
||||
log("\nPromoting nodes:");
|
||||
promote(tree.getRoot(), grammar);
|
||||
}
|
||||
|
||||
private static void promote(ASTNode root, Grammar grammar) {
|
||||
final Collection<ASTNode> toRemove = new HashSet<>();
|
||||
private static void promote(SyntaxTreeNode root, Grammar grammar) {
|
||||
final Collection<SyntaxTreeNode> toRemove = new HashSet<>();
|
||||
|
||||
for (ASTNode child : root.getChildren()) {
|
||||
for (SyntaxTreeNode child : root.getChildren()) {
|
||||
promote(child, grammar);
|
||||
|
||||
// Impliziert, dass die for-schleife nur 1x läuft, deshalb ist child das richtige Kind
|
||||
@ -57,15 +57,15 @@ public final class ASTCompacter {
|
||||
}
|
||||
|
||||
// Entfernt [delIfEmpty] Nodes (löscht Nodes ohne Inhalt)
|
||||
public static void deleteIfEmpty(AST tree, Grammar grammar) {
|
||||
public static void deleteIfEmpty(SyntaxTree tree, Grammar grammar) {
|
||||
log("\nDeleting empty nodes:");
|
||||
deleteIfEmpty(tree.getRoot(), grammar);
|
||||
}
|
||||
|
||||
private static void deleteIfEmpty(ASTNode root, Grammar grammar) {
|
||||
final Collection<ASTNode> toRemove = new HashSet<>();
|
||||
private static void deleteIfEmpty(SyntaxTreeNode root, Grammar grammar) {
|
||||
final Collection<SyntaxTreeNode> toRemove = new HashSet<>();
|
||||
|
||||
for (ASTNode child : root.getChildren()) {
|
||||
for (SyntaxTreeNode child : root.getChildren()) {
|
||||
deleteIfEmpty(child, grammar);
|
||||
|
||||
if (!grammar.canDeleteIfEmpty(child)) {
|
||||
@ -82,15 +82,15 @@ public final class ASTCompacter {
|
||||
}
|
||||
|
||||
// Löscht redundante Informationen in [delChildren]-Nodes (z.b. IF-child von COND) und Epsilon-Nodes
|
||||
public static void deleteChildren(AST tree, Grammar grammar) {
|
||||
public static void deleteChildren(SyntaxTree tree, Grammar grammar) {
|
||||
log("Removing redundant children:");
|
||||
deleteChildren(tree.getRoot(), grammar);
|
||||
}
|
||||
|
||||
private static void deleteChildren(ASTNode root, Grammar grammar) {
|
||||
final Collection<ASTNode> toRemove = new HashSet<>();
|
||||
private static void deleteChildren(SyntaxTreeNode root, Grammar grammar) {
|
||||
final Collection<SyntaxTreeNode> toRemove = new HashSet<>();
|
||||
|
||||
for (ASTNode child : root.getChildren()) {
|
||||
for (SyntaxTreeNode child : root.getChildren()) {
|
||||
deleteChildren(child, grammar);
|
||||
|
||||
if (!grammar.canDeleteChild(root, child)) {
|
||||
@ -107,13 +107,13 @@ public final class ASTCompacter {
|
||||
}
|
||||
|
||||
// Umbenennungen
|
||||
private static void renameTo(AST tree, Grammar grammar) {
|
||||
private static void renameTo(SyntaxTree tree, Grammar grammar) {
|
||||
log("\nRenaming nodes:");
|
||||
renameTo(tree.getRoot(), grammar);
|
||||
}
|
||||
|
||||
private static void renameTo(ASTNode root, Grammar grammar) {
|
||||
for (ASTNode child : root.getChildren()) {
|
||||
private static void renameTo(SyntaxTreeNode root, Grammar grammar) {
|
||||
for (SyntaxTreeNode child : root.getChildren()) {
|
||||
renameTo(child, grammar);
|
||||
|
||||
if (!grammar.canBeRenamed(root)) {
|
||||
@ -126,15 +126,15 @@ public final class ASTCompacter {
|
||||
}
|
||||
}
|
||||
|
||||
public static void nameToValue(AST tree, Grammar grammar) {
|
||||
public static void nameToValue(SyntaxTree tree, Grammar grammar) {
|
||||
log("\nMoving names to values:");
|
||||
nameToValue(tree.getRoot(), grammar);
|
||||
}
|
||||
|
||||
private static void nameToValue(ASTNode root, Grammar grammar) {
|
||||
final Collection<ASTNode> toRemove = new HashSet<>();
|
||||
private static void nameToValue(SyntaxTreeNode root, Grammar grammar) {
|
||||
final Collection<SyntaxTreeNode> toRemove = new HashSet<>();
|
||||
|
||||
for (ASTNode child : root.getChildren()) {
|
||||
for (SyntaxTreeNode child : root.getChildren()) {
|
||||
nameToValue(child, grammar);
|
||||
|
||||
if (!grammar.canMoveNameToVal(root, child)) {
|
||||
@ -154,15 +154,15 @@ public final class ASTCompacter {
|
||||
}
|
||||
|
||||
// Assignment bekommt den Identifier als Value anstatt als Child
|
||||
public static void valueToValue(AST tree, Grammar grammar) {
|
||||
public static void valueToValue(SyntaxTree tree, Grammar grammar) {
|
||||
log("\nMoving values to values:");
|
||||
valueToValue(tree.getRoot(), grammar);
|
||||
}
|
||||
|
||||
private static void valueToValue(ASTNode root, Grammar grammar) {
|
||||
final Collection<ASTNode> toRemove = new HashSet<>();
|
||||
private static void valueToValue(SyntaxTreeNode root, Grammar grammar) {
|
||||
final Collection<SyntaxTreeNode> toRemove = new HashSet<>();
|
||||
|
||||
for (ASTNode child : root.getChildren()) {
|
||||
for (SyntaxTreeNode child : root.getChildren()) {
|
||||
valueToValue(child, grammar);
|
||||
|
||||
if (!grammar.hasValToVal(root, child)) {
|
||||
|
@ -1,126 +0,0 @@
|
||||
package parser.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ASTNode {
|
||||
|
||||
private final int line;
|
||||
private String name;
|
||||
private String value;
|
||||
private List<ASTNode> children = new ArrayList<>();
|
||||
|
||||
public ASTNode(String name, int line) {
|
||||
this.name = name;
|
||||
this.line = line;
|
||||
this.value = "";
|
||||
}
|
||||
|
||||
public void addChild(ASTNode ASTNode) {
|
||||
this.children.add(ASTNode);
|
||||
}
|
||||
|
||||
public boolean hasChildren() {
|
||||
return !this.children.isEmpty();
|
||||
}
|
||||
|
||||
public List<ASTNode> getChildren() {
|
||||
return this.children;
|
||||
}
|
||||
|
||||
public void setChildren(List<ASTNode> children) {
|
||||
this.children = children;
|
||||
}
|
||||
|
||||
public void setChildren(ASTNode... children) {
|
||||
this.children = new ArrayList<>();
|
||||
this.children.addAll(Arrays.asList(children));
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.name, this.value, this.children, this.line);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof ASTNode) {
|
||||
return this.name.equals(((ASTNode) obj).name)
|
||||
&& this.value.equals(((ASTNode) obj).value)
|
||||
&& this.children.equals(((ASTNode) obj).children)
|
||||
&& this.line == ((ASTNode) obj).line;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// toString() und print() von hier: https://stackoverflow.com/a/8948691
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder buffer = new StringBuilder(50);
|
||||
this.print(buffer, "", "");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
private void print(StringBuilder buffer, String prefix, String childrenPrefix) {
|
||||
buffer.append(prefix);
|
||||
buffer.append(this.name);
|
||||
if (!this.value.isBlank()) {
|
||||
buffer.append(": ");
|
||||
buffer.append(this.value);
|
||||
}
|
||||
buffer.append('\n');
|
||||
|
||||
for (final Iterator<ASTNode> it = this.children.listIterator(); it.hasNext(); ) {
|
||||
final ASTNode next = it.next();
|
||||
if (it.hasNext()) {
|
||||
next.print(buffer, childrenPrefix + "├── ", childrenPrefix + "│ ");
|
||||
} else {
|
||||
next.print(buffer, childrenPrefix + "└── ", childrenPrefix + " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public long size() {
|
||||
return 1 + this.children.stream().mapToLong(ASTNode::size).sum();
|
||||
}
|
||||
|
||||
public int getLine() {
|
||||
return this.line;
|
||||
}
|
||||
|
||||
public ASTNode deepCopy() {
|
||||
final ASTNode newNode = new ASTNode(this.name, this.line);
|
||||
|
||||
newNode.value = this.value;
|
||||
newNode.children = this.children.stream()
|
||||
.map(ASTNode::deepCopy)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return this.children.isEmpty();
|
||||
}
|
||||
}
|
74
src/main/java/parser/ast/SyntaxTree.java
Normal file
74
src/main/java/parser/ast/SyntaxTree.java
Normal file
@ -0,0 +1,74 @@
|
||||
package parser.ast;
|
||||
|
||||
import parser.grammar.Grammar;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Repräsentiert konkrete und abstrakte Parse-/Syntaxbäume.
|
||||
*/
|
||||
public class SyntaxTree {
|
||||
|
||||
private final SyntaxTreeNode root;
|
||||
|
||||
public SyntaxTree(SyntaxTreeNode root) {
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formt einen konkreten Parsebaum in einein abstrakten SyntaxTree um.
|
||||
*
|
||||
* @param grammar Die Parsegrammatik wird benötigt um die Umformungen durchzuführen.
|
||||
*/
|
||||
public static SyntaxTree toAbstractSyntaxTree(SyntaxTree concreteSyntaxTree, Grammar grammar) {
|
||||
final SyntaxTree abstractSyntaxTree = concreteSyntaxTree.deepCopy();
|
||||
|
||||
ASTCompacter.clean(abstractSyntaxTree, grammar);
|
||||
ASTBalancer.balance(abstractSyntaxTree);
|
||||
System.out.println("Tree processing successful.");
|
||||
|
||||
return abstractSyntaxTree;
|
||||
}
|
||||
|
||||
public SyntaxTree deepCopy() {
|
||||
return new SyntaxTree(this.root.deepCopy());
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
public SyntaxTreeNode getRoot() {
|
||||
return this.root;
|
||||
}
|
||||
|
||||
public long size() {
|
||||
return this.root.size();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return this.root.isEmpty();
|
||||
}
|
||||
|
||||
// Overrides
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.root);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || this.getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final SyntaxTree that = (SyntaxTree) o;
|
||||
return this.root.equals(that.root);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.root.toString();
|
||||
}
|
||||
}
|
136
src/main/java/parser/ast/SyntaxTreeNode.java
Normal file
136
src/main/java/parser/ast/SyntaxTreeNode.java
Normal file
@ -0,0 +1,136 @@
|
||||
package parser.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Repräsentiert einen Token aus dem Quellprogramm im Parsebaum,
|
||||
* oder eine abstrakte Anweisung im Abstrakten Syntaxbaum.
|
||||
*/
|
||||
public class SyntaxTreeNode {
|
||||
|
||||
private final int line;
|
||||
private String name;
|
||||
private String value;
|
||||
private List<SyntaxTreeNode> children = new ArrayList<>();
|
||||
|
||||
public SyntaxTreeNode(String name, int line) {
|
||||
this.name = name;
|
||||
this.line = line;
|
||||
this.value = "";
|
||||
}
|
||||
|
||||
public SyntaxTreeNode deepCopy() {
|
||||
final SyntaxTreeNode newNode = new SyntaxTreeNode(this.name, this.line);
|
||||
|
||||
newNode.value = this.value;
|
||||
newNode.children = this.children.stream()
|
||||
.map(SyntaxTreeNode::deepCopy)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
// Getters, Setters
|
||||
|
||||
public boolean isEmpty() {
|
||||
return this.children.isEmpty();
|
||||
}
|
||||
|
||||
public long size() {
|
||||
return 1 + this.children.stream().mapToLong(SyntaxTreeNode::size).sum();
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getLine() {
|
||||
return this.line;
|
||||
}
|
||||
|
||||
public List<SyntaxTreeNode> getChildren() {
|
||||
return this.children;
|
||||
}
|
||||
|
||||
public void setChildren(List<SyntaxTreeNode> children) {
|
||||
this.children = children;
|
||||
}
|
||||
|
||||
public void setChildren(SyntaxTreeNode... children) {
|
||||
this.children = new ArrayList<>();
|
||||
this.children.addAll(Arrays.asList(children));
|
||||
}
|
||||
|
||||
public void addChild(SyntaxTreeNode syntaxTreeNode) {
|
||||
this.children.add(syntaxTreeNode);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
// Printing
|
||||
|
||||
// toString() und treePrint() von hier: https://stackoverflow.com/a/8948691
|
||||
private void treePrint(StringBuilder buffer, String prefix, String childrenPrefix) {
|
||||
buffer.append(prefix);
|
||||
buffer.append(this.name);
|
||||
if (!this.value.isBlank()) {
|
||||
buffer.append(": ");
|
||||
buffer.append(this.value);
|
||||
}
|
||||
buffer.append('\n');
|
||||
|
||||
for (final Iterator<SyntaxTreeNode> it = this.children.listIterator(); it.hasNext(); ) {
|
||||
final SyntaxTreeNode next = it.next();
|
||||
if (it.hasNext()) {
|
||||
next.treePrint(buffer, childrenPrefix + "├── ", childrenPrefix + "│ ");
|
||||
} else {
|
||||
next.treePrint(buffer, childrenPrefix + "└── ", childrenPrefix + " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Overrides
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NonFinalFieldReferencedInHashCode")
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.line, this.name, this.value, this.children);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NonFinalFieldReferenceInEquals")
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || this.getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final SyntaxTreeNode that = (SyntaxTreeNode) o;
|
||||
return this.line == that.line && this.name.equals(that.name)
|
||||
&& this.value.equals(that.value) && this.children.equals(that.children);
|
||||
}
|
||||
|
||||
// toString() und treePrint() von hier: https://stackoverflow.com/a/8948691
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder buffer = new StringBuilder();
|
||||
this.treePrint(buffer, "", "");
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package parser.grammar;
|
||||
|
||||
import parser.ast.ASTNode;
|
||||
import parser.ast.SyntaxTreeNode;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
@ -243,7 +243,7 @@ public class Grammar {
|
||||
* Es wird nicht root promoted, sondern roots einziges Kind.
|
||||
* Checkt auch auf Anzahl der Kinder.
|
||||
*/
|
||||
public boolean canPromoteChild(ASTNode root) {
|
||||
public boolean canPromoteChild(SyntaxTreeNode root) {
|
||||
return this.canPromoteChild(root.getName())
|
||||
&& root.getChildren().size() == 1
|
||||
&& root.getValue().isEmpty();
|
||||
@ -257,10 +257,10 @@ public class Grammar {
|
||||
/**
|
||||
* Checkt auch auf Anzahl der Kinder und vorhandene Value.
|
||||
*/
|
||||
public boolean canDeleteIfEmpty(ASTNode root) {
|
||||
public boolean canDeleteIfEmpty(SyntaxTreeNode root) {
|
||||
return this.canDeleteIfEmpty(root.getName())
|
||||
&& root.getValue().isEmpty()
|
||||
&& !root.hasChildren();
|
||||
&& root.isEmpty();
|
||||
}
|
||||
|
||||
public boolean canDeleteIfEmpty(String sym) {
|
||||
@ -272,9 +272,9 @@ public class Grammar {
|
||||
* Checkt auch auf Anzahl der Kinder.
|
||||
* Epsilon-Knoten werden immer gelöscht.
|
||||
*/
|
||||
public boolean canDeleteChild(ASTNode parent, ASTNode child) {
|
||||
public boolean canDeleteChild(SyntaxTreeNode parent, SyntaxTreeNode child) {
|
||||
return this.canDeleteChild(parent.getName(), child.getName())
|
||||
&& !child.hasChildren();
|
||||
&& child.isEmpty();
|
||||
}
|
||||
|
||||
public boolean canDeleteChild(String parent, String child) {
|
||||
@ -284,7 +284,7 @@ public class Grammar {
|
||||
}
|
||||
|
||||
|
||||
public boolean canBeRenamed(ASTNode root) {
|
||||
public boolean canBeRenamed(SyntaxTreeNode root) {
|
||||
return this.canBeRenamed(root.getName());
|
||||
}
|
||||
|
||||
@ -292,7 +292,7 @@ public class Grammar {
|
||||
return this.actions.get(RENAMETO).contains(sym);
|
||||
}
|
||||
|
||||
public String getNewName(ASTNode root) {
|
||||
public String getNewName(SyntaxTreeNode root) {
|
||||
return this.getNewName(root.getName());
|
||||
}
|
||||
|
||||
@ -301,7 +301,7 @@ public class Grammar {
|
||||
}
|
||||
|
||||
|
||||
public boolean hasValToVal(ASTNode parent, ASTNode child) {
|
||||
public boolean hasValToVal(SyntaxTreeNode parent, SyntaxTreeNode child) {
|
||||
return this.hasValToVal(parent.getName(), child.getName());
|
||||
}
|
||||
|
||||
@ -314,7 +314,7 @@ public class Grammar {
|
||||
/**
|
||||
* Checkt auch auf bereits existierende Values.
|
||||
*/
|
||||
public boolean canMoveNameToVal(ASTNode parent, ASTNode child) {
|
||||
public boolean canMoveNameToVal(SyntaxTreeNode parent, SyntaxTreeNode child) {
|
||||
return this.canMoveNameToVal(parent.getName(), child.getName())
|
||||
&& parent.getValue().isEmpty();
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package typechecker;
|
||||
|
||||
import parser.ast.AST;
|
||||
import parser.ast.ASTNode;
|
||||
import parser.ast.SyntaxTree;
|
||||
import parser.ast.SyntaxTreeNode;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@ -20,9 +20,9 @@ public final class TypeChecker {
|
||||
|
||||
// TODO: nodeTable?
|
||||
// Wirft exception bei typeerror, return nodeTable?
|
||||
public static Map<ASTNode, String> validate(AST tree) {
|
||||
public static Map<SyntaxTreeNode, String> validate(SyntaxTree tree) {
|
||||
final TypeTable table = TypeTable.fromAST(tree);
|
||||
final Map<ASTNode, String> nodeTable = new HashMap<>();
|
||||
final Map<SyntaxTreeNode, String> nodeTable = new HashMap<>();
|
||||
|
||||
System.out.println(" - Validating syntax-tree...");
|
||||
|
||||
@ -34,8 +34,8 @@ public final class TypeChecker {
|
||||
return nodeTable;
|
||||
}
|
||||
|
||||
private static void validate(ASTNode root, TypeTable table, Map<ASTNode, String> nodeTable) {
|
||||
for (ASTNode child : root.getChildren()) {
|
||||
private static void validate(SyntaxTreeNode root, TypeTable table, Map<SyntaxTreeNode, String> nodeTable) {
|
||||
for (SyntaxTreeNode child : root.getChildren()) {
|
||||
validate(child, table, nodeTable);
|
||||
}
|
||||
|
||||
@ -55,7 +55,7 @@ public final class TypeChecker {
|
||||
} else if ("par_expr".equals(root.getName())) {
|
||||
// Nodetable Eintrag für Klammern
|
||||
|
||||
final ASTNode centerChild = root.getChildren().get(1);
|
||||
final SyntaxTreeNode centerChild = root.getChildren().get(1);
|
||||
|
||||
nodeTable.put(root, nodeTable.get(centerChild));
|
||||
} else if ("IDENTIFIER".equals(root.getName())) {
|
||||
@ -73,10 +73,10 @@ public final class TypeChecker {
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateAssignment(ASTNode root, TypeTable table, Map<ASTNode, String> nodeTable) {
|
||||
private static void validateAssignment(SyntaxTreeNode root, TypeTable table, Map<SyntaxTreeNode, String> nodeTable) {
|
||||
final String identifier = root.getValue();
|
||||
final String identifierType = table.getSymbolType(identifier);
|
||||
final ASTNode literalNode = root.getChildren().get(0);
|
||||
final SyntaxTreeNode literalNode = root.getChildren().get(0);
|
||||
final String literalType = nodeTable.get(literalNode);
|
||||
|
||||
log("Validating Assignment: " + identifierType + ": " + identifier + " = " + literalType);
|
||||
@ -88,12 +88,12 @@ public final class TypeChecker {
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateExpression(ASTNode root, TypeTable table, Map<ASTNode, String> nodeTable) {
|
||||
private static void validateExpression(SyntaxTreeNode root, TypeTable table, Map<SyntaxTreeNode, String> nodeTable) {
|
||||
final String op = root.getValue();
|
||||
|
||||
log("Validating Expression: " + root.getValue());
|
||||
|
||||
if (!root.hasChildren()) {
|
||||
if (root.isEmpty()) {
|
||||
// Keine Kinder
|
||||
|
||||
System.out.println("Line " + root.getLine() + " Operatorerror: Can't use [" + op + "] without arguments");
|
||||
@ -115,7 +115,7 @@ public final class TypeChecker {
|
||||
}
|
||||
|
||||
final List<String> requiredType = table.getMethodArgumentType(op);
|
||||
for (ASTNode child : root.getChildren()) {
|
||||
for (SyntaxTreeNode child : root.getChildren()) {
|
||||
// Jedes Child muss korrekten Typ zurückgeben
|
||||
|
||||
final String childReturnType = nodeTable.get(child);
|
||||
@ -137,8 +137,8 @@ public final class TypeChecker {
|
||||
}
|
||||
|
||||
if ("EQUAL".equals(op) || "NOT_EQUAL".equals(op)) {
|
||||
final ASTNode left = root.getChildren().get(0);
|
||||
final ASTNode right = root.getChildren().get(1);
|
||||
final SyntaxTreeNode left = root.getChildren().get(0);
|
||||
final SyntaxTreeNode right = root.getChildren().get(1);
|
||||
|
||||
if (!nodeTable.get(left).equals(nodeTable.get(right))) {
|
||||
System.out.println("Line " + root.getLine() + " Typeerror: Can't use [" + op + "] with arguments of type [" + nodeTable.get(left) + "] and [" + nodeTable.get(right) + "]");
|
||||
|
@ -1,7 +1,7 @@
|
||||
package typechecker;
|
||||
|
||||
import parser.ast.AST;
|
||||
import parser.ast.ASTNode;
|
||||
import parser.ast.SyntaxTree;
|
||||
import parser.ast.SyntaxTreeNode;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@ -53,7 +53,7 @@ public class TypeTable {
|
||||
Map.entry("NOT_EQUAL", Arrays.asList("INTEGER_TYPE", "BOOLEAN_TYPE", "STRING_TYPE")));
|
||||
}
|
||||
|
||||
public static TypeTable fromAST(AST tree) {
|
||||
public static TypeTable fromAST(SyntaxTree tree) {
|
||||
System.out.println(" - Building TypeTable...");
|
||||
final Map<String, String> tableOut = new HashMap<>();
|
||||
|
||||
@ -64,13 +64,13 @@ public class TypeTable {
|
||||
return new TypeTable(tableOut);
|
||||
}
|
||||
|
||||
private static void scanTree(ASTNode root, Map<? super String, String> table) {
|
||||
for (ASTNode child : root.getChildren()) {
|
||||
private static void scanTree(SyntaxTreeNode root, Map<? super String, String> table) {
|
||||
for (SyntaxTreeNode child : root.getChildren()) {
|
||||
scanTree(child, table);
|
||||
}
|
||||
|
||||
if ("declaration".equals(root.getName())) {
|
||||
final ASTNode child = root.getChildren().get(0);
|
||||
final SyntaxTreeNode child = root.getChildren().get(0);
|
||||
|
||||
log("Adding Entry " + child.getValue() + " -> " + root.getValue());
|
||||
final String oldEntry = table.put(child.getValue(), root.getValue());
|
||||
|
@ -11,8 +11,8 @@ import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import parser.StupsParser;
|
||||
import parser.ast.AST;
|
||||
import parser.ast.ASTNode;
|
||||
import parser.ast.SyntaxTree;
|
||||
import parser.ast.SyntaxTreeNode;
|
||||
import parser.grammar.Grammar;
|
||||
import typechecker.TypeChecker;
|
||||
|
||||
@ -53,13 +53,13 @@ class FlowGraphGeneratorTest {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static AST lexParseProgram(String prog) {
|
||||
private static SyntaxTree lexParseProgram(String prog) {
|
||||
final Lexer lex = new StupsLexer(CharStreams.fromString(prog));
|
||||
|
||||
final AST tree = parser.parse(lex.getAllTokens(), lex.getVocabulary());
|
||||
tree.postprocess(stupsGrammar);
|
||||
final SyntaxTree tree = parser.parse(lex.getAllTokens(), lex.getVocabulary());
|
||||
final SyntaxTree ast = SyntaxTree.toAbstractSyntaxTree(tree, stupsGrammar);
|
||||
|
||||
return tree;
|
||||
return ast;
|
||||
}
|
||||
|
||||
private static void codegenToFile(String src) {
|
||||
@ -218,8 +218,8 @@ class FlowGraphGeneratorTest {
|
||||
final String program = buildArithmeticProg(prog);
|
||||
System.out.println(program);
|
||||
|
||||
final AST tree = lexParseProgram(program);
|
||||
final Map<ASTNode, String> nodeTable = TypeChecker.validate(tree);
|
||||
final SyntaxTree tree = lexParseProgram(program);
|
||||
final Map<SyntaxTreeNode, String> nodeTable = TypeChecker.validate(tree);
|
||||
final FlowGraphGenerator gen = FlowGraphGenerator.fromAST(tree, nodeTable, "TestOutput");
|
||||
final FlowGraph srcProg = gen.generateGraph();
|
||||
|
||||
@ -235,8 +235,8 @@ class FlowGraphGeneratorTest {
|
||||
final String program = buildIfElseProgram(expr, condition, ifBlock, elseBlock);
|
||||
System.out.println(program);
|
||||
|
||||
final AST tree = lexParseProgram(program);
|
||||
final Map<ASTNode, String> nodeTable = TypeChecker.validate(tree);
|
||||
final SyntaxTree tree = lexParseProgram(program);
|
||||
final Map<SyntaxTreeNode, String> nodeTable = TypeChecker.validate(tree);
|
||||
final FlowGraphGenerator gen = FlowGraphGenerator.fromAST(tree, nodeTable, "TestOutput");
|
||||
final FlowGraph srcProg = gen.generateGraph();
|
||||
|
||||
@ -278,8 +278,8 @@ class FlowGraphGeneratorTest {
|
||||
final String program = buildLogicProgram(expr);
|
||||
System.out.println(program);
|
||||
|
||||
final AST tree = lexParseProgram(program);
|
||||
final Map<ASTNode, String> nodeTable = TypeChecker.validate(tree);
|
||||
final SyntaxTree tree = lexParseProgram(program);
|
||||
final Map<SyntaxTreeNode, String> nodeTable = TypeChecker.validate(tree);
|
||||
final FlowGraphGenerator gen = FlowGraphGenerator.fromAST(tree, nodeTable, "TestOutput");
|
||||
final FlowGraph srcProg = gen.generateGraph();
|
||||
|
||||
@ -295,8 +295,8 @@ class FlowGraphGeneratorTest {
|
||||
final String program = buildLoopProgram(expr, condition, body);
|
||||
System.out.println(program);
|
||||
|
||||
final AST tree = lexParseProgram(program);
|
||||
final Map<ASTNode, String> nodeTable = TypeChecker.validate(tree);
|
||||
final SyntaxTree tree = lexParseProgram(program);
|
||||
final Map<SyntaxTreeNode, String> nodeTable = TypeChecker.validate(tree);
|
||||
final FlowGraphGenerator gen = FlowGraphGenerator.fromAST(tree, nodeTable, "TestOutput");
|
||||
final FlowGraph srcProg = gen.generateGraph();
|
||||
|
||||
@ -310,8 +310,8 @@ class FlowGraphGeneratorTest {
|
||||
final String program = readProgram(prog);
|
||||
System.out.print(program);
|
||||
|
||||
final AST tree = lexParseProgram(program);
|
||||
final Map<ASTNode, String> nodeTable = TypeChecker.validate(tree);
|
||||
final SyntaxTree tree = lexParseProgram(program);
|
||||
final Map<SyntaxTreeNode, String> nodeTable = TypeChecker.validate(tree);
|
||||
final FlowGraphGenerator gen = FlowGraphGenerator.fromAST(tree, nodeTable, "TestOutput");
|
||||
final FlowGraph srcProg = gen.generateGraph();
|
||||
|
||||
@ -323,8 +323,8 @@ class FlowGraphGeneratorTest {
|
||||
void compileEmptyProgramTest() {
|
||||
final String program = readProgram("EmptyFile.stups");
|
||||
|
||||
final AST tree = lexParseProgram(program);
|
||||
final Map<ASTNode, String> nodeTable = TypeChecker.validate(tree);
|
||||
final SyntaxTree tree = lexParseProgram(program);
|
||||
final Map<SyntaxTreeNode, String> nodeTable = TypeChecker.validate(tree);
|
||||
|
||||
assertThatThrownBy(() -> FlowGraphGenerator.fromAST(tree, nodeTable, "TestOutput"))
|
||||
.isInstanceOf(CodeGenerationException.class);
|
||||
|
@ -11,8 +11,8 @@ import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import parser.StupsParser;
|
||||
import parser.ast.AST;
|
||||
import parser.ast.ASTNode;
|
||||
import parser.ast.SyntaxTree;
|
||||
import parser.ast.SyntaxTreeNode;
|
||||
import parser.grammar.Grammar;
|
||||
import typechecker.TypeChecker;
|
||||
|
||||
@ -40,18 +40,18 @@ class LivenessAnalysisTest {
|
||||
stupsGrammar = grammar;
|
||||
}
|
||||
|
||||
private static AST lexParseProgram(String prog) {
|
||||
private static SyntaxTree lexParseProgram(String prog) {
|
||||
final Lexer lex = new StupsLexer(CharStreams.fromString(prog));
|
||||
|
||||
final AST tree = parser.parse(lex.getAllTokens(), lex.getVocabulary());
|
||||
tree.postprocess(stupsGrammar);
|
||||
final SyntaxTree tree = parser.parse(lex.getAllTokens(), lex.getVocabulary());
|
||||
final SyntaxTree ast = SyntaxTree.toAbstractSyntaxTree(tree, stupsGrammar);
|
||||
|
||||
return tree;
|
||||
return ast;
|
||||
}
|
||||
|
||||
private static LivenessAnalysis initLivenessAnalysis(String program) {
|
||||
final AST tree = lexParseProgram(program);
|
||||
final Map<ASTNode, String> nodeTable = TypeChecker.validate(tree);
|
||||
final SyntaxTree tree = lexParseProgram(program);
|
||||
final Map<SyntaxTreeNode, String> nodeTable = TypeChecker.validate(tree);
|
||||
final FlowGraphGenerator gen = FlowGraphGenerator.fromAST(tree, nodeTable, "TestOutput");
|
||||
final FlowGraph graph = gen.generateGraph();
|
||||
final DataFlowGraph dataGraph = DataFlowGraph.fromFlowGraph(graph);
|
||||
|
@ -1,45 +0,0 @@
|
||||
package parser.ast;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class ASTTest {
|
||||
|
||||
@Test
|
||||
void testOneNode() {
|
||||
final ASTNode root = new ASTNode("Wurzel", 1);
|
||||
|
||||
final AST tree = new AST(root);
|
||||
|
||||
assertThat(tree).hasToString("Wurzel\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testThreeNodesBinary() {
|
||||
final ASTNode root = new ASTNode("Wurzel", 1);
|
||||
final ASTNode childA = new ASTNode("A", 1);
|
||||
final ASTNode childB = new ASTNode("B", 1);
|
||||
|
||||
root.addChild(childA);
|
||||
root.addChild(childB);
|
||||
|
||||
final AST tree = new AST(root);
|
||||
|
||||
assertThat(tree).hasToString("Wurzel\n├── A\n└── B\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testThreeNodesLinear() {
|
||||
final ASTNode root = new ASTNode("Wurzel", 1);
|
||||
final ASTNode childA = new ASTNode("A", 1);
|
||||
final ASTNode childB = new ASTNode("B", 1);
|
||||
|
||||
root.addChild(childA);
|
||||
childA.addChild(childB);
|
||||
|
||||
final AST tree = new AST(root);
|
||||
|
||||
assertThat(tree).hasToString("Wurzel\n└── A\n └── B\n");
|
||||
}
|
||||
}
|
@ -4,22 +4,22 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class ASTBalancerTest {
|
||||
class SyntaxTreeBalancerTest {
|
||||
|
||||
//expr
|
||||
//├── expr: SUB
|
||||
//| └── INTEGER_LIT: 2
|
||||
//└── INTEGER_LIT: 1
|
||||
private static AST tree1() {
|
||||
final AST tree = new AST(new ASTNode("epxr", 1));
|
||||
private static SyntaxTree tree1() {
|
||||
final SyntaxTree tree = new SyntaxTree(new SyntaxTreeNode("epxr", 1));
|
||||
|
||||
final ASTNode right = new ASTNode("INTEGER_LIT", 1);
|
||||
final SyntaxTreeNode right = new SyntaxTreeNode("INTEGER_LIT", 1);
|
||||
right.setValue("1");
|
||||
|
||||
final ASTNode left = new ASTNode("expr", 1);
|
||||
final SyntaxTreeNode left = new SyntaxTreeNode("expr", 1);
|
||||
left.setValue("SUB");
|
||||
|
||||
final ASTNode lleft = new ASTNode("INTEGER_LIT", 1);
|
||||
final SyntaxTreeNode lleft = new SyntaxTreeNode("INTEGER_LIT", 1);
|
||||
lleft.setValue("2");
|
||||
left.setChildren(lleft);
|
||||
|
||||
@ -28,22 +28,22 @@ class ASTBalancerTest {
|
||||
return tree;
|
||||
}
|
||||
|
||||
private static AST tree2() {
|
||||
final AST tree = new AST(new ASTNode("expr", 1));
|
||||
private static SyntaxTree tree2() {
|
||||
final SyntaxTree tree = new SyntaxTree(new SyntaxTreeNode("expr", 1));
|
||||
|
||||
final ASTNode right = new ASTNode("INTEGER_LIT", 1);
|
||||
final SyntaxTreeNode right = new SyntaxTreeNode("INTEGER_LIT", 1);
|
||||
right.setValue("1");
|
||||
|
||||
final ASTNode left = new ASTNode("expr", 1);
|
||||
final SyntaxTreeNode left = new SyntaxTreeNode("expr", 1);
|
||||
left.setValue("SUB");
|
||||
|
||||
final ASTNode lleft = new ASTNode("expr", 1);
|
||||
final SyntaxTreeNode lleft = new SyntaxTreeNode("expr", 1);
|
||||
lleft.setValue("SUB");
|
||||
|
||||
final ASTNode lright = new ASTNode("INTEGER_LIT", 1);
|
||||
final SyntaxTreeNode lright = new SyntaxTreeNode("INTEGER_LIT", 1);
|
||||
lright.setValue("2");
|
||||
|
||||
final ASTNode llleft = new ASTNode("INTEGER_LIT", 1);
|
||||
final SyntaxTreeNode llleft = new SyntaxTreeNode("INTEGER_LIT", 1);
|
||||
llleft.setValue("3");
|
||||
|
||||
lleft.setChildren(llleft);
|
||||
@ -54,22 +54,22 @@ class ASTBalancerTest {
|
||||
return tree;
|
||||
}
|
||||
|
||||
private static AST tree3() {
|
||||
final AST tree = new AST(new ASTNode("expr", 1));
|
||||
private static SyntaxTree tree3() {
|
||||
final SyntaxTree tree = new SyntaxTree(new SyntaxTreeNode("expr", 1));
|
||||
|
||||
final ASTNode right = new ASTNode("INTEGER_LIT", 1);
|
||||
final SyntaxTreeNode right = new SyntaxTreeNode("INTEGER_LIT", 1);
|
||||
right.setValue("1");
|
||||
|
||||
final ASTNode left = new ASTNode("expr", 1);
|
||||
final SyntaxTreeNode left = new SyntaxTreeNode("expr", 1);
|
||||
left.setValue("SUB");
|
||||
|
||||
final ASTNode lleft = new ASTNode("expr", 1);
|
||||
final SyntaxTreeNode lleft = new SyntaxTreeNode("expr", 1);
|
||||
lleft.setValue("MUL");
|
||||
|
||||
final ASTNode lright = new ASTNode("INTEGER_LIT", 1);
|
||||
final SyntaxTreeNode lright = new SyntaxTreeNode("INTEGER_LIT", 1);
|
||||
lright.setValue("2");
|
||||
|
||||
final ASTNode llleft = new ASTNode("INTEGER_LIT", 1);
|
||||
final SyntaxTreeNode llleft = new SyntaxTreeNode("INTEGER_LIT", 1);
|
||||
llleft.setValue("3");
|
||||
|
||||
lleft.setChildren(llleft);
|
||||
@ -82,7 +82,7 @@ class ASTBalancerTest {
|
||||
|
||||
@Test
|
||||
void testTree1Flip() {
|
||||
final AST tree = tree1();
|
||||
final SyntaxTree tree = tree1();
|
||||
|
||||
ASTBalancer.flip(tree);
|
||||
|
||||
@ -92,7 +92,7 @@ class ASTBalancerTest {
|
||||
|
||||
@Test
|
||||
void testTree1Flip2x() {
|
||||
final AST tree = tree1();
|
||||
final SyntaxTree tree = tree1();
|
||||
|
||||
ASTBalancer.flip(tree);
|
||||
ASTBalancer.flip(tree);
|
||||
@ -102,7 +102,7 @@ class ASTBalancerTest {
|
||||
|
||||
@Test
|
||||
void testTree2Flip() {
|
||||
final AST tree = tree2();
|
||||
final SyntaxTree tree = tree2();
|
||||
|
||||
ASTBalancer.flip(tree);
|
||||
|
||||
@ -114,7 +114,7 @@ class ASTBalancerTest {
|
||||
|
||||
@Test
|
||||
void testTree2Flip2x() {
|
||||
final AST tree = tree2();
|
||||
final SyntaxTree tree = tree2();
|
||||
|
||||
ASTBalancer.flip(tree);
|
||||
ASTBalancer.flip(tree);
|
||||
@ -124,7 +124,7 @@ class ASTBalancerTest {
|
||||
|
||||
@Test
|
||||
void testTree1LeftPrecedence() {
|
||||
final AST tree = tree1();
|
||||
final SyntaxTree tree = tree1();
|
||||
ASTBalancer.flip(tree);
|
||||
|
||||
ASTBalancer.leftPrecedence(tree);
|
||||
@ -135,7 +135,7 @@ class ASTBalancerTest {
|
||||
|
||||
@Test
|
||||
void testTree2LeftPrecedence() {
|
||||
final AST tree = tree2();
|
||||
final SyntaxTree tree = tree2();
|
||||
ASTBalancer.flip(tree);
|
||||
|
||||
ASTBalancer.leftPrecedence(tree);
|
||||
@ -146,11 +146,11 @@ class ASTBalancerTest {
|
||||
|
||||
@Test
|
||||
void testTree2OperatorPrecedence() {
|
||||
final AST tree = tree2();
|
||||
final SyntaxTree tree = tree2();
|
||||
ASTBalancer.flip(tree);
|
||||
ASTBalancer.leftPrecedence(tree);
|
||||
|
||||
final AST tree1 = tree2();
|
||||
final SyntaxTree tree1 = tree2();
|
||||
ASTBalancer.flip(tree1);
|
||||
ASTBalancer.leftPrecedence(tree1);
|
||||
|
||||
@ -161,7 +161,7 @@ class ASTBalancerTest {
|
||||
|
||||
@Test
|
||||
void testTree3OperatorPrecedence() {
|
||||
final AST tree = tree3();
|
||||
final SyntaxTree tree = tree3();
|
||||
ASTBalancer.flip(tree);
|
||||
ASTBalancer.leftPrecedence(tree);
|
||||
|
@ -17,21 +17,21 @@ import java.nio.file.Paths;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class ASTCompacterTest {
|
||||
class SyntaxTreeCompacterTest {
|
||||
|
||||
private static Grammar grammar;
|
||||
private static StupsParser parser;
|
||||
|
||||
@BeforeAll
|
||||
static void init() throws IOException, URISyntaxException {
|
||||
final Path path = Paths.get(ASTCompacterTest.class.getClassLoader().getResource("exampleGrammars/Grammar.grammar").toURI());
|
||||
final Path path = Paths.get(SyntaxTreeCompacterTest.class.getClassLoader().getResource("exampleGrammars/Grammar.grammar").toURI());
|
||||
grammar = Grammar.fromFile(path);
|
||||
parser = StupsParser.fromGrammar(grammar);
|
||||
}
|
||||
|
||||
private static AST getTree(String program) {
|
||||
private static SyntaxTree getTree(String program) {
|
||||
try {
|
||||
final Path path = Paths.get(ASTCompacterTest.class.getClassLoader().getResource("examplePrograms/" + program).toURI());
|
||||
final Path path = Paths.get(SyntaxTreeCompacterTest.class.getClassLoader().getResource("examplePrograms/" + program).toURI());
|
||||
final String programCode = Files.readString(path, StandardCharsets.US_ASCII);
|
||||
final Lexer lex = new StupsLexer(CharStreams.fromString(programCode));
|
||||
return parser.parse(lex.getAllTokens(), lex.getVocabulary());
|
||||
@ -44,7 +44,7 @@ class ASTCompacterTest {
|
||||
|
||||
@Test
|
||||
void testDeleteChildren() {
|
||||
final AST tree = getTree("GeneralOperator.stups");
|
||||
final SyntaxTree tree = getTree("GeneralOperator.stups");
|
||||
final long before = tree.size();
|
||||
|
||||
ASTCompacter.deleteChildren(tree, grammar);
|
||||
@ -54,7 +54,7 @@ class ASTCompacterTest {
|
||||
|
||||
@Test
|
||||
void testPromote() {
|
||||
final AST tree = getTree("GeneralOperator.stups");
|
||||
final SyntaxTree tree = getTree("GeneralOperator.stups");
|
||||
final long before = tree.size();
|
||||
|
||||
ASTCompacter.promote(tree, grammar);
|
||||
@ -64,7 +64,7 @@ class ASTCompacterTest {
|
||||
|
||||
@Test
|
||||
void testDeleteEmpty() {
|
||||
final AST tree = getTree("GeneralOperator.stups");
|
||||
final SyntaxTree tree = getTree("GeneralOperator.stups");
|
||||
ASTCompacter.deleteChildren(tree, grammar);
|
||||
final long before = tree.size();
|
||||
|
||||
@ -75,7 +75,7 @@ class ASTCompacterTest {
|
||||
|
||||
@Test
|
||||
void testClean() {
|
||||
final AST tree = getTree("GeneralOperator.stups");
|
||||
final SyntaxTree tree = getTree("GeneralOperator.stups");
|
||||
|
||||
ASTCompacter.clean(tree, grammar);
|
||||
|
45
src/test/java/parser/ast/SyntaxTreeTest.java
Normal file
45
src/test/java/parser/ast/SyntaxTreeTest.java
Normal file
@ -0,0 +1,45 @@
|
||||
package parser.ast;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class SyntaxTreeTest {
|
||||
|
||||
@Test
|
||||
void testOneNode() {
|
||||
final SyntaxTreeNode root = new SyntaxTreeNode("Wurzel", 1);
|
||||
|
||||
final SyntaxTree tree = new SyntaxTree(root);
|
||||
|
||||
assertThat(tree).hasToString("Wurzel\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testThreeNodesBinary() {
|
||||
final SyntaxTreeNode root = new SyntaxTreeNode("Wurzel", 1);
|
||||
final SyntaxTreeNode childA = new SyntaxTreeNode("A", 1);
|
||||
final SyntaxTreeNode childB = new SyntaxTreeNode("B", 1);
|
||||
|
||||
root.addChild(childA);
|
||||
root.addChild(childB);
|
||||
|
||||
final SyntaxTree tree = new SyntaxTree(root);
|
||||
|
||||
assertThat(tree).hasToString("Wurzel\n├── A\n└── B\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testThreeNodesLinear() {
|
||||
final SyntaxTreeNode root = new SyntaxTreeNode("Wurzel", 1);
|
||||
final SyntaxTreeNode childA = new SyntaxTreeNode("A", 1);
|
||||
final SyntaxTreeNode childB = new SyntaxTreeNode("B", 1);
|
||||
|
||||
root.addChild(childA);
|
||||
childA.addChild(childB);
|
||||
|
||||
final SyntaxTree tree = new SyntaxTree(root);
|
||||
|
||||
assertThat(tree).hasToString("Wurzel\n└── A\n └── B\n");
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@ import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import parser.ParseException;
|
||||
import parser.StupsParser;
|
||||
import parser.ast.AST;
|
||||
import parser.ast.SyntaxTree;
|
||||
import parser.grammar.Grammar;
|
||||
import typechecker.AssignmentTypeMismatchException;
|
||||
import typechecker.OperatorTypeMismatchException;
|
||||
@ -36,12 +36,12 @@ class TypeCheckerTest {
|
||||
+ "}}";
|
||||
}
|
||||
|
||||
private AST getTree(String expr) {
|
||||
private SyntaxTree getTree(String expr) {
|
||||
final Lexer lex = new StupsLexer(CharStreams.fromString(exprToProg(expr)));
|
||||
final AST tree = this.stupsParser.parse(lex.getAllTokens(), lex.getVocabulary());
|
||||
tree.postprocess(this.grammar);
|
||||
final SyntaxTree tree = this.stupsParser.parse(lex.getAllTokens(), lex.getVocabulary());
|
||||
final SyntaxTree ast = SyntaxTree.toAbstractSyntaxTree(tree, this.grammar);
|
||||
|
||||
return tree;
|
||||
return ast;
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
|
@ -6,7 +6,7 @@ import org.antlr.v4.runtime.Lexer;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import parser.StupsParser;
|
||||
import parser.ast.AST;
|
||||
import parser.ast.SyntaxTree;
|
||||
import parser.grammar.Grammar;
|
||||
import typechecker.SymbolAlreadyDefinedException;
|
||||
import typechecker.TypeTable;
|
||||
@ -33,14 +33,14 @@ class TypeTableTest {
|
||||
parser = StupsParser.fromGrammar(grammar);
|
||||
}
|
||||
|
||||
private static AST getTree(String program) {
|
||||
private static SyntaxTree getTree(String program) {
|
||||
try {
|
||||
final Path path = Paths.get(TypeTableTest.class.getClassLoader().getResource("examplePrograms/" + program).toURI());
|
||||
final String programCode = Files.readString(path, StandardCharsets.US_ASCII);
|
||||
final Lexer lex = new StupsLexer(CharStreams.fromString(programCode));
|
||||
final AST tree = parser.parse(lex.getAllTokens(), lex.getVocabulary());
|
||||
tree.postprocess(grammar);
|
||||
return tree;
|
||||
final SyntaxTree tree = parser.parse(lex.getAllTokens(), lex.getVocabulary());
|
||||
final SyntaxTree ast = SyntaxTree.toAbstractSyntaxTree(tree, grammar);
|
||||
return ast;
|
||||
} catch (Exception ignore) {
|
||||
ignore.printStackTrace();
|
||||
}
|
||||
@ -50,7 +50,7 @@ class TypeTableTest {
|
||||
|
||||
@Test
|
||||
void testSingleSymbol() {
|
||||
final AST tree = getTree("SingleSymbol.stups");
|
||||
final SyntaxTree tree = getTree("SingleSymbol.stups");
|
||||
|
||||
final TypeTable table = TypeTable.fromAST(tree);
|
||||
|
||||
@ -60,7 +60,7 @@ class TypeTableTest {
|
||||
|
||||
@Test
|
||||
void testMultipleSymbol() {
|
||||
final AST tree = getTree("MultipleSymbol.stups");
|
||||
final SyntaxTree tree = getTree("MultipleSymbol.stups");
|
||||
|
||||
final TypeTable table = TypeTable.fromAST(tree);
|
||||
|
||||
@ -75,14 +75,14 @@ class TypeTableTest {
|
||||
|
||||
@Test
|
||||
void testExistingSymbol() {
|
||||
final AST tree = getTree("ExistingSymbol.stups");
|
||||
final SyntaxTree tree = getTree("ExistingSymbol.stups");
|
||||
|
||||
assertThatThrownBy(() -> TypeTable.fromAST(tree)).isInstanceOf(SymbolAlreadyDefinedException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExistingSymbol2() {
|
||||
final AST tree = getTree("ExistingSymbol2.stups");
|
||||
final SyntaxTree tree = getTree("ExistingSymbol2.stups");
|
||||
|
||||
assertThatThrownBy(() -> TypeTable.fromAST(tree)).isInstanceOf(SymbolAlreadyDefinedException.class);
|
||||
}
|
||||
|
Reference in New Issue
Block a user