2012-04-16 21 views
8

pyparsing kullanarak çağırır. Bir özyinelemeli-iniş ayrıştırıcı beri Ama, aynı zamanda ayrıştırmak için kolay olmalıdır:Ayrıştırma iç içe fonksiyon Ben fonksiyon şeklinde çağrıları ayrıştırmak için <code>pyparsing</code> kullanmaya çalışıyorum

Ben alamıyorum ne
f(g(x), y) 

. İşte haşlanmış aşağı örnek:

from pyparsing import Forward, Word, alphas, alphanums, nums, ZeroOrMore, Literal 

lparen = Literal("(") 
rparen = Literal(")") 

identifier = Word(alphas, alphanums + "_") 
integer = Word(nums) 

functor = identifier 

# allow expression to be used recursively 
expression = Forward() 

arg = identifier | integer | expression 
args = arg + ZeroOrMore("," + arg) 

expression << functor + lparen + args + rparen 

print expression.parseString("f(x, y)") 
print expression.parseString("f(g(x), y)") 

Ve burada çıkış var:

['f', '(', 'x', ',', 'y', ')'] 
Traceback (most recent call last): 
    File "tmp.py", line 14, in <module> 
    print expression.parseString("f(g(x), y)") 
    File "/usr/local/lib/python2.6/dist-packages/pyparsing-1.5.6-py2.6.egg/pyparsing.py", line 1032, in parseString 
    raise exc 
pyparsing.ParseException: Expected ")" (at char 3), (line:1, col:4) 

neden ayrıştırıcı tek başına bir tanımlayıcı olarak iç ifadesinin functor yorumlamak geliyor?

cevap

4

arg tanımı solda başka başlar öğe ile düzenlenmelidir, bu yüzden tercihli eşleştirilir:

arg = expression | identifier | integer 
+0

Güzel yakalamak, @Jason! – PaulMcG

11

Nice catch identifierarg tanımına içinde expression maskeleme olduğunu bulmaktan üzerinde . İşte ayrıştırıcı diğer bazı ipuçları verilmiştir:

x + ZeroOrMore(',' + x) pyparsing ayrıştırıcıları çok yaygın desen, yani pyparsing sen delimitedList(x) o ifadeyi değiştirmek için izin veren bir yardımcı yöntemi delimitedList içerir. Aslında, delimitedList başka bir şey yapar - sınırlayıcıların ayrıştırma zamanında yararlı olduğu fikrine dayanarak sınırlayıcı virgülleri (veya isteğe bağlı delim argümanı kullanılarak verilirse başka bir sınırlayıcıyı) bastırır, ancak yalnızca elemeyi yapmaya çalışırken dağınık tokenlardır daha sonra verileri ayrıştırdı. Böylece, args = delimitedList(arg) olarak args yeniden yazabilirsiniz, ve bir listede sadece args alırsınız, hiçbir "üstesinden gelmek" zorunda kalmazsınız.

Parçalı belirteçlerinizde gerçek yapı oluşturmak için Group sınıfını kullanabilirsiniz. senin args yana

arg = Group(expression) | identifier | integer 
expression << functor + Group(lparen + args + rparen) 

: Bu fonksiyon yuvalama bir seviyeye aşağı gidince söylemek '(' ve ')' arayan bu liste yürütmek zorunda kalmadan, sizin için yuvalama hiyerarşisini inşa edecek '

lparen = Literal("(").suppress() 
rparen = Literal(")").suppress() 

Ben varsayalım: sizin için Group ed ediliyor sınırlayan virgül gibi, onlar ayrıştırma sırasında işlerini yapmak beri, daha fazla, parens bastırmak olabiliriz ancak jeton gruplama ile, artık gerekli h() 'geçerli bir işlev çağrısıdır, sadece bir hata yok. Sen args Optional kullanarak isteğe bağlı olarak izin verebilir:

expression << functor + Group(lparen + Optional(args) + rparen) 

Şimdi ayrıştırmak olabilir "f (g (x), y sa())".

Püskürtme işlemine hoş geldiniz!

+3

Tüm yararlı yorumlar için teşekkürler!Bu örnek aslında püskürme belgelerinden uyarlanmıştır; Gerçek ayrıştırıcımda anlattığınız tekniklerin çoğunu kullanıyorum. (Ve dil uygulama şimdi yaklaşık 6 saat içinde kullanılabilir Python içinde pyparsing ile prototipleme şaşırtıcı derecede hızlıdır.) – JasonFruit

+0

Suppress ("(") 've' Literal ("(").) '? – dashesy

+1

Herhangi bir fark yok.' Expr.suppress() '' Supres (expr) 'döndürür ve bir dize Bastırma için başlatıcı olarak iletilirse, dize bir Literal'a yükseltilir. – PaulMcG

0

Paul'ün mesajı çok yardımcı oldu. Sadece başkalarının başvuru için, aynı aşağıdaki gibi (burada basitleştirilmiş sözde ayrıştırıcı yapısını göstermek için,) for loops tanımlamak için kullanılabilir:

sep = Literal(';') 
if_ = Keyword('if') 
then_ = Keyword('then') 
elif_ = Keyword('elif') 
end_ = Keyword('end') 

if_block = Forward() 
do_block = Forward() 

stmt = other | if_block 
stmts = OneOrMore(stmt +sep) 

case = Group(guard +then_ +stmts) 
cases = case +OneOrMore(elif_ +case) 

if_block << if_ +cases +end_