Skip to content

Instantly share code, notes, and snippets.

@capttwinky
Created September 28, 2011 20:59
Show Gist options
  • Save capttwinky/1249239 to your computer and use it in GitHub Desktop.
Save capttwinky/1249239 to your computer and use it in GitHub Desktop.
an rplish expression parser
# -*- coding: latin-1 -*-
from decimal import Decimal
import re
import operator as op
d = lambda n: Decimal(n)
lstFns=['+','-','*','/']
dictFns=dict(zip(lstFns,[op.__add__,op.__sub__,op.__mul__,op.__truediv__]))
printDebug = False
def dprint(thingIn):
if printDebug:
print "%r"%thingIn
class rplParse(object):
"""parser for rpl strings
rplstring := () denotes a list
all lists must have two elements
element := another list, a function or a digit
function := +, -, * and / := true div
"""
def __init__(self, strRpl):
self.parseTree = myTree()
self.parseRPL(re.split(r'(\w+)',strRpl))
def parseRPL(self, rplIn):
if not rplIn:
return
car, cdr = rplIn[0], rplIn[1:]
myD = isDec(car)
if myD and not myD.isdigit(): # == False:
for myC in car:
self.buildTree(myC)
else:
self.parseTree.data(myD)
self.parseRPL(cdr)
def buildTree(self, cIn):
if cIn == '(':
self.parseTree.start()
elif cIn == ')':
self.parseTree.stop()
elif cIn in lstFns:
self.parseTree.data(dictFns.get(cIn,None))
elif cIn.isdigit():
print cIn
raise Exception("digits!!!")
elif cIn != ",":
raise Exception("extraInfo: %s"%cIn)
def renderCalc(self):
return renderCalc(self.parseTree())
def renderCalc(treeIn):
if len(treeIn) != 2:
dprint("\n!!!!%i\n"%len(treeIn))
for myThing in treeIn:
dprint("\t@%s"%myThing)
raise Exception("list with len != 2: %s"%treeIn)
tree1 = list(treeIn)
for myI, myBranch in enumerate(treeIn):
if isIter(myBranch):
tree1[myI] = renderCalc(myBranch)
myTypes = [type(myThing) for myThing in tree1]
myFn = myTypes.count(type(dir))
if myFn:
dprint("found fn")
xForm = tree1.pop(myTypes.index(type(dir)))
target = tree1.pop()
if isIter(target):
dprint('isitr')
target = renderCalc(target)
dprint(type(target))
myRet = reduce(xForm, target)
else:
try:
myRet = [d(myBranch) for myBranch in tree1]
except:
dprint("%r"%treeIn)
dprint("%r"%myTypes)
raise
dprint("MYRET: %r"%myRet)
return myRet
class myTree:
def __init__(self):
self.root = []
self.curBranch = self.root
self.stack = []
def start(self):
self.curBranch.append([])
self.stack.append(self.curBranch)
self.curBranch = self.curBranch[-1]
def stop(self):
parent = self.stack.pop()
self.curBranch = parent
def data(self, dIn):
if not dIn: dIn = '0'
self.curBranch.append(dIn)
def __call__(self):
return self.curBranch[0]
def __repr__(self):
return "%r"%self.curBranch[0]
def isIter(myIn):
return hasattr(myIn, '__iter__')
def isDec(myIn):
try:
myRet = filter(lambda x:d(x), myIn)
except Exception as e:
myRet = myIn
#if myIn == '0': myRet = 0
return myRet
def rplSolver(rplString):
try:
myParse = rplParse(rplString)
except Exception as e:
print "tree not made: %s"%e
raise e
try:
return myParse.renderCalc()
except Exception as e:
print "parsecalc didn't work: %s"%e
print "%r"%myParse.parseTree
raise e
def myTests():
import sys
rplStrings = [
("(*((+((+(2,2))(-(13,8))))(/(36,6))))",54),
('(*((+(2,2))(+(3,3))))',24),
("(+(4(*(2,8))))",20),
("(+((+(2,2))2))",6),
("(+((+(2,3))0))", 5)
]
for rplString, myResponse in rplStrings:
myTotal = rplSolver(rplString)
try:
assert myTotal==myResponse, "bad calculation, %s != %s"%(myTotal, myResponse)
except Exception as e:
raise
print "'%s' = %i"%(rplString,myTotal)
if __name__ == '__main__':
import sys
try:
myTotal = rplSolver(sys.argv[1])
print myTotal
except:
myTests()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment