C Bison移位/减少编程语言语法的冲突

C Bison移位/减少编程语言语法的冲突,c,parsing,bison,yacc,compiler-compiler,C,Parsing,Bison,Yacc,Compiler Compiler,我正在编写一个编程语言解析器,我陷入了这种转换/减少冲突中 下面是parser.output文件中的冲突状态,该文件是通过使用-v运行bison获得的 State 1 24 ident: TIDENT . 26 call: TIDENT . TLPAREN args TRPAREN TLPAREN shift, and go to state 24 TLPAREN [reduce using rule 24 (ident)] $default r

我正在编写一个编程语言解析器,我陷入了这种转换/减少冲突中

下面是parser.output文件中的冲突状态,该文件是通过使用-v运行bison获得的

State 1

   24 ident: TIDENT .
   26 call: TIDENT . TLPAREN args TRPAREN

    TLPAREN  shift, and go to state 24

    TLPAREN   [reduce using rule 24 (ident)]
    $default  reduce using rule 24 (ident)
冲突发生在我尝试实现调用规则时,它似乎与正常的ident规则冲突

这里是语法的一些部分,(为了简单起见,删除了一些动作,但不需要它们。另外,我不确定规则的定义顺序是否重要,如果我错了,请纠正我)

(大写字母是代币)

ident规则很简单

ident: TIDENT
          ;
Args,由call使用

args: /* empty */
        |
        expr
        |
        args TCOMMA expr
        ;
调用函数的调用

call:
       TIDENT TLPAREN args TRPAREN
       ;
表达式的表达式

expr:
    number
    |
    ternary
    |
    bool
    |
    string
    |
    ident
    |
    call
    |
    TLPAREN expr TRPAREN
    |
    expr TPLUS expr
    |
    expr TMINUS expr
    |
    expr TSLASH expr
    |
    expr TSTAR expr
    |
    expr TGT expr
    |
    expr TGE expr
    | 
    expr TLT expr
    |
    expr TLE expr
    ;
问题是:为什么语法有移位/减少冲突,你如何解决它?我见过类似样式的解析器,它们没有冲突,这真的很奇怪

如果您需要查看复制的完整语法,这里有一个hastebin


如果您需要有关其他任何内容的更多详细信息,请在注释中告诉我,我将相应地编辑问题。

问题是,当解析器移动了一个TIDENT标记并向前看一个
TLPAREN
标记时,语法允许两种选择:

  • TIDENT
    减少为
    ident
    ,或
  • TLPAREN
    移动
  • Bison通常会通过选择轮班来解决轮班/减少冲突,如果在这种情况下这是您想要的,那么您可以忽略警告

    但是,在这种特殊情况下,您应该能够通过更改
    调用的规则来解决冲突
    生产:

    call:
           ident TLPAREN args TRPAREN
           ;
    
    根据该规则,如果不先将
    TIDENT
    减少为
    ident
    ,则将
    TLPAREN
    切换为


    可选地,您可以考虑完全删除<代码> IDON/CONT>非终结符,而直接使用<代码> TeTunt,直接在您现在使用“代码> IDN/CODE >的地方。也许还有其他选择。哪种方法最适合你可能取决于你试图用你的语义动作做什么。我无法对此做出更具体的评论,因为您选择了不考虑语义操作。

    问题是,当解析器移动了一个TIDENT标记并向前看一个
    TLPAREN
    标记时,语法允许两种选择:

  • TIDENT
    减少为
    ident
    ,或
  • TLPAREN
    移动
  • Bison通常会通过选择轮班来解决轮班/减少冲突,如果在这种情况下这是您想要的,那么您可以忽略警告

    但是,在这种特殊情况下,您应该能够通过更改
    调用的规则来解决冲突
    生产:

    call:
           ident TLPAREN args TRPAREN
           ;
    
    根据该规则,如果不先将
    TIDENT
    减少为
    ident
    ,则将
    TLPAREN
    切换为


    可选地,您可以考虑完全删除<代码> IDON/CONT>非终结符,而直接使用<代码> TeTunt,直接在您现在使用“代码> IDN/CODE >的地方。也许还有其他选择。哪种方法最适合你可能取决于你试图用你的语义动作做什么。我无法对此做出更具体的评论,因为您选择了不考虑语义操作。

    Bison默认生成一个LR解析器,它是一个自底向上的解析器,可以决定是否移动或减少标记的每个状态

    冲突非常简单,输出本身也能很好地解释(我不知道还有什么不清楚),它告诉你:

    如果我找到了一个
    标识符
    ,我应该通过规则24将其减少为
    标识符
    非终端,还是应该像
    调用
    规则那样移动它

    这是因为一旦减少了,你就不能转移,反之亦然,这确实造成了冲突

    要解决冲突,您需要在解析器的相同状态下移动该选择,以便它能够根据上下文进行决定

    由于
    ident
    只有一个终端
    ident
    规则,同样适用于呼叫,因此您可以轻松地将所有内容移动到同一级别,使其始终移动:

    expr: 
      IDENT | 
      IDENT LPAREN args RPAREN |
      ...
    

    或者对
    call
    expr
    本身使用相同的
    ident
    非终端,这样它将始终减少它。

    Bison默认生成一个LR解析器,它是一个自底向上的解析器,可以决定是否移动令牌或减少令牌

    冲突非常简单,输出本身也能很好地解释(我不知道还有什么不清楚),它告诉你:

    如果我找到了一个
    标识符
    ,我应该通过规则24将其减少为
    标识符
    非终端,还是应该像
    调用
    规则那样移动它

    这是因为一旦减少了,你就不能转移,反之亦然,这确实造成了冲突

    要解决冲突,您需要在解析器的相同状态下移动该选择,以便它能够根据上下文进行决定

    由于
    ident
    只有一个终端
    ident
    规则,同样适用于呼叫,因此您可以轻松地将所有内容移动到同一级别,使其始终移动:

    expr: 
      IDENT | 
      IDENT LPAREN args RPAREN |
      ...
    

    或者对
    call
    expr
    本身使用相同的
    ident
    非终结符,以便始终减少它。

    这里的基本问题是语法不明确,因为语句不需要终止(
    stmts:stmts stmt
    ),并且语句可以是表达式。因此,两个表达式可以在没有任何标点的情况下一个接一个地出现。这意味着
    f(3)
    可以是一个表达式(函数调用)或两个表达式(
    f
    (3)

    如果您很高兴解析器总是将其解释为函数调用(这是它的默认行为,因为它更喜欢移位),那么您可以只添加两个优先级d