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

Resolving a shift/reduce conflict in an LALR parser

我一直在使用ply为我的语言构建一个解析器,但是我有一个移位/减少冲突,这给我带来了一些麻烦。我的语言具有泛型类型,带有语法ALLA C++模板。所以现在我有这样的规则:

1
2
3
4
5
6
    expression : expression LESS expression %prec COMPARISON
    expression : template
    template : NAME
             | NAME LESS templates GREATER
    templates : template
              | templates COMMA template

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

1
a < 2

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

1
2
3
4
5
6
7
8
9
10
11
12
13
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++的系统,但是我认为它仍然是可能的,但是我更喜欢一种局限于语法的解决方案。


yacc解析器并不是特别强大,尝试一个上下文无关的解析可能要求太多。我建议使用某种技巧使yacc的行为像解析上下文相关语法一样,或者,不要试图使用解析器来强制执行每个语法规则。

  • 添加context
    在分析类型时进行识别,设置标志或调用方法将其传递给扫描仪,然后在这种情况下为<>返回不同的终端符号。
  • Simplify grammar
    或者,继续使用统一的表达式/模板语法作为模板生产的一部分,并在代码中错误地删除模板语法以外的任何内容。解析器是系统中功能最差的部分,因此尽可能将工作推送到代码中。(对代码没有限制,对yacc有很多限制。)

我不是说这些是你唯一的选择。如果你花了几天时间在状态表上纠结,把语法调整到Yacc满意的程度,我想你会"成功",但这不值得。此时,您还可以编写一个递归下降解析器。(rd是更多的代码行,你看不到bnfish yacc中整齐排列的语法,但至少你可以解析任何东西,而且你永远不会陷入"它不起作用"的困惑中。)

python有没有与ruby的树梢相当的东西?这就解决了问题。野牛的%glr-parser特性也可以"解决"这样的问题,尽管是以相当于bfi的方式。