# L-14 MCS 275 Fri 15 Feb 2008 : evalpostfix.py

# evaluation of expressions in postfix format
# for example: 1 2 3 * 4 + 7 - +
# operands and operators are separated by spaces

operators = ['+','-','*','/']

def UpdatePValue(S,op,c):
   """
   Evaluates operations to numbers, via an
   update of the stack S with a character c,
   where op is the current operand.
   If c is an operator, then its arguments
   are popped from the stack and the result
   of the operation is pushed on the stack.
   The new S and op are returned as (S,op).
   """
   if c == ' ':
      if op != '':
         S.insert(0,op)
         op = ''
      return (S,op)
   elif c in operators:
      p = S.pop(0) + c + S.pop(0)
      value = eval(p)
      S.insert(0,str(value))
      return (S,op)
   else:
      return (S,op + c)

def UpdateIValue(S,op,c):
   """
   Evaluates operations to numbers, via an
   update of the stack S with a character c,
   where op is the current operand.
   If c is a closing bracket, then two
   operands and an operator are popped
   from the stack and the result
   of the operation is pushed on the stack.
   The new S and op are returned as (S,op).
   """
   if c in operators:
      if op != '':
         S.insert(0,op)
         op = ''
      S.insert(0,c)
      return (S,op)
   elif c == ')':
      if op == '': op = S.pop(0)
      p = S.pop(0)
      p = S.pop(0) + p + op
      value = eval(p)
      S.insert(0,str(value))
      return (S,'')
   elif c != '(':
      return (S,op + c)
   else:
      return (S,op)

def Bracket(a):
   """
   Returns a with round brackets around
   it if a is not a number.
   """
   if a.isalnum():
      return a
   else:
      return '(' + a + ')'

def EvalString(S,op,c):
   """
   Evaluates operations to a string, via an
   update of the stack S with a character c,
   where op is the current operand.
   If c is an operator, then its arguments
   are popped from the stack and the result
   of the operation is pushed on the stack.
   The new S and op are returned as (S,op).
   """
   if c == ' ':
      if op != '':
         S.insert(0,op)
         op = ''
      return (S,op)
   elif c in operators:
      p = Bracket(S.pop(0)) + c
      p = p + Bracket(S.pop(0))
      S.insert(0,p)
      return (S,op)
   else:
      return (S,op + c)

def EvalPostFix(e):
   """
   Returns the value of the expression e,
   given as string in postfix notation.
   An exception handler prints the stack.
   """
   op = ''
   S = []
   try:
      for c in e:
         (S,op) = UpdatePValue(S,op,c)
         print 'S =', S
      return S[0]
   except:
      print 'exception raised at '
      print 'c =', c, 'S =', S
      return 0

def EvalInFix(e):
   """
   Returns the value of the expression e,
   gvien as string in infix notation.
   An exception handler prints the stack.
   """
   op = ''
   S = []
   try:
      for c in e:
         (S,op) = UpdateIValue(S,op,c)
         print 'S =', S
      return S[0]
   except:
      print 'exception raised at '
      print 'c =', c, 'S =', S
      return 0

def ToInFix(e):
   """
   Converts the postfix expression in
   the string e to an infix expression.
   An exception handler prints the stack.
   """
   op = ''
   S = []
   try:
      for c in e:
         (S,op) = EvalString(S,op,c)
         print 'S =', S
      return S[0]
   except:
      print 'exception raised at '
      print 'c =', c, 'S =', S
      return 0

def main():
   """
   Prompts the user for a postfix
   expression and evaluates it.
   """
   e = raw_input('Postfix expression : ')
   v = EvalPostFix(e)
   print e, 'evaluates to', v
   f = ToInFix(e)
   print 'infix :', f
   v = eval(f)
   print 'evaluates to', v
   f = '(' + f + ')'
   v = EvalInFix(f)
   print f, 'evaluates to', v

main()
