136 lines
3.2 KiB
Java
136 lines
3.2 KiB
Java
package cd.ir;
|
|
|
|
import cd.ir.Ast.BinaryOp;
|
|
import cd.ir.Ast.BooleanConst;
|
|
import cd.ir.Ast.Expr;
|
|
import cd.ir.Ast.UnaryOp;
|
|
import cd.ir.Symbol.VariableSymbol;
|
|
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
import java.util.Optional;
|
|
|
|
import static cd.Config.FALSE;
|
|
import static cd.Config.TRUE;
|
|
|
|
/**
|
|
* A visitor that only visits {@link Expr} nodes.
|
|
* calculates the compile time value of an rhs in an assignment statement or the boolean value of a condition
|
|
*/
|
|
public class CompileTimeEvaluator extends ExprVisitor<Integer, Map<VariableSymbol, Integer>> {
|
|
|
|
// if the expression contains non constant variables, field or index; or if the expression is a read()
|
|
// no compile Time value can be computed
|
|
private boolean failedToEvaluate;
|
|
|
|
public Optional<Integer> calc(Ast.Expr ast) {
|
|
return calc(ast, new HashMap<>());
|
|
}
|
|
|
|
public Optional<Integer> calc(Ast.Expr ast, Map<VariableSymbol, Integer> constantMap) {
|
|
try {
|
|
failedToEvaluate = false;
|
|
Integer result = visit(ast, constantMap);
|
|
if (failedToEvaluate)
|
|
return Optional.empty();
|
|
else
|
|
return Optional.of(result);
|
|
} catch (ArithmeticException e) {
|
|
return Optional.empty();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected Integer dfltExpr(Expr ast, Map<VariableSymbol, Integer> arg) {
|
|
failedToEvaluate = true;
|
|
return Integer.MIN_VALUE;
|
|
}
|
|
|
|
|
|
@Override
|
|
public Integer binaryOp(BinaryOp ast, Map<VariableSymbol, Integer> arg) {
|
|
boolean tempResult;
|
|
int left = visit(ast.left(), arg);
|
|
int right = visit(ast.right(), arg);
|
|
|
|
switch (ast.operator) {
|
|
case B_TIMES:
|
|
return left * right;
|
|
case B_PLUS:
|
|
return left + right;
|
|
case B_MINUS:
|
|
return left - right;
|
|
case B_DIV:
|
|
return left / right;
|
|
case B_MOD:
|
|
return left % right;
|
|
case B_AND:
|
|
tempResult = (left == TRUE) && (right == TRUE);
|
|
break;
|
|
case B_OR:
|
|
tempResult = (left == TRUE) || (right == TRUE);
|
|
break;
|
|
case B_EQUAL:
|
|
tempResult = left == right;
|
|
break;
|
|
case B_NOT_EQUAL:
|
|
tempResult = left != right;
|
|
break;
|
|
case B_LESS_THAN:
|
|
tempResult = left < right;
|
|
break;
|
|
case B_LESS_OR_EQUAL:
|
|
tempResult = left <= right;
|
|
break;
|
|
case B_GREATER_THAN:
|
|
tempResult = left > right;
|
|
break;
|
|
case B_GREATER_OR_EQUAL:
|
|
tempResult = left >= right;
|
|
break;
|
|
default:
|
|
throw new RuntimeException("Invalid binary operator");
|
|
}
|
|
return tempResult ? TRUE : FALSE;
|
|
}
|
|
|
|
|
|
@Override
|
|
public Integer unaryOp(UnaryOp ast, Map<VariableSymbol, Integer> arg) {
|
|
int result = visit(ast.arg(), arg);
|
|
|
|
switch (ast.operator) {
|
|
case U_PLUS:
|
|
return result;
|
|
case U_MINUS:
|
|
return -result;
|
|
case U_BOOL_NOT:
|
|
return result == FALSE ? TRUE : FALSE;
|
|
default:
|
|
throw new RuntimeException("Invalid unary operator");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public Integer booleanConst(BooleanConst ast, Map<VariableSymbol, Integer> arg) {
|
|
return ast.value ? TRUE : FALSE;
|
|
}
|
|
|
|
@Override
|
|
public Integer intConst(Ast.IntConst ast, Map<VariableSymbol, Integer> arg) {
|
|
return ast.value;
|
|
}
|
|
|
|
// check if a given Variable has a constant value
|
|
@Override
|
|
public Integer var(Ast.Var ast, Map<VariableSymbol, Integer> arg) {
|
|
if (arg.containsKey(ast.sym)) {
|
|
return arg.get(ast.sym);
|
|
} else {
|
|
failedToEvaluate = true;
|
|
return Integer.MIN_VALUE;
|
|
}
|
|
}
|
|
|
|
}
|