/* Each of these classes should be in their own file. See the zip for all classes and files. */ /* PostfixCalc.java */ import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; import java.util.Stack; import java.util.EmptyStackException; import java.util.StringTokenizer; /** * A post-fix calculator. * * @author Zach Tomaszewski * @version 1.0 * @date 20 Oct 2001 */ public class PostfixCalc { static int[] variables = new int[26]; public static void main(String[] args) { try{ printInstructions(); System.out.println("Press q to quit."); String input = getInput(); while (!input.equalsIgnoreCase("q") && !input.equals("")){ System.out.println(calculate(input)); input = getInput(); } }catch (InvalidOperandsException ioe){ System.out.println("You have entered something that does not parse."); System.out.println("The most common cause of this error is that you "+ "forgot to put spaces b/w all operators and operands."); System.out.println("Other possiblities are that you have entered assignment "+ "(=) operands in the wrong order, or entered something that "+ "is not a number."); main(new String[0]); }catch (TooFewOperandsException tfoe){ System.out.println("There was an error during computation: there were "+ "too many operators for the number of operands."); main(new String[0]); }catch (TooManyOperandsException tmoe){ System.out.println("There was an error during computation: there were " + "too few operators for the number of operands."); main(new String[0]); }catch (DivideByZeroException dbze){ System.out.println("You have tried to divide by zero!"); main(new String[0]); } } /** *Print a brief message concerning the nature of this *calculator and prompts the user for an input string. */ protected static void printInstructions(){ System.out.println("\nThis postfix calculator accepts the +,-,*,/, %, and = operators."); System.out.println("You must include spaces between all operands and operators."); System.out.println("Example: \"23 5 + 7 /\" returns \"4\"."); System.out.println("Assignment (=) is not communicative: \"x 3 =\" is valid"+ " while \"3 x =\" is not."); System.out.println("The letters a through z can be used for variable assignment."); } /** * Gets a line of keyboard input from the user */ protected static String getInput(){ try{ BufferedReader stdin = new BufferedReader( new InputStreamReader(System.in)); System.out.print("Enter an operation: "); String input = stdin.readLine(); return input; }catch (IOException ioe) { System.out.println("There was an IOException. Please try again."); return getInput(); } } /** * Performs post-fix calculation on the given string. * Accepted operators are +,-,*,/, %, and =. All operators * and operands must be separated by spaces. Can assign * values to variables a-z. * * @param operation String of operations to be computed * @return the integer result of the calculation * @throws InvalidOperandsException * when input is not a valid integer or operator; * @throws TooFewOperandsException * when there are missing operands of the given operations * @throws TooManyOperandsException * when there are operands left over after all given operations * are evaluated. * @throws DivideByZeroException when an operation would result in division * by zero. */ public static int calculate(String operation) throws InvalidOperandsException, TooFewOperandsException, TooManyOperandsException, DivideByZeroException{ Stack operandStack = new Stack(); StringTokenizer tokens = new StringTokenizer(operation); String token; int operand; char currentChar; while (tokens.hasMoreTokens()) { token = tokens.nextToken(); if (token.length() > 1) { //should be a double digit number; try{ operand = Integer.parseInt(token); operandStack.push(new Integer(operand)); }catch (NumberFormatException nfe){ throw new InvalidOperandsException(); } }else { // a single character currentChar = token.charAt(0); if (Character.isDigit(currentChar)){ operandStack.push(new Integer(Character.digit(currentChar, 10))); }else if (Character.isLowerCase(currentChar)) { //a variable! operandStack.push(new Character(currentChar)); }else { //needs to be an operator try{ Object opObject2 = operandStack.pop(); Object opObject1 = operandStack.pop(); if (currentChar == '=') { //assignment, special case if (!isCharacter(opObject1)){ //not assigning to a variable throw new InvalidOperandsException(); }else { int op2 = getIntValue(opObject2); //set variable value char tempChar = ((Character)opObject1).charValue(); variables[Character.digit(tempChar, 36) - 10] = op2; operandStack.push(opObject1); //put the variable back on the stack } }else{//some other operator int op2 = getIntValue(opObject2); int op1 = getIntValue(opObject1); switch (currentChar){ case '+': operandStack.push(new Integer(op1 + op2)); break; case '-': operandStack.push(new Integer(op1 - op2)); break; case '*': operandStack.push(new Integer(op1 * op2)); break; case '/': if (op2 == 0) {throw new DivideByZeroException();} operandStack.push(new Integer(op1 / op2)); break; case '%': operandStack.push(new Integer(op1 % op2)); break; default: throw new InvalidOperandsException(); } }//end else }catch (EmptyStackException ese){ throw new TooFewOperandsException(); } }//end else }//end else }//end while int result; if (!operandStack.isEmpty()) { result = getIntValue(operandStack.pop()); }else { //recieved no input to begin with result = 0; } if (!operandStack.isEmpty()) { throw new TooManyOperandsException(); }else { return result; } }//end method private static boolean isCharacter(Object ofUnknownClass){ return ofUnknownClass.getClass().equals(new Character('a').getClass()); } /** * @param obj must be either Character or Integer * @return the int value of the Integer, * or the value of the Character variable from the variables[] */ private static int getIntValue(Object obj){ if (isCharacter(obj)){ //if it's a variable, get char... char tempChar = ((Character)obj).charValue(); //...and convert to value in array variables. return (variables[Character.digit(tempChar, 36) - 10]); }else { //it's just an integer return((Integer)obj).intValue(); } } }//end class /* InvalidOperandsExceptions.java */ /** * An exception class for use with certain types of calculators * * @author Zach Tomaszewski * @date 20 Oct 2001 * @see PostfixCalc */ class InvalidOperandsException extends NumberFormatException{ protected InvalidOperandsException(){ super(); } }//end class /** * An exception class for use with certain types of calculators * * @author Zach Tomaszewski * @date 20 Oct 2001 * @see PostfixCalc */ class TooFewOperandsException extends Exception{ protected TooFewOperandsException(){ super(); } }//end class /** * An exception class for use with certain types of calculators * * @author Zach Tomaszewski * @date 20 Oct 2001 * @see PostfixCalc */ class TooManyOperandsException extends Exception{ protected TooManyOperandsException(){ super(); } }//end class /** * An exception class for use with certain types of calculators * * @author Zach Tomaszewski * @date 20 Oct 2001 * @see PostfixCalc */ class DivideByZeroException extends Exception{ protected DivideByZeroException(){ super(); } }//end class