Lex入门

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

原文地址:https://www.cnblogs.com/youxin/p/3009121.html