一个含歧义性的表达式示例:
expression: expression '+' expression { $$=$1+$3; }
| expression '-' expression { $$=$1-$3; }
| expression '*' expression { $$=$1*$3; }
| expression '/' expression
{ if($3==0)
yyerror("divided by zero.");
else
$$ = $1 / $3
}
| '-' expression { $$=-$2; }
| '(' expression ')' { $$=$2; }
| NUMBER { $$=$1; }
该语法存在模糊性。例如:输入2+3*4意味着(2+3)4或2+(34)。
如果编译上面那样的语法,yacc将会报存在移进规约冲突,表明它无法决定是先从堆栈上移进(shift)标记,还是先规约(reduce)规则。
歧义的处理:指定优先级和结合性
**有两种方式可以指定语法中的优先级和结合规则:**隐式地和显示地
**隐式:**使用单独的非终结符号为每个优先级重新编写语法,例:
expression: expression '+' mulexp
| expression '-' mulexp
| mulexp
;
mulexp: mulexp '*' primary
| mulexp '/' primary
| primary
;
primary: '(' expression ')'
| '-' primary
| NUMBER
;
**显示:**在定义部分添加这些行
%left ‘+’ ‘-’
%left ‘*’ ‘/’
%nonassoc UMINUS
自上而下,优先级递增
包含优先级的语法分析程序:
词法分析程序ch1-2.l
%{
#include "y.tab.h"
extern int yylval;
%}
%%
[0-9]+ {yylval=atoi(yytext); return NUMBER;}
[ \t] ;
\n return 0;
. return yytext[0];
%%
int yywrap()
{
return 1;
}
语法分析程序ch1-2.y
%{
#include <stdio.h>
%}
%token NAME NUMBER
%left '+' '-'
%left '*' '/'
%nonassoc UMINUS
%%
statement: NAME '=' expression
| expression { printf("=%d\n",$1); }
;
expression: expression '+' expression { $$=$1+$3; }
| expression '-' expression { $$=$1-$3; }
| expression '*' expression { $$=$1*$3; }
| expression '/' expression
{ if($3==0)
yyerror("divided by zero.");
else
$$ = $1 / $3;
}
| '-' expression %prec UMINUS { $$=-$2; }
| '(' expression ')' { $$=$2; }
| NUMBER { $$=$1; }
;
%%
extern FILE *yyin;
int main(){
do{
yyparse();
}while(!feof(yyin));
}
void yyerror(char *s){
fprintf(stderr,"%s\n",s);
}