使用递归语法进行 pyparsing
pyparsing with a recursive grammar
我无法使用 pyparsing 正确解析递归语法。下面代码中的测试 #5 失败了,尽管我认为它会将它识别为 "param" 解析器的三个匹配项(其中两个嵌套在一个 "parent" 下):
import pyparsing as p
DOUBLE_QUOTE = p.Word('"')
SINGLE_QUOTE = p.Word("'")
COMMA = p.Suppress(p.Word(","))
EQUALS = p.Suppress(p.Word("="))
RIGHT_PAREN = p.Suppress(p.Word(")"))
LEFT_PAREN = p.Suppress(p.Word("("))
WORD = p.Word(p.alphanums + '<' + '<' + '>' + '/' + '.' + ':' + \
';' + '-' + '_' + '$' + '+' + '*' + '&' + '!' + '%' + '?' + '@' + '\')
QUOTED_STRING = p.QuotedString("'") | p.QuotedString('"')
value = WORD | QUOTED_STRING
value_list = value + p.ZeroOrMore(COMMA + value)
keyword = WORD
pv1 = value
pv2 = (LEFT_PAREN + value_list + RIGHT_PAREN)
pv3 = p.Forward()
param = keyword + EQUALS + p.Group(p.OneOrMore(pv3) | pv2 | pv1)
pv3 << (LEFT_PAREN + param + RIGHT_PAREN)
parser = p.OneOrMore(p.Group(param))
tests = []
tests.append("""l1=v1""")
tests.append("""l1=(v1,v2,v3)""")
tests.append("""l1=(v1,v2,v3) l1=(v4, v5, v6)""")
tests.append("""l1=(l2=v1)""")
tests.append("""l1=v1 l1=v2""")
# This test fails
tests.append("""l1=(l2=(l3=v1))""")
results = []
for (i, test_string) in enumerate(tests):
try:
results.append(parser.parseString(test_string))
except Exception as e:
print("Failed test #{}".format(i))
print(e)
我哪里错了?
我在检查你的递归是否正确时花了一些时间才弄明白这个问题。但事实证明你的代码很好,除了代码顶部的 2 行代码(我假设已更正)
错误是由于您使用 p.Word
而不是 p.Literal
设置括号造成的。因此,通过将您的代码更改为它应该可以工作:
RIGHT_PAREN = p.Suppress(p.Literal(")"))
LEFT_PAREN = p.Suppress(p.Literal("("))
来自 PyParsing wiki 的提示:
Literal - construct with a string to be matched exactly
Word - one or more contiguous characters; construct with a string containing the set of allowed initial characters, and an optional second string of allowed body characters;
我无法使用 pyparsing 正确解析递归语法。下面代码中的测试 #5 失败了,尽管我认为它会将它识别为 "param" 解析器的三个匹配项(其中两个嵌套在一个 "parent" 下):
import pyparsing as p
DOUBLE_QUOTE = p.Word('"')
SINGLE_QUOTE = p.Word("'")
COMMA = p.Suppress(p.Word(","))
EQUALS = p.Suppress(p.Word("="))
RIGHT_PAREN = p.Suppress(p.Word(")"))
LEFT_PAREN = p.Suppress(p.Word("("))
WORD = p.Word(p.alphanums + '<' + '<' + '>' + '/' + '.' + ':' + \
';' + '-' + '_' + '$' + '+' + '*' + '&' + '!' + '%' + '?' + '@' + '\')
QUOTED_STRING = p.QuotedString("'") | p.QuotedString('"')
value = WORD | QUOTED_STRING
value_list = value + p.ZeroOrMore(COMMA + value)
keyword = WORD
pv1 = value
pv2 = (LEFT_PAREN + value_list + RIGHT_PAREN)
pv3 = p.Forward()
param = keyword + EQUALS + p.Group(p.OneOrMore(pv3) | pv2 | pv1)
pv3 << (LEFT_PAREN + param + RIGHT_PAREN)
parser = p.OneOrMore(p.Group(param))
tests = []
tests.append("""l1=v1""")
tests.append("""l1=(v1,v2,v3)""")
tests.append("""l1=(v1,v2,v3) l1=(v4, v5, v6)""")
tests.append("""l1=(l2=v1)""")
tests.append("""l1=v1 l1=v2""")
# This test fails
tests.append("""l1=(l2=(l3=v1))""")
results = []
for (i, test_string) in enumerate(tests):
try:
results.append(parser.parseString(test_string))
except Exception as e:
print("Failed test #{}".format(i))
print(e)
我哪里错了?
我在检查你的递归是否正确时花了一些时间才弄明白这个问题。但事实证明你的代码很好,除了代码顶部的 2 行代码(我假设已更正)
错误是由于您使用 p.Word
而不是 p.Literal
设置括号造成的。因此,通过将您的代码更改为它应该可以工作:
RIGHT_PAREN = p.Suppress(p.Literal(")"))
LEFT_PAREN = p.Suppress(p.Literal("("))
来自 PyParsing wiki 的提示:
Literal - construct with a string to be matched exactly
Word - one or more contiguous characters; construct with a string containing the set of allowed initial characters, and an optional second string of allowed body characters;