yacc学习笔记(二)算术表达式歧义性和优先级

一个含歧义性的表达式示例:

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);
}
发布了8 篇原创文章 · 获赞 2 · 访问量 212

猜你喜欢

转载自blog.csdn.net/sxqinjh/article/details/104614866
今日推荐