Lex 主要功能是生成一个词法分析器(scanner)的 C 源码,描述规则采用正则表达式(regular expression)。描述词法分析器的文件 *.l 经过lex编译后,生成一个lex.yy.c 的文件,然后由 C 编译器编译生成一个词法分析器。词法分析器,简言之,就是将输入的各种符号,转化成相应的标识符(token),转化后的标识符很容易被后续阶段处理,如YACC 或 Bison,过程如图
,“lex”和“yacc”这两个名字所代表的也包括这些工具的 GNU 版本 flex 和 bison。 给出的代码应该适用于所有主流版本,比如 MKS yacc。它完全是一个融洽的大家族!
Flex (fast lexical analyser generator) 是 Lex 的另一个替代品。它经常和自由软件 Bison 语法分析器生成器 一起使用。Flex 最初由 Vern Paxson 于 1987 年用C语言写成。Flex手册里对 Flex 描述如下:
Flex是一个生成扫描器的工具,能够识别文本中的词法模式。Flex 读入给定的输入文件,如果没有给定文件名的话,则从标准输入读取,从而获得一个关于需要生成的扫描器的描述。此描述叫做 规则,由正则表达式和 C代码对组成。Flex 的输出是一个 C 代码文件——lex.yy.c——其中定义了yylex() 函数。编译输出文件并且和 -lfl 库链接生成一个可执行文件。当运行可执行文件的时候,它分析输入文件,为每一个正则表达式寻找匹配。当发现一个匹配时,它执行与此正则表达式相关的C代码。Flex 不是GNU工程,但是GNU为Flex 写了手册。
总之,Flex 是词法分析工具,它读取输入源文件,然后生成 C 语言源程序,通常默认的是 "lex.yy.c", 该文件中包含 yylex( ) 例程,并且可以被 C 编译器编译链接为可执行文件,在该词法分析器运行时,它会根据已定义的规则,在遇到一定的匹配模式时执行相应的 C 代码,从而完成词法分析动作
gcc lex.yy.c 报错:
In function `yylex':
lex.yy.c:(.text+0x39b): undefined reference to `yywrap'
/tmp/ccIx8oEA.o: In function `input':
lex.yy.c:(.text+0xcdb): undefined reference to `yywrap'
The scanner calls this function on end of file, so you can point it to another file and continue scanning its contents. If you don't need this, use
%option noyywrap (一般在文件开头加,类似这样
%option noyywrap
%{ /* * * * * * * * * * * * * * * DEFINITIONS * * * * * * * * * * * * * * */ %}
)
or link with -lfl
to use the default yywrap() function in the library fl
.(就是gcc lex.yy.c -lfl )
还有一种办法,我们自己写一个不做什么的yywrap()函数;
int yywrap() { return 1; }
以上3中解决方案都可以。
输入几行字,计算行数,单词数和字符数.
%option noyywrap
%{
int chars = 0;
int words = 0;
int lines = 0;
%}
%%
[a-zA-Z]+ { words++; chars += strlen(yytext); }
\n { chars++; lines++; }
. { chars++; }
%%
main(int argc, char **argv)
{
yylex();
printf("%8d%8d%8d\n", lines, words, chars);
}
{}内的是c编写的动作
按照下面过程编译。
#flex test.l
#gcc lex.yy.c -o main.out
#./main.out (不要再这行接着输入文字,flex不会计数的)
hello world
you can say
按ctrl+d结束
输出结果 2 5 24
修改上面的例子,将正则表达式放在全局声明中:
%{ int chars = 0; int words = 0; int lines = 0; %} mywords [a-zA-Z]+ mylines \n mychars . %% {mywords} { words++; chars += strlen(yytext); } {mylines} { chars++; lines++; } {mychars} { chars++; } %% main(int argc, char **argv) { yylex(); printf("%8d%8d%8d\n", lines, words, chars); }
小知识:
flex有很多选项,我们不想使用默认的lex.yy.c名字,加上
-o lexname 就可以了。
flex -o b.yy.c b.l
可以使用man flex查看帮助
The Scanner as Coroutine(协同程序)
即怎样将扫描到的标记给其他程序使用,下面的例子,希望扫描到+ 或 -时做一个特殊输出。
当调用yylex时,若扫描到return对应的标记时,yylex返回,且值就为return后的值;
若没扫描到return对应的标记,yylex继续执行,不返回。
下次调用自动从前一次的扫描位置处开始。
%option noyywrap %{ enum yytokentype{ ADD=259, SUB=260 }; %} myadd "+" mysub "-" myother . %% {myadd} { return ADD;} {mysub} { return SUB;} {myother} {printf("Mystery character\n");} %% main(int argc,char **argv) { int token; while(token=yylex()) { if(token==ADD||token==SUB ) {//yylex的返回值只能是ADD 或 SUB. printf("meet + or -\n"); } else { printf("this else statement will not be printed, \ because if yylex return,the retrun value must be ADD or SUB."); } } }
$./b.out
h+f-w
Mystery character
meet + or -
Mystery character
meet + or -
Mystery character
参考:http://www.cnblogs.com/vestinfo/archive/2012/09/29/2708931.html
http://xiaoxia.org/2011/10/24/writing-a-compiler-learning-gnu-flex-write-a-lexical-analyzer/
http://web.eecs.utk.edu/~bvz/cs461/notes/flex/
http://www.ibm.com/developerworks/cn/linux/sdk/lex/
http://www.ibm.com/developerworks/cn/linux/l-lexyac.html
http://course.cug.edu.cn/bianyi/shiyan/CHAPTER/f1.htm
http://wenku.baidu.com/view/5b46758da0116c175f0e4898.html