【问题标题】:Solve conflict shift/reduce with simple calculator grammar用简单的计算器语法解决冲突转移/减少
【发布时间】:2012-10-25 12:02:29
【问题描述】:

您好,我刚刚开始在 bison/yacc 中进行一些解析。现在我的第一个程序已经失败了。什么地方出了错?我正在使用以下示例: original source of tutorial

%{
    #include <stdio.h>
    int yylex(void);
    void yyerror(char *);
%}


%token INTEGER

%%

program:
        program expr '\n'         { printf("%d\n", $2); }
        | 
        ;

expr:
        INTEGER                   { $$ = $1; }
        | expr '+' expr           { $$ = $1 + $3; }
        | expr '-' expr           { $$ = $1 - $3; }
        ;

%%

void yyerror(char *s) {
    fprintf(stderr, "%s\n", s);
}

int main(void) {
    yyparse();
    return 0;
}

使用 2.4.1 版的 bison 我收到此错误:

conflicts: 4 shift/reduce

【问题讨论】:

标签: bison yacc


【解决方案1】:

试试看:

expr:
    INTEGER                   { $$ = $1; }
    | expr '+' INTEGER           { $$ = $1 + $3; }
    | expr '-' INTEGER           { $$ = $1 - $3; }

bison/yacc 不喜欢右递归。如果输入是1+2+3,则当解析器到达1+2+ 时,它无法决定将1+2 减少为expr 或转移另一个令牌以将2+3 减少为expr。通过在右侧指定INTEGER,它可以决定一看到1+2就减少,只留下expr + 3,然后再次减少。

您还可以通过指定 +- 保持关联来解决此问题,从而将减少 1+2 的优先级高于移动新令牌。在序言中添加该行:

%left '+' '-'

希望对你有帮助。

【讨论】:

  • 感谢您的回答。我只是自己想通了。它让我更加清楚。
  • Bison 的右递归没有问题。如果你想要一个右关联 = 运算符,你可以使用 expr : INTEGER '=' expr;;没关系。问题是当你在 both 两边都有expr 时;那么语法是模棱两可的。正如您所说,您可以通过优先声明来解决歧义。
  • “不喜欢右递归”在这里无关紧要。它们都支持,但在考虑堆栈空间时更喜欢左递归(这里不是这种情况)。这里的问题是语法模棱两可,并没有说“1-2-3”是“(1-2)-3”还是“1-(2-3)”。当然%left '-'是做的权利,但这与Bison喜不喜欢无关。
  • 我说 OP 正在“开始”使用 yacc,我说“喜欢”是为了给他一个简单的规则可以遵循,该规则适用于所有用例的 90%。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-03
  • 1970-01-01
相关资源
最近更新 更多