利用 flex 和 bison 写一个计算器
指令
flex -ocalc.c calc.l
bison -ocalc.tab.h calc.y
gcc -o aa calc.c calc.tab.h
aa.exe
calc.l
%{
/*
* 一个简单计算器的Lex词法文件
*/
#include <stdlib.h>
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;
}
sin {
return SIN;
}
cos {
return COS;
}
sqrt {
return SQRT;
}
pow {
return POW;
}
log {
return LOG;
}
ln {
return LN;
}
/* 运算符 */
[-+()=/*!^,[&|{%\n] {return *yytext;}
/* 空白被忽略 */
[ \t] ;
/* 其他字符都是非法的 */
. yyerror("无效的输入字符");
%%
int yywrap(void)
{
return 1;
}
calc.y
%token INTEGER VARIABLE SIN COS SQRT POW LOG LN
%left '+' '-'
%left '*' '/'
%left '^' '['
%left '&' '|' '{'
%left '!'
%left '~'
%left '%'
%{
#define YYSTYPE double
#define __STDC__ 0
#define wypi (0.017453292519943)
#include "math.h"
#include <stdio.h>
#include <stdlib.h>
void yyerror(char*);
int yylex(void);
double sym[26];
%}
%%
program:
program statement '\n'
|
;
statement:
expr {
printf("%g\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 '[' expr {$$ = pow($3,1.0/$1);}
|expr '&' expr {$$ = (int)($1)&(int)($3);}
|expr '|' expr {$$ = (int)($1)|(int)($3);}
|POW'('expr','expr')' {$$ = pow($3,$5);}
|SQRT'('expr')' {$$ = sqrt($3);}
|'{' expr {$$ =!$2;}
|SIN'('expr')' {$$ = sin($3*wypi);}
|COS'('expr')' {$$ = cos($3*wypi);}
|LOG'('expr')' {$$ = log10($3);}
|LN'('expr')' {$$ = log($3);}
|expr '!' {
$$ = 1;
while($1>1)
{
$$ *=$1;
$1--;
}
}
|expr '%' expr {
$$=(int)($1)%(int)($3);
}
|'('expr')' {$$ = $2;}
;
%%
void yyerror(char* s)
{
fprintf(stderr, "%s\n", s);
}
int main(void)
{
yyparse();
return 0;
}