Project 2: Evaluating Expressions Using

Stacks

Overview

For this project, you will implement a program to evaluate a postfix (Reverse Polish or

RPN) expression. To make the program more versatile, you’ll also provide code to

convert infix expressions (the kind used in standard arithmetic) and prefix (Polish or PN)

expressions to postfix expressions. In this way, your program will be able to evaluate

prefix, infix and postfix expressions. Many language translators (e.g. compiler) do

something similar to convert expressions into code that is easy to execute on a

computer.

For this assignment, you will use an implementation of the Abstract Data Type Stack.

Your programs should work with either implementation from Lab 3 – the one based on a

linked data structure or the one based on Python’s List data type, but for consistency

with grading, use the stack_array.py implementation. You must add, commit, and push

a correct implementation of this file.

Notes:

● Postfix expressions will only consist of numbers (integers, reals, positive or

negative) and the five operators separated by spaces. You may assume a

capacity of 30 for the Stack will be sufficient for any expression that your

programs will be required to handle.

● In addition to the operators + – * / shown in class, your programs should handle

the exponentiation operator. In this assignment, the exponential operator will be

denoted by ^. For example, 2^3=8 and 3^2=9.

(https://en.wikipedia.org/wiki/Exponentiation)

● For infix expressions, the exponentiation operator has higher precedence than

the * or /. For example, 2*3^2 = 2*9 = 18 not 6^2=36

● Also, for infix expressions, the exponentiation operator associates from right to

left. The other operators (+,-,*, /) associate left to right. Think carefully about what

this means. For example: 2^3^2 = 2^(3^2) = 2^9 = 512 not (2^3)^2= 8^2=64

1

CPE202 Spring 2020

● Infix expressions may also have parentheses – consider that for the

infix_to_postfix() function.

● Every class and function must come with a brief purpose statement in its

docstring. In separate comments you should explain the arguments and what is

returned by the function or method (i.e. docstrings).

● Every class must come with __init__, __eq__, and __repr__.

● You must provide test cases that completely test all functions.

● Use descriptive names for data structures and helper functions. You must name

your files and functions (methods) as specified in this instruction.

Modules and Functions

Your code will be contained in these files:

● stack_array.py

● exp_eval.py

● exp_eval_testcases.py

Algorithms

Evaluating a Postfix (RPN) Expression

While RPN will look strange until you are familiar with it, here you can begin to see

some of its advantages for programmers. One such advantage of RPN is that it

removes the need for parentheses. Infix notation supports operator precedence (∗ and ⁄

have higher precedence than + and −) and thus needs parentheses to override this

precedence. This makes parsing such expressions much more difficult. RPN has no

notion of precedence, the operators are processed in the order they are encountered.

This makes evaluating RPN expressions fairly straightforward and is a perfect

application for a stack data structure, just follow these steps:

● Process the expression from left-to-right

● When a value is encountered:

○ Push the value onto the stack

● When an operator is encountered:

○ Pop the required number of values from the stack

○ Perform the operation

2

CPE202 Spring 2020

○ Push the result back onto the stack

● Return the last value remaining on the stack

For example, given the expression 5 1 2 + 4 ^ + 3 – :

Input Type Stack Notes

5 Value 5 Push 5 onto stack

1 Value 1 5 Push 1 onto stack

2 Value 2 1 5 Push 2 onto stack

+ Operator 3 5 Pop two operands (1, 2), perform operation (1+2=3), and push

result onto stack

4 Value 4 3 5 Push 4 onto stack

^ Operator 81 5 Pop two operands (3, 4), perform operation (3^4=81), and push

result onto stack

+ Operator 86 Pop two operands (5, 81), perform operation (5+81=86), and

push result onto stack

3 Value 3 86 Push 3 onto stack

− Operator 83 Pop two operands (86, 3), perform operator (86−3=83), and

push result onto stack

Result 83

Converting Infix Expressions to Postfix (RPN)

You can also use a stack to convert an infix expression to an RPN expression via the

Shunting-yard algorithm. The steps are shown below. Note that the algorithm is more

complex that what was shown in class, because the project will include a power

operator.

● Process the expression from left-to-right

● When you encounter a value:

○ Append the value to the RPN expression

● When you encounter an opening parenthesis:

○ Push it onto the stack

● When you encounter a closing parenthesis:

○ Until the top of stack is an opening parenthesis, pop operators off the

stack and append them to the RPN expression

○ Pop the opening parenthesis from the stack (but don’t put it into the RPN

expression)

● When you encounter an operator, o1:

○ While there is an operator, o2, at the top of the stack and either

3

CPE202 Spring 2020

■ o1 is left-associative and its precedence is less than or equal to that

of o2, or

■ o1 is right-associative, and has precedence less than that of o2

● Pop o2 from the stack and append it to the RPN expression

○ Finally, push o1 onto the stack

● When you get to the end of the infix expression, pop (and append to the RPN

expression) all remaining operators

For example, given the expression 3 + 4 * 2 / ( 1 – 5 ) ^ 2 ^ 3:

operator precedence associativity

^ high Right

* medium Left

/ medium Left

+ low Left

− low Left

Input Action RPN Stack Notes

3 Append 3 to expression 3

+ Push + onto stack 3 +

4 Append 4 to expression 3 4 +

* Push * onto stack 3 4 * + * has higher precedence

than +

2 Append 2 to expression 3 4 2 * +

/ Pop *, push / 3 4 2 * / + / and * have same

precedence

/ has higher precedence

than +

( Push ( to stack 3 4 2 * ( / +

1 Append 1 to expression 3 4 2 * 1 ( / +

– Push – to stack 3 4 2 * 1 – ( / +

5 Append 5 to expression 3 4 2 * 1 5 – ( / +

) Pop stack 3 4 2 * 1 5 – / + Pop and append operators

until opening parenthesis;

then pop opening

parenthesis

^ Push ^ to stack 3 4 2 * 1 5 – ^ / + ^ has higher precedence

than /

2 Append 2 to expression 3 4 2 * 1 5 – 2 ^ / +

^ Push ^ to stack 3 4 2 * 1 5 – 2 ^ ^ / + ^ is evaluated

right-to-left

3 Append 3 to expression 3 4 2 * 1 5 – 2 3 ^ ^ / +

end Pop entire stack to 3 4 2 * 1 5 – 2 3

output ^ ^ / +

4

CPE202 Spring 2020

Converting Prefix Expressions (PN) to Postfix

● Read the Prefix expression in reverse order (from right to left)

○ When an operand is encountered, push it onto the stack

○ When an operator is encountered:

■ Pop two operands/strings rom the stack: op1 = pop(), op2 = pop()

■ Create a string by concatenating the two operands/strings and the

operator after them: string = op1 + op2 + operator (remember

space separation between tokens).

■ Push the resultant string back to the stack

● Repeat the above steps until end of Prefix expression

● The one string remaining on the Stack is the resultant Postfix expression

For example, given the Prefix expression: * – 3 / 2 1 – / 4 5 6

Input Action Stack Notes

6 Push ‘6’ onto stack ‘6’ Read from right to left

5 Push ‘5’ onto stack ‘5’ ‘6’

4 Push ‘4’ onto stack ‘4’ ‘5’ ‘6’

/ Pop ‘4’, ‘5’, combine ‘4 5 /’ ‘6’ Keep tokens space separated

with /, push onto stack

– Pop ‘4 5 /’, ‘6’, combine ‘4 5 / 6 -’

with -, push onto stack

1 Push 1 onto stack ‘1’ ‘4 5 / 6 -’

2 Push 2 onto stack ‘2’ ‘1’ ‘4 5 / 6 -’

/ Pop ‘2’,’1’, combine ‘2 1 /’ ‘4 5 / 6 -’

with /, push onto stack

3 Push 3 onto stack ‘3’ ‘2 1 /’ ‘4 5 / 6 -’

– Pop ‘3’,‘2 1 /’, combine ‘3 2 1 / -’ ‘4 5 / 6 -’

with -, push onto stack

* Pop ‘3 2 1 / -’,‘4 5 / 6 -’, ‘3 2 1 / – 4 5 / 6 – *’

combine with *, push onto

stack

end Pop entire stack to output Result: ‘3 2 1 / – 4 5 / 6 – *’

Tests

● Write sufficient tests using unittest to ensure full functionality and correctness of

your program.

5

CPE202 Spring 2020

● Make sure that your tests test each branch of your program and any edge

conditions. You do not need to test for correct input in the assignment, other than

what is specified above.

● postfix_eval(input_str) should raise a ValueError if a divisor is 0.

● OPTIONAL (25 ExtraPoints): postfix_eval(input_str) should raise a

PostfixFormatException if the input is not well-formed. Specifically, it should raise

this exception with the following messages in the following conditions:

○ “Invalid token” if one of the tokens is neither a valid operand nor a valid

operator. You may use Python builtin string functions such as isdigit(),

dictionary construct, and in operator for this.

○ “Insufficient operands” if the expression does not contain sufficient

operands.

○ “Too many operands” if the expression contains too many operands.

○ You may create a helper function for this.

○ Note: to raise an exception with a message: raise

PostfixFormatException(“Here is a message”)

○ This is how you define PostfixFormatError

class PostfixFormatException(Exception):

pass

This is how you can raise PostfixFormatError.

def test_raise(x):

if x == None:

raise PostfixFormatException(“OH NO!”)

return 10/x

if __name__ == ‘__main__’:

try:

test_raise(None)

except PostfixFormatException as err:

print(err)

● You may assume that when infix_to_postfix(input_str) is called that input_str is a

well formatted, correct infix expression containing only numbers, the specified

operators, parentheses () and that the tokens are space separated. You may use

the Python functions split and join.

● You may assume that when prefix_to_postfix(input_str) is called that input_str is

a well formatted, correct prefix expression containing only numbers, the specified

operators, and that the tokens are space separated. You may use the Python

functions split and join.

● You can assume that the user will validate postfix expressions prior to calling the

postfix evaluation function, so postfix_eval(input_str) will always be called with a

6

CPE202 Spring 2020

valid postfix expression except for a case where you decide to implement the

aforementioned optional requirement.

Submission

You must submit all the files necessary to run your program. Zip your files into one zip

file named as project2_<your calpoly username.zip. Submit the zip file to Canvas. We

will grade your work manually.

7

Sale!