From dcc943fa192a4913fa0a7cf163cd98945acf5e91 Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 24 Jun 2016 00:55:40 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=BE=D0=BF=D1=82=D0=B8=D0=BC=D0=B8=D0=B7=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8F:=20=D1=83=D0=BF=D1=80=D0=BE=D1=89=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=B2=D1=8B=D1=80=D0=B0=D0=B6=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/com/annimon/ownlang/parser/Optimizer.java | 4 + .../visitors/ExpressionSimplification.java | 146 ++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 src/com/annimon/ownlang/parser/visitors/ExpressionSimplification.java diff --git a/src/com/annimon/ownlang/parser/Optimizer.java b/src/com/annimon/ownlang/parser/Optimizer.java index 0940dc3..fbe8c99 100644 --- a/src/com/annimon/ownlang/parser/Optimizer.java +++ b/src/com/annimon/ownlang/parser/Optimizer.java @@ -3,6 +3,7 @@ package com.annimon.ownlang.parser; import com.annimon.ownlang.parser.ast.Statement; import com.annimon.ownlang.parser.visitors.ConstantFolding; import com.annimon.ownlang.parser.visitors.DeadCodeElimination; +import com.annimon.ownlang.parser.visitors.ExpressionSimplification; public final class Optimizer { @@ -18,14 +19,17 @@ public final class Optimizer { final ConstantFolding constantFolding = new ConstantFolding(); final DeadCodeElimination deadCodeElimination = new DeadCodeElimination(); + final ExpressionSimplification expressionSimplification = new ExpressionSimplification(); Statement result = statement; for (int i = 0; i < level; i++) { result = (Statement) result.accept(constantFolding, null); result = (Statement) result.accept(deadCodeElimination, null); + result = (Statement) result.accept(expressionSimplification, null); } System.out.print(constantFolding.summaryInfo()); System.out.print(deadCodeElimination.summaryInfo()); + System.out.print(expressionSimplification.summaryInfo()); System.out.println(); return result; } diff --git a/src/com/annimon/ownlang/parser/visitors/ExpressionSimplification.java b/src/com/annimon/ownlang/parser/visitors/ExpressionSimplification.java new file mode 100644 index 0000000..79c4c35 --- /dev/null +++ b/src/com/annimon/ownlang/parser/visitors/ExpressionSimplification.java @@ -0,0 +1,146 @@ +package com.annimon.ownlang.parser.visitors; + +import com.annimon.ownlang.lib.NumberValue; +import com.annimon.ownlang.lib.Types; +import com.annimon.ownlang.lib.Value; +import com.annimon.ownlang.parser.Optimizer; +import com.annimon.ownlang.parser.ast.BinaryExpression; +import com.annimon.ownlang.parser.ast.ConditionalExpression; +import com.annimon.ownlang.parser.ast.Node; +import com.annimon.ownlang.parser.ast.UnaryExpression; +import com.annimon.ownlang.parser.ast.ValueExpression; +import com.annimon.ownlang.parser.ast.VariableExpression; + +/** + * Performs expression simplification. + */ +public class ExpressionSimplification extends OptimizationVisitor implements Optimizer.Info { + + private int simplificationsCount; + + public ExpressionSimplification() { + simplificationsCount = 0; + } + + @Override + public int optimizationsCount() { + return simplificationsCount; + } + + @Override + public String summaryInfo() { + if (optimizationsCount() == 0) return ""; + final StringBuilder sb = new StringBuilder(); + if (simplificationsCount > 0) { + sb.append("\nExpression simplifications: ").append(simplificationsCount); + } + return sb.toString(); + } + + @Override + public Node visit(BinaryExpression s, Void t) { + // operations with 0 + final boolean expr1IsZero = isIntegerValue(s.expr1, 0); + if (expr1IsZero || isIntegerValue(s.expr2, 0)) { + switch (s.operation) { + case ADD: + // 0 + x2 to x2, x1 + 0 to x1 + simplificationsCount++; + return expr1IsZero ? s.expr2 : s.expr1; + + case SUBTRACT: + simplificationsCount++; + if (expr1IsZero) { + // 0 - x2 to -x2 + return new UnaryExpression(UnaryExpression.Operator.NEGATE, s.expr2); + } + // x1 - 0 to x1 + return s.expr1; + + case MULTIPLY: + // 0 * x2 to 0, x1 * 0 to 0 + simplificationsCount++; + return new ValueExpression(0); + + case DIVIDE: + // 0 / x2 to 0 + if (expr1IsZero) { + simplificationsCount++; + return new ValueExpression(0); + } + break; + } + } + + // operations with 1 + final boolean expr1IsOne = isIntegerValue(s.expr1, 1); + if (expr1IsOne || isIntegerValue(s.expr2, 1)) { + switch (s.operation) { + case MULTIPLY: + // 1 * x2 to x2, x1 * 1 to x1 + simplificationsCount++; + return expr1IsOne ? s.expr2 : s.expr1; + + case DIVIDE: + // x1 / 1 to x1 + if (!expr1IsOne) { + simplificationsCount++; + return s.expr1; + } + break; + } + } + + // x1 / -1 to -x1 + if (isIntegerValue(s.expr2, -1)) { + simplificationsCount++; + return new UnaryExpression(UnaryExpression.Operator.NEGATE, s.expr1); + } + + // x - x to 0 + if (isSameVariables(s.expr1, s.expr2) && s.operation == BinaryExpression.Operator.SUBTRACT) { + simplificationsCount++; + return new ValueExpression(0); + } + + return super.visit(s, t); + } + + @Override + public Node visit(ConditionalExpression s, Void t) { + if (isIntegerValue(s.expr1, 0) && s.operation == ConditionalExpression.Operator.AND) { + // 0 && x2 to 0 + simplificationsCount++; + return new ValueExpression(0); + } + if (isIntegerValue(s.expr1, 1) && s.operation == ConditionalExpression.Operator.OR) { + // 1 || x2 to 1 + simplificationsCount++; + return new ValueExpression(1); + } + return super.visit(s, t); + } + + + private boolean isIntegerValue(Node node, int valueToCheck) { + if (!(node instanceof ValueExpression)) return false; + + final Value value = ((ValueExpression) node).value; + if (value.type() != Types.NUMBER) return false; + + final Number number = ((NumberValue) value).raw(); + if ( (number instanceof Integer) || (number instanceof Short) || (number instanceof Byte)) { + return number.intValue() == valueToCheck; + } + return false; + } + + private boolean isSameVariables(Node n1, Node n2) { + if ( (n1 instanceof VariableExpression) && (n2 instanceof VariableExpression) ) { + final VariableExpression v1 = (VariableExpression) n1; + final VariableExpression v2 = (VariableExpression) n2; + return v1.name.equals(v2.name); + } + return false; + } +}