有了token之后呢,就用yacc(本人用的是GNU的可以在windows下面运行的bison)才处理这些符号。也就是写出一个个的状态,最后得到分析结果。
下面是yacc文件的代码(cal.y):
%{
#include <stdio.h>
#include <math.h>
%}
%union{ double real; /* real value */
int integer; /* integer value */
}
%token <real> REAL
%token <integer> INTEGER
%start lines
%token NUMBER NL
%token PLUS MINUS TIMES DIVIDE MODULE POWER LP RP
%type <real> rexpr
%type <integer> iexpr
%left PLUS MINUS /*left associative */
%left TIMES DIVIDE MODULE /*left associative */
%left POWER
%left UNARYMINUS
%%
lines: /* nothing */
| lines line NL
| lines error NL
{ yyerror();yyerrok; }
;
line : iexpr
{printf("%d\n",$1);}
| rexpr
{printf("%lf\n",$1);}
;
iexpr: INTEGER
{ $$ = $1; }
| iexpr PLUS iexpr
{ $$ = $1 + $3;}
| iexpr MINUS iexpr
{ $$ = $1 - $3;}
| iexpr TIMES iexpr
{ $$ = $1 * $3;}
| iexpr DIVIDE iexpr
{ if($3)
$$ = $1 / $3;
else
{
$$ = $1;
printf (stderr, "%d.%d-%d.%d: division by zero",
@3.first_line, @3.first_column,
@3.last_line, @3.last_column);
}
}
| iexpr MODULE iexpr
{ $$ = $1 % $3; }
| iexpr POWER iexpr
{ $$ = pow($1, $3);}
| MINUS iexpr %prec UNARYMINUS
{ $$ = - $2;}
| LP iexpr RP
{ $$ = $2;}
| LP iexpr error
{ $$ = $2; yyerror("missing ')'"); yyerrok;}
| PLUS iexpr %prec UNARYMINUS
{ $$ = $2;}
;
rexpr :REAL
{ $$ = $1; }
| rexpr PLUS rexpr
{ $$ = $1 + $3; }
| rexpr MINUS rexpr
{ $$ = $1 - $3; }
| rexpr TIMES rexpr
{ $$ = $1 * $3; }
| rexpr DIVIDE rexpr
{
if ($3)
$$ = $1 / $3;
else
{
$$ = $1;
printf (stderr, "%d.%d-%d.%d: division by zero",
@3.first_line, @3.first_column,
@3.last_line, @3.last_column);
}
}
| rexpr POWER rexpr
{ $$ = pow($1,$3); }
| LP rexpr RP
{ $$ = $2; }
| LP rexpr error
{ $$ = $2; yyerror("missing ')'"); yyerrok;}
| MINUS rexpr %prec UNARYMINUS
{ $$ = -$2; }
| PLUS rexpr %prec UNARYMINUS
{ $$ = $2;}
| iexpr PLUS rexpr
{ $$ = (double)$1 + $3;}
| iexpr MINUS rexpr
{ $$ = (double)$1 - $3;}
| iexpr TIMES rexpr
{ $$ = (double)$1 * $3;}
| iexpr DIVIDE rexpr
{ if($3)
$$ = (double)$1 / $3;
else
{ $$ = $1;
printf (stderr, "%d.%d-%d.%d: division by zero",
@3.first_line, @3.first_column,
@3.last_line, @3.last_column);
}
}
| iexpr POWER rexpr
{ $$ = pow((double)$1,$3); }
| rexpr PLUS iexpr
{ $$ = $1 + (double)$3;}
| rexpr MINUS iexpr
{ $$ = $1 - (double)$3;}
| rexpr TIMES iexpr
{ $$ = $1 * (double)$3;}
| rexpr DIVIDE iexpr
{ if($3)
$$ = $1 / (double)$3;
else
{ $$ = $1;
printf (stderr, "%d.%d-%d.%d: division by zero",
@3.first_line, @3.first_column,
@3.last_line, @3.last_column);
}
}
| rexpr POWER iexpr
{ $$ = pow($1,(double)$3); }
;
%%
void main()
{
yyparse();
}
int yyerror(char* msg)
{
printf("Error: %s encountered \n", msg);
}
这样一个支持+,-,×,/,^,以及括号运算的计算器就做成了。所用时间不会超过半个小时,如果用c,或c++写个算符优先文法的话可是一个不小的工程。由此可见lex和yacc的魅力了!
编译命令是:fLex cal.l
bison -d -v cal.y
pause
任何建议,问题,欢迎:[email protected]
本文地址:http://com.8s8s.com/it/it24318.htm