2012-04-16 74 views
8

我試圖用pyparsing解析形式函數調用:解析嵌套函數調用使用pyparsing

f(x, y) 

這很容易。但由於它是一個遞歸下降解析器,因此它也應該很容易解析:

f(g(x), y) 

這就是我無法得到的。這裏有一個熬濃例如:

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)") 

而這裏的輸出:

['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) 

爲什麼我的解析器解釋內表達的仿函數作爲一個獨立的標識?

回答

4

arg定義應安排與左側與另一啓動項目,所以它是優先匹配:

arg = expression | identifier | integer 
+0

尼斯抓,@Jason! – PaulMcG 2012-04-17 08:36:09

11

尼斯風風火火搞清楚這identifier在您的arg定義屏蔽expression 。以下是解析器中的其他一些提示:

x + ZeroOrMore(',' + x)是pyparsing解析器中非常常見的模式,因此pyparsing包含幫助器方法delimitedList,它允許您用delimitedList(x)替換該表達式。實際上,delimitedList還有另外一件事情 - 它基於分隔符在解析時間時非常有用的概念,抑制分隔逗號(或其他分隔符,如果使用可選delim參數給出的),但在嘗試篩選整個分隔符時之後解析數據。因此,您可以將參數重寫爲args = delimitedList(arg),並且您將只列出參數列表中的所有參數,不必使用逗號來「跳過」。

您可以使用Group類來創建解析令牌中的實際結構。這將會爲您構建您的嵌套層次結構,而不必走這個列表尋找「(」和「)」來告訴你,當你走下來的水平的函數嵌套:

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

由於您的ARGS正在Group版適合你,你可以進一步抑制括號,因爲像劃定逗號,他們在分析過程中做他們的工作,但您的令牌的分組,他們不再是必要的:

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

我認爲' h()'是一個有效的函數調用,只是沒有參數。您可以允許使用ARGS到Optional是可選:

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

現在你可以解析 「F(G(X),Y,H())」。

歡迎來到pyparsing!

+3

感謝所有有用的評論!這個例子實際上是根據pyparsing文檔改編的;我使用了我在實際解析器中描述的大部分技巧。 (並且語言實現現在可以在大約6個小時的工作中使用--- python中的原型製作非常快速。) – JasonFruit 2012-04-17 18:09:44

+0

'Suppress(「(」)'和'Literal(「(」)。suppress( )'? – dashesy 2015-01-21 21:59:35

+1

沒什麼區別,'expr.suppress()'返回'Suppress(expr)',並且如果一個字符串作爲Suppress的初始化符被傳遞,則字符串被提升爲Literal。 – PaulMcG 2015-01-22 01:31:43

0

Paul的帖子幫了很大忙。只是爲他人蔘考,同樣可以被用來定義for loops如下(這裏簡化僞解析器,以顯示結構):

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_