Parsing 解决LALR解析器中的移位/减少冲突

Parsing 解决LALR解析器中的移位/减少冲突,parsing,yacc,lalr,ply,Parsing,Yacc,Lalr,Ply,我一直在使用PLY为我的语言构建一个解析器,但是我遇到了一个shift/reduce冲突,这给我带来了一些麻烦。我的语言具有泛型类型,语法为ALLA C++模板。所以现在我有如下规则: expression : expression LESS expression %prec COMPARISON expression : template template : NAME | NAME LESS templates GREATER tem

我一直在使用PLY为我的语言构建一个解析器,但是我遇到了一个shift/reduce冲突,这给我带来了一些麻烦。我的语言具有泛型类型,语法为ALLA C++模板。所以现在我有如下规则:

    expression : expression LESS expression %prec COMPARISON
    expression : template
    template : NAME
             | NAME LESS templates GREATER
    templates : template
              | templates COMMA template
但是,我发现它无法解析:

a < 2
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'>
PLY:解析调试开始
州:0
堆栈:。
行动:转移和转到状态42
国家:42
堆栈:名称。
措施:移位和转到状态81
州:81
堆栈:无名称。
错误:错误:无名称。
如果需要更多的解析器,我可以提供它。谢谢


编辑:向我建议的一个解决方案是使类型成为它们自己的标记。这需要做一点工作,因为我的语言没有使用预处理器,包括C/C++之类的系统。不过,我认为这仍然是可能的,我更喜欢仅限于语法的解决方案。

Yacc解析器不是特别强大,尝试无上下文解析可能要求太多。我建议使用某种技巧使yacc像解析上下文敏感语法一样工作,或者,不要尝试使用解析器强制执行所有语法规则

  • 添加上下文
    在分析类型时进行识别,设置标志或调用方法将其传达给扫描仪,然后在这种情况下为
    返回不同的终端符号
  • 简化语法
    或者,继续使用统一的表达式/模板语法作为模板生成的一部分,并在代码中删除除模板语法以外的任何内容。解析器是系统中功能最差的部分,因此尽可能将工作转化为代码。(对代码没有限制,对yacc有很多限制。)
我不是说这些是你唯一的选择。如果你花了几天时间对状态表感到困惑,并调整语法,使yacc满意,我想你会“成功”,但这不值得。此时,您可能已经编写了一个递归下降解析器。(RD是更多的代码行,你看不到BNFish yacc中整齐排列的语法,但至少你可以解析任何东西,你永远不会陷入“它不工作”的困惑。)


Python和Ruby有什么等价物吗?这将解决问题。Bison的
%glr解析器
功能也可以“解决”类似的问题,尽管是以一种相当BFI的方式。

不幸的是,如果不使用特定的模板规则,语法将更加模糊,并且在更琐碎的情况下失败。我认为您是对的,我需要添加上下文,这对于简单的情况(内置类型或该文件中定义的类型)来说很容易,但是对于使用导入系统的情况来说很难。哦,好吧:)