CSCI 112: Programming and Algorithms II
Fall 2005
Program 4: Post-fix Calculator
Code due: 8am Friday October 21
(copied to your ecst turn-in directory, see below)
Grading Weight: 3 (programs will have a weight between 1 - 5)


Overview:

The standard form of equations, 2 + 4, is called infix because the operator (+ in this example) is "in" the middle of the operands (2 and 4 in this example).  This form has the drawback of not being able to control the order in which the operators are applied without using parentheses.  For example, if you want 2 + 4 multiplied by 5, you have to write (2+4)*5.  While this is easy to do in a programming language, it is difficult to do on a standard calculator.

Postfix notation (also called Reverse Polish Notation or RPN) is much better suited for calculators.  In postfix notation, the operator goes after the operand.  For example, the equation 2 4 + means 2 plus 4, and the expression 2 4 + 5 * means to first apply + to 2 and 4 and then apply * to the result of 2 + 4 and 5.  The result is (2 + 4) * 5 and you didn't have to type in the "(" and ")".

Postfix calculators are easily implemented using a stack data structure.  When the user enters an operand, it is inserted on to the stack (in stacks, inserting on top of the stack is called push).  When the user enters a binary operator, the 2 operands on top of the stack are removed (popped), the operator is applied to them, and the result is pushed on to the stack.

If at the end of the input, there is one and only one operand on the stack, then the input was a valid expression and the value on the stack is the result of evaluating that expression.

This assignment is to implement an RPN calculator that can evaluate any legal expression and catch all illegal input (except numbers with so many digits that they won't fit into a double).  As soon as illegal input is encountered, print the error message (see below) and call exit(1).

Program Requirements:

Implementation:

Implement your stack from scratch using dynamic allocation.  In other words, your stack must look like a linked-list.  You may not use a stack from a library.  Create a class Node to hold the elements of the stack.  This class must be nested inside of class Dstack.

Implement your program using the following class:
class Dstack
Stack of doubles that provides at least the following functions:
push - push a new element on top of the stack
pop  -  remove and return the top element from the stack (must be able to deal with an empty stack)
~Dstack - a correct destructor
You may use whatever return types and arguments you see fit.  You may add additional functions if you need them.
Put main() in the file calc.cpp


Input:

Your program must read a single equation from standard input.   The operators are + - * / ^ (^ is power, 2 4 ^ is 2 raised to the power of 4).  Numbers can be any double number, for example 4, 4.2, .2, 0.2, 0000.233.  You can assume that the number is small enough to fit into a double variable (I won't give you a number with 200 digits).

Your program should ignore all white space (spaces, tabs, newlines).

If two numbers are in a row, there must be a space between them.  For example, 42 is the number forty-two, and 4  2 are the numbers four and two.

There do not have to be spaces between numbers and operators.  For example, 10 10+ is a legal equation.

There do not have to be spaces between two operators.  For example, 10 10 10++ is a legal equation.


Files:


Each class should have a .h file and a .cpp file (note that the filenames are all lower case):

dstack.h
dstack.cpp

In addition to the above files, you will need to turn in a file containing your main() function:

calc.cpp

Program Output:

If the input is a correct post-fix expression, your program should print the result.

For example, if the input is 10 10+, your program should output 20 followed by a newline, and nothing else (don't print any prompts or "aswer =").


Errors and Error Messages:

If the input is not a valid post-fix expression, your program should print the following to standard error:
 Error: Invalid expression.

followed by a newline (not a blank line, but a newline) and then call exit(1).

Your program must check for all types of errors (except numbers that are too large).



Hints:

The algorithm is:

while (not the end of the input)

If the next input is a number, read it and push it on the stack
If the next input is an operator, read it, pop 2 operands off of the stack, apply the operator, push the result onto the stack
if there is one number on the stack, print it
else error


I suggest you implement and test the stack before you tackle the calculator aspects of the program.  You will have to write a few lines of code in main() to do this testing, but it will save you time in the long run.

You can't just use getline() or cin >> string_variable for this program because you usually don't know if an operator or an operand (a number) will be the next thing in the input stream.  You will need to use cin.peek() to look at the next character in the input.  cin.peek() returns the next character without actually reading it.  In other words, the next character you read will be the one returned by cin.peek().  If it is whitespace (space, tab, newline) you can skip it using cin.ignore().  If it is a legal operator, you can read the single character using cin >> char_variable.  If the next character is a digit, you can use cin >> double_variable to read the entire number.  cin.peek() returns EOF (which is defined as -1) if end-of-file is true.




General Requirements:

I will deduct 10 percent if your program does not compile using my Makefile on the lab machines.  Thus you must make sure to use the filenames listed below (do not capitalize your filenames), and if you are working on windows, you should compile and test your program on one of the department's suns before turning it in.

We will grade your program using another program, so if your program does not work exactly as specified below you will lose points.

The first lines of all your files (.h and .cpp) must contain:
/****
last name, first name
ecst_username@ecst.csuchico.edu
112 Program 4: RPN Calculator
****/

How to turn in code:

If you download my Makefile, and have your program on a Department machine, you can submit your program by typing:
$ make submit
Look carefully at the output to make sure all the following files were copied:
calc.cpp
dstack.h
dstack.cpp
You may submit as many times as you want before the deadline.  Once the deadline passes, you will not be able to submit.

You can also just copy (using local cp or remote scp) or sftp the above files into the directory:
/user/projects/csci112/p4/USERNAME
where USERNAME is your ecst username.

See how to turn in assignments  for detailed instructions on how to turn in the assignment.

Note:  You will not be able to access this directory once the deadline has passed.

Late assignments:

If you do not finish by the deadline (see top for the deadline), you may turn your assignment in up to 24 hours late.  You will lose 15% for turning your assignment in 1-24 hours late.

If you turn your assignment in late, copy your assignment into the following directory
:
/user/projects/csci112/p4_late/USERNAME
Assignments will not be accepted if more than 24 hours late.

If you are working on the department machines and you have a copy of my makefile, you can submit your files using
"make submit_late"

Extra credit:

You will get 10 points extra credit if your program passes all the extra credit tests, and a fraction of 10 points if it passes some of the extra credit tests.  Since these are multi-character operators, you will have to modify how you read the input. 

Implement the following operators:

sqrt   calculate the square root of the previous number,  15 sqrt means the square root of 15.

cos   calculate the cosine of the previous number, 30 cos means the cosine of 30

sin    calculate the sine of the previous number, 45 sin means the sine of 45

Note: Assume the user is entering degrees.  Since the math.h functions cos() and sin() expect the angle in radians you will ahve to convert the number to radians.  Use the constant M_PI from math.h to perform the conversion.


ave   remove all the operands off the stack, calculate there average and push the result on to the stack