implement operator precedence + test
This commit is contained in:
@ -1,5 +1,7 @@
|
||||
package parser.ast;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import static util.Logger.log;
|
||||
@ -19,7 +21,7 @@ public final class ExpressionBalancer {
|
||||
|
||||
// Baum spiegeln, damit höhere Ebenen links sind und EXPR vorwärts laufen
|
||||
public static void flip(AST tree) {
|
||||
log("Flipping expressions");
|
||||
log("Flipping tree for ltr evaluation");
|
||||
flip(tree.getRoot());
|
||||
}
|
||||
|
||||
@ -34,7 +36,7 @@ public final class ExpressionBalancer {
|
||||
// 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) {
|
||||
log("Rotating expressions for left-precedence");
|
||||
log("Left-rotating expressions for left-precedence");
|
||||
leftPrecedence(tree.getRoot());
|
||||
}
|
||||
|
||||
@ -53,28 +55,28 @@ public final class ExpressionBalancer {
|
||||
boolean change;
|
||||
|
||||
do {
|
||||
change = leftRotate(root);
|
||||
change = specialLeftRotate(root);
|
||||
} while (change);
|
||||
}
|
||||
|
||||
// Die Letzte Rotation ist keine richtige Rotation, dort wird false zurückgegeben
|
||||
private static boolean leftRotate(Node root) {
|
||||
private static boolean specialLeftRotate(Node root) {
|
||||
Node left = root.getChildren().get(0);
|
||||
Node right = root.getChildren().get(1);
|
||||
|
||||
// Verhindert Wurzel mit nur einem EXPR-Child
|
||||
// Verhindert Wurzel mit nur einem EXPR-Child (nach oben "hängende" Wurzel)
|
||||
if (endOfExpr(right)) {
|
||||
root.setName(right.getName());
|
||||
root.setValue(right.getValue());
|
||||
root.setChildren(left, right.getChildren().get(0));
|
||||
return false;
|
||||
return false; // Braucht keine weitere Rotation
|
||||
}
|
||||
|
||||
Node insertLeft = new Node(root.getName());
|
||||
insertLeft.setValue(right.getValue());
|
||||
insertLeft.setValue(right.getValue()); // Operation wird linksvererbt
|
||||
insertLeft.setChildren(left, right.getChildren().get(0));
|
||||
|
||||
root.setName(right.getName());
|
||||
root.setName(right.getName()); // Value wird nicht gesetzt, da ans linke Kind vererbt
|
||||
root.setChildren(insertLeft, right.getChildren().get(1));
|
||||
|
||||
return true;
|
||||
@ -94,7 +96,54 @@ public final class ExpressionBalancer {
|
||||
return root.getChildren().size() == 1;
|
||||
}
|
||||
|
||||
// 0 - Unary: -, +, !
|
||||
// 1 - Multiplicative: *, /, %
|
||||
// 2 - Additive: +, -
|
||||
// 3 - Comparative: <, <=, >, >=
|
||||
// 4 - Equality: ==, !=
|
||||
// 5 - Logical AND: &&
|
||||
// 6 - Logical OR: ||
|
||||
public static void operatorPrecedence(AST tree) {
|
||||
log("Right-rotating expressions for operator-precedence");
|
||||
operatorPrecedence(tree.getRoot());
|
||||
}
|
||||
|
||||
public static void operatorPrecedence(Node root) {
|
||||
for (Node child : root.getChildren()) {
|
||||
operatorPrecedence(child);
|
||||
}
|
||||
|
||||
if (preceding(root)) {
|
||||
simpleRightRotate(root);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean preceding(Node root) {
|
||||
Node op = getExpr(root);
|
||||
|
||||
if (op == null || !root.getName().equals("EXPR") || root.getValue().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Collection<String> arithHigh = Arrays.asList("MUL", "DIV", "MOD");
|
||||
Collection<String> arithLow = Arrays.asList("ADD", "SUB");
|
||||
Collection<String> logHigh = Arrays.asList("AND");
|
||||
Collection<String> logLow = Arrays.asList("OR");
|
||||
|
||||
return (arithHigh.contains(root.getValue()) && arithLow.contains(op.getValue()))
|
||||
|| (logHigh.contains(root.getValue()) && logLow.contains(op.getValue()));
|
||||
}
|
||||
|
||||
private static void simpleRightRotate(Node root) {
|
||||
Node left = root.getChildren().get(0);
|
||||
Node right = root.getChildren().get(1);
|
||||
|
||||
Node insertRight = new Node(root.getName());
|
||||
insertRight.setValue(root.getValue());
|
||||
insertRight.setChildren(left.getChildren().get(1), right);
|
||||
|
||||
root.setName(left.getName());
|
||||
root.setValue(left.getValue());
|
||||
root.setChildren(left.getChildren().get(0), insertRight);
|
||||
}
|
||||
}
|
||||
|
@ -54,6 +54,32 @@ class ExpressionBalancerTest {
|
||||
return tree;
|
||||
}
|
||||
|
||||
private static AST tree3() {
|
||||
AST tree = new AST(new Node("EXPR"));
|
||||
|
||||
Node right = new Node("INTEGER_LIT");
|
||||
right.setValue("1");
|
||||
|
||||
Node left = new Node("EXPR");
|
||||
left.setValue("SUB");
|
||||
|
||||
Node lleft = new Node("EXPR");
|
||||
lleft.setValue("MUL");
|
||||
|
||||
Node lright = new Node("INTEGER_LIT");
|
||||
lright.setValue("2");
|
||||
|
||||
Node llleft = new Node("INTEGER_LIT");
|
||||
llleft.setValue("3");
|
||||
|
||||
lleft.setChildren(llleft);
|
||||
left.setChildren(lleft, lright);
|
||||
|
||||
tree.getRoot().setChildren(left, right);
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTree1Flip() {
|
||||
AST tree = tree1();
|
||||
@ -105,7 +131,7 @@ class ExpressionBalancerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTree1Rotate() {
|
||||
void testTree1LeftPrecedence() {
|
||||
AST tree = tree1();
|
||||
ExpressionBalancer.flip(tree);
|
||||
System.out.println("Before:\n" + tree);
|
||||
@ -118,7 +144,7 @@ class ExpressionBalancerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTree2Rotate() {
|
||||
void testTree2LeftPrecedence() {
|
||||
AST tree = tree2();
|
||||
ExpressionBalancer.flip(tree);
|
||||
System.out.println("Before:\n" + tree);
|
||||
@ -129,4 +155,37 @@ class ExpressionBalancerTest {
|
||||
assertThat(tree.size()).isEqualTo(5);
|
||||
assertThat(tree.getRoot().getValue()).isEqualTo("SUB");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTree2OperatorPrecedence() {
|
||||
AST tree = tree2();
|
||||
ExpressionBalancer.flip(tree);
|
||||
ExpressionBalancer.leftPrecedence(tree);
|
||||
System.out.println("Before:\n" + tree);
|
||||
|
||||
AST tree1 = tree2();
|
||||
ExpressionBalancer.flip(tree1);
|
||||
ExpressionBalancer.leftPrecedence(tree1);
|
||||
|
||||
ExpressionBalancer.operatorPrecedence(tree);
|
||||
System.out.println("After:\n" + tree);
|
||||
|
||||
assertThat(tree).isEqualTo(tree1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTree3OperatorPrecedence() {
|
||||
AST tree = tree3();
|
||||
ExpressionBalancer.flip(tree);
|
||||
ExpressionBalancer.leftPrecedence(tree);
|
||||
System.out.println("Before:\n" + tree);
|
||||
|
||||
assertThat(tree.getRoot().getValue()).isEqualTo("MUL");
|
||||
|
||||
ExpressionBalancer.operatorPrecedence(tree);
|
||||
System.out.println("After:\n" + tree);
|
||||
|
||||
assertThat(tree.size()).isEqualTo(5);
|
||||
assertThat(tree.getRoot().getValue()).isEqualTo("SUB");
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user