implement operator precedence + test

This commit is contained in:
ChUrl
2020-12-13 14:05:26 +01:00
parent 290f1fe240
commit 9aafbb3095
2 changed files with 118 additions and 10 deletions

View File

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

View File

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