我有以下类似JSON的递归语法:
aerof_bnf_spec = """
inputfile
block
block inputfile
block
under key { values }
values
key = value;
key = value; values
block
block values
key
string
value
string
real
int
"""
LBRACK, RBRACK, LBRACE, RBRACE, EQUAL, SEMICOLON = map(Suppress, "[]{}=;")
TAG = Suppress("under")
caps = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
lowers = caps.lower()
digits = "0123456789"
# define value
aerofNumber = pyparsing_common.number()
aerofFilePath = dblQuotedString().setParseAction(removeQuotes)
aerofString = Word(caps + lowers + digits)
aerofValue = (aerofNumber | aerofFilePath | aerofString)
# define key
aerofKey = Word(caps + lowers + digits)
# define key = value;
aerofPair = Group(aerofKey + EQUAL + aerofValue + SEMICOLON)
#define values and block recursively
aerofBlock = Forward()
aerofValues = Forward()
aerofBlock << Group(TAG + aerofKey + LBRACE + aerofValues + RBRACE)
aerofValues << Dict((aerofPair | aerofBlock) + ZeroOrMore(aerofValues) )
# define inputfile
aerofInputFile = Dict(OneOrMore(aerofBlock))
# remove comment
aerofComment = cppStyleComment
aerofInputFile.ignore(aerofComment)
我从
改变aerofValues << Dict((aerofPair | aerofBlock | (aerofPair + aerofValues)|(aerofBlock + aerofValues)) )
到
aerofValues << Dict((aerofPair | aerofBlock) + ZeroOrMore(aerofValues) )
代码工作正常。我的问题是:
答案 0 :(得分:1)
aerofValues << Dict((aerofPair | aerofBlock |
(aerofPair + aerofValues) | (aerofBlock + aerofValues)))
因为&#39; |&#39;解析为MatchFirst表达式,匹配的第一个列出的表达式将用于匹配。如果我将整数列表定义为:
integer_list <<= (integer | integer + integer_list)
并尝试解析&#34; 1 2 3 4&#34;,只需匹配前导&#39; 1&#39;即可满足我们的integer_list。改为:
integer_list <<= (integer + integer_list | integer)
现在让我们首先尝试整数列表,如果找不到多个整数,那么看看是否只存在一个整数。但我建议用pyparsing实现这个:
integer_list = OneOrMore(integer)
所以你的陈述非常接近等价,我认为第一个陈述如果重新排序到:
aerofValues << Dict(((aerofPair + aerofValues) | (aerofBlock + aerofValues) | aerofPair | aerofBlock) )
或者只是:
aerofValues << Dict(OneOrMore(aerofPair | aeroOfBlock))
Pyparsing几乎支持任何BNF语法,只要你不包含左递归。 Pyparsing会炸掉这个表达式:
integer_list <<= (integer_list + integer | integer)
默认情况下,pyparsing本身不做任何预测,但您可以使用NotAny
(或运算符'~'
)和FollowedBy
来指定前瞻。
此外,正如您在正则表达式中看到的那样,pyparsing不会进行回溯。