#!/usr/bin/env python # -*- coding: utf-8 -*- # Version 1.1 12/05/2010 # *************************************************************************** # * Copyright (C) 2010, Paul Lutus * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU General Public License as published by * # * the Free Software Foundation; either version 2 of the License, or * # * (at your option) any later version. * # * * # * This program is distributed in the hope that it will be useful, * # * but WITHOUT ANY WARRANTY; without even the implied warranty of * # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * # * GNU General Public License for more details. * # * * # * You should have received a copy of the GNU General Public License * # * along with this program; if not, write to the * # * Free Software Foundation, Inc., * # * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * # *************************************************************************** import sys, re, readline, types from math import * from operator import * class RPNCalc: def fmtprint(self,a,b): print("%6s | %s" % (a,b)) def helptxt(self): self.fmtprint("Enter","For") print("-" * 20) for tup in (self.com2args,self.com1arg,self.coms): for item in tup: self.fmtprint(item[0],item[2]) def found(self,s,tup): for item in tup: if(s == item[0]): self.node = item return True return False def __init__(self): self.stack = [] self.com2args = ( ("+" , add,"y + x"), ("-" , sub,"y - x"), ("*" , mul,"y * x"), ("/" , div,"y / x"), ("%" , fmod,"y % x"), ("^" , pow,"y ^ x"), ("hyp", hypot,"hypot(x,y)"), ) self.com1arg = ( ("sin" , sin, "sin(x)"), ("cos" , cos, "cos(x)"), ("tan" , tan, "tan(x)"), ("asin" , asin, "asin(x)"), ("acos" , acos, "acos(x)"), ("atan" , atan, "atan(x)"), ("sinh" , sinh, "sinh(x)"), ("cosh" , cosh, "cosh(x)"), ("tanh" , tanh, "tanh(x)"), ("asinh", asinh, "asinh(x)"), ("acosh", acosh, "acosh(x)"), ("atanh", atanh, "atanh(x)"), ("sqrt" , sqrt, "sqrt(x)"), ("log" , log, "log(x)"), ("exp" , exp, "exp(x)"), ("ceil" , ceil, "ceil(x)"), ("floor", floor, "floor(x)"), ("erf" , erf, "erf(x)"), ("erfc" , erfc, "erfc(x)"), ("!" , factorial, "x!"), ("abs" , fabs, "|x|"), ("deg" , degrees,"degree(x)"), ("rad" , radians,"radian(x)"), ) self.coms = ( ("pi", lambda: self.stack.insert(0,pi),"Pi"), ("e" , lambda: self.stack.insert(0,e),"e (base of natural logarithms)"), ("d" , lambda: self.stack.pop(0),"Drop x"), ("x" , lambda: self.stack.insert(0,self.stack[0]),"Enter x"), ("" , lambda: self.stack.insert(0,self.stack[0]),"Enter x (press Enter)"), ("s" , lambda: self.stack.insert(0,self.stack.pop(1)),"Swap x <-> y"), ("h" , self.helptxt,"Help"), ("q" , lambda: 0,"Quit"), ) def process(self): spregex = re.compile("\s+") stacklbl = "tzyx" line = "" while (line != "q"): while(len(self.stack) < 4): self.stack.append(0.0) for i, n in enumerate(self.stack[3::-1]): if(type(n) == int): try: n = float(n) except: n = float('inf') s = "f" # default display format an = abs(n) if(an > 1e10 or an < 1e-10 and an != 0.0): s = "e" # switch to scientific notation fs = ("%.16" + s) % n # line up decimal points p = 10 + len(fs) - fs.find('.') print("%s: %*s" % (stacklbl[i],p,fs)) line = input("Entry (h = help, q = quit): ") for tok in spregex.split(line): try: # parsing a number self.stack.insert(0,float(tok)) except: # it's not a number try: # look for command if (self.found(tok, self.com2args)): self.stack.insert(0,self.node[1](self.stack.pop(1),self.stack.pop(0))) elif (self.found(tok, self.com1arg)): self.stack.insert(0,self.node[1](self.stack.pop(0))) elif (self.found(tok, self.coms)): self.node[1]() else: print("Error: token \"%s\" not found!" % tok) except: print("Error:", sys.exc_info()[0]) RPNCalc().process()