实习日志(1)初识flex & bison (计算器的设计)

来源:互联网 发布:fx2n编程手册 编辑:程序博客网 时间:2024/05/29 09:23
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">我怎么也没想到来公司了竟然是做编译原理相关的工作。  毕竟没有学过编译原理 ,看到正则表达式就晕了。T_T</span>

刚刚拿到flex & bison 这本书的时候 感觉一头雾水,完全知道干什么的。第一天看了词法分析工具flex。直接用flex写出统计单词,行数,字符数的程序,比起直接用C++去模拟,简单的多了。顿时就感觉这个东西好叼。然后就看到了bison 这个这个东西, 后来才懂flex & bison 这2个东西 一个时词法分析,一个时语法分析。2个东西在一起就可以写编译器了。。。。

* wc程序 */%option noyywrap%{int chars = 0;int words =0;int lines = 0;%}%%[a-zA-Z]+{ ++words;chars += strlen(yytext) ;}\n  { ++lines ; ++chars;}.   { ++chars ; }%%int main(int argc,char* argv[]){yylex();printf("%d %d %d\n",lines,words,chars);return 0;}



虽然写一个计算器其实时很简单的,但是还是整整用了2天才写出一个完成功能的计算器 。。。。

首先是写词法分析分析器 calc1-2.l ,包含了调试的代码 

/*calc1-2.l*/%{#define YYSTYPE double#include "calc1-2.tab.h"#include <stdlib.h>#ifdef debug    YYSTYPE yylval;#endif%}%%"+"     { return ADD; }"-"     { return SUB; }"*"     { return MUL; }"/"     { return DIV; }"|"     { return ABS; }"("     { return OP; }")"     { return CP; }([0-9]*\.?[0-9]+|[0-9]+\.)  { yylval = atof(yytext); return NUMBER;}"sqrt"  { return SQRT; }"**"    { return SQR; }\n      { return EOL; }[ \t]   {}"//".*  {}%%#ifdef debugint main(int argc ,char* argv[]){    int token;    while(token = yylex())    {        printf("%d",token);        if(token ==NUMBER)        {            printf("= %f\n",yylval);        }        else            printf("\n");    }    return 0;}#endif

然后就是些语法分析器。我想实现的功能比较多,所以刚开始写规则的时候有点乱,后来理清楚了,才运行正确。 

语法分析器 calc1-2.y

/* calc1-2.y*/%{#define YYSTYPE double#include<stdio.h>#include<math.h>%}%token NUMBER%token ADD SUB MUL DIV ABS%token EOL%token OP CP%token SQR SQRT%%calclist:    | calclist exp EOL { printf("ans = %f\n>>> " ,$2 );  }    ;exp: factor { $$ = $1; }    | exp ADD factor { $$ = $1 + $3 ; }    | exp SUB factor { $$ = $1 - $3 ; }    ;factor: tmp { $$ =$1; }    | factor MUL tmp { $$ = $1 * $3; }    | factor DIV tmp { $$ = $1 / $3; }    ;tmp: term { $$ = $1; }    | SUB tmp { $$ = -$2; }    | tmp SQR tmp { $$ = pow($1,$3);  /*printf("%d %d %d\n",$1,$2,$3);*/}    ;term: NUMBER { $$ = $1;}    | ABS exp ABS { $$ = fabs($2);}    | OP exp CP { $$ = $2; }    | SQRT OP exp CP { $$ = sqrt($3) ;/*printf(" %d %d %d\n",$1,$2,$3);*/ }    ;%%int main(){    printf(">>> ");    while(1)        yyparse();    return 0;}yyerror(char *s){    fprintf(stderr,"error : %s\n",s);}

关于用yylval传递值得问题,一开始的计算器都整数的,后来想改成浮点数,不知道怎么改。后来在一篇博客上看到了。宏定义 YYSYYPE 的类型成自己想要的类型,一般定义成公用体。  最坑了一点是是 宏定义一定要定义在代码首行,不然一直错误。 我这里卡了好久。 。。  


关于编译,看到了makfile这个东西,所以就去看了一点基础的。  用makefile 可以实现自动化编译。

/*makefile*/calc1-2: calc1-2.l calc1-2.y bison -d calc1-2.yflex -o calc1-2.lex.c calc1-2.lcc -o $@ calc1-2.tab.c calc1-2.lex.c -llcalc1-2.lex:calc1-2.y calc1-2.lbison -d calc1-2.yflex -o calc1-2.lex.c calc1-2.lcc -D debug -o $@ calc1-2.lex.c -llclean:rm calc1-2.lex.crm calc1-2.tab.hrm calc1-2.tab.crm calc1-2

编译  calc1-2 没有调试的

➜  calc1-2  make calc1-2bison -d calc1-2.ycalc1-2.y: warning: 2 shift/reduce conflicts [-Wconflicts-sr]flex -o calc1-2.lex.c calc1-2.lcc -o calc1-2 calc1-2.tab.c calc1-2.lex.c -llcalc1-2.tab.c:1141:16: warning: implicit declaration of function 'yylex' is invalid in C99 [-Wimplicit-function-declaration]      yychar = yylex ();               ^calc1-2.tab.c:1354:7: warning: implicit declaration of function 'yyerror' is invalid in C99 [-Wimplicit-function-declaration]      yyerror (YY_("syntax error"));      ^calc1-2.y:46:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]yyerror(char *s)^calc1-2.y:49:1: warning: control reaches end of non-void function [-Wreturn-type]}^4 warnings generated.


编译带调试功能的calc1-2.lex

➜  calc1-2  make calc1-2.lexbison -d calc1-2.ycalc1-2.y: warning: 2 shift/reduce conflicts [-Wconflicts-sr]flex -o calc1-2.lex.c calc1-2.lcc -D debug -o calc1-2.lex calc1-2.lex.c -llcalc1-2.l:32:17: warning: using the result of an assignment as a condition without parentheses [-Wparentheses]    while(token = yylex())          ~~~~~~^~~~~~~~~calc1-2.l:32:17: note: place parentheses around the assignment to silence this warning    while(token = yylex())                ^          (              )calc1-2.l:32:17: note: use '==' to turn this assignment into an equality comparison    while(token = yylex())                ^                ==1 warning generated.


运行calc1-2 测试

➜  calc1-2  ./calc1-2>>> 5/2 + 2ans = 4.500000>>> sqrt(3)**2ans = 3.000000>>> 1+4**0.5    ans = 3.000000>>> ^C


清除生成的所有文件

➜  calc1-2  make cleanrm calc1-2.lex.crm calc1-2.tab.hrm calc1-2.tab.crm calc1-2




0 0
原创粉丝点击