package freegraph; /*** * ExpressionStack, by Martin Lovell 1999 * Freeware */ import java.util.*; /** * ExpressionStack converts a free-form Infix expression into Postfix, or * Reverse Polish Notation (RPN). The expression is parsed into tokens, and * converted to RPN using a standard stack technique. After converted to RPN, * the expression is on a stack which can be easily evaluated using * ExpressionEvaluator. *

* The stack technique involves using 3 stacks, an infix stack, a hold stack, * and an RPN stack. Following a algorithm, items on the infix stack are * tested, and based on what is on the top of the HOLD stack, one of 5 "ACTION" * constants are followed. The ExpressionItem.getAction() method is called * on the ExpressionItem on the top of the infix stack to determine which * action to take. *

* When the InfixExpression property is set, the expression is parsed, and the * RPN stack is immediately available. *

* The algorithm used is from: Tanenbaum, Andrew S. 1990. * Structured Computer Organization, 3rd ed., * New Jersey: Prentice Hall. (pp. 268-272) * @see ExpressionEvaluator */ public class ExpressionStack extends Stack { /** * Action indicating that the top of the infix stack should be put on the * top of the RPN stack */ final public static int ACTION_INFIX_TO_RPN_STACK = 0; /** * Action indicating that the top of the infix stack should be put on the * top of the hold stack */ final public static int ACTION_INFIX_TO_HOLD_STACK = 1; /** * Action indicating that the top of the hold stack should be put on the * top of the RPN stack */ final public static int ACTION_HOLD_TO_RPN_STACK = 2; /** * Action indicating that the top of the hold stack should be deleted */ final public static int ACTION_DELETE_HOLD = 3; /** * Action indicating that conversion is complete */ final public static int ACTION_COMPLETE = 4; /** * Action indicating that an error has occured because an unexpected * token was encountered */ final public static int ACTION_ERROR = 5; /*** * the string holding the current infixExpression which is being * represented by the stack. */ private String infixExpression = ""; /** * Constructs a new ExpressionStack for the infixExpression. * @param infixExpression a free-form infix expression */ public ExpressionStack(String infixExpression) throws ExpressionException { setInfixExpression(infixExpression); } /** * Constructs a new ExpressionStack which initially has no * infixExpression */ public ExpressionStack() { } /** * internal method because StringBuffer.delete is not available in * Java 1.1 */ private static void strBuffSub(StringBuffer b, int startIndex) { String s = b.toString().substring(startIndex); b.setLength(s.length()); for (int i = 0; i < s.length(); i++) { b.setCharAt(i, s.charAt(i)); } } /** * Internally used method to convert the infixExpression to an RPN stack. * This method uses the ExpressionParse private class to perform the actual * parsing. */ private void convertToPostfix() throws ExpressionException { if (infixExpression == null || infixExpression.length() < 1) { return; } ExpressionParser exprParse = new ExpressionParser(infixExpression); Stack reversePostfix = new Stack(); Stack holdStack = new Stack(); Stack infixStack = exprParse.getExpressionItemStack(); ExpressionItem exprItem = (ExpressionItem) infixStack.pop(); int action = 5; ExpressionItem topOfHold; whileLoop:while (exprItem != null) { if (holdStack.size() > 0) { topOfHold = (ExpressionItem) holdStack.peek(); } else { topOfHold = null; } action = exprItem.getAction(topOfHold); switch (action) { case ACTION_INFIX_TO_RPN_STACK: reversePostfix.push(exprItem); break; case ACTION_INFIX_TO_HOLD_STACK: holdStack.push(exprItem); break; case ACTION_HOLD_TO_RPN_STACK: reversePostfix.push(holdStack.pop()); continue; //don't read another item case ACTION_DELETE_HOLD: holdStack.pop(); break; case ACTION_COMPLETE: break whileLoop; case ACTION_ERROR: throw new ExpressionException( "Error Converting to Postfix"); } try { exprItem = (ExpressionItem) infixStack.pop(); } catch (Exception e) { exprItem = null; } } if (holdStack.size() > 0) { topOfHold = (ExpressionItem) holdStack.peek(); } else { topOfHold = null; } while (topOfHold != null && (topOfHold instanceof ExpressionItem.BiOperator || topOfHold instanceof ExpressionItem.UnOperator)) { reversePostfix.push(holdStack.pop()); if (holdStack.size() > 0) { topOfHold = (ExpressionItem) holdStack.peek(); } else { topOfHold = null; } } if (holdStack.size() > 0) { throw new ExpressionException("Error Converting to Postfix"); } //this.clear(); clear not available in 1.1 while (this.size() > 0) { this.removeElementAt(0); } while (reversePostfix.size() > 0) { this.push(reversePostfix.pop()); } } /** * sets the infix expression for the stack. The expression is converted * to postfix and is available through the stack. */ public void setInfixExpression(String infixExpression) throws ExpressionException { this.infixExpression = infixExpression; convertToPostfix(); } public String getInfixExpression() { return infixExpression; } /*** * ExpressionParser used by ExpressionStack to parse the infix string into * expression items */ private static class ExpressionParser { String expression; StringBuffer expr; /** * Creates a new ExpressionParser to parse the expression * @param expression the expression this instance will parse */ public ExpressionParser(String expression) { this.expression = expression; } /** * reads the next ExpressionItem from the ExpressionStack. This * method is used internally */ private ExpressionItem readExpressionItem(StringBuffer str) { if (str.length() <= 0) { return null; } /* --- START: New code --- Thanks to Aaron Patzer ELE, Princeton University */ //check for whitespace while (Character.isWhitespace(str.charAt(0))) { strBuffSub(str, 1); } /* --- END: New code --- */ char c = Character.toUpperCase(str.charAt(0)); //check for number if ( (c >= '0' && c <= '9') || c == '.') { StringBuffer resultStr = new StringBuffer(); do { resultStr.append(str.charAt(0)); strBuffSub(str, 1); if (str.length() > 0) { c = str.charAt(0); } } while (str.length() > 0 && ( (c >= '0' && c <= '9') || c == '.')); return new ExpressionItem.Number( Double.valueOf(resultStr.toString()).doubleValue()); } //check for Parenthesis if (c == '(' || c == ')') { strBuffSub(str, 1); return new ExpressionItem.Parenthesis( c == '(' ? ExpressionItem.Parenthesis.LEFT : ExpressionItem.Parenthesis.RIGHT); } int newKind = -1; //check for bi operator String strString = str.toString().toUpperCase(); for (int i = 0; i < ExpressionItem.BiOperator.OPERATORS.length; i++) { if (strString.startsWith(ExpressionItem.BiOperator.OPERATORS[i])) { newKind = i; strBuffSub(str, ExpressionItem.BiOperator.OPERATORS[i].length()); break; } } if (newKind != -1) { return new ExpressionItem.BiOperator(newKind); } //check for unary operator for (int i = 0; i < ExpressionItem.UnOperator.OPERATORS.length; i++) { if (strString.startsWith(ExpressionItem.UnOperator.OPERATORS[i])) { newKind = i; strBuffSub(str, ExpressionItem.UnOperator.OPERATORS[i].length()); break; } } if (newKind != -1) { return new ExpressionItem.UnOperator(newKind); } //check for a Variable if (c >= 'A' && c <= 'Z') { strBuffSub(str, 1); return new ExpressionItem.Variable(c); } return null; } /*** * internally used method to fix an infix stack by converting subtraction * operators to negative operators where appropiate, removing all positive * operators and inserts implicit multiplication. *

It does the following to fix the expression:
* * 1) If the first position is +, it is removed, if it * is -, it is converted from subtraction to negative operator.
* 2) If + or - are after ( or after an operator, then * remove the + and convert - to negative operator.
* 3) Add implicit multiplication with ) followed by * an operator, variable, number or (.
* 4) Add implicit multiplication with ( preceded by * an operator, variable, number or ).
* * (ExpressionParser does some down casting on the ExpressionItems when * fixing expressions. Perhaps there is a design which would avoid * this; however, it works fine in this case.) * */ private void fixInfixStack(Stack infixStack) { if (infixStack.size() < 2) { return; } int i = 0; ExpressionItem e1, e2; //fix negative or positive in first position // If the first position is +, it is removed, if it // is -, it is converted from subtraction to negative operator. // e1 = (ExpressionItem) infixStack.elementAt(0); if (e1 instanceof ExpressionItem.BiOperator) { if ( ( (ExpressionItem.BiOperator) e1).getKind() == ExpressionItem.BiOperator.SUBTR) { infixStack.setElementAt( new ExpressionItem.UnOperator(ExpressionItem.UnOperator. NEG), 0); } else if ( ( (ExpressionItem.BiOperator) e1).getKind() == ExpressionItem.BiOperator.ADD) { infixStack.removeElementAt(0); } } // fix other negative and positives and implicit multiplication while (i < infixStack.size() - 1) { e1 = (ExpressionItem) infixStack.elementAt(i); e2 = (ExpressionItem) infixStack.elementAt(i + 1); // if + or - are after ( or after a operator, then // remove the + and convert - to negative operator if (e1 instanceof ExpressionItem.UnOperator || e1 instanceof ExpressionItem.BiOperator || (e1 instanceof ExpressionItem.Parenthesis && ( (ExpressionItem.Parenthesis) e1).getKind() == ExpressionItem.Parenthesis.LEFT)) { if (e2 instanceof ExpressionItem.BiOperator && ( (ExpressionItem.BiOperator) e2).getKind() == ExpressionItem.BiOperator.SUBTR) { infixStack.setElementAt( new ExpressionItem.UnOperator( ExpressionItem.UnOperator.NEG), i + 1); } else if (e2 instanceof ExpressionItem.BiOperator && ( (ExpressionItem.BiOperator) e2).getKind() == ExpressionItem.BiOperator.ADD) { infixStack.removeElementAt(i + 1); } } //Add implicit multiplication with ) followed by //an operator, variable, number or ( if (e1 instanceof ExpressionItem.Parenthesis && ( (ExpressionItem.Parenthesis) e1).getKind() == ExpressionItem.Parenthesis.RIGHT && (e2 instanceof ExpressionItem.UnOperator || e2 instanceof ExpressionItem.Variable || e2 instanceof ExpressionItem.Number || (e2 instanceof ExpressionItem.Parenthesis && ( (ExpressionItem.Parenthesis) e2).getKind() == ExpressionItem.Parenthesis.LEFT) )) { infixStack.insertElementAt( new ExpressionItem.BiOperator(ExpressionItem.BiOperator. MULT), i + 1); } //Add implicit multiplication with ( preceded by //an operator, variable, number or ) if ( (e1 instanceof ExpressionItem.Variable || e1 instanceof ExpressionItem.Number) && (e2 instanceof ExpressionItem.Variable || e2 instanceof ExpressionItem.Number || e2 instanceof ExpressionItem.UnOperator || (e2 instanceof ExpressionItem.Parenthesis && ( (ExpressionItem.Parenthesis) e2).getKind() == ExpressionItem.Parenthesis.LEFT))) { infixStack.insertElementAt( new ExpressionItem.BiOperator(ExpressionItem.BiOperator. MULT), i + 1); } i++; } } /** * Parses and fixes the expression and returns the stack of expression * items. */ public Stack getExpressionItemStack() { expr = new StringBuffer(expression); ExpressionItem exprItem = readExpressionItem(expr); Stack infixStack = new Stack(); while (exprItem != null) { infixStack.push(exprItem); exprItem = readExpressionItem(expr); } fixInfixStack(infixStack); Stack resultStack = new Stack(); while (infixStack.size() > 0) { resultStack.push(infixStack.pop()); } return resultStack; } } }