代码
// calc.lex
%{
#include <stdio.h>
#define YYSTYPE double
#include "calc_y.h"
#define PRINT printf("%s", yytext)
%}
num [0-9]
real {num}+|{num}+"."{num}+
add "+"
sub "-"
mul "*"
div "/"
eq "="
lb "("
rb ")"
sin "sin"
cos "cos"
ln "ln"
log10 "log10"
tanh "tanh"
sqrt "sqrt"
exp "exp"
abs "abs"
lr [/r/n]
space [ /t]
quit [q]
%%
{real} { PRINT; yylval = strtod(yytext, NULL); return REAL; }
{add} { PRINT; return ADD; }
{sub} { PRINT; return SUB; }
{mul} { PRINT; return MUL; }
{div} { PRINT; return DIV; }
{eq} { PRINT; return EQ; }
{lb} { PRINT; return LB; }
{rb} { PRINT; return RB; }
{sin} { PRINT; return SIN; }
{cos} { PRINT; return COS; }
{ln} { PRINT; return LN; }
{log10} { PRINT; return LOG10; }
{tanh} { PRINT; return TANH; }
{sqrt} { PRINT; return SQRT; }
{exp} { PRINT; return EXP; }
{abs} { PRINT; return ABS; }
{lr} { return LR; }
{quit} { exit(0); }
{space} {}
. {}
%%
int yywrap()
{
return 1;
}
// calc.y
%{
#include <stdio.h>
#include <math.h>
#define YYSTYPE double
extern int yylineno;
%}
%token REAL EQ LR
%right SIN COS LN LOG10 TANH SQRT EXP ABS
%left ADD SUB
%left MUL DIV
%left RB
%right LB
%right UARY
%%
input:
| input line
;
line: LR
| exp LR { printf("=%f/n", $1); }
;
exp: REAL { $$ = $1; }
| exp ADD exp { $$ = $1 + $3; }
| exp SUB exp { $$ = $1 - $3; }
| exp MUL exp { $$ = $1 * $3; }
| exp DIV exp { $$ = $1 / $3; }
| ADD exp %prec UARY { $$ = $2; }
| SUB exp %prec UARY { $$ = -$2; }
| LB exp RB { $$ = $2; }
| SIN LB exp RB { $$ = sin($3); }
| COS LB exp RB { $$ = cos($3); }
| LN LB exp RB { $$ = log($3); }
| LOG10 LB exp RB { $$ = log10($3); }
| TANH LB exp RB { $$ = tanh($3); }
| SQRT LB exp RB { $$ = sqrt($3); }
| EXP LB exp RB { $$ = exp($3); }
| ABS LB exp RB { $$ = fabs($3); }
;
%%
int main()
{
yyparse();
return 0;
}
int yyerror(char *msg)
{
printf("error: %s in line %d/n", msg, yylineno);
return 0;
}
// makefile
all:calc_y.c calc_l.c
gcc -g -o calc calc_y.c calc_l.c -lm
calc_l.c:calc.lex calc.y
flex -o calc_l.c calc.lex
calc_y.c:calc.y
bison -d -o calc_y.c calc.y
clean:
@rm -f calc *.c *.h
// exam.txt
10.6/2
3.3*3
10+5
8-3
4*2
1+3*2-5
-1+5
+1+5
5*(3-1)+6
sin(3.1415926/2)
cos(0)
abs(-10.5)
sqrt(16)
ln(5)
log10(10)
exp(5)
// 使用方法 1
$ ./calc < exam.txt
// 是用方法2
$ ./calc
1+3
1+3=4
q
$