/*
* Expression.java - Parse and evaluate expressions for BASIC.
*
* Copyright (c) 1996 Chuck McManis, All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software
* and its documentation for NON-COMMERCIAL purposes and without
* fee is hereby granted provided that this copyright notice
* appears in all copies.
*
* CHUCK MCMANIS MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE
* SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. CHUCK MCMANIS
* SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT
* OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
*/
import java.io.PrintStream;
import java.util.Hashtable;
/**
* This is the base class for the simple expressions.
*
* Expressions are parsed by the class ParseExpression which creates
* a parse tree using objects of type expression. The subclasses
* ConstantExpression and VariableExpression
* hold specific types of indivisable elements.
*
* See the class ParseExpression for the grammar and precidence rules.
*/
class Expression {
Expression arg1, arg2;
int oper;
/**
* These are the valid operator types.
*/
final static int OP_ADD = 1; // Addition '+'
final static int OP_SUB = 2; // Subtraction '-'
final static int OP_MUL = 3; // Multiplication '*'
final static int OP_DIV = 4; // Division '/'
final static int OP_EXP = 5; // Exponentiation '**'
final static int OP_AND = 6; // Bitwise AND '&'
final static int OP_IOR = 7; // Bitwise inclusive OR '|'
final static int OP_XOR = 8; // Bitwise exclusive OR '^'
final static int OP_NOT = 9; // Unary negation '!'
final static int OP_NEG = 10; // Unary minus
final static String opVals[] = {
"", "+", "-", "*", "/", "^", "&", "|", "#", "!", "-",
};
protected Expression() {
}
/**
* Create a new expression.
*/
protected Expression(int op, Expression a, Expression b) {
arg1 = a;
arg2 = b;
oper = op;
}
/**
* Create a unary expression.
*/
protected Expression(int op, Expression a) {
arg2 = a;
oper = op;
}
public String toString() {
StringBuffer sb = new StringBuffer("(");
if (arg1 != null)
sb.append(arg1.toString());
sb.append(opVals[oper]+arg2.toString()+")");
return sb.toString();
}
String unparse() {
if (arg1 == null) {
return opVals[oper]+arg2.unparse();
}
return "("+arg1.unparse()+" "+opVals[oper]+" "+arg2.unparse()+")";
}
/**
* This method evaluates the expression in the context of the
* passed in program. It throws runtime errors for things like
* no such variable and divide by zero.
*
* Note that for boolean operations the value 1.0 == true and
* the value 0.0 is equivalent to false.
*/
double value(Hashtable vars) throws ExecError {
switch (oper) {
case OP_ADD :
return arg1.value(vars) + arg2.value(vars);
case OP_SUB :
return arg1.value(vars) - arg2.value(vars);
case OP_MUL :
return arg1.value(vars) * arg2.value(vars);
case OP_DIV :
if (arg2.value(vars) == 0) {
throw new ExecError("divide by zero!");
}
return arg1.value(vars) / arg2.value(vars);
case OP_XOR :
return (double)(((long) arg1.value(vars)) ^ ((long) arg2.value(vars)));
case OP_IOR :
return (double)(((long) arg1.value(vars)) | ((long) arg2.value(vars)));
case OP_AND :
return (double)(((long) arg1.value(vars)) & ((long) arg2.value(vars)));
case OP_EXP :
return (Math.pow(arg1.value(vars), arg2.value(vars)));
case OP_NOT :
return (double)(~((long)(arg2.value(vars))));
case OP_NEG :
return 0 - arg2.value(vars);
default:
throw new ExecError("Illegal operator in expression!");
}
}
}