CMPU 102 - Assignment 5 Due: by 11:59 PM on Friday, October 7th

In this assignment, you will implement an algorithm to parse arithmetic expressions in Reverse Polish Notation (RPN) format and return them as Expression objects.  (You may remember Expression from Lecture 4.)

$Revision: 1.1 $

Reverse Polish Notation (RPN)

RPN is a way of writing mathematical expressions.  The defining characteristic of RPN is that unlike ordinary infix notation, where binary operators are placed between their operands, in RPN all operators come after their operands.  Example:

Infix: 3 + 4
RPN: 3 4 +

One advantage RPN has over traditional infix notation is that correctly formed RPN expressions are unambiguous: there is no need to use parentheses to force the evaluation order of particular sub-expressions.  For example, consider the following (ambiguous) infix expression:

3 * 4 + 5

Depending on whether or not the multiplication is performed before the addition, we can get two different results:

(3 * 4) + 5  --> 17
3 * (4 + 5)  --> 27

In RPN, the order of evaluation is explicit:

3 4 * 5 +  --> 17
3 4 5 + *  --> 27

Stacks and RPN

As we discussed in class, stacks provide an easy way to evaluate RPN expressions.  The rules are very simple:

  1. Simple expressions, such as literal values, are pushed onto the stack directly

  2. To evaluate the result of an operator that takes one or more operands, first pop the operands off the stack, compute the result, and push the result onto the stack

Essentially, the stack saves the values of operands until they are needed by the operator they are part of.  When the entire expression has been parsed and evaluated, the stack should contain a single value representing the result.

Your Task

In this assignment, rather than directly evaluating RPN expressions, you will evaluate them symbolically.  What that means is that rather than computing a literal result each time you see an operator, you will build an Expression object that will be able to compute the result of the expression at a later time.

So, why compute the result of the expression symbolically?  One reason is that the expression might contain a variable whose exact value is not known.  By computing a symbolic version of the expression, it can be evaluated later when the variable has been assigned a value.  Even better, we can evaluate a symbolic expression many times for different values of the variable.

In your RPN expression parser, whenever you see the token "x", you will push a special Variable object on the stack (which will be provided as a parameter to the parsing method).  This object represents the variable x.  By changing the value of this variable, we can evaluate the entire expression for many values of x, which we then use to implement a GUI program that visually displays a graph of a function entered in RPN format:

Specifications

You will need to handle expression strings that contain the following kinds of sub-expressions:

Simple expressions: literal numeric values ("3", "4.5", "-0.8"), and the x variable ("x").

Unary expressions: the sine and cosine functions.  For example, "x sin" means the sine of x, and "x cos" means the cosine of x.  (The Math.sin and Math.cos methods may be used to compute these functions.)

Binary expressions: the "+", "-", "*", and "/" operators perform addition, subtraction, multiplication, and division, respectively.

If the RPN string you are given to parse is invalid, you should throw an exception.  Any kind of RuntimeException is fine, including IllegalArgumentException, IllegalStateException, EmptyStackException, etc.

Getting Started

Start by importing the file rpncalc.zip into Eclipse: from the menu, choose "File->Import->Existing Projects into Workspace", click "Select archive file", select "shapes.zip" from the file selection dialog, and then click the "Finish" button.

You will implement the RPNParser.parse method so that it parses the input string given and returns an Expression object representing the overall expression.  Two Expression classes are provided for you as an example: Addition and Subtraction.  You will need to add other Expression classes to implement the other operators described above.  (Adding a new class in Eclipse.)

The Expression to use when you see the symbol "x" is the value of the xVariable parameter passed to the RPNParser.parse method.

You may implement your own stack, or you may use the java.util.Stack class.  In most respects, java.util.Stack is like the stack classes we discussed in class, except that rather than having a getTop method, it has a peek method to get the top value on the stack (without removing it from the stack).

To test your implementation, you should add new JUnit test cases to the TestRPNParser class.  Several example tests are provided.  You may also run the main method of the PlottingCalculator class, which plots the function represented by an RPN expression visually for a range of X values.  (Running a main method in Eclipse.)

Submitting your work

To submit the project, type the following commands in a terminal window (hitting return after each command):

cd
cd eclipse-workspace
submit102 rpncalc

You may submit as many times as you wish.  The final submission prior to the deadline will be graded.