2014-01-26 15 views
8

Pyparsing funktionierte gut für eine sehr kleine Grammatik, aber als die Grammatik wuchs, ging die Leistung und der Speicherverbrauch durch das Dach.pyparsing Leistung und Speichernutzung

Mein aktueller gramar ist:

newline = LineEnd() 
minus = Literal ('-') 
plus = Literal ('+') 
star = Literal ('*') 
dash = Literal ('/') 
dashdash = Literal ('//') 
percent = Literal ('%') 
starstar = Literal ('**') 
lparen = Literal ('(') 
rparen = Literal (')') 
dot = Literal ('.') 
comma = Literal (',') 
eq = Literal ('=') 
eqeq = Literal ('==') 
lt = Literal ('<') 
gt = Literal ('>') 
le = Literal ('<=') 
ge = Literal ('>=') 
not_ = Keyword ('not') 
and_ = Keyword ('and') 
or_ = Keyword ('or') 
ident = Word (alphas) 
integer = Word (nums) 

expr = Forward() 
parenthized = Group (lparen + expr + rparen) 
trailer = (dot + ident) 
atom = ident | integer | parenthized 
factor = Forward() 
power = atom + ZeroOrMore (trailer) + Optional (starstar + factor) 
factor << (ZeroOrMore (minus | plus) + power) 
term = ZeroOrMore (factor + (star | dashdash | dash | percent)) + factor 
arith = ZeroOrMore (term + (minus | plus)) + term 
comp = ZeroOrMore (arith + (eqeq | le | ge | lt | gt)) + arith 
boolNot = ZeroOrMore (not_) + comp 
boolAnd = ZeroOrMore (boolNot + and_) + boolNot 
boolOr = ZeroOrMore (boolAnd + or_) + boolAnd 
match = ZeroOrMore (ident + eq) + boolOr 
expr << match 
statement = expr + newline 
program = OneOrMore (statement) 

Wenn ich analysieren die folgenden

print (program.parseString ('3*(1+2*3*(4+5))\n')) 

Es dauert ziemlich lange:

~/Desktop/m2/pyp$ time python3 slow.py 
['3', '*', ['(', '1', '+', '2', '*', '3', '*', ['(', '4', '+', '5', ')'], ')']] 

real 0m27.280s 
user 0m25.844s 
sys 0m1.364s 

Und die Speichernutzung geht bis zu 1,7 GiB (sic!).

Habe ich einen schwerwiegenden Fehler bei der Implementierung dieser Grammatik gemacht oder wie sonst kann ich die Speichernutzung in erträglichen Grenzen halten?

+0

Gleiche Sache mit lex und yacc in Sekundenbruchteilen. – Hyperboreus

Antwort

11

Nach dem Import pyparsing ermöglicht packrat Parsen Parsen Verhalten memoize:

ParserElement.enablePackrat() 

Dies sollte eine große Verbesserung in der Leistung machen.

+0

Danke, ich werde es versuchen. – Hyperboreus

+1

Für die Aufzeichnung geht das von 3,5 Sekunden auf 0,036 Sekunden auf meinem Computer, fast eine 100-fache Verbesserung. Gibt es einen Grund, warum Memoization nicht automatisch aktiviert wird - schlägt es in einigen Randfällen fehl? – Hooked

+1

@Hooked: Details zu packrat-Parsing mit Pyparssing finden Sie in diesem Artikel in der FAQ zu pyparsing (http://pyparsing-public.wikispaces.com/FAQs#toc3). Siehe auch [this SO thread] (https://stackoverflow.com/q/1410477/857390) für Packat-Parsing im Allgemeinen. –