yacc:22减少/减少冲突

时间:2017-02-01 10:37:19

标签: compiler-construction yacc lex

%%

%token IDENTIFIER NUMBER SIZEOF
%token PTR DOT
%token TYPEDEF INT FLOAT VOID STRUCT
%token IF ELSE WHILE RETURN FOR DO SWITCH CASE BREAK DEFAULT CONTINUE
%token PRINTF SCANF
%token STRING
%token PREPROC

%left GT LT LE GE NE EQ
%left AND OR

%right '='
%left '+' '-'
%left '*' '/'

%%
start:  Function
    |   Declaration
    ;

Function:   Type IDENTIFIER '(' ArgList ')' CompoundStmt
    |   Type IDENTIFIER '('')' CompoundStmt
    ;

ArgList:    ArgList ',' Arg
    |   Arg
    ;

Arg:    Type IDENTIFIER
    ;

Type:   INT
    |   FLOAT
    |   VOID
    ;

CompoundStmt:   '{' StmtList '}'
    |   '{''}'
    ;

StmtList:   StmtList Stmt
    | Stmt
    ;

Stmt:   WhileStmt
    |   Declaration
    |   ForStmt
    |   IfStmt
    |   PrintStmt
    |   ScanStmt
    |   ';'
    ;

WhileStmt:  WHILE '(' Expr ')' Stmt
    |   WHILE '(' Expr ')' CompoundStmt
    ;

ForStmt:    FOR '(' Expr ';' Expr ';' Expr ')' Stmt
    |   FOR '(' Expr ';' Expr ';' Expr ')' CompoundStmt
    ;

IfStmt: IF '(' Expr ')' Stmt
    |   IF '(' Expr ')' CompoundStmt
    ;

PrintStmt:  PRINTF '(' Expr ')' ';'
    ;

ScanStmt:   SCANF '(' Expr ')' ';'
    ;

Expr:   Expr LE Expr
    |   Expr GE Expr
    |   Expr GT Expr
    |   Expr LT Expr
    |   Expr NE Expr
    |   Expr EQ Expr
    |   Assignment
    |   ArrayUsage
    ;

ArrayUsage: IDENTIFIER '[' Assignment ']'
    ;

Declaration:    Type Assignment ';'
    |   Assignment ';'
    |   FunctionCall ';'
    |   ArrayUsage ';'
    |   Type ArrayUsage ';'
    |   StructStmt ';'
    ;

StructStmt: STRUCT IDENTIFIER '{' Type Assignment '}'
    ;

FunctionCall:   IDENTIFIER '('')'
    |   IDENTIFIER '(' Assignment ')'
    ;

Assignment: IDENTIFIER '=' Assignment
    |   IDENTIFIER '=' FunctionCall
    |   IDENTIFIER '=' ArrayUsage
    |   ArrayUsage '=' Assignment
    |   IDENTIFIER ',' Assignment
    |   NUMBER ',' Assignment
    |   IDENTIFIER '+' Assignment
    |   IDENTIFIER '-' Assignment
    |   IDENTIFIER '*' Assignment
    |   IDENTIFIER '/' Assignment
    |   NUMBER '+' Assignment
    |   NUMBER '-' Assignment
    |   NUMBER '*' Assignment
    |   NUMBER '/' Assignment
    |   '\'' Assignment '\''
    |   '(' Assignment ')'
    |   '-' Assignment
    |   '-' NUMBER
    |   '-' IDENTIFIER
    |   NUMBER
    |   IDENTIFIER
    ;

%%
include"lex.yy.c"

int main(int argc,char *argv[])
{
    FILE *file;
        file = fopen(argv[1], "r");
        if (!file)
        {
            fprintf(stderr, "Could not open %s\n", argv[1]);
            exit(1);
        }
        yyin = file;

    if(!yyparse())
        printf("\nParsing done");
    else
        printf("\nParsing failed");

    fclose(yyin);

        return 0;
    }

跑步时:

yacc scanner.y          // scanner.y being by yacc code

我收到以下错误:

yacc: 22 reduce/reduce conflicts.

如果有两个或更多规则适用于相同的输入序列,则会发生减少/减少冲突。这通常表明语法中存在严重错误。

这里有什么错误?

2 个答案:

答案 0 :(得分:2)

问题来自规则中的含糊不清

Assignment: '-' Assignment
          |   '-' NUMBER
          |   '-' IDENTIFIER
          |   NUMBER
          |   IDENTIFIER

如果您有输入- IDENTIFIER或(- NUMBER),您可以在一步(上面的第2或第3规则)或两步(第4或第5步)中将其缩小为Assignment规则,然后是第1条规则)。最简单的解决方法是删除上面的第2和第3条规则,这将迫使它总是减少两步。您可能还希望通过定义假'-' Assignment标记(优先级高于所有二元运算符)来赋予UNARY规则更高的优先级,lexer永远不会返回,但允许您说

Assignment: '-' Assignment %prec UNARY

赋予该规则更高的优先权。

答案 1 :(得分:0)

你可以使用带有-v选项的bison,你会得到详细的输出。我收到了

State 32 conflicts: 11 reduce/reduce
State 33 conflicts: 11 reduce/reduce

这些州看起来像这样:

State 32

