com.objectwave.utility
Class StringCalculator

java.lang.Object
  |
  +--com.objectwave.utility.StringCalculator

public class StringCalculator
extends java.lang.Object

A class which will evaluate stringified arithmetic / boolean expressions. Standard order of evaluation of operators is honored. Nested parentheses are supported, only round ones though: "(" and ")". Where each #, $, and "b" is any expression which evaluates to a numberic, string, or boolean value, respectively: Arithmetic operators supported are #+# #-# -# #*# #/# #^# (result type #) Boolean operators supported are b&&b b||b !b (result type b) Numeric comparisons supported are #==# #!=# #<=# #>=# #<# #># (result type b) Numeric comparisons supported are $==$ $!=$ $<=$ $>=$ $<$ $>$ $in$ (result type b) The "condition assignment" operator b?#:# (result type #) There is a reserved keyword "null" for null comparisons. The only support for this explicit null object is the "==" operator. All of == null null == null == null are valid expressions, all of which return true IFF is the "null" object. This allows expressions to handle objects that may be null: they'd be represented in the expression by "null" rather than by their value type. The null comparison would probably by useful in conjunction with the "?:" operator: "(%a%==null ? 0:0 : %a%)" ==> "(23.4==null ? 0.0 : 23.4)" (This example assumes that external methods provide symbol-substitution capabilities.) All numeric values are promoted to type "double" for execution. The following patterns are recognized as numbers, where {0-9}* means 0 or more digits, {0-9}+ means 1 or more digits, and [xxx] means "xxx" is optional: {0-9}*.{0-9}+ or {0-9}+[.{0-9}*] Since all numeric expressions are represented as doubles, people unfamiliar with floating-point arithmetic may be surprised at some of the results. For instance, the comparison "2^54 == 2^54-1" will return true, since for these extremely large numbers (on the order of 10^16) floating point representation cannot distingish between these numbers (their internal representations are identical). String are supported only for comparison operations with other strings. A string is defined as a literal, delimited by double-quote characters ("). Note that there is no support for escape sequences, so a string cannot contain a (") character, and "\t" will not be translated to a tab character. Ditto for \r, \n, \\, and any other escape sequence. The special operator for strings, "in", requires some explanation. "in" takes two string operands, the rhs being assumed to be a comma-delimited list of substrings. The method will return true iif the lhs string exists as one on the comma-delimited elements of the rhs string. This match must be exact for the method to succeed: whitespace is not taken care of for you. The tokens "true" and "false" are recognized as static boolean values. Note that the string "9 * -5" is not valid: two arithmetic operators cannot be adjacent. Use the string "9 * (-5)" instead. Note that the string "5<6<7" is not valid: the communative property of comparison operators is not honored: you must use "5<6 && 6<7" instead. Note that the symbol "_" is explicitly disallowed. It is substituted internally to represent the negation operator, to distingish between subtraction and negation operations. Finally, note that the boolean expression "5<6 && !2<3" is valid: a "!" operator can follow another boolean operator. Also, "!!true" is valid. Redundant, but valid. The order of evaluation of operators is (from highest to lowest priority): #^#, -#, #/#, #*#, #-#, #+#, #<=#, #>=#, #==#, #!=#, #<#, #>#, $<=$, $>=$, $==$, $!=$, $<$, $>$, $in$, !b, b&&b, b||b, b?#:#

Version:
$Id: StringCalculator.java,v 2.1 2002/07/31 15:55:23 dave_hoag Exp $
Author:
Steve Sinclair

Nested Class Summary
 class StringCalculator.CalcItem
          An abstraction of the symbols found within an expression string.
protected  class StringCalculator.ParseNumber
          Parse a string to a double.
static class StringCalculator.Test
           
 
Field Summary
protected  java.lang.Object result
           
protected static StringCalculator.CalcItem staticCalcItem
           
protected  boolean verbose
          Private Section:
 
Constructor Summary
StringCalculator()
           
 
Method Summary
 java.util.Vector convertToReversePolish(java.util.Vector symbols)
          A call to createSymbols must be made prior to calling this method.
 java.util.Vector createSymbols(java.lang.String expression)
           
 java.util.Vector createSymbols(java.lang.String expression, boolean defaultUnknown)
           
 void dumpSymbols(java.util.Vector v)
          Used for debugging.
 void dumpSymbols(java.util.Vector v, int begin, int end)
          Used for debugging.
 java.lang.Object evaluateExpression(java.lang.String expression)
          Parse the symbols from the string, convert their ordering for easier execution, and execute the expression.
 java.lang.Object executeExpression(java.util.Vector symbols)
          Assuming that the "symbols" vector is a reverse-polish ordered sequence of CalcItem objects, evaluate the expression using a simple stack.
 java.util.Vector getFalseResults(java.util.Vector symbols)
          Find all of the permutations that will make the symbols evalutate to false.
 java.lang.Object getResult()
           
protected static java.util.Vector getResults(StringCalculator calc, java.util.Vector symbols, java.util.Vector settings, boolean condition)
           
 java.util.Vector getTrueResults(java.util.Vector symbols)
          Find all of the permutations that will make the symbols evalutate to true.
static void main(java.lang.String[] args)
           
static void main2(java.lang.String[] args)
           
