Pyparsing 中的递归文法
Recursive Grammar in Pyparsing
我有以下类似 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) )
代码运行良好。我的问题是:
- 它们看起来一样吗?
- 如果是这样,为什么第一种形式在 pyparsing 中不起作用?
- pyparsing 是否支持所有 BNF 语法?
aerofValues << Dict((aerofPair | aerofBlock |
(aerofPair + aerofValues) | (aerofBlock + aerofValues)))
因为“|”解析为 MatchFirst 表达式,匹配的第一个列出的表达式将用于匹配。如果我将整数列表定义为:
integer_list <<= (integer | integer + integer_list)
并尝试解析“1 2 3 4”,我们的 integer_list 将通过仅匹配前导“1”来满足。更改为:
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 不会像您在正则表达式中看到的那样进行回溯。
我有以下类似 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) )
代码运行良好。我的问题是:
- 它们看起来一样吗?
- 如果是这样,为什么第一种形式在 pyparsing 中不起作用?
- pyparsing 是否支持所有 BNF 语法?
aerofValues << Dict((aerofPair | aerofBlock |
(aerofPair + aerofValues) | (aerofBlock + aerofValues)))
因为“|”解析为 MatchFirst 表达式,匹配的第一个列出的表达式将用于匹配。如果我将整数列表定义为:
integer_list <<= (integer | integer + integer_list)
并尝试解析“1 2 3 4”,我们的 integer_list 将通过仅匹配前导“1”来满足。更改为:
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 不会像您在正则表达式中看到的那样进行回溯。