天天看点

yacc文法规则解决运算符优先级

优先级错误2-3*4=-4? 

把上一个博文的程序扩展成支持加减乘除的程序,需要扩充cal.y的文法规则

%{
#include <stdio.h>
%}

%token PRINT NUMBER
%%
statement: 
	PRINT expression		{
								printf("\ntest yacc PRINT expression\n");
								printf("result is %d", $2);
							}
	|expression 			{
								printf("\ntest yacc expression\n");
								printf("%d is the result", $1);
							}
	;

expression: 
	expression '*' NUMBER 	{
								printf("\ntest yacc expression + NUMBER\n");
								$$ = $1 * $3;
							}
	|expression '/' NUMBER 	{
								printf("\ntest yacc expression + NUMBER\n");
								$$ = $1 / $3;
							}
	|expression '+' NUMBER 	{
								printf("\ntest yacc expression + NUMBER\n");
								$$ = $1 + $3;
							}
	|expression '-' NUMBER 	{
								printf("\ntest yacc expression + NUMBER\n");
								$$ = $1 - $3;
							}
	|NUMBER 				{
								printf("\ntest yacc NUMBER\n");
								$$ = $1;
							} 
           
nosourcesmatoMacBook-Pro:cal nosources$ yacc -d cal.y && lex cal.l && cc -o cal yyy.c -ly -ll
nosourcesmatoMacBook-Pro:cal nosources$ ./cal
           
print 2-3*4

test lex print

test lex NUMBER

test yacc NUMBER

test lex -
test lex NUMBER

test yacc expression + NUMBER

test lex *
test lex NUMBER

test yacc expression + NUMBER

test yacc PRINT expression
result is -4
           

可见

2-3*4
           

输出的结果是-4,这个是因为我们的文法没有优先级,我们按照问发的匹配顺序发现确实是会的到-4的结果,怎么让程序先计算3*4呢?两种方式

隐式的指定优先级

cal.y

%{
#include <stdio.h>
%}

%token PRINT NUMBER
%%
statement: 
	PRINT expression		{
								printf("\ntest yacc PRINT expression\n");
								printf("result is %d", $2);
							}
	|expression 			{
								printf("\ntest yacc expression\n");
								printf("%d is the result", $1);
							}
	;

expression: 
	expression '+' mulexp 	{
								printf("\ntest yacc expression + expression\n");
								$$ = $1 + $3;
							}
	|expression '-' mulexp 	{
								printf("\ntest yacc expression - expression\n");
								$$ = $1 - $3;
							}
	|mulexp 				{
								printf("\ntest yacc mulexp\n");
								$$ = $1;
							} 

mulexp:
	|NUMBER '*' NUMBER 		{
								printf("\ntest yacc NUMBER '*' NUMBER\n");
								$$ = $1 * $3;
							}
	|NUMBER '/' NUMBER 		{
								printf("\ntest yacc NUMBER '/' NUMBER\n");
								$$ = $1 / $3;
							}
	|NUMBER 		 		{
								printf("\ntest yacc NUMBER\n");
								$$ = $1;
							}

           

这样做了之后,mulexp变成了更小的规则,所以会先规约这个规则,优先级也就对了

显示的指定

%{
#include <stdio.h>
%}

%token PRINT NUMBER

%left '+' '-'
%left '*' '/'
%%
statement: 
	PRINT expression		{
								printf("\ntest yacc PRINT expression\n");
								printf("result is %d", $2);
							}
	|expression 			{
								printf("\ntest yacc expression\n");
								printf("%d is the result", $1);
							}
	;

expression: 
	expression '*' expression 	{
								printf("\ntest yacc expression + expression\n");
								$$ = $1 * $3;
							}
	|expression '/' expression 	{
								printf("\ntest yacc expression + expression\n");
								$$ = $1 / $3;
							}
	|expression '+' expression 	{
								printf("\ntest yacc expression + expression\n");
								$$ = $1 + $3;
							}
	|expression '-' expression 	{
								printf("\ntest yacc expression + expression\n");
								$$ = $1 - $3;
							}
	|NUMBER 				{
								printf("\ntest yacc NUMBER\n");
								$$ = $1;
							} 
           

%left定义了左结合的优先级,也可以用%right定义右结合优先级

什么时候使用优先规则

优先规则不可随便使用,以上例子实在表达式下,大家都很清楚是什么意思,但是通常的程序很难正确理解 有两种情况:

  1. 表达是语法,为了解决if-then-else结构中虚挂的else冲突
  2. 如果可以的话,应该调整语法删除冲突