38 ArrayUsage: IDENTIFIER . '[' Assignment ']'
48 Assignment: IDENTIFIER . '=' Assignment
49           | IDENTIFIER . '=' FunctionCall
50           | IDENTIFIER . '=' ArrayUsage
52           | IDENTIFIER . ',' Assignment
54           | IDENTIFIER . '+' Assignment
55           | IDENTIFIER . '-' Assignment
56           | IDENTIFIER . '*' Assignment
57           | IDENTIFIER . '/' Assignment
66           | '-' IDENTIFIER .
68           | IDENTIFIER .

'='  shift, and go to state 18
'+'  shift, and go to state 19
'-'  shift, and go to state 20
'*'  shift, and go to state 21
'/'  shift, and go to state 22
','  shift, and go to state 24
'['  shift, and go to state 25

GT        reduce using rule 66 (Assignment)
GT        [reduce using rule 68 (Assignment)]
LT        reduce using rule 66 (Assignment)
LT        [reduce using rule 68 (Assignment)]
LE        reduce using rule 66 (Assignment)
LE        [reduce using rule 68 (Assignment)]
GE        reduce using rule 66 (Assignment)
GE        [reduce using rule 68 (Assignment)]
NE        reduce using rule 66 (Assignment)
NE        [reduce using rule 68 (Assignment)]
EQ        reduce using rule 66 (Assignment)
EQ        [reduce using rule 68 (Assignment)]
')'       reduce using rule 66 (Assignment)
')'       [reduce using rule 68 (Assignment)]
'}'       reduce using rule 66 (Assignment)
'}'       [reduce using rule 68 (Assignment)]
';'       reduce using rule 66 (Assignment)
';'       [reduce using rule 68 (Assignment)]
']'       reduce using rule 66 (Assignment)
']'       [reduce using rule 68 (Assignment)]
'\''      reduce using rule 66 (Assignment)
'\''      [reduce using rule 68 (Assignment)]
$default  reduce using rule 66 (Assignment)


State 33

53 Assignment: NUMBER . ',' Assignment
58           | NUMBER . '+' Assignment
59           | NUMBER . '-' Assignment
60           | NUMBER . '*' Assignment
61           | NUMBER . '/' Assignment
65           | '-' NUMBER .
67           | NUMBER .

'+'  shift, and go to state 26
'-'  shift, and go to state 27
'*'  shift, and go to state 28
'/'  shift, and go to state 29
','  shift, and go to state 30

GT        reduce using rule 65 (Assignment)
GT        [reduce using rule 67 (Assignment)]
LT        reduce using rule 65 (Assignment)
LT        [reduce using rule 67 (Assignment)]
LE        reduce using rule 65 (Assignment)
LE        [reduce using rule 67 (Assignment)]
GE        reduce using rule 65 (Assignment)
GE        [reduce using rule 67 (Assignment)]
NE        reduce using rule 65 (Assignment)
NE        [reduce using rule 67 (Assignment)]
EQ        reduce using rule 65 (Assignment)
EQ        [reduce using rule 67 (Assignment)]
')'       reduce using rule 65 (Assignment)
')'       [reduce using rule 67 (Assignment)]
'}'       reduce using rule 65 (Assignment)
'}'       [reduce using rule 67 (Assignment)]
';'       reduce using rule 65 (Assignment)
';'       [reduce using rule 67 (Assignment)]
']'       reduce using rule 65 (Assignment)
']'       [reduce using rule 67 (Assignment)]
'\''      reduce using rule 65 (Assignment)
'\''      [reduce using rule 67 (Assignment)]
$default  reduce using rule 65 (Assignment)

正如您所看到的,这两种状态下的相同令牌可以减少使用不同的规则。

问题在于分配规则:

Assignment: IDENTIFIER '=' Assignment
|   IDENTIFIER '=' FunctionCall
|   IDENTIFIER '=' ArrayUsage
|   ArrayUsage '=' Assignment
|   IDENTIFIER ',' Assignment
|   NUMBER ',' Assignment
|   IDENTIFIER '+' Assignment
|   IDENTIFIER '-' Assignment
|   IDENTIFIER '*' Assignment
|   IDENTIFIER '/' Assignment
|   NUMBER '+' Assignment
|   NUMBER '-' Assignment
|   NUMBER '*' Assignment
|   NUMBER '/' Assignment
|   '\'' Assignment '\''
|   '(' Assignment ')'
|   '-' Assignment
|   '-' NUMBER
|   '-' IDENTIFIER
|   NUMBER
|   IDENTIFIER
;

我猜你应该使用特殊的一元减号和重写规则,如下所示:

Assignment: IDENTIFIER '=' Assignment
|   IDENTIFIER '=' FunctionCall
|   IDENTIFIER '=' ArrayUsage
|   ArrayUsage '=' Assignment
|   IDENTIFIER ',' Assignment
|   NUMBER ',' Assignment
|   IDENTIFIER '+' Assignment
|   IDENTIFIER '-' Assignment
|   IDENTIFIER '*' Assignment
|   IDENTIFIER '/' Assignment
|   NUMBER '+' Assignment
|   NUMBER '-' Assignment
|   NUMBER '*' Assignment
|   NUMBER '/' Assignment
|   '\'' Assignment '\''
|   '(' Assignment ')'
|   '-' Assignment
|   UMINUS NUMBER
|   UMINUS IDENTIFIER
|   NUMBER
|   IDENTIFIER
;

定义如下:

%token IDENTIFIER NUMBER SIZEOF UMINUS

并且做到了

%nonassoc UMINUS