protected  int matchBracket(int idx, java.util.Vector symbols)
          Assuming that symbols[idx] is a "(" symbol, return the index of it's matching rhs symbol.
protected  int nextNonWhitespace(java.lang.String str, int idx)
          Returns str.length() if EOS is reached.
protected  int operatorPriority(java.lang.String op)
          Return the priority of the given operation "op".
protected  void performOperation(StringCalculator.CalcItem operation, java.util.Stack expressionStack)
           
protected  int prefixIsOperator(java.lang.String string, int idx)
          Return # of chars which are the operator, else 0.
protected  java.util.Vector processBrackets(int leftParen, int end, java.util.Vector symbols)
          We've found a "(" in place of an atomic value: that's ok, so long as it has a matching ")" with parsable contents in between.
 boolean resultIsNumeric()
           
 void shortDump(java.util.Vector v)
           
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

verbose

protected boolean verbose
Private Section:


result

protected java.lang.Object result

staticCalcItem

protected static StringCalculator.CalcItem staticCalcItem
Constructor Detail

StringCalculator

public StringCalculator()
Method Detail

evaluateExpression

public java.lang.Object evaluateExpression(java.lang.String expression)
                                    throws java.lang.ArithmeticException,
                                           java.text.ParseException,
                                           java.util.EmptyStackException
Parse the symbols from the string, convert their ordering for easier execution, and execute the expression. Note that there's three types of exception thrown by this method.

java.lang.ArithmeticException
java.text.ParseException
java.util.EmptyStackException

convertToReversePolish

public java.util.Vector convertToReversePolish(java.util.Vector symbols)
                                        throws java.text.ParseException
A call to createSymbols must be made prior to calling this method.

java.text.ParseException
See Also:
createSymbols(java.lang.String)

createSymbols

public java.util.Vector createSymbols(java.lang.String expression)
                               throws java.text.ParseException
java.text.ParseException

createSymbols

public java.util.Vector createSymbols(java.lang.String expression,
                                      boolean defaultUnknown)
                               throws java.text.ParseException
Parameters:
defaultUnknown - - If a symbol is unknown, or unresolvable, just assume it is a string.
java.text.ParseException

dumpSymbols

public void dumpSymbols(java.util.Vector v)
Used for debugging.


dumpSymbols

public void dumpSymbols(java.util.Vector v,
                        int begin,
                        int end)
Used for debugging.


executeExpression

public java.lang.Object executeExpression(java.util.Vector symbols)
                                   throws java.lang.ArithmeticException,
                                          java.text.ParseException,
                                          java.util.EmptyStackException
Assuming that the "symbols" vector is a reverse-polish ordered sequence of CalcItem objects, evaluate the expression using a simple stack.

java.lang.ArithmeticException
java.text.ParseException
java.util.EmptyStackException

getResult

public java.lang.Object getResult()

main

public static void main(java.lang.String[] args)

getTrueResults

public java.util.Vector getTrueResults(java.util.Vector symbols)
Find all of the permutations that will make the symbols evalutate to true.

Parameters:
symbols - Vector of CalcItems, should have been converted to reverse polish notation prior to calling this method.

getFalseResults

public java.util.Vector getFalseResults(java.util.Vector symbols)
Find all of the permutations that will make the symbols evalutate to false.

Parameters:
symbols - Vector of CalcItems, should have been converted to reverse polish notation prior to calling this method.

getResults

protected static java.util.Vector getResults(StringCalculator calc,
                                             java.util.Vector symbols,
                                             java.util.Vector settings,
                                             boolean condition)
Parameters:
symbols - Vector of CalcItems, should have been converted to reverse polish notation prior to calling this method.
calc - - The calculator that was/will be used to evaluate the expression.
settings - Vector - A vector used internally to keep track of the value list.
condition - boolean - Get the patterns that make the condition evaluate to this value.
Returns:
Vector Each element in the vector is the string of conditions that would make the expression evaluate to true.

main2

public static void main2(java.lang.String[] args)

matchBracket

protected int matchBracket(int idx,
                           java.util.Vector symbols)
Assuming that symbols[idx] is a "(" symbol, return the index of it's matching rhs symbol.


nextNonWhitespace

protected int nextNonWhitespace(java.lang.String str,
                                int idx)
Returns str.length() if EOS is reached.


operatorPriority

protected int operatorPriority(java.lang.String op)
Return the priority of the given operation "op". "op" is assumed to be a valid operation.


performOperation

protected void performOperation(StringCalculator.CalcItem operation,
                                java.util.Stack expressionStack)
                         throws java.lang.ArithmeticException,
                                java.text.ParseException
java.lang.ArithmeticException
java.text.ParseException

prefixIsOperator

protected int prefixIsOperator(java.lang.String string,
                               int idx)
Return # of chars which are the operator, else 0.


processBrackets

protected java.util.Vector processBrackets(int leftParen,
                                           int end,
                                           java.util.Vector symbols)
                                    throws java.text.ParseException
We've found a "(" in place of an atomic value: that's ok, so long as it has a matching ")" with parsable contents in between.

java.text.ParseException

resultIsNumeric

public boolean resultIsNumeric()

shortDump

public void shortDump(java.util.Vector v)