[Tutor] A simple RPN calculator
Scot W. Stevenson
scot@possum.in-berlin.de
Wed, 28 Aug 2002 06:50:39 +0200
Hello there,
I had started a thread about Reverse Polish Notation calculators a while
ago, and Gregor actually wrote one, and I did that smart-ass thing of
coming back and saying, hey, really neat, Gregor, but how about the
following functions...So I guess I owe him some code =8).
Included is my attempt at a simple RPN calculator, any feedback of course
would be most appreciated.
Y, Scot
============================================================
#!/usr/bin/env python
# Simple Reverse Polish Notation Calculator
# Scot W. Stevenson 28. August 2002
# For the Python Tutor Mailinglist
import cmd, sys
class rpn_calc(cmd.Cmd):
"""Simple RPN calculator"""
def __init__(self, stacksize=4):
self.stack = [0]*stacksize
self.stacksize = len(self.stack)
self.lastregister = self.stacksize-1
self.intro='Simple RPN Calculator\nScot W. Stevenson 28. Aug 2002'
self.lastx = 0
self.operations = { '+': self.do_add,
'-': self.do_subtract,
'*': self.do_multiply,
'/': self.do_divide,
'^': self.do_power}
# Helper functions
def _stacklift(self, new_x):
"""Lift stack by one entry, last register is lost"""
del self.stack[self.lastregister]
self.stack.insert(0, new_x)
def _stackdrop(self, new_x):
"""Drop stack by one entry, losing Y register entry, last register
is doubled"""
self.stack.append(self.stack[self.lastregister])
del self.stack[0]
self.stack[0]=new_x
# Catch numbers and operators
def default(self, entry):
"""Catch numbers and operators and process them. If entry is
neither number nor operator, ignore and pass on to cmd
loop."""
# Catch numbers
try:
number = float(entry)
self.lastx = self.stack[0]
self._stacklift(number)
except ValueError:
pass
# Catch operations
if entry in self.operations:
operation = self.operations[entry]
operation()
# Show X register after each command
def postcmd(self, *dummy):
"""Display the contents of the X register after each
command"""
print " %f" % self.stack[0]
# Calculator commands
def do_add(self, dummy=None):
result = self.stack[1] + self.stack[0]
self._stackdrop(result)
def do_clrx(self, rest):
"""Clear X register"""
self.stack[0] = 0
def do_divide(self, dummy=None):
try:
result = self.stack[2] / self.stack[0]
self._stackdrop(result)
except ZeroDivisionError:
print "*** Division by Zero Error ***"
def do_enter(self, dummy):
"""Perform a stack lift; last register value is lost,
first (X) register value is pushed into the second (Y)
register"""
self._stacklift(self.stack[0])
def emptyline(self, dummy=None):
"""An empty line is treated like hitting the ENTER key"""
self.do_enter(None)
def do_lastx(self, dummy):
"""Restore X register value from before the operation in the
X register, performing a stack lift"""
self._stacklift(self.lastx)
def do_multiply(self, dummy=None):
try:
result = self.stack[1] * self.stack[0]
self._stackdrop(result)
except OverflowError:
print '*** Overflow Error ***'
def do_power(self, dummy=None):
try:
result = pow(self.stack[1], self.stack[0])
self._stackdrop(result)
except OverflowError:
print '*** Overflow Error ***'
def do_print(self, rest):
"""Print stack. Mostly used for debugging"""
for i in range(self.stacksize-1, -1, -1):
print 'Reg %s: %f' % (i, self.stack[i])
def do_quit(self, dummy):
sys.exit()
def do_rdown(self, dummy):
"""Roll down stack"""
self.stack.append(self.stack[0])
del self.stack[0]
def do_rup(self, dummy):
"""Roll up stack"""
self.stack.insert(0, self.stack[self.lastregister])
del self.stack[self.lastregister+1]
def do_subtract(self, dummy=None):
result = self.stack[1] - self.stack[0]
self._stackdrop(result)
def do_xy(self, dummy):
"""Swap X and Y registers"""
self.stack[0], self.stack[1] = self.stack[1], self.stack[0]
# Help texts
def help_add(self):
print 'Add X and Y register. Use "+" key or "add" command'
def help_clrx(self):
print 'Clear X register'
def help_divide(self):
print 'Divide X by Y register. Use "/" key or "divide" command'
def help_enter(self):
print 'Push stack up by one, last register is lost'
def help_help(self):
print 'Prints list of commands'
def help_lastx(self):
print 'Retrieves value of the X register from before the last'
print 'operation and pushes it in the X register, lifting the'
print 'stack.'
def help_multiply(self):
print 'Multiply X by Y register. Use "*" key or "subtract" command'
def help_power(self):
print 'Take Y to the Xth power. Use "^" key or "power" command'
def help_print(self):
print 'Print stack. Used mostly for debugging'
def help_rdown(self):
print 'Rolls stack downwards'
def help_rup(self):
print 'Rolls stack upwards'
def help_quit(self):
print 'Quit program'
def help_subtract(self):
print 'Subtract X from Y register. Use "-" key or "subtract" cmd'
def help_xy(self):
print 'Swaps X and Y registers'
# Main loop
if __name__ == '__main__':
testcalc = rpn_calc()
testcalc.cmdloop()