Python lrparsing模块;无法解析简单的递归语法

expr = Ref('expr')
block = '{' + Repeat(expr) + '}'
expr = block | Token(re='[0-9]')
START = expr

这是使用Python的lrparsing模块的语法.该模块报告语法中没有冲突.

它无法解析带有错误的字符串{{0}}
lrparsing.ParseError:第1行第5列:在尝试匹配状态11中的块时期望__end_of_input__时得到’}’

堆栈状态一步一步是:

shift  '{'; ItemSet:5='{'
shift  '{'; ItemSet:5='{' ItemSet:5='{'
shift  /[0-9]/; ItemSet:4=/[0-9]/ ItemSet:5='{' ItemSet:5='{'
reduce '}'; ItemSet:4=/[0-9]/ -- ItemSet:7=expr ItemSet:5='{' ItemSet:5='{'
reduce '}'; ItemSet:7=expr -- ItemSet:9=expr ItemSet:5='{' ItemSet:5='{'
shift  '}'; ItemSet:11='}' ItemSet:9=expr ItemSet:5='{' ItemSet:5='{'

哪个afaik意味着它正在移动{{0,然后看到}将0减少到expr,然后再次减少}而没有先移动它,这使bajeezus混淆了我.

这是一个错误,还是我在做一些无限简单和愚蠢的事情?

如果这是我的语法,我将如何重构它以满足我永恒的热情和热情的欲望?如果这是一个错误,有人可以指导我一个python模块,其语法与lrparsing最相似吗?

编辑:
重构为:

blocks = Ref('blocks')
block = Ref('block')
expr = Ref('expr')
blocks = blocks + block | THIS*0 # THIS*0 is the idiomatic way of getting the empty string
block = '{' + expr + '}'
expr = blocks | Token(re='[0-9]')
START = expr

允许正确的解析.我现在的问题是……为什么?我觉得lrparsing会早些时候向我抱怨任何解析问题……重复是不是按照我期望的方式工作?

最佳答案 lrparsing有一个bug;它没有正确考虑递归重复.

您的实际问题可以通过简单的递归来解决,就像您在扩展编辑中所做的那样,尽管杂乱少一点.

block = Ref('block')
block = '{' + block + '}' | Token(re='[0-9]')
START = block

另请注意,您的原始语法允许输入{{0 {1}}}. (原因是可重复的部分可以扩展为简单的数字或再次扩展.)考虑到你的第二个语法,你可能不希望这样.

我确实用pyparsing完成了一些工作,但语法却大相径庭.类似的例子:

from pyparsing import Forward, Literal, nums, oneOf, Word

l = lambda c: Literal(c).suppress()
block = Forward()
block << (Word(nums, exact=1) ^ l('{') + block + l('}'))
print(block.parseString("{{0}}"))

输出:

['0']

希望有所帮助.

点赞