#!/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 + ' : ') 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("o"); i.out += token def down(i,op) : say("d"); i.stack += [op] def up(i) : say("u"); 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) 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") print Shunt("1 + 2 + 3") print Shunt("1 + 2 / 3") print Shunt("a * b + c / d") print Shunt("a * b + c * d")