/* * Primitive Collections for Java. * Copyright (C) 2003 Søren Bak * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ import bak.pcj.list.DoubleStack; import bak.pcj.list.DoubleArrayStack; /** * This class implements an evaluator for postfix notation * expressions. The class demonstrates the use of primitive * stacks. * * @author Søren Bak * @version 1.1 2003/17/2 */ public class Calculator { // --------------------------------------------------------------- // Tokenization // --------------------------------------------------------------- // Lexemes for tokens private static final int NUM = 0; private static final int MUL = 1; private static final int DIV = 2; private static final int ADD = 3; private static final int SUB = 4; private static final int END = 5; // Thrown to indicate a malformed expression private static class ParserException extends Exception { ParserException(String s) { super(s); } } // Tokenizer for expressions private static class Tokenizer { private char nextChar; private int nextToken; private double nextValue; private int ptr; private String input; StringBuffer num = new StringBuffer(); Tokenizer(String input) throws ParserException { setInput(input); } void setInput(String input) throws ParserException { this.input = input; ptr = 0; nextChar(); advance(); } // Advance to next character in input private void nextChar() { nextChar = ptr == input.length() ? '\0' : input.charAt(ptr++); } // Skip whitespace from input private void skipws() { while (nextChar == ' ' || nextChar == '\t') nextChar(); } // Advance to next token in input void advance() throws ParserException { skipws(); if (nextChar == '*') { nextChar(); nextToken = MUL; } else if (nextChar == '/') { nextChar(); nextToken = DIV; } else if (nextChar == '+') { nextChar(); nextToken = ADD; } else if (nextChar == '-') { nextChar(); nextToken = SUB; } else if (nextChar >= '0' && nextChar <= '9') { num.setLength(0); num.append(nextChar); nextChar(); while ((nextChar >= '0' && nextChar <= '9') || nextChar == '.') { num.append(nextChar); nextChar(); } try { nextValue = Double.parseDouble(num.toString()); nextToken = NUM; } catch (NumberFormatException e) { throw new ParserException("Illegal number: " + num.toString()); } } else if (nextChar == '\0') { nextToken = END; } else { throw new ParserException("Illegal character: " + nextChar); } } // Returns next token in input int next() { return nextToken; } // Returns double value of next NUM token in input double value() { return nextValue; } } // --------------------------------------------------------------- // Evaluation // --------------------------------------------------------------- /** * Evaluates a postfix expression. * * @param input * a character sequence representation of the * expression to evaluate. * * @return the value of the expression. * * @throws NullPointerException * if input is null. * * @throws ParserException * if the expression is malformed. */ public double evaluate(String input) throws ParserException { return evaluate(new Tokenizer(input)); } private double evaluate(Tokenizer lex) throws ParserException { try { DoubleStack stack = new DoubleArrayStack(); int token; while ((token = lex.next()) != END) { if (token == NUM) stack.push(lex.value()); else if (token == MUL) { double v2 = stack.pop(); double v1 = stack.pop(); stack.push(v1*v2); } else if (token == DIV) { double v2 = stack.pop(); double v1 = stack.pop(); stack.push(v1/v2); } else if (token == ADD) { double v2 = stack.pop(); double v1 = stack.pop(); stack.push(v1+v2); } else if (token == SUB) { double v2 = stack.pop(); double v1 = stack.pop(); stack.push(v1-v2); } lex.advance(); } double result = stack.pop(); if (!stack.isEmpty()) throw new ParserException("Stack is not empty"); return result; } catch (IndexOutOfBoundsException e) { // Thrown when stack is empty throw new ParserException("Stack was empty"); } } public static void main(String[] args) { try { Calculator calc = new Calculator(); System.out.println(calc.evaluate(args[0])); } catch (ParserException pe) { System.out.println("Syntax error: " + pe.getMessage()); } catch (ArithmeticException ae) { System.out.println("Arithmetic error: " + ae.getMessage()); } } }