我无法识别的 Yacc shift/reduce
Yacc shift/reduce that I cannot identify
所以我有这个 .y 文件,我试图用它的参数解析和评估一个函数,但是有一个我无法识别的 shift/reduce 冲突:
.y
%{
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "types.h"
#define YYDEBUG 0
/* prototypes */
nodeType *opr(int oper, int nops, ...);
nodeType *id(int i);
nodeType *con(int value);
void freeNode(nodeType *p);
void yyerror(char *s);
nodeType *RadEc;
int sym[26]; /* symbol table */
%}
%union {
int iValue; /* integer value */
char sIndex; /* symbol table index */
nodeType *nPtr; /* node pointer */
};
%token <iValue> INTEGER
%token <sIndex> VARIABLE
%token WHILE IF PRINT SUBRAD ENDSUB THEN DO ENDIF RAD
%nonassoc IFX
%nonassoc ELSE
%left GE LE EQ NE '>' '<'
%left '+' '-'
%left '*' '/'
%nonassoc UMINUS
%type <nPtr> statement expr stmt_list
%type <iValue> expresie
%start program
%%
program : declaratii cod { exit(0); }
;
declaratii: SUBRAD stmt_list ENDSUB { RadEc=; }
| /* NULL */
;
statement : '\n' { $$ = opr(';', 2, NULL, NULL); }
| expr '\n' { $$ = ; }
| PRINT expr '\n' { $$ = opr(PRINT, 1, ); }
| VARIABLE '=' expr '\n' { $$ = opr('=', 2, id(), ); }
| DO stmt_list WHILE expr { $$ = opr(WHILE, 2, , ); }
| IF expr THEN stmt_list ENDIF %prec IFX { $$ = opr(IF, 2, , ); }
| IF expr THEN stmt_list ELSE stmt_list ENDIF { $$ = opr(IF, 3, , , ); }
;
stmt_list : statement
| stmt_list statement { $$ = opr(';', 2, , ); }
;
expr : INTEGER { $$ = con(); }
| VARIABLE { $$ = id(); }
| '-' expr %prec UMINUS { $$ = opr(UMINUS, 1, ); }
| expr '+' expr { $$ = opr('+', 2, , ); }
| expr '-' expr { $$ = opr('-', 2, , ); }
| expr '*' expr { $$ = opr('*', 2, , ); }
| expr '/' expr { $$ = opr('/', 2, , ); }
| expr '<' expr { $$ = opr('<', 2, , ); }
| expr '>' expr { $$ = opr('>', 2, , ); }
| expr GE expr { $$ = opr(GE, 2, , ); }
| expr LE expr { $$ = opr(LE, 2, , ); }
| expr NE expr { $$ = opr(NE, 2, , ); }
| expr EQ expr { $$ = opr(EQ, 2, , ); }
| '(' expr ')' { $$ = ; }
;
cod : '.' {exit(0);}
| instruc '\n' cod
;
instruc : '\n'
| PRINT expresie {printf("%d\n",);}
| VARIABLE '=' expresie {sym[]=;}
| RAD'('expresie','expresie','expresie')' {sym[0]=; sym[1]=; sym[2]=; ex(RadEc);}
;
expresie : INTEGER { $$ = ; }
| VARIABLE { $$ = sym[]; }
| '-' expresie %prec UMINUS { $$ = -; }
| expresie '+' expresie { $$ = +; }
| expresie '-' expresie { $$ = -; }
| expresie '*' expresie { $$ = *; }
| expresie '/' expresie { $$ = /; }
| expresie '<' expresie { $$ = <; }
| expresie '>' expresie { $$ = >; }
| expresie GE expresie { $$ = >=; }
| expresie LE expresie { $$ = <=; }
| expresie NE expresie { $$ = !=; }
| expresie EQ expresie { $$ = ==; }
| '(' expresie ')' { $$ = ; }
;
%%
nodeType *con(int value)
{
nodeType *p;
/* allocate node */
if ((p = malloc(sizeof(conNodeType))) == NULL)
yyerror("out of memory");
/* copy information */
p->type = typeCon;
p->con.value = value;
return p;
}
nodeType *id(int i)
{
nodeType *p;
/* allocate node */
if ((p = malloc(sizeof(idNodeType))) == NULL)
yyerror("out of memory");
/* copy information */
p->type = typeId;
p->id.i = i;
return p;
}
nodeType *opr(int oper, int nops, ...)
{
va_list ap;
nodeType *p;
size_t size;
int i;
/* allocate node */
size = sizeof(oprNodeType) + (nops - 1) * sizeof(nodeType*);
if ((p = malloc(size)) == NULL)
yyerror("out of memory");
/* copy information */
p->type = typeOpr;
p->opr.oper = oper;
p->opr.nops = nops;
va_start(ap, nops);
for (i = 0; i < nops; i++)
p->opr.op[i] = va_arg(ap, nodeType*);
va_end(ap);
return p;
}
void freeNode(nodeType *p)
{
int i;
if (!p)
return;
if (p->type == typeOpr) {
for (i = 0; i < p->opr.nops; i++)
freeNode(p->opr.op[i]);
}
free (p);
}
int ex(nodeType *p)
{
if (!p)
return 0;
switch(p->type)
{
case typeCon: return p->con.value;
case typeId: return sym[p->id.i];
case typeOpr: switch(p->opr.oper)
{
case WHILE: while(ex(p->opr.op[0]))
ex(p->opr.op[1]);
return 0;
case IF: if (ex(p->opr.op[0]))
ex(p->opr.op[1]);
else if (p->opr.nops > 2)
ex(p->opr.op[2]);
return 0;
case PRINT: printf("%d\n", ex(p->opr.op[0]));
return 0;
case ';': ex(p->opr.op[0]);
return ex(p->opr.op[1]);
case '=': return sym[p->opr.op[0]->id.i] = ex(p->opr.op[1]);
case UMINUS: return -ex(p->opr.op[0]);
case '+': return ex(p->opr.op[0]) + ex(p->opr.op[1]);
case '-': return ex(p->opr.op[0]) - ex(p->opr.op[1]);
case '*': return ex(p->opr.op[0]) * ex(p->opr.op[1]);
case '/': return ex(p->opr.op[0]) / ex(p->opr.op[1]);
case '<': return ex(p->opr.op[0]) < ex(p->opr.op[1]);
case '>': return ex(p->opr.op[0]) > ex(p->opr.op[1]);
case GE: return ex(p->opr.op[0]) >= ex(p->opr.op[1]);
case LE: return ex(p->opr.op[0]) <= ex(p->opr.op[1]);
case NE: return ex(p->opr.op[0]) != ex(p->opr.op[1]);
case EQ: return ex(p->opr.op[0]) == ex(p->opr.op[1]);
}
}
}
void yyerror(char *s)
{
fprintf(stdout, "%s\n", s);
}
int main(void)
{
#if YYDEBUG
yydebug = 1;
#endif
yyparse();
return 0;
}
我尝试了不同的方法来查看我是否丢失了一些东西,但我在这方面还很陌生,仍然无法很好地解决冲突。
非常感谢任何帮助。
你的语法允许语句是表达式,它允许两个语句按顺序出现,没有任何分隔符。
现在,下面两个都是表达式:
a
-1
假设它们在语句列表中看起来像那样。这与这个单一的表达方式有何不同?
a - 1
歧义总是表现为解析冲突。
顺便说一下,分隔的 if
语句(带有 endif
标记)不能表现出悬空的 else
歧义。 endif
括号使解析明确。因此,所有从不同语法复制的优先设备在这里都是完全多余的。
所以我有这个 .y 文件,我试图用它的参数解析和评估一个函数,但是有一个我无法识别的 shift/reduce 冲突:
.y
%{
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "types.h"
#define YYDEBUG 0
/* prototypes */
nodeType *opr(int oper, int nops, ...);
nodeType *id(int i);
nodeType *con(int value);
void freeNode(nodeType *p);
void yyerror(char *s);
nodeType *RadEc;
int sym[26]; /* symbol table */
%}
%union {
int iValue; /* integer value */
char sIndex; /* symbol table index */
nodeType *nPtr; /* node pointer */
};
%token <iValue> INTEGER
%token <sIndex> VARIABLE
%token WHILE IF PRINT SUBRAD ENDSUB THEN DO ENDIF RAD
%nonassoc IFX
%nonassoc ELSE
%left GE LE EQ NE '>' '<'
%left '+' '-'
%left '*' '/'
%nonassoc UMINUS
%type <nPtr> statement expr stmt_list
%type <iValue> expresie
%start program
%%
program : declaratii cod { exit(0); }
;
declaratii: SUBRAD stmt_list ENDSUB { RadEc=; }
| /* NULL */
;
statement : '\n' { $$ = opr(';', 2, NULL, NULL); }
| expr '\n' { $$ = ; }
| PRINT expr '\n' { $$ = opr(PRINT, 1, ); }
| VARIABLE '=' expr '\n' { $$ = opr('=', 2, id(), ); }
| DO stmt_list WHILE expr { $$ = opr(WHILE, 2, , ); }
| IF expr THEN stmt_list ENDIF %prec IFX { $$ = opr(IF, 2, , ); }
| IF expr THEN stmt_list ELSE stmt_list ENDIF { $$ = opr(IF, 3, , , ); }
;
stmt_list : statement
| stmt_list statement { $$ = opr(';', 2, , ); }
;
expr : INTEGER { $$ = con(); }
| VARIABLE { $$ = id(); }
| '-' expr %prec UMINUS { $$ = opr(UMINUS, 1, ); }
| expr '+' expr { $$ = opr('+', 2, , ); }
| expr '-' expr { $$ = opr('-', 2, , ); }
| expr '*' expr { $$ = opr('*', 2, , ); }
| expr '/' expr { $$ = opr('/', 2, , ); }
| expr '<' expr { $$ = opr('<', 2, , ); }
| expr '>' expr { $$ = opr('>', 2, , ); }
| expr GE expr { $$ = opr(GE, 2, , ); }
| expr LE expr { $$ = opr(LE, 2, , ); }
| expr NE expr { $$ = opr(NE, 2, , ); }
| expr EQ expr { $$ = opr(EQ, 2, , ); }
| '(' expr ')' { $$ = ; }
;
cod : '.' {exit(0);}
| instruc '\n' cod
;
instruc : '\n'
| PRINT expresie {printf("%d\n",);}
| VARIABLE '=' expresie {sym[]=;}
| RAD'('expresie','expresie','expresie')' {sym[0]=; sym[1]=; sym[2]=; ex(RadEc);}
;
expresie : INTEGER { $$ = ; }
| VARIABLE { $$ = sym[]; }
| '-' expresie %prec UMINUS { $$ = -; }
| expresie '+' expresie { $$ = +; }
| expresie '-' expresie { $$ = -; }
| expresie '*' expresie { $$ = *; }
| expresie '/' expresie { $$ = /; }
| expresie '<' expresie { $$ = <; }
| expresie '>' expresie { $$ = >; }
| expresie GE expresie { $$ = >=; }
| expresie LE expresie { $$ = <=; }
| expresie NE expresie { $$ = !=; }
| expresie EQ expresie { $$ = ==; }
| '(' expresie ')' { $$ = ; }
;
%%
nodeType *con(int value)
{
nodeType *p;
/* allocate node */
if ((p = malloc(sizeof(conNodeType))) == NULL)
yyerror("out of memory");
/* copy information */
p->type = typeCon;
p->con.value = value;
return p;
}
nodeType *id(int i)
{
nodeType *p;
/* allocate node */
if ((p = malloc(sizeof(idNodeType))) == NULL)
yyerror("out of memory");
/* copy information */
p->type = typeId;
p->id.i = i;
return p;
}
nodeType *opr(int oper, int nops, ...)
{
va_list ap;
nodeType *p;
size_t size;
int i;
/* allocate node */
size = sizeof(oprNodeType) + (nops - 1) * sizeof(nodeType*);
if ((p = malloc(size)) == NULL)
yyerror("out of memory");
/* copy information */
p->type = typeOpr;
p->opr.oper = oper;
p->opr.nops = nops;
va_start(ap, nops);
for (i = 0; i < nops; i++)
p->opr.op[i] = va_arg(ap, nodeType*);
va_end(ap);
return p;
}
void freeNode(nodeType *p)
{
int i;
if (!p)
return;
if (p->type == typeOpr) {
for (i = 0; i < p->opr.nops; i++)
freeNode(p->opr.op[i]);
}
free (p);
}
int ex(nodeType *p)
{
if (!p)
return 0;
switch(p->type)
{
case typeCon: return p->con.value;
case typeId: return sym[p->id.i];
case typeOpr: switch(p->opr.oper)
{
case WHILE: while(ex(p->opr.op[0]))
ex(p->opr.op[1]);
return 0;
case IF: if (ex(p->opr.op[0]))
ex(p->opr.op[1]);
else if (p->opr.nops > 2)
ex(p->opr.op[2]);
return 0;
case PRINT: printf("%d\n", ex(p->opr.op[0]));
return 0;
case ';': ex(p->opr.op[0]);
return ex(p->opr.op[1]);
case '=': return sym[p->opr.op[0]->id.i] = ex(p->opr.op[1]);
case UMINUS: return -ex(p->opr.op[0]);
case '+': return ex(p->opr.op[0]) + ex(p->opr.op[1]);
case '-': return ex(p->opr.op[0]) - ex(p->opr.op[1]);
case '*': return ex(p->opr.op[0]) * ex(p->opr.op[1]);
case '/': return ex(p->opr.op[0]) / ex(p->opr.op[1]);
case '<': return ex(p->opr.op[0]) < ex(p->opr.op[1]);
case '>': return ex(p->opr.op[0]) > ex(p->opr.op[1]);
case GE: return ex(p->opr.op[0]) >= ex(p->opr.op[1]);
case LE: return ex(p->opr.op[0]) <= ex(p->opr.op[1]);
case NE: return ex(p->opr.op[0]) != ex(p->opr.op[1]);
case EQ: return ex(p->opr.op[0]) == ex(p->opr.op[1]);
}
}
}
void yyerror(char *s)
{
fprintf(stdout, "%s\n", s);
}
int main(void)
{
#if YYDEBUG
yydebug = 1;
#endif
yyparse();
return 0;
}
我尝试了不同的方法来查看我是否丢失了一些东西,但我在这方面还很陌生,仍然无法很好地解决冲突。
非常感谢任何帮助。
你的语法允许语句是表达式,它允许两个语句按顺序出现,没有任何分隔符。
现在,下面两个都是表达式:
a
-1
假设它们在语句列表中看起来像那样。这与这个单一的表达方式有何不同?
a - 1
歧义总是表现为解析冲突。
顺便说一下,分隔的 if
语句(带有 endif
标记)不能表现出悬空的 else
歧义。 endif
括号使解析明确。因此,所有从不同语法复制的优先设备在这里都是完全多余的。