解决LALR解析器中的shift / reduce冲突

时间:2009-11-27 17:42:36

标签: parsing yacc lalr ply

我一直在使用PLY为我的语言构建一个解析器,但是我有一个转移/减少冲突,这让我有些麻烦。我的语言具有泛型类型,其语法为ala C ++模板。所以现在我有这样的规则:

    expression : expression LESS expression %prec COMPARISON
    expression : template
    template : NAME
             | NAME LESS templates GREATER
    templates : template
              | templates COMMA template

但是,我发现它无法解析:

a < 2

(这是一个明显原因的问题)。以下是调试输出:

PLY: PARSE DEBUG START

State  : 0
Stack  : . <Token: 'NAME' 'a'>
Action : Shift and goto state 42

State  : 42
Stack  : NAME . <Token: 'LESS' '<'>
Action : Shift and goto state 81

State  : 81
Stack  : NAME LESS . <Token: 'NUMBER' '2'>
ERROR: Error  : NAME LESS . <Token: 'NUMBER' '2'>

如果需要更多我的解析器,我可以提供它。感谢。

编辑:向我建议的一个解决方案是将类型设为自己的令牌。这需要一点点工作,因为我的语言没有使用预处理器包括像C / C ++这样的系统,但是我认为它仍然是可能的,但我更喜欢限制语法的解决方案。

1 个答案:

答案 0 :(得分:1)

Yacc解析器并不是特别强大,并且尝试无上下文解析可能会对它提出太多要求。我建议使用某种技巧来使yacc像解析上下文敏感语法一样,或者,不要尝试使用解析器来强制执行每个语法规则。

  • 添加上下文
    识别解析类型时,设置标志或调用方法将其传达给扫描程序,然后为{{1}返回不同的终端符号在这种情况下和<
  • 简化语法
    或者,继续使用统一的表达式/模板语法进行部分模板制作,并在代码中输出除模板语法之外的任何内容。解析器是系统中功能最少的部分,因此尽可能将工作推送到代码中。 (代码没有限制,对yacc有很多限制。)

我不是说这些是你唯一的选择。如果你花费数天时间在状态表上迷惑并将语法调整到yacc对它感到满意的程度,我想你会“成功”,但这不值得。那时你也可以写一个递归下降解析器。 (RD是更多的代码行,你不会看到BNFish yacc中整齐排列的语法,但至少你可以解析任何东西,你永远不会陷入“它不起作用”的难题。)

Python是否与Ruby的Treetop等效?那样可以解决问题。 Bison的>功能也可以“解决”这样的问题,尽管是以相当的BFI方式。