我無法將這個EBNF表達式翻譯成Pyparsing,任何想法?Pyparsing中的遞歸
token:: [A-Z]
P:: !|token;P|(P^P)|(P*P)
問題是當使用遞歸時,解釋器失敗。 這樣的表達應該是有效的:
(ASD;!^FFF;!)
A;B;C;!
(((A;!^B;!)^C;D;!)*E;!)
我無法將這個EBNF表達式翻譯成Pyparsing,任何想法?Pyparsing中的遞歸
token:: [A-Z]
P:: !|token;P|(P^P)|(P*P)
問題是當使用遞歸時,解釋器失敗。 這樣的表達應該是有效的:
(ASD;!^FFF;!)
A;B;C;!
(((A;!^B;!)^C;D;!)*E;!)
建設有Pyparsing遞歸語法,你要想到一點由內向外,用pyparsing的正向類。使用轉發,您可以爲稍後定義的表達式定義一個空的佔位符。這是在pyparsing這個BNF開始:
EXCLAM,SEMI,HAT,STAR = map(Literal,"!;^*")
LPAR,RPAR = map(Suppress,"()")
token = oneOf(list(alphas.upper()))
我用文字來定義你的運營商,但抑制分組()的,我們將使用pyparsing組物理組的成果轉化爲子列表。
現在我們定義佔位表達轉發:
expr = Forward()
現在我們可以使用這個佔位符(我們不得不使用「< < =」爲賦值運算符,這樣EXPR保持爲構建表達式轉發,而不是反彈到表達本身)。這是我的第一關,使用您的BNF作爲-是:
expr <<= (EXCLAM |
token + SEMI + expr |
Group(LPAR + expr + HAT + expr + RPAR) |
Group(LPAR + expr + STAR + expr + RPAR))
這給了這些結果:
(ASD;!^FFF;!)
^
Expected ";" (at char 2), (line:1, col:3)
A;B;C;!
['A', ';', 'B', ';', 'C', ';', '!']
(((A;!^B;!)^C;D;!)*E;!)
[[[['A', ';', '!', '^', 'B', ';', '!'], '^', 'C', ';', 'D', ';', '!'], '*', 'E', ';', '!']]
似乎有你的BNF一個不成文的規矩,即一個或多個令牌可以一起被本也容易固定爲:
expr <<= (EXCLAM |
OneOrMore(token) + SEMI + expr |
Group(LPAR + expr + HAT + expr + RPAR) |
Group(LPAR + expr + STAR + expr + RPAR))
現在給出:
(ASD;!^FFF;!)
[['A', 'S', 'D', ';', '!', '^', 'F', 'F', 'F', ';', '!']]
A;B;C;!
['A', ';', 'B', ';', 'C', ';', '!']
(((A;!^B;!)^C;D;!)*E;!)
[[[['A', ';', '!', '^', 'B', ';', '!'], '^', 'C', ';', 'D', ';', '!'], '*', 'E', ';', '!']]
但是看起來我們可以從其他分組中受益,因此二進制「^」和「*」運算符的操作數更加清晰。所以我看中了:
expr <<= (EXCLAM |
Group(OneOrMore(token) + SEMI + ungroup(expr)) |
Group(LPAR + expr + HAT + expr + RPAR) |
Group(LPAR + expr + STAR + expr + RPAR))
而且我覺得這個版本輸出的現在可以更容易地處理:
(ASD;!^FFF;!)
[[['A', 'S', 'D', ';', '!'], '^', ['F', 'F', 'F', ';', '!']]]
A;B;C;!
[['A', ';', 'B', ';', 'C', ';', '!']]
(((A;!^B;!)^C;D;!)*E;!)
[[[[['A', ';', '!'], '^', ['B', ';', '!']], '^', ['C', ';', 'D', ';', '!']], '*', ['E', ';', '!']]]
下面是完整的腳本:
from pyparsing import *
EXCLAM,SEMI,HAT,STAR = map(Literal,"!;^*")
LPAR,RPAR = map(Suppress,"()")
token = oneOf(list(alphas.upper()))
expr = Forward()
expr <<= (EXCLAM |
Group(OneOrMore(token) + SEMI + ungroup(expr)) |
Group(LPAR + expr + HAT + expr + RPAR) |
Group(LPAR + expr + STAR + expr + RPAR))
tests = """\
(ASD;!^FFF;!)
A;B;C;!
(((A;!^B;!)^C;D;!)*E;!)""".splitlines()
for t in tests:
print t
try:
print expr.parseString(t).dump()
except ParseException as pe:
print ' '*pe.loc + '^'
print pe
print
最後需要注意的:我認爲「AAA」是連續3個「A」代幣。如果你的意思是代幣是1個或多個alpha的詞組,那麼把表達式中的'OneOrMore(token)'改爲'Word(alphas.upper())' - 然後你會得到這個結果作爲你的第一個測試用例:
[[['ASD', ';', '!'], '^', ['FFF', ';', '!']]]
這使得Lisp符號工作xD!
from pyparsing import *
def pushFirst(strg, loc, toks):
toks[0][2], toks[0][1] = toks[0][1], toks[0][2]
def parseTerm(term):
"""
EBNF syntax elements
EXCLAM = !
HAT =^
STAR = *
SEMI = ;
LPAR = (
RPAR = )
"""
EXCLAM,HAT,STAR = map(Literal,"!^*")
LPAR,RPAR = map(Suppress,"()")
SEMI = Suppress(";")
token = oneOf(list(alphas.upper()))
expr = Forward()
expr <<= (
EXCLAM |
Group(Word(alphas.upper()) + SEMI + ungroup(expr)) |
Group(LPAR + expr + HAT + expr + RPAR).setParseAction(pushFirst) |
Group(LPAR + expr + STAR + expr + RPAR).setParseAction(pushFirst)
)
try:
result = expr.parseString(term)
except ParseException as pe:
print ' '*pe.loc + '^'
print pe
return result[0]
def computeTerm(term):
print term
term = (parseTerm("(((AXX;!^B;!)^C;D;!)*E;!)"))
computeTerm(term)
好吧,這是蠻力,但看起來你已經超越了pyparsingness的第二級,使用解析操作。祝賀你,並樂於與pyparsing! – PaulMcG
哇,你做到了! 只是,還有一個問題... 我想更新像*和^這樣的二元運算符來作爲前綴符號,比如Lisp。在文檔中有一個使用字符串的例子,但不知道如何將其轉換爲數組。 喜歡的東西: ' 集團(LPAR + EXPR +帽子+ EXPR + RPAR)到 集團(LPAR + EXPR + EXPR +帽子+ RPAR) ' – ccamacho
'EXPR EXPR HAT'聽起來像*後綴*符號給我。這種方式會不會像你一樣工作?如果您希望STAR和HAT具有相同的優先級,請嘗試'Group(LPAR + expr + expr +(STAR | HAT)+ RPAR)'。 – PaulMcG