Yacc实现简单的计算器并自主实现yylex函数
Yacc是用于构造语法分析器的常用工具,本文中用Yacc实现了一个简单的计算器,并自主实现了yylex()函数,通常这个函数不写的话系统也会自动生成一个,但自己写一遍有助于理解编译器的工作原理,对于新手学习很有帮助。这个计算器在进行输入时,简单表达式以分号结束,它会自动忽略空格和tab。
%{
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#define YYSTYPE double
int yylex();
extern int yyparse();
FILE* yyin;
void yyerror(const char* s);
%}
%token ADD SUB MUL DIV NUMBER
%left ADD SUB
%left MUL DIV
%right UMINUS
%%
lines : lines expr ';' {printf("%g\n",$2);}
| lines ';'
|
;
expr : expr ADD expr {$$=$1+$3;}
| expr SUB expr {$$=$1-$3;}
| expr MUL expr {$$=$1*$3;}
| expr DIV expr {$$=$1/$3;}
| '(' expr ')' {$$=$2;}
| SUB expr %prec UMINUS {$$=-$2;}
| NUMBER
;
%%
int yylex()
{
int t;
while(1)
{
t=getchar();
if(t==' '||t=='\t'||t=='\n')
{}
else if(isdigit(t))
{ yylval=0;
while(isdigit(t)){yylval=yylval*10+t-'0';t=getchar();}
ungetc(t,stdin);
return NUMBER;
}
else{
switch(t)
{
case '+':
return ADD;
case '-':
return SUB;
case '*':
return MUL;
case '/':
return DIV;
default:
return t;
}
}
}
}
int main(void)
{
yyin = stdin;
do{
yyparse();
}while(!feof(yyin));
return 0;
}
void yyerror(const char* s)
{
fprintf(stderr,"Parse error:%s\n",s);
exit(1);
}
在Linux系统下,这个文件应保存为.y格式,可以用bison进行编译,具体命令如下(假如我们写的代码保存在cal.y文件中):
bison -d cal.y
这条命令执行完成之后会生成一个cal.tab.c 和一个 cal.tab.h
然后用gcc编译cal.tab.c即可
gcc cal.tab.c -o cal
生成可执行程序cal后运行即可