转移/减少冲突yacc

时间:2009-11-14 18:41:36

标签: c parsing yacc

请参阅以下yacc代码。 如果我删除生产要素:'!' expr,解析冲突消失了。 这里发生了什么?

%{
#include <stdio.h>
#include <ctype.h>

%}


%token TRUE
%token FALSE


%%
line    : line expr '\n'    {   printf("%d\n", $2); }
    | line '\n'
|
;
expr    :   expr "or" term  {   printf("expr : expr or term\n"); $$ = $1 | $3; }
|   term        {   printf("expr : term\n");     }
;
term    :   term "and" factor   {   printf("term : term and factor\n"); $$ = $1 & $3; }
|   factor      {   printf("term : factor\n");  }
;
factor  :   '(' expr ')'    {   printf("factor : (expr)\n"); $$ = $2; }
|   '!' expr    {   printf("factor : !expr\n"); $$ = !$2;   }
|   TRUE        {   printf("factor : TRUE\n");  }
|   FALSE       {   printf("factor : FALSE\n"); }
;
%%

#include "lex.yy.c"

int main(int argc, char** argv)
{
while (yyparse() == 0) {
    }

    return 0;
}

2 个答案:

答案 0 :(得分:2)

在我看来,可能会出现冲突,因为当解析器看到'!'时,它会遇到重写'expr'的问题。忽略'因素'的其他作品,特别是看这两个作品:

expr    : expr "or" term  { printf("expr : expr or term\n"); $$ = $1 | $3; }
        | term            { printf("expr : term\n"); }
        ;

factor  : '!' expr        { printf("factor : !expr\n"); $$ = !$2; }

由于expr是递归的,当解析器看到'!'时,它知道否定适用于下面的expr,但是如果你写“!TRUE OR TRUE”,那么这个否定只适用于第一个true,或者整个分离?

编辑:换句话说,它无法决定是否需要改变“或”或减少“expr”。

在yacc中设置-v命令行选项将生成一个.output文件,其中包含各种好处,包括shift / reduce冲突的诊断信息。它会向您显示DFA的所有状态以及发生冲突的位置,有时会告诉您原因。

在他们自己的生产中将否定性逻辑地“介于”“术语”和“因素”之间应该可以解决问题。

答案 1 :(得分:1)

如果您将factor: ! expr更改为factor: ! factor,则冲突将会消失。

仅分析第一个冲突,问题是term可以缩减为expr或变得更复杂term。如果没有!,则只能使用一个前瞻符号做出此决定。

请注意,shift / reduce冲突不一定是错误。通过转移来解决冲突,这可能是你想要的。大多数真正的生产语法都包含许多转移/减少冲突。