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

代码运行良好。我的问题是:

  1. 它们看起来一样吗?
  2. 如果是这样,为什么第一种形式在 pyparsing 中不起作用?
  3. 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 不会像您在正则表达式中看到的那样进行回溯。