利用 flex 和 bison 写一个计算器
实现实数范围内的加减乘除、乘方、开方,三角函数sin、cos运算
a)在命令提示符下依次执行一下两行命令
flex 文件名.lex
bison -o文件名.c 文件名.y
编译的话,可用命令提示符,不过需要自己搭建环境
gcc -o 可执行程序名称 lex.yy.c bison生成的文件名.c
当然可以用其他的方法去运行,不过需要在bison生成的.c文件中加入lex生成的文件的文件名,这样就可以在codeblocks里面或者其他c语言的编译环境下,直接运行bison生成的.c文件
lex程序
%{
/*
* 一个简单计算器的Lex词法文件
*/
#include <stdlib.h>
#define YYSTYPE double
void yyerror(char*);
// #include "calc.tab.h"
%}
%%
/* a-z为变量 */
[a-z] {
yylval = *yytext - 'a';
return VARIABLE;
}
\.?[0-9]+|[0-9]+\.[0-9]* {
yylval = atof(yytext);
return INTEGER;
}
[-+(),=/*\n] {return *yytext;}
sin {return SIN;}
cos {return COS;}
sqrt {return SQRT;}
pow {return POW;}
[ \t] ;
. yyerror("无效的输入字符");
%%
int yywrap(void)
{
return 1;
}
bison程序
%token INTEGER VARIABLE COS SQRT POW SIN
%left '+' '-'
%left '*' '/'
%left SIN
%{
#define YYSTYPE double
// #define __STDC__ 0
//#include "calc_d_tab.h"
#define YYSTYPE double
#define pi 3.1415926
#include<math.h>
void yyerror(char*);
int yylex(void);
double sym[26];
%}
%%
program:
program statement '\n'
|
;
statement:
expr {printf("%f\n", $1);}
|VARIABLE '=' expr {sym[(int)$1] = $3;}
;
expr:
INTEGER
|VARIABLE {$$ = sym[(int)$1];}
|expr '+' expr {$$ = $1 + $3;}
|expr '-' expr {$$ = $1 - $3;}
|expr '*' expr {$$ = $1 * $3;}
|expr '/' expr {$$ = $1 / $3;}
|'('expr')' {$$ = $2;}
|POW '(' expr ',' expr ')' {$$ = pow($3,$5);}
|SIN'('expr')' {$$ = sin($3*pi/180.0);}
|COS '(' expr ')' {$$ = cos($3*pi/180.0);}
|SQRT '(' expr ')' {$$ = sqrt($3);}
;
%%
void yyerror(char* s)
{
fprintf(stderr, "%s\n", s);
}
#include "lex.yy.c"
int main(void)
{
printf("A simple calculator.\n");
yyparse();
return 0;
}