flex,前身是lex,lex是1975年由Mike Lesk和当时尚在AT&T实习的Eric Schmidt共同完成的基于UNIX环境的词法分析器的生成工具。这个lex很有名气,但是无奈效率太低加上有bug,让人用的很不爽。后来伯克利实验室的Vern Paxson用C重新写了lex,并命名为flex(Fast Lexical Analyzer Generator)。
Bison,bison的前身是传说中的yacc,yacc是由贝尔实验室的S.C.Johnson基于Knuth大神的LR分析技术,于1975~1978年写成。1987年 UC Berkeley 的Bob Corbett在BSD下重写了yacc。在后来GNU project接管了项目,添加了很多特性,形成了今天的GNU Bison语法分析器生成工具。
这里提供的bison和flex的程序长这个样子:
看着很多人拿到老师的文档按部就班的做了,可是……很迷
下面给大家展示一下爽的一笔的实验过程:
先看下老师的指示和相应的文件:
文件呢,这里有前言说的flex和bison工具还有现有的tiny编译器的一些工具
进行flex生成词法分析器操作:
将flex放到tiny.l旁边,命令行执行,生成lex.yy.c
进行bison生成语法分析器操作:
将bison放到tiny.y旁边,命令行执行,生成tiny.tab.h&tiny.tab.c
构建工程,将所需要的所有文件放到一个文件夹中(可以忽略,个人强迫症)【注意,如果选了.h就一定要带上.c,老师的文件有缺漏】
构建工程【easy不说,最好是c项目+Console Application】—–记住flex生成的文件也要放进来,图中忘记截图的
之后!
打开global.h
将位于第30行附近的#include “y.tab.h”换成#include “tiny.tab.h”
进行第一次编译!
编译之后会是这样的错误:
这是因为我们没有拷贝词法语法分析包(因为我们使用的flex和bison生成的,而不是tiny编译器自己的)
这里只需要将analyze的开关关上即可。
/* set NO_PARSE to TRUE to get a scanner-only compiler */
#define NO_PARSE FALSE
/* set NO_ANALYZE to TRUE to get a parser-only compiler */
#define NO_ANALYZE TRUE
进行第二次编译(第一次出现很多warning和错误,再编译一次让warning消停会)
这个时候会有这样的错误
还是不要方,这里的问题是yylex的重复定义,你们还记得书上是怎么要求yacc的吗,最后面一定要有yylex,但是我们的这些个代码中已经在词法分析器的时候就已经设计好可yylex,解决方法很多,最简单粗暴的就是将tiny.tab.c中的yylex(最下面)给删了:
这个时候进行第三次编译,错误将会变成:
这里是一些类型强制转化的问题,和IDE有关,DEV C++貌似都有这个问题codeblocks等没有,所以大家可以开心进行最后这个讲得通的修改吧~
改完之后进行第四次编译出现这个爽歪歪的错误:
这里就开始解释不通了,这错误我们读一下,大概是有一些函数没有成功的声明,由于是多文件的编程,我们看到tiny.tab.c文件中去:
#include "globals.h"
#include "util.h"
#include "scan.h"
#include "parse.h"
引入的是这几个文件,发现出错的函数都是在这里
#include "util.h"
我们神奇的将这个.h改成.c
回到main函数,编译第五遍:
还是错的,但是错变成这样了:
说没有define那我们……就再define一下吧
#include "globals.h"
#include "util.h"
#define ENDFILE 0
/* Procedure printToken prints a token
* and its lexeme to the listing file
*/
void printToken( TokenType token, const char* tokenString )
再一次的编译:
我们发现这个yywrap的可恶,不过之前的实验是自己做的同学理论上也是会遇到这个问题的,直接去yy.lex.c文件中找到注释中yywrap的位置,声明一下就好了,让这个函数有返回值就好!
#define yywrap() 1
/* Flag which is used to allow yywrap()'s to do buffer switches
* instead of setting up a fresh yyin. A bit of a hack ...
*/
大概是222行
这时候再一次的编译:
我还能说什么……
就这样……
结束了……
不过,如果幸运,你的电脑还会遇到这个问题:
这个时候……转战codeblocks吧
/* allocate and set tracing flags */
int EchoSource = TRUE;
int TraceScan = TRUE;
int TraceParse = FALSE;
int TraceAnalyze = FALSE;
int TraceCode = FALSE;
编译运行,然后,命令行执行生成的exe,和sample
大功告成
至于解释那个.h换.c
论坛里有人说是因为……重名定义了,然后如果直接引用实现,表示声明这个引用才是唯一引用。
最后我们看下原理:
就不详细说了,等我下次更新编译原理板块再说吧