rework SyntaxTree (AST)

This commit is contained in:
ChUrl
2021-01-31 18:39:41 +01:00
parent bb3e4dfb58
commit 108a2001e8
25 changed files with 481 additions and 453 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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();
}
}

View 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();
}
}

View File

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

View File

@ -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) + "]");

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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