package typechecking;
import parser.ASTadditiveArithmeticTerm;
import parser.ASTarithmeticTerm;
import parser.ASTatomicArithmeticTerm;
import parser.ASTmultiplicativeArithmeticTerm;
import parser.ParseException;
import parser.SimpleNode;
import parser.SparcTranslatorTreeConstants;
/**
* Evaluate given term (if it is valuable, i.e, it has no variables)
*
*/
public class TermEvaluator {
ASTarithmeticTerm aterm;
/**
* Constructor
*
* @param aterm
* term to be stored in class field
*/
public TermEvaluator(ASTarithmeticTerm aterm) {
this.aterm = aterm;
}
/**
* @return true if term stored in aterm field is valuable
*/
public boolean isEvaluable() {
return isEvaluable(aterm);
}
/**
* Find value of the term stored in aterm field.
*
* @return value of term
* @throws ParseException
* if aterm contains variables or division by zero occurs
*/
public long evaluate() throws ParseException {
return evaluate((ASTadditiveArithmeticTerm) aterm.jjtGetChild(0));
}
/**
* Find value of the term
*
* @param aterm
* additive arithmetic term
* @return value of term
* @throws ParseException
* if term contains variables or division by zero occurs
*/
private long evaluate(ASTadditiveArithmeticTerm aterm)
throws ParseException {
long result = 0;
for (int i = 0; i < aterm.jjtGetNumChildren(); i++) {
if (aterm.image.charAt(i) == '+') {
result += evaluate((ASTmultiplicativeArithmeticTerm) aterm
.jjtGetChild(i));
} else {
result -= evaluate((ASTmultiplicativeArithmeticTerm) aterm
.jjtGetChild(i));
}
}
return result;
}
/**
* Find value of the term
*
* @param mterm
* multiplicative arithmetic term
* @return value of term
* @throws ParseException
* if term contains variables or division by zero occurs
*/
private long evaluate(ASTmultiplicativeArithmeticTerm mterm)
throws ParseException {
long value = evaluate((ASTatomicArithmeticTerm) mterm.jjtGetChild(0));
for (int i = 1; i < mterm.jjtGetNumChildren(); i++) {
ASTatomicArithmeticTerm child = (ASTatomicArithmeticTerm) mterm
.jjtGetChild(i);
switch (mterm.image.charAt(i - 1)) {
case '*':
value *= evaluate((ASTatomicArithmeticTerm) mterm
.jjtGetChild(i));
break;
case '/':
long div = evaluate(child);
if (div == 0)
throw new ParseException("Division By Zero at line "
+ child.getBeginLine() + " column "
+ child.getBeginColumn());
value /= div;
break;
case '%':
long remdiv = evaluate(child);
if (remdiv == 0)
throw new ParseException("Division By Zero at line "
+ child.getBeginLine() + " column "
+ child.getBeginColumn());
value %= remdiv;
break;
}
}
return value;
}
/**
* Find value of the term
*
* @param atterm
* atomic arithmetic term
* @return value of term
* @throws ParseException
* if term contains variables or division by zero occurs
*/
private long evaluate(ASTatomicArithmeticTerm atterm) throws ParseException {
if (!atterm.image.matches("([1-9][0-9]*)|0")
&& !atterm.image.startsWith("(")) {
throw new ParseException("term at line " + atterm.getBeginLine()
+ " column " + atterm.getBeginColumn()
+ " contains variables and not evaluable");
} else if (atterm.image.startsWith("(")) {
TermEvaluator te = new TermEvaluator(
(ASTarithmeticTerm) atterm.jjtGetChild(0));
return te.evaluate();
} else
return Integer.parseInt(atterm.image);
}
/**
* Check if given term is valuable
*
* @param n
* term represented in AST node
* @return true if term is valuable (has no variables)
*/
private boolean isEvaluable(SimpleNode n) {
if (n.getId() == SparcTranslatorTreeConstants.JJTATOMICARITHMETICTERM) {
if (n.jjtGetNumChildren() > 0
&& ((SimpleNode) n.jjtGetChild(0)).getId() == SparcTranslatorTreeConstants.JJTVAR) {
return false;
}
}
boolean result = true;
for (int i = 0; i < n.jjtGetNumChildren(); i++) {
if (!isEvaluable((SimpleNode) n.jjtGetChild(i))) {
result = false;
}
}
return result;
}
}