#!/usr/bin/python

"""
From wikipedia: http://en.wikipedia.org/wiki/Reverse_Polish_notation

In reverse Polish notation the operators follow their operands; for
instance, to add 3 and 4, one would write '3 4 +' rather than '3 + 4'.

If there are multiple operations, the operator is given immediately
after its second operand; so the expression written '3 - 4 + 5' in
conventional notation would be written '3 4 - 5 +' in RPN: first
subtract 4 from 3, then add 5 to that.

An advantage of RPN is that it obviates the need for parentheses that
are required by infix. While '3 - 4 * 5' can also be written
'3 - (4 * 5)', that means something quite different from'(3 - 4) * 5'. In
postfix, the former could be written '3 4 5 * -', which unambiguously
means '3 (4 5 *) -' which reduces to '3 20 -'; the latter could be
written '3 4 - 5 *' (or 5 3 4 - *, if you wish to keep similar
formatting), which unambiguously means '(3 4 -) 5 *'.

The reverse Polish scheme was proposed in 1954 by Burks, Warren, and
Wright[1] and was independently reinvented by F. L. Bauer and
E. W. Dijkstra in the early 1960s to reduce computer memory access and
utilize the stack to evaluate expressions. The algorithms and notation
for this scheme were extended by Australian philosopher and computer
scientist Charles Hamblin in the mid-1950s.[2][3]

During the 1970s and 1980s, RPN was known to many calculator users, as
it was used in some handheld calculators of the time designed for
advanced users: for example, the HP-10C series and Sinclair Scientific
calculators.

In computer science, postfix notation is often used in stack-based and
concatenative programming languages.

"""

from go import *

#---| lib stuff |------

import sys
def say(x):
  sys.stdout.write(x)

#--- interpreter for reverse polish notation

def postorder(x):
  return postorder1(x,[])

def postorder1(x,out):
  leaf  = lambda y: not isinstance(y,list)
  left  = lambda y: y[0]
  head  = lambda y: y[1]
  right = lambda y: y[2]
  if leaf(x):
    out += [x]
  else:
    postorder1(left(x), out)
    postorder1(right(x),out)
    postorder1(head(x), out)
  return out

#@go
def _postorder():
  print postorder( [[1, "+",2],
                    "*",
                    [2, "-", 3]] )

#-----------------------------------------
# evaluator for rpn
                     
def rpn(input):
  minus    = lambda x,y : float(x) - float(y)
  plus     = lambda x,y : float(x) + float(y)
  mult     = lambda x,y : float(x) * float(y)
  args     = {"+" : plus, 
              "*" : mult, 
              "-" : minus}
  operator = lambda x: x in args
  stack    = []
  while input:
    token = input.pop(0)
    if not operator(token):
      stack += [token]
    else:
      two = stack.pop()
      one = stack.pop()
      f= args[token]
      stack += [f(one,two)]
  return stack[0]

@go
def _shunt():
  say("5 + ((1 + 2) * 4) - 3 = " )
  print rpn([5,1,2,"+",4,"*","+",3,"-"])

# -------------------------------------------
# infix to rpn translator

# class stuff definitions

class Op:
  all = []
  def __init__(i,name,precedence=100):
    i.name=name
    i.precedence = precedence
    Op.all += [i]
  def __repr__(i):
    return i.name + '{' + str(i.precedence) + '}'
 
# parsing utils 
def isa(x):
  "Try to find the operator names 'x'. Else fail."
  for y in Op.all:
    if x == y.name: return y
  return None
    
def isNum(x):
  "Let Python do the heavy lifting"
  try: return int(x)
  except ValueError:
    try: return float(x)
    except ValueError:
      return None

# main engine 
import re
class Shunt:
  """ Simple version of Edsger Dijkstra's shunting yard algorithm.
      No associativity, brackets, function symbols, arguments.
      No error checking.
      For full version, see http://goo.gl/pakbVu
  """
  def __init__(i,str):
    say(str + ' : \n')
    i.out   = []
    i.stack = []
    for token in i.tokens(str): 
      i.shunt(token)
    # tidy up
    while i.stack: i.up()
  def __repr__(i)   : return str(i.out)
  def over(i,token) : say("\to\n"); i.out   += token
  def down(i,op)    : say("\td\n"); i.stack += [op]
  def up(i)         : say("\tu\n"); i.out   += [i.stack.pop()] 
  def somethingIsMoreImportant(i,op):
    return i.stack and op.precedence <= i.stack[-1].precedence
  def tokens(i,str): 
    "dumb tokenizer: assumes tokens one char wide)"
    return list(re.sub("[ \t]*","",str)) 
  def shunt(i,token):
    op = isa(token)
    say(token)
    if not op:
      i.over(token)
    else:
      while i.somethingIsMoreImportant(op):
        i.up()
      i.down(op)
  
# demos
@go
def _shunt():
  Op.all = []
  Op('+',1)
  Op('*',2)
  Op('/',2)
  print Shunt("1 + 2")         # 1 2 +
  print Shunt("1 + 2 + 3")     # 1 2 + 3 +
  print Shunt("1 + 2 / 3")     # 1 2 3 / +
  print Shunt("a * b + c / d") # a b * c d / +
  print Shunt("a * b + c * d") # a b * c d * +
  print "\n",Shunt("a+b * c + d")
