#!/usr/bin/python3
# ====================================================================
# evaluate a list of RPN tokens
# ====================================================================
import sys
from infix_stack import Stack
import user_interface as ui
explanation = '''
Entered a RPN expression as a string. The operands and operators
should be seperated by spaces or commas. For example: '1,2 + /,3'
'''
msg0 = 'error: badly formed RPN expression'
msg1 = 'error: not enough tokens on the stack for binary operator'
# --------------------------------------------------------------------
# ---- convert string to number (int or float)
# --------------------------------------------------------------------
def _number(string):
tf,n = ui.is_integer(string)
if tf is True: return(True,n)
tf,n = ui.is_float(string)
if tf is True: return(True,n)
return (False,0)
# --------------------------------------------------------------------
# ---- evaluate RPN expression
# --------------------------------------------------------------------
def evaluate_rpn(tokens:list) -> tuple:
# ---- convert the token list into a stack of operators
# ---- and operands
stack = Stack()
for token in tokens:
tf,n = _number(token[0])
if tf:
stack.push(n) # operand
continue
op = token[0] # operator
print(f'op={op:<2} stack={stack.as_list()}')
if op == '+': # add
a = stack.pop()
b = stack.pop()
stack.push(b+a)
continue
if op == '-': # subtract
a = stack.pop()
b = stack.pop()
stack.push(b-a)
continue
if op == '*': # multiply
a = stack.pop()
b = stack.pop()
stack.push(b*a)
continue
if op == '/': # divide
a = stack.pop()
b = stack.pop()
stack.push(b/a)
continue
if op == '%': # modulus (remandier)
a = stack.pop()
b = stack.pop()
stack.push(b%a)
continue
if op == '**': # power
a = stack.pop()
b = stack.pop()
stack.push(b**a)
continue
if op == '//': # floor
a = stack.pop()
b = stack.pop()
stack.push(b//a)
continue
print()
print(msg0)
print(f'error: bad operator ({op})')
break
# ---- return results
if stack.is_empty():
print(msg0)
print('error: stack is empty - no results')
return(False,0)
if stack.length() > 1:
print(msg0)
print('error: stack contains more than one value')
print(f'stack: {stack.as_list()}')
return(False,0)
return(True,stack.tos())
# --------------------------------------------------------------------
# ---- main
# --------------------------------------------------------------------
if __name__ == '__main__':
print(explanation)
while True:
# ---- ask the user to enter an RPM expression
print()
ex = ui.get_user_input('Enter RPN expression: ')
if not ex: break
# ---- convert expression string into a list of strings
strings = ex.replace(',',' ').split()
if len(strings) == 0:
print()
print('Error: empty expression')
continue
##print()
##print(f'exp: {strings}')
##print()
# ---- convert a list of strings to a list of tokens
# ---- (add fake type/precedence)
tokens = []
for tok in strings:
tokens.append((tok,99))
# ---- evaluate token list
tf,value = evaluate_rpn(tokens)
print()
print(f'success = {tf}')
print(f'RPN value = {value}')