# this file available at: https://arachnoid.com/files/python01/ import math import re # this import is essential for prior-entry recovery using "input()" import readline # type: ignore from typing import List, Any class RPNCalculator: stack : List[float] = [] labels : str = 'xyzt' def exec(self) -> None: while True: try: self.show_stack() inp_str = input("Enter: ") # parse entered string into separate arguments args : List[str | Any] = re.split(r'\s+',inp_str) for arg in args: if len(arg) > 0: try: # scan for number v = float(arg) self.push(v) valid = True except: # not a number valid = False modify_stack = True stack_size = len(self.stack) r = 0 if not valid and stack_size >= 2: valid = True # 2-argument functions x,y = self.stack[:2] match arg: case '/': r = y/x case '*': r = y*x case '+': r = y+x case '-': r = y-x case '^': r = y**x case 'xy': # swap x and y self.stack[:2] = y,x modify_stack = False case _: valid = False # if valid result if valid and modify_stack: # discard 'y' value self.stack.pop(0) # replace 'x' value self.stack[0] = r if not valid and stack_size >= 1: # 1-argument functions x = self.stack[0] valid = True match arg: case '!': r = math.factorial(int(x)) case 'sin': r = math.sin(x) case 'cos': r = math.cos(x) case 'tan': r = math.tan(x) case 'asin': r = math.asin(x) case 'acos': r = math.acos(x) case 'atan': r = math.atan(x) case 'sqrt': r = math.sqrt(x) case 'log': r = math.log(x) case 'exp': r = math.exp(x) case 'e': # duplicate bottom stack value self.push(self.stack[0]) modify_stack = False case 'r': # "remove" = drop lowest stack value self.stack.pop(0) modify_stack = False case 'c': # clear stack self.stack = [] modify_stack = False case _: valid = False # if valid result if valid and modify_stack: # replace 'x' value self.stack[0] = r if not valid: # push constants onto stack or quit valid = True match arg: case 'pi': self.push(math.pi) case 'tau': self.push(math.pi * 2) case 'q': # quit the calculator program quit() case _: valid = False if not valid: # no more possibilities print(f'Error: "{arg}" not found or not valid for stack contents.') except Exception as err: # primarily for math domain errors print(f'Error: {err}') def show_stack(self) -> None: print() top = len(self.labels)-1 for n in range(top,-1,-1): v = '' if n < len(self.stack): try: v = f'{self.stack[n]:.16g}' except Exception as err: v = f'Error: {err}' print(f'{self.labels[n]} : {v}') #print() def push(self,v:float) -> None: self.stack.insert(0,v) # end of RPNCalculator class def main(): calc = RPNCalculator() calc.exec() if __name__ == "__main__": main()