ParseTreeCleaner + SyntaxTreeRebalancer
This commit is contained in:
@ -7,28 +7,42 @@ import java.util.HashSet;
|
||||
|
||||
import static util.Logger.log;
|
||||
|
||||
public final class ASTCompacter {
|
||||
/**
|
||||
* Wendet in der Grammatik definierte Regeln auf einen Parsebaum an.
|
||||
* Dies ist der erste Schritt zum Abstrakten Syntaxbaum.
|
||||
*
|
||||
* <ul>
|
||||
* <li>Löscht redundante Knoten</li>
|
||||
* <li>Löscht leere Knoten</li>
|
||||
* <li>Komprimiert Äste, welche nur Informationen hochpropagieren</li>
|
||||
* <li>Führt Umbenennungen durch</li>
|
||||
* <li>Verschiebt Informationen in Knoten-Namen und -Wert</li>
|
||||
* </ul>
|
||||
*/
|
||||
public final class ParseTreeCleaner {
|
||||
|
||||
private ASTCompacter() {}
|
||||
private ParseTreeCleaner() {}
|
||||
|
||||
public static void clean(SyntaxTree tree, Grammar grammar) {
|
||||
deleteChildren(tree, grammar);
|
||||
deleteIfEmpty(tree, grammar);
|
||||
promote(tree, grammar);
|
||||
public static void clean(SyntaxTree parseTree, Grammar grammar) {
|
||||
deleteChildren(parseTree, grammar);
|
||||
deleteIfEmpty(parseTree, grammar);
|
||||
promote(parseTree, grammar);
|
||||
|
||||
renameTo(tree, grammar);
|
||||
nameToValue(tree, grammar);
|
||||
valueToValue(tree, grammar);
|
||||
renameTo(parseTree, grammar);
|
||||
nameToValue(parseTree, grammar);
|
||||
valueToValue(parseTree, grammar);
|
||||
|
||||
log("\nCleaned Tree:\n" + tree);
|
||||
log("\nCleaned Tree:\n" + parseTree);
|
||||
log("-".repeat(100));
|
||||
System.out.println(" - Compressing syntax-tree...");
|
||||
}
|
||||
|
||||
// Entfernt [promote]-able Nodes (Reicht Werte nach oben)
|
||||
public static void promote(SyntaxTree tree, Grammar grammar) {
|
||||
/**
|
||||
* Es werden Werte nach oben gereicht von [promote]-able Nodes.
|
||||
*/
|
||||
public static void promote(SyntaxTree parseTree, Grammar grammar) {
|
||||
log("\nPromoting nodes:");
|
||||
promote(tree.getRoot(), grammar);
|
||||
promote(parseTree.getRoot(), grammar);
|
||||
}
|
||||
|
||||
private static void promote(SyntaxTreeNode root, Grammar grammar) {
|
||||
@ -49,17 +63,19 @@ public final class ASTCompacter {
|
||||
root.setValue(child.getValue());
|
||||
root.setChildren(child.getChildren());
|
||||
|
||||
child.setValue("REMOVE"); // If both childs have the same identity both are removed
|
||||
child.setValue("REMOVE"); // If both childs have the same identity both are removed, so change one
|
||||
toRemove.add(child);
|
||||
}
|
||||
|
||||
root.getChildren().removeAll(toRemove);
|
||||
}
|
||||
|
||||
// Entfernt [delIfEmpty] Nodes (löscht Nodes ohne Inhalt)
|
||||
public static void deleteIfEmpty(SyntaxTree tree, Grammar grammar) {
|
||||
/**
|
||||
* Löscht leere Knoten mit [delIfEmpty].
|
||||
*/
|
||||
public static void deleteIfEmpty(SyntaxTree parseTree, Grammar grammar) {
|
||||
log("\nDeleting empty nodes:");
|
||||
deleteIfEmpty(tree.getRoot(), grammar);
|
||||
deleteIfEmpty(parseTree.getRoot(), grammar);
|
||||
}
|
||||
|
||||
private static void deleteIfEmpty(SyntaxTreeNode root, Grammar grammar) {
|
||||
@ -74,17 +90,19 @@ public final class ASTCompacter {
|
||||
|
||||
log("Removing " + child.getName());
|
||||
|
||||
child.setValue("REMOVE"); // If both childs have the same identity both are removed
|
||||
child.setValue("REMOVE"); // If both childs have the same identity both are removed, so change one
|
||||
toRemove.add(child);
|
||||
}
|
||||
|
||||
root.getChildren().removeAll(toRemove);
|
||||
}
|
||||
|
||||
// Löscht redundante Informationen in [delChildren]-Nodes (z.b. IF-child von COND) und Epsilon-Nodes
|
||||
public static void deleteChildren(SyntaxTree tree, Grammar grammar) {
|
||||
/**
|
||||
* Löscht redundante Informationen in [delChildren]-Nodes (z.b. IF-child von COND) und Epsilon-Nodes.
|
||||
*/
|
||||
public static void deleteChildren(SyntaxTree parseTree, Grammar grammar) {
|
||||
log("Removing redundant children:");
|
||||
deleteChildren(tree.getRoot(), grammar);
|
||||
deleteChildren(parseTree.getRoot(), grammar);
|
||||
}
|
||||
|
||||
private static void deleteChildren(SyntaxTreeNode root, Grammar grammar) {
|
||||
@ -99,17 +117,19 @@ public final class ASTCompacter {
|
||||
|
||||
log("Removing " + root.getName() + " -> " + child.getName());
|
||||
|
||||
child.setValue("REMOVE"); // If both childs have the same identity both are removed
|
||||
child.setValue("REMOVE"); // If both childs have the same identity both are removed, so change one
|
||||
toRemove.add(child);
|
||||
}
|
||||
|
||||
root.getChildren().removeAll(toRemove);
|
||||
}
|
||||
|
||||
// Umbenennungen
|
||||
private static void renameTo(SyntaxTree tree, Grammar grammar) {
|
||||
/**
|
||||
* Führt Umbenennungen durch.
|
||||
*/
|
||||
private static void renameTo(SyntaxTree parseTree, Grammar grammar) {
|
||||
log("\nRenaming nodes:");
|
||||
renameTo(tree.getRoot(), grammar);
|
||||
renameTo(parseTree.getRoot(), grammar);
|
||||
}
|
||||
|
||||
private static void renameTo(SyntaxTreeNode root, Grammar grammar) {
|
||||
@ -126,9 +146,12 @@ public final class ASTCompacter {
|
||||
}
|
||||
}
|
||||
|
||||
public static void nameToValue(SyntaxTree tree, Grammar grammar) {
|
||||
/**
|
||||
* Verschiebt Knotennamen von [nametoval]-Nodes in Parent-Values und löscht das Child.
|
||||
*/
|
||||
public static void nameToValue(SyntaxTree parseTree, Grammar grammar) {
|
||||
log("\nMoving names to values:");
|
||||
nameToValue(tree.getRoot(), grammar);
|
||||
nameToValue(parseTree.getRoot(), grammar);
|
||||
}
|
||||
|
||||
private static void nameToValue(SyntaxTreeNode root, Grammar grammar) {
|
||||
@ -146,17 +169,21 @@ public final class ASTCompacter {
|
||||
|
||||
root.setValue(child.getName());
|
||||
|
||||
child.setValue("REMOVE"); // If both childs have the same identity both are removed
|
||||
child.setValue("REMOVE"); // If both childs have the same identity both are removed, so change one
|
||||
toRemove.add(child);
|
||||
}
|
||||
|
||||
root.getChildren().removeAll(toRemove);
|
||||
}
|
||||
|
||||
// Assignment bekommt den Identifier als Value anstatt als Child
|
||||
public static void valueToValue(SyntaxTree tree, Grammar grammar) {
|
||||
/**
|
||||
* [valtoval]-Nodes bekommen den Child-Namen als Value anstatt als Child.
|
||||
* Wird z.B. durchgeführt bei Assignments: Der Assignment-Node bekommt den
|
||||
* Variablennamen als Wert anstatt als Child-Node.
|
||||
*/
|
||||
public static void valueToValue(SyntaxTree parseTree, Grammar grammar) {
|
||||
log("\nMoving values to values:");
|
||||
valueToValue(tree.getRoot(), grammar);
|
||||
valueToValue(parseTree.getRoot(), grammar);
|
||||
}
|
||||
|
||||
private static void valueToValue(SyntaxTreeNode root, Grammar grammar) {
|
||||
@ -165,36 +192,31 @@ public final class ASTCompacter {
|
||||
for (SyntaxTreeNode child : root.getChildren()) {
|
||||
valueToValue(child, grammar);
|
||||
|
||||
if (!grammar.hasValToVal(root, child)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!root.getValue().isBlank()) {
|
||||
// Do not overwrite
|
||||
if (!grammar.hasValToVal(root, child) || !root.getValue().isBlank()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (root.getChildren().size() == 2
|
||||
&& root.getChildren().get(0).getName().equals(root.getChildren().get(1).getName())) {
|
||||
// Special case where variable is assigned another variable
|
||||
// Case where variable is assigned another variable with the same name
|
||||
|
||||
log("Special case: Var to var assignment");
|
||||
log("Moving " + root.getChildren().get(1).getValue() + " to value of " + root.getName());
|
||||
log(root.toString());
|
||||
|
||||
root.setValue(root.getChildren().get(1).getValue());
|
||||
|
||||
root.getChildren().get(1).setValue("REMOVE"); // If both childs have the same identity both are removed
|
||||
root.getChildren().get(1).setValue("REMOVE"); // If both childs have the same identity both are removed, so change one
|
||||
toRemove.add(root.getChildren().get(1));
|
||||
|
||||
continue;
|
||||
} else {
|
||||
// Usual case where an expression is assigned
|
||||
|
||||
log("Moving " + child.getValue() + " to value of " + root.getName());
|
||||
log(root.toString());
|
||||
|
||||
root.setValue(child.getValue());
|
||||
toRemove.add(child);
|
||||
}
|
||||
|
||||
log("Moving " + child.getValue() + " to value of " + root.getName());
|
||||
log(root.toString());
|
||||
|
||||
root.setValue(child.getValue());
|
||||
toRemove.add(child);
|
||||
}
|
||||
|
||||
root.getChildren().removeAll(toRemove);
|
@ -23,8 +23,8 @@ public class SyntaxTree {
|
||||
public static SyntaxTree toAbstractSyntaxTree(SyntaxTree concreteSyntaxTree, Grammar grammar) {
|
||||
final SyntaxTree abstractSyntaxTree = concreteSyntaxTree.deepCopy();
|
||||
|
||||
ASTCompacter.clean(abstractSyntaxTree, grammar);
|
||||
ASTBalancer.balance(abstractSyntaxTree);
|
||||
ParseTreeCleaner.clean(abstractSyntaxTree, grammar);
|
||||
SyntaxTreeRebalancer.rebalance(abstractSyntaxTree);
|
||||
System.out.println("Tree processing successful.");
|
||||
|
||||
return abstractSyntaxTree;
|
||||
|
@ -6,11 +6,19 @@ import java.util.Set;
|
||||
|
||||
import static util.Logger.log;
|
||||
|
||||
public final class ASTBalancer {
|
||||
/**
|
||||
* Ein SyntaxTree wird an bestimmten Stellen rotiert, sodass bestimmte Eigenschaften
|
||||
* korrekt repräsentiert werden (Operatorpräzedenz, Linkassoziativität etc.).
|
||||
*/
|
||||
public final class SyntaxTreeRebalancer {
|
||||
|
||||
private static final Map<String, Integer> priority;
|
||||
private static final Set<String> unary;
|
||||
private static final Set<String> commutative;
|
||||
/**
|
||||
* Jedem Operator wird eine Priorität zugewiesen, 0 ist die höchste.
|
||||
*/
|
||||
private static final Map<String, Integer> operatorPriority;
|
||||
|
||||
private static final Set<String> unaryOperators;
|
||||
private static final Set<String> commutativeOperators;
|
||||
|
||||
//!: Operatorpräzedenz
|
||||
// 0 - Unary: -, +, !
|
||||
@ -21,44 +29,56 @@ public final class ASTBalancer {
|
||||
// 5 - Logical AND: &&
|
||||
// 6 - Logical OR: ||
|
||||
static {
|
||||
priority = Map.ofEntries(Map.entry("NOT", 0),
|
||||
Map.entry("MUL", 1),
|
||||
Map.entry("DIV", 1),
|
||||
Map.entry("MOD", 1),
|
||||
Map.entry("ADD", 2),
|
||||
Map.entry("SUB", 2),
|
||||
Map.entry("LESS", 3),
|
||||
Map.entry("LESS_EQUAL", 3),
|
||||
Map.entry("GREATER", 3),
|
||||
Map.entry("GREATER_EQUAL", 3),
|
||||
Map.entry("EQUAL", 4),
|
||||
Map.entry("NOT_EQUAL", 4),
|
||||
Map.entry("AND", 5),
|
||||
Map.entry("OR", 6));
|
||||
operatorPriority = Map.ofEntries(Map.entry("NOT", 0),
|
||||
Map.entry("MUL", 1),
|
||||
Map.entry("DIV", 1),
|
||||
Map.entry("MOD", 1),
|
||||
Map.entry("ADD", 2),
|
||||
Map.entry("SUB", 2),
|
||||
Map.entry("LESS", 3),
|
||||
Map.entry("LESS_EQUAL", 3),
|
||||
Map.entry("GREATER", 3),
|
||||
Map.entry("GREATER_EQUAL", 3),
|
||||
Map.entry("EQUAL", 4),
|
||||
Map.entry("NOT_EQUAL", 4),
|
||||
Map.entry("AND", 5),
|
||||
Map.entry("OR", 6));
|
||||
|
||||
unary = Set.of("NOT", "ADD", "SUB");
|
||||
unaryOperators = Set.of("NOT", "ADD", "SUB");
|
||||
|
||||
commutative = Set.of("ADD", "MUL", "EQUAL", "NOT_EQUAL", "AND", "OR");
|
||||
commutativeOperators = Set.of("ADD", "MUL", "EQUAL", "NOT_EQUAL", "AND", "OR");
|
||||
}
|
||||
|
||||
private ASTBalancer() {}
|
||||
private SyntaxTreeRebalancer() {}
|
||||
|
||||
public static void balance(SyntaxTree tree) {
|
||||
flip(tree);
|
||||
leftPrecedence(tree);
|
||||
operatorPrecedence(tree);
|
||||
flipCommutativeExpr(tree);
|
||||
/**
|
||||
* Ein Abstrakter Syntaxbaum wird umbalanciert.
|
||||
*
|
||||
* <ul>
|
||||
* <li>Baum wird gespiegelt, damit die Ausdrücke vorwárts laufen (Tiefste Ebenen müssen nach links)</li>
|
||||
* <li>Linkspräzedenz wird durch Links-Rotationen durchgesetzt</li>
|
||||
* <li>Operatorpräzedenz wird durch Rechtsrotationen durchgesetzt</li>
|
||||
* <li>Kommutative Ausdrücke werden gespiegelt, damit die tiefen Teilausdrücke zuerst berechnet werden</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static void rebalance(SyntaxTree abstractSyntaxTree) {
|
||||
flip(abstractSyntaxTree);
|
||||
leftPrecedence(abstractSyntaxTree);
|
||||
operatorPrecedence(abstractSyntaxTree);
|
||||
flipCommutativeExpr(abstractSyntaxTree);
|
||||
|
||||
log(tree.toString());
|
||||
log(abstractSyntaxTree.toString());
|
||||
log("-".repeat(100));
|
||||
|
||||
System.out.println(" - Balancing syntax-tree...");
|
||||
}
|
||||
|
||||
// Baum spiegeln, damit höhere Ebenen links sind und EXPR vorwärts laufen
|
||||
public static void flip(SyntaxTree tree) {
|
||||
/**
|
||||
* Baum spiegeln, damit höhere Ebenen links sind und EXPR vorwärts laufen.
|
||||
*/
|
||||
public static void flip(SyntaxTree abstractSyntaxTree) {
|
||||
log("Flipping tree for ltr evaluation");
|
||||
flip(tree.getRoot());
|
||||
flip(abstractSyntaxTree.getRoot());
|
||||
}
|
||||
|
||||
private static void flip(SyntaxTreeNode root) {
|
||||
@ -69,9 +89,12 @@ public final class ASTBalancer {
|
||||
Collections.reverse(root.getChildren());
|
||||
}
|
||||
|
||||
public static void flipCommutativeExpr(SyntaxTree tree) {
|
||||
/**
|
||||
* Kommutative Ausdrücke werden gespiegelt, damit die tiefen Teilexpressions zuerst berechnet werden.
|
||||
*/
|
||||
public static void flipCommutativeExpr(SyntaxTree abstractSyntaxTree) {
|
||||
log("Flipping commutative expressions for stack efficiency");
|
||||
flipCommutativeExpr(tree.getRoot());
|
||||
flipCommutativeExpr(abstractSyntaxTree.getRoot());
|
||||
}
|
||||
|
||||
private static void flipCommutativeExpr(SyntaxTreeNode root) {
|
||||
@ -79,9 +102,12 @@ public final class ASTBalancer {
|
||||
flipCommutativeExpr(child);
|
||||
}
|
||||
|
||||
if ("expr".equals(root.getName()) && commutative.contains(root.getValue())) {
|
||||
if ("expr".equals(root.getName()) && commutativeOperators.contains(root.getValue())) {
|
||||
// Ausdruck ist kommutativ
|
||||
|
||||
if (root.getChildren().size() == 2 && root.getChildren().get(0).size() < root.getChildren().get(1).size()) {
|
||||
// Make the bigger subtree the left one
|
||||
|
||||
log("Flipping " + root.getName() + ": " + root.getValue() + " for stack efficiency.");
|
||||
log(root.toString());
|
||||
|
||||
@ -90,14 +116,15 @@ 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(SyntaxTree tree) {
|
||||
/**
|
||||
* Führt Linksrotationen durch für Linkspräzedenz.
|
||||
* Es werden EXPR-Nodes (2 Childs, 1 davon EXPR, Kein Wert) solange wie möglich linksrotiert.
|
||||
*/
|
||||
public static void leftPrecedence(SyntaxTree abstractSyntaxTree) {
|
||||
log("Left-rotating expressions for left-precedence");
|
||||
leftPrecedence(tree.getRoot());
|
||||
leftPrecedence(abstractSyntaxTree.getRoot());
|
||||
}
|
||||
|
||||
// Es wird solange rotiert bis die letzte "Rotation" durchgeführt wurde
|
||||
private static void leftPrecedence(SyntaxTreeNode root) {
|
||||
for (SyntaxTreeNode child : root.getChildren()) {
|
||||
leftPrecedence(child);
|
||||
@ -116,7 +143,12 @@ public final class ASTBalancer {
|
||||
} while (change);
|
||||
}
|
||||
|
||||
// Die Letzte Rotation ist keine richtige Rotation, dort wird false zurückgegeben
|
||||
/**
|
||||
* Führt eine Linksrotation durch.
|
||||
* Diese ist nicht regulär, da der Operator linksvererbt wird.
|
||||
*
|
||||
* @return Es wird false zurückgegeben, sobald keine weitere Rotation mehr möglich ist.
|
||||
*/
|
||||
private static boolean specialLeftRotate(SyntaxTreeNode root) {
|
||||
log("Special-Left-Rotation around " + root.getName());
|
||||
log(root.toString());
|
||||
@ -157,13 +189,18 @@ public final class ASTBalancer {
|
||||
return root.getChildren().size() == 1;
|
||||
}
|
||||
|
||||
public static void operatorPrecedence(SyntaxTree tree) {
|
||||
/**
|
||||
* Führt Rechtsrotationen durch für Operatorpräzedenz.
|
||||
* Es wird solange rechtsrotiert, bis alle Operatoren mit hoher Priorität tiefer stehen
|
||||
* als die Operatoren mit niedriger Priorität.
|
||||
*/
|
||||
public static void operatorPrecedence(SyntaxTree abstractSyntaxTree) {
|
||||
log("Right-rotating expressions for operator-precedence");
|
||||
|
||||
boolean changed;
|
||||
|
||||
do {
|
||||
changed = operatorPrecedence(tree.getRoot());
|
||||
changed = operatorPrecedence(abstractSyntaxTree.getRoot());
|
||||
} while (changed);
|
||||
}
|
||||
|
||||
@ -182,6 +219,9 @@ public final class ASTBalancer {
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ermittelt, ob der ParentNode höhere Priorität als der ChildNode hat.
|
||||
*/
|
||||
private static boolean preceding(SyntaxTreeNode parent, SyntaxTreeNode child) {
|
||||
if (!"expr".equals(parent.getName()) || parent.getValue().isEmpty()
|
||||
|| !"expr".equals(child.getName()) || child.getValue().isEmpty()) {
|
||||
@ -189,13 +229,13 @@ public final class ASTBalancer {
|
||||
}
|
||||
|
||||
// Unary operators have the highest precedence
|
||||
if (child.getChildren().size() == 1 && unary.contains(child.getValue())) {
|
||||
if (child.getChildren().size() == 1 && unaryOperators.contains(child.getValue())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Less equals higher
|
||||
{
|
||||
return priority.get(parent.getValue()) < priority.get(child.getValue());
|
||||
return operatorPriority.get(parent.getValue()) < operatorPriority.get(child.getValue());
|
||||
}
|
||||
}
|
||||
|
@ -17,21 +17,21 @@ import java.nio.file.Paths;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class SyntaxTreeCompacterTest {
|
||||
class ParseTreeCleanerTest {
|
||||
|
||||
private static Grammar grammar;
|
||||
private static StupsParser parser;
|
||||
|
||||
@BeforeAll
|
||||
static void init() throws IOException, URISyntaxException {
|
||||
final Path path = Paths.get(SyntaxTreeCompacterTest.class.getClassLoader().getResource("exampleGrammars/Grammar.grammar").toURI());
|
||||
final Path path = Paths.get(ParseTreeCleanerTest.class.getClassLoader().getResource("exampleGrammars/Grammar.grammar").toURI());
|
||||
grammar = Grammar.fromFile(path);
|
||||
parser = StupsParser.fromGrammar(grammar);
|
||||
}
|
||||
|
||||
private static SyntaxTree getTree(String program) {
|
||||
try {
|
||||
final Path path = Paths.get(SyntaxTreeCompacterTest.class.getClassLoader().getResource("examplePrograms/" + program).toURI());
|
||||
final Path path = Paths.get(ParseTreeCleanerTest.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());
|
||||
@ -47,7 +47,7 @@ class SyntaxTreeCompacterTest {
|
||||
final SyntaxTree tree = getTree("GeneralOperator.stups");
|
||||
final long before = tree.size();
|
||||
|
||||
ASTCompacter.deleteChildren(tree, grammar);
|
||||
ParseTreeCleaner.deleteChildren(tree, grammar);
|
||||
|
||||
assertThat(before - tree.size()).isEqualTo(3);
|
||||
}
|
||||
@ -57,7 +57,7 @@ class SyntaxTreeCompacterTest {
|
||||
final SyntaxTree tree = getTree("GeneralOperator.stups");
|
||||
final long before = tree.size();
|
||||
|
||||
ASTCompacter.promote(tree, grammar);
|
||||
ParseTreeCleaner.promote(tree, grammar);
|
||||
|
||||
assertThat(before - tree.size()).isEqualTo(14);
|
||||
}
|
||||
@ -65,10 +65,10 @@ class SyntaxTreeCompacterTest {
|
||||
@Test
|
||||
void testDeleteEmpty() {
|
||||
final SyntaxTree tree = getTree("GeneralOperator.stups");
|
||||
ASTCompacter.deleteChildren(tree, grammar);
|
||||
ParseTreeCleaner.deleteChildren(tree, grammar);
|
||||
final long before = tree.size();
|
||||
|
||||
ASTCompacter.deleteIfEmpty(tree, grammar);
|
||||
ParseTreeCleaner.deleteIfEmpty(tree, grammar);
|
||||
|
||||
assertThat(before - tree.size()).isEqualTo(2);
|
||||
}
|
||||
@ -77,7 +77,7 @@ class SyntaxTreeCompacterTest {
|
||||
void testClean() {
|
||||
final SyntaxTree tree = getTree("GeneralOperator.stups");
|
||||
|
||||
ASTCompacter.clean(tree, grammar);
|
||||
ParseTreeCleaner.clean(tree, grammar);
|
||||
|
||||
assertThat(tree.size()).isEqualTo(28);
|
||||
}
|
@ -4,7 +4,7 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class SyntaxTreeBalancerTest {
|
||||
class SyntaxTreeRebalancerTest {
|
||||
|
||||
//expr
|
||||
//├── expr: SUB
|
||||
@ -84,7 +84,7 @@ class SyntaxTreeBalancerTest {
|
||||
void testTree1Flip() {
|
||||
final SyntaxTree tree = tree1();
|
||||
|
||||
ASTBalancer.flip(tree);
|
||||
SyntaxTreeRebalancer.flip(tree);
|
||||
|
||||
assertThat(tree.getRoot().getChildren().get(0).getName()).isEqualTo("INTEGER_LIT");
|
||||
assertThat(tree.getRoot().getChildren().get(1).getName()).isEqualTo("expr");
|
||||
@ -94,8 +94,8 @@ class SyntaxTreeBalancerTest {
|
||||
void testTree1Flip2x() {
|
||||
final SyntaxTree tree = tree1();
|
||||
|
||||
ASTBalancer.flip(tree);
|
||||
ASTBalancer.flip(tree);
|
||||
SyntaxTreeRebalancer.flip(tree);
|
||||
SyntaxTreeRebalancer.flip(tree);
|
||||
|
||||
assertThat(tree).isEqualTo(tree1());
|
||||
}
|
||||
@ -104,7 +104,7 @@ class SyntaxTreeBalancerTest {
|
||||
void testTree2Flip() {
|
||||
final SyntaxTree tree = tree2();
|
||||
|
||||
ASTBalancer.flip(tree);
|
||||
SyntaxTreeRebalancer.flip(tree);
|
||||
|
||||
assertThat(tree.getRoot().getChildren().get(0).getName()).isEqualTo("INTEGER_LIT");
|
||||
assertThat(tree.getRoot().getChildren().get(1).getName()).isEqualTo("expr");
|
||||
@ -116,8 +116,8 @@ class SyntaxTreeBalancerTest {
|
||||
void testTree2Flip2x() {
|
||||
final SyntaxTree tree = tree2();
|
||||
|
||||
ASTBalancer.flip(tree);
|
||||
ASTBalancer.flip(tree);
|
||||
SyntaxTreeRebalancer.flip(tree);
|
||||
SyntaxTreeRebalancer.flip(tree);
|
||||
|
||||
assertThat(tree).isEqualTo(tree2());
|
||||
}
|
||||
@ -125,9 +125,9 @@ class SyntaxTreeBalancerTest {
|
||||
@Test
|
||||
void testTree1LeftPrecedence() {
|
||||
final SyntaxTree tree = tree1();
|
||||
ASTBalancer.flip(tree);
|
||||
SyntaxTreeRebalancer.flip(tree);
|
||||
|
||||
ASTBalancer.leftPrecedence(tree);
|
||||
SyntaxTreeRebalancer.leftPrecedence(tree);
|
||||
|
||||
assertThat(tree.size()).isEqualTo(3);
|
||||
assertThat(tree.getRoot().getValue()).isEqualTo("SUB");
|
||||
@ -136,9 +136,9 @@ class SyntaxTreeBalancerTest {
|
||||
@Test
|
||||
void testTree2LeftPrecedence() {
|
||||
final SyntaxTree tree = tree2();
|
||||
ASTBalancer.flip(tree);
|
||||
SyntaxTreeRebalancer.flip(tree);
|
||||
|
||||
ASTBalancer.leftPrecedence(tree);
|
||||
SyntaxTreeRebalancer.leftPrecedence(tree);
|
||||
|
||||
assertThat(tree.size()).isEqualTo(5);
|
||||
assertThat(tree.getRoot().getValue()).isEqualTo("SUB");
|
||||
@ -147,14 +147,14 @@ class SyntaxTreeBalancerTest {
|
||||
@Test
|
||||
void testTree2OperatorPrecedence() {
|
||||
final SyntaxTree tree = tree2();
|
||||
ASTBalancer.flip(tree);
|
||||
ASTBalancer.leftPrecedence(tree);
|
||||
SyntaxTreeRebalancer.flip(tree);
|
||||
SyntaxTreeRebalancer.leftPrecedence(tree);
|
||||
|
||||
final SyntaxTree tree1 = tree2();
|
||||
ASTBalancer.flip(tree1);
|
||||
ASTBalancer.leftPrecedence(tree1);
|
||||
SyntaxTreeRebalancer.flip(tree1);
|
||||
SyntaxTreeRebalancer.leftPrecedence(tree1);
|
||||
|
||||
ASTBalancer.operatorPrecedence(tree);
|
||||
SyntaxTreeRebalancer.operatorPrecedence(tree);
|
||||
|
||||
assertThat(tree).isEqualTo(tree1);
|
||||
}
|
||||
@ -162,12 +162,12 @@ class SyntaxTreeBalancerTest {
|
||||
@Test
|
||||
void testTree3OperatorPrecedence() {
|
||||
final SyntaxTree tree = tree3();
|
||||
ASTBalancer.flip(tree);
|
||||
ASTBalancer.leftPrecedence(tree);
|
||||
SyntaxTreeRebalancer.flip(tree);
|
||||
SyntaxTreeRebalancer.leftPrecedence(tree);
|
||||
|
||||
assertThat(tree.getRoot().getValue()).isEqualTo("MUL");
|
||||
|
||||
ASTBalancer.operatorPrecedence(tree);
|
||||
SyntaxTreeRebalancer.operatorPrecedence(tree);
|
||||
|
||||
assertThat(tree.size()).isEqualTo(5);
|
||||
assertThat(tree.getRoot().getValue()).isEqualTo("SUB");
|
Reference in New Issue
Block a user