implement operator precedence + test
This commit is contained in:
@ -1,5 +1,7 @@
|
|||||||
package parser.ast;
|
package parser.ast;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
import static util.Logger.log;
|
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
|
// Baum spiegeln, damit höhere Ebenen links sind und EXPR vorwärts laufen
|
||||||
public static void flip(AST tree) {
|
public static void flip(AST tree) {
|
||||||
log("Flipping expressions");
|
log("Flipping tree for ltr evaluation");
|
||||||
flip(tree.getRoot());
|
flip(tree.getRoot());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +36,7 @@ public final class ExpressionBalancer {
|
|||||||
// Führt Linksrotationen durch
|
// Führt Linksrotationen durch
|
||||||
// Es werden EXPR-Nodes (2 Childs, 1 davon EXPR, Kein Wert) solange wie möglich linksrotiert
|
// 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(AST tree) {
|
||||||
log("Rotating expressions for left-precedence");
|
log("Left-rotating expressions for left-precedence");
|
||||||
leftPrecedence(tree.getRoot());
|
leftPrecedence(tree.getRoot());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,28 +55,28 @@ public final class ExpressionBalancer {
|
|||||||
boolean change;
|
boolean change;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
change = leftRotate(root);
|
change = specialLeftRotate(root);
|
||||||
} while (change);
|
} while (change);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Die Letzte Rotation ist keine richtige Rotation, dort wird false zurückgegeben
|
// 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 left = root.getChildren().get(0);
|
||||||
Node right = root.getChildren().get(1);
|
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)) {
|
if (endOfExpr(right)) {
|
||||||
root.setName(right.getName());
|
root.setName(right.getName());
|
||||||
root.setValue(right.getValue());
|
root.setValue(right.getValue());
|
||||||
root.setChildren(left, right.getChildren().get(0));
|
root.setChildren(left, right.getChildren().get(0));
|
||||||
return false;
|
return false; // Braucht keine weitere Rotation
|
||||||
}
|
}
|
||||||
|
|
||||||
Node insertLeft = new Node(root.getName());
|
Node insertLeft = new Node(root.getName());
|
||||||
insertLeft.setValue(right.getValue());
|
insertLeft.setValue(right.getValue()); // Operation wird linksvererbt
|
||||||
insertLeft.setChildren(left, right.getChildren().get(0));
|
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));
|
root.setChildren(insertLeft, right.getChildren().get(1));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -94,7 +96,54 @@ public final class ExpressionBalancer {
|
|||||||
return root.getChildren().size() == 1;
|
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) {
|
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;
|
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
|
@Test
|
||||||
void testTree1Flip() {
|
void testTree1Flip() {
|
||||||
AST tree = tree1();
|
AST tree = tree1();
|
||||||
@ -105,7 +131,7 @@ class ExpressionBalancerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testTree1Rotate() {
|
void testTree1LeftPrecedence() {
|
||||||
AST tree = tree1();
|
AST tree = tree1();
|
||||||
ExpressionBalancer.flip(tree);
|
ExpressionBalancer.flip(tree);
|
||||||
System.out.println("Before:\n" + tree);
|
System.out.println("Before:\n" + tree);
|
||||||
@ -118,7 +144,7 @@ class ExpressionBalancerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testTree2Rotate() {
|
void testTree2LeftPrecedence() {
|
||||||
AST tree = tree2();
|
AST tree = tree2();
|
||||||
ExpressionBalancer.flip(tree);
|
ExpressionBalancer.flip(tree);
|
||||||
System.out.println("Before:\n" + tree);
|
System.out.println("Before:\n" + tree);
|
||||||
@ -129,4 +155,37 @@ class ExpressionBalancerTest {
|
|||||||
assertThat(tree.size()).isEqualTo(5);
|
assertThat(tree.size()).isEqualTo(5);
|
||||||
assertThat(tree.getRoot().getValue()).isEqualTo("SUB");
|
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