借助Lex的词法分析和Yacc的语法分析,制作一个简易的计算器。
词法分析 mycalc.l
%{
#include <stdio.h>
#include "y.tab.h"
int yywrap(void)
{
return 1;
}
%}
%%
"+" return ADD;
"-" return SUB;
"*" return MUL;
"/" return DIV;
"\n" return CR;
"(" return LB;
")" return RB;
([1-9][0-9]*)|0|([0-9]+\.[0-9]+) {
double temp;
sscanf(yytext, "%lf", &temp);
printf("%lf \n", temp);
yylval.double_value = temp;
return DOUBLE_LITERAL;
}
[ \t] ;
. {
fprintf(stderr, "lexical error.\n");
exit(1);
}
%%
lex mycalc.l 生成文件 lex.yy.c
语法分析 mycal.y
%{
#include <stdio.h>
#include <stdlib.h>
#define YYDEBUG 1
%}
%union {
int int_value;
double double_value;
}
%token <double_value> DOUBLE_LITERAL
%token ADD SUB MUL DIV CR LB RB
%type <double_value> expression term primary_expression
%%
line_list
: line
| line_list line
;
line
: expression CR
{
printf(">> %f ------ \n", $1);
}
;
expression
: term
| expression ADD term
{
$$ = $1 + $3;
printf("%f + %f = %f\n", $$, $1, $3);
}
| expression SUB term
{
$$ = $1 - $3;
printf("%f - %f = %f\n", $$, $1, $3);
}
;
term
: primary_expression
| term MUL primary_expression
{
$$ = $1 * $3;
printf("%f * %f = %f\n", $$, $1, $3);
}
| term DIV primary_expression
{
$$ = $1 / $3;
printf("%f / %f = %f\n", $$, $1, $3);
}
;
primary_expression
: DOUBLE_LITERAL
| LB expression RB
{
$$ = $2;
printf("( %f )", $2);
}
;
%%
int yyerror(char const *str)
{
extern char *yytext;
fprintf(stderr, "parser error near %s\n", yytext);
return 0;
}
int main(void)
{
extern int yyparse(void);
extern FILE *yyin;
yyin = stdin;
if (yyparse()) {
fprintf(stderr, "Error ! Error ! Error ! \n");
exit(1);
}
}
yacc -dv mycalc.y 生成文件 y.tab.h y.tab.c y.output
为了方便编译,加入一个makefile文件
mycalc: *.c *.h
cc -o mycalc *.c
*.c *.h : mycalc.l mycalc.y
echo " - gen .h .c file";
lex mycalc.l
yacc -dv mycalc.y
clean:
rm mycalc
rm *.c *.h *.output
run:
./mycalc