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

<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 debug
int 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.y
	flex -o calc1-2.lex.c calc1-2.l
	cc -o $@ calc1-2.tab.c calc1-2.lex.c -ll


calc1-2.lex:calc1-2.y calc1-2.l
	bison -d calc1-2.y
	flex -o calc1-2.lex.c calc1-2.l
	cc -D debug -o $@ calc1-2.lex.c -ll

clean:
	rm calc1-2.lex.c
	rm calc1-2.tab.h
	rm calc1-2.tab.c
	rm calc1-2

编译  calc1-2 没有调试的

➜  calc1-2  make calc1-2
bison -d calc1-2.y
calc1-2.y: warning: 2 shift/reduce conflicts [-Wconflicts-sr]
flex -o calc1-2.lex.c calc1-2.l
cc -o calc1-2 calc1-2.tab.c calc1-2.lex.c -ll
calc1-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.lex
bison -d calc1-2.y
calc1-2.y: warning: 2 shift/reduce conflicts [-Wconflicts-sr]
flex -o calc1-2.lex.c calc1-2.l
cc -D debug -o calc1-2.lex calc1-2.lex.c -ll
calc1-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 + 2
ans = 4.500000
>>> sqrt(3)**2
ans = 3.000000
>>> 1+4**0.5    
ans = 3.000000
>>> ^C


清除生成的所有文件

➜  calc1-2  make clean
rm calc1-2.lex.c
rm calc1-2.tab.h
rm calc1-2.tab.c
rm calc1-2




你可能感兴趣的:(工作,Flex,biosn)