由多次出现的解析项YACC-PLY引起的无限递归

时间:2013-08-02 09:15:52

标签: python yacc ply

我正在处理一个Yacc(一个ply)并且我不知道如何在不使程序因无限递归而崩溃的情况下更多地出现解析项。 假设我有:

def p_Attribute(p):
    ''' Attribute : STRING
                  | NUMBER 
                  | Attribute
                  | empty '''
[do stuff] 

注:的 问题类似于:Python PLY zero or more occurrences of a parsing item但是提出的解决方案不起作用,我总是有无限的递归。

1 个答案:

答案 0 :(得分:1)

这里的问题实际上就是你的语法。类Yacc解析器不适用于这种规则,因为它需要减少属性以减少属性,因此无限递归。 (编辑以添加注释:如果右手Attribute需要一些非空的非模糊标记,例如Attribute : STRING | NUMBER | '$' Attribute | empty可解析并且允许任意数量的$标记,那就没关系在其他可接受的Attribute之前。但实际上,Attributeempty这两个选项都可以完全为空。这是一个减少/减少冲突,它在这里解决得很厉害。我认为减少/减少冲突可能会“按照需要”解决,如果你先把空规则放在首位 - 但这仍然是“错误的方法”,一般而言。)

大概你想要三件事之一(但不确定哪一个,所以想象一下解析器生成器的混乱:-)):

  • 零个或多个序列中的属性(相当于类似regexp的“x *”)
  • 序列中的一个或多个属性(相当于类似regexp的“x +”)
  • 零或一个属性,但不多(相当于类似regexp的“x?”)

对于所有这三个方面,一般来说,你应该首先定义一个非终端,它只能识别一个有效的属性,例如:

Exactly_One_Attribute : STRING | NUMBER

(我将在下面拼写Attribute。)

然后定义一个规则,接受您要为序列(或optional-attribute)允许的内容。例如:

Zero_Or_More_Attributes : Zero_Or_More_Attributes Attribute | empty

(这使用“左递归”,这应该是最有效的。使用正确的递归 - 见下面 - 如果你真的想要识别其他顺序的项目。)

要求至少一个属性:

One_Or_More_Attributes: One_Or_More_Attributes Attribute | Attribute

(在此示例中也是左递归),或:

Attribute_opt : empty | Attribute

允许“无”(空)或恰好一个属性。


右递归版本只是:

Zero_Or_More_Attributes : Attribute Zero_Or_More_Attributes | empty

作为一般规则,当使用正确的递归时,解析器必须“移动”(推入其解析堆栈)更多的令牌。最终解析器会遇到一个不符合规则的令牌(在这种情况下,不是STRINGNUMBER),然后它可以使用右递归规则开始减少每个移位的令牌,工作在STRING - 和 - NUMBER从右到左。使用左递归,它可以更早地进行减少,从左到右工作。看到 http://www.gnu.org/software/bison/manual/html_node/Algorithm.html#Algorithm了解更多信息。