Created
September 28, 2011 20:59
-
-
Save capttwinky/1249239 to your computer and use it in GitHub Desktop.
an rplish expression parser
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- 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