Using a Stack to Evaluate Postfix Expressions (postfix)
CS 162 - Spring 2008

Due: Monday, April 18

Goals
- to use the built-in stack class (import java.util.Stack)
- to catch and handle exceptions (import java.util.EmptyStackException and java.util.NoSuchElementException)
- to use (not build) an applet to exercise your code in addition to using JUnit
- to focus on the parts of a project you need to change and just use the rest
- to build the class file from scratch but meeting the required specifications

Overview
For this assignment, you'll build a postfix expression evaluator class (PostfixEvaluator). This will use a stack to hold the numbers. You can interact with your code through an applet that calls it. There are also JUnit tests which your program needs to pass.

You do not write the stack, the token scanner, the applet, or the JUnit tests. You write the expression evaluator class (PostfixEvaluator) from scratch. There are several supporting files within the course files director (~liffick162/assignfiles/postfix) to make your job easier. Just use them.

Specifications
Copy the files from the course files directory and create a new project using the existing project that came with those files. Next, create a PostfixEvaluator class that has a public static evaluate method. That method takes in a String as input and returns the String result of evaluating the input as a postfix expression (which may be an error message). Use the algorithm we've discussed in class and in the book.

For example, an expression of  15 4 * 24 - 0.5 * 100 3 7 + / * should result in  180.0

You must use a Stack of Double in your evaluation.

Input numbers can be real numbers (normal notation) but may not be negative. The result may be negative.

Allowed operations are addition(+), subtraction(-), multiplication(*), and division(/). Any other operator should cause an error message to be printed.

The evaluate method returns a string. That string is the value of the postfix expression if it is well formed and leaves the stack empty...if the expression is not well formed, it returns an error message. For instance, if there are extra values on the stack, the method returns an error message which may include the result but must note that it is not valid.

If an exception occurs, your code should catch it and return a string describing the problem. Your program should not throw any exceptions. Your messages should be very similar to the following.

Unusual or exceptional condition Message
input string is empty or all spaces or tabs No input.
EmptyStackException Stack Underflow. Not enough operands on stack.
values remain on stack after end of input Computed answer, but values remain on stack.
evaluation ended before end of input Computed answer, but not all input used.
parentheses in input ( and ) have no meaning here

Implementation Details

The PostfixEvaluator class does not have a constructor and does not create any instances. It does not have instance variables. It has a public static evaluate method that takes in a String and returns a String as noted above.

My solution also has a private static method (not visible outside the class) that takes a stack and the Character operator and performs the operation (similar to the evaluateStackTops method in Figure 6.5 in your book...don't throw any exceptions, however). Any exceptions raised in that method are handled in the evaluate method. A switch statement comes in handy here...remember the breaks.

You are provided TokenScanner and Token classes that you must use. Do not modify them. The TokenScanner class breaks a string into parts called Tokens. You can ask Tokens whether they are numbers or operators and handle them appropriately. These classes have Javadoc comments and pages...you may also read the code (you don't actually need to look at the code if you understand the Javadoc descriptions).

Construct a TokenScanner by passing in a String to the TokenScanner constructor. The String argument passed in to the evaluate method is what you need to tokenize. Write a loop using hasNextToken() and nextToken() much as you would for a Scanner.

The Token class is documented and has methods isOperator( ), isNumber( ), numberValue( ), and operatorCharValue( ). Note that Token recognizes left and right parentheses although they are not part of valid postfix expressions...your code will consider them a special kind of error (they are valid for infix expressions, but this program isn't dealing with infix expressions). There is also information about operator precedence in Token, but you can ignore that for this assignment as well.

Your evaluate method should catch a variety of exceptions. For some of those (e.g. NoSuchElementException), the action can be to just return e.getMessage( ); (look this method up by doing an Internet search on "Java getMessage"). Your code should not let any reasonable exceptions escape; the JUnit tests attempt to raise the exceptions we expect your program to handle. If you pass those JUnit tests, your program's exception handling is okay.

Ideas for Getting Started

  1. Understand the problem and the many resources you have.
  2. Copy the files (~liffick162/assignfiles/postfix) and create a project based on those files.
  3. Create a PostfixEvaluator class with an evaluate method. Have it initially just return its input String as its result.
  4. Run the PostfixApplet. Don't go on until you get this much to "work."
  5. Write the loop that uses TokenScanner to break the input into Tokens. Look at the Tokens either by printing them to System.out or building a String and returning that.
  6. Don't try to handle the error conditions until you get the evaluator to produce the correct results for valid input.
  7. Once you get proper evaluations for valid input, you can begin enhancing your code to handle each exception or error condition, one at a time. Be sure to run the JUnit tests to try to uncover bugs.