lex02.flex的使用 下载本文

内容发布更新时间 : 2024/11/19 5:48:29星期一 下面是文章的全部内容请认真阅读。

从lex&yacc说到编译器(2.flex的使用)

作者:tangl_99 QQ:8664220

msn:tangl_99@hotmail.com email:tangl_99@sohu.com

看了第一篇的关于正则表达式的说明后,下面我们就来通过它,使用flex这个词法分析工具来构造我们的编译器的词法分析器.

关于lex的教程应该是很多,这里我就简单地介绍一下,然后着重后面的lex和yacc的配合使用以及其技巧.所以,如果你不看了后还是不太明白lex或者yacc的使用,请你自己上网去查查,这方面的教程是很多的.我知道的一篇常见的就是 Yacc 与 Lex 快速入门 Lex 与 Yacc 介绍

它的作者就是Ashish Bansal.

Flex就是fast lex的意思.而lex就是Lexical Analyzar的意思.flex可以在cygwin或者gnupro中找到.它是unix的一个工具,属于GNU组织产品.网上也可以找到单独可以在windows下用的版本. 我们一般把我们的词法扫描程序要扫描的一些单词(token)用正则表达式写好,然后作为lex的输入文件,输入命令flex xxx.l(xxx.l就是输入文件),lex经过处理后,就能得到一个名字叫lex.yy.c的C源代码.这个C源代码文件,就是我们的词法扫描程序.通常lex为我们生成的词法分析器的C源代码都是十分复杂而且庞大的,我们一般根本不会去查看里面的代码(放心好了,flex这个东西不会出错的)

下面让我们看看几个我已经使用过的几个lex输入文件.

这是一个前段时间我为GBA上的一个RPG游戏写的脚本引擎所使用的lex输入文件(部分) 例2.1 %{

/* need this for the call to atof() below */ #include #include #include #include \ %}

digit [0-9]

number (\hexnumber \

letter [a-zA-Z]

identifier ({letter}|_)({number}|{letter}|_)* newline [\\n] whitespace [ \\t]+ string \\\comment \%%

{string} { return VM_STRING; } \ { return VMIN_LOGO; } \ { return VMIN_FACEIN; } \ { return VMIN_FACEOUT; } \ { return VMIN_LOAD_TILE; } \\\ { return VMIN_CREATE_MAP; } \\ } \LOG; } \LOG;} \ { return VMIN_FIGHT; } \ { return VMIN_DELAY; } \ { return VMIN_PRESS_A; } \ { return VMIN_PRESS_B; } \ { return VMIN_PRESS_R; } \ { return VMIN_PRESS_L; } \\{number} { return VM_NUMBER; } {whitespace} { /* skip whitespace */ } {identifier} { return VM_ID; } {newline} ; . ; %% int yywrap() {

return 1; }

这里的lex输入文件一共有三个部分,用%%分开.第一部分中的%{和}%中的内容就是直接放在lex输出C代码中的顶部.我们通过它可以来定义一些所需要的宏,函数和include一些头文件等等.我的这个lex输入文件中也没什么特别的东西,就是常规的C源文件的include头文件 %{

/* need this for the call to atof() below */

#include #include #include #include \%}

第一部分中,除了前面的%{和}%包含的部分,下面的就是正则表达式的定义. 看了第一篇的正则表达式,这样你就能够在这里派上用场了. 让我们来看看我这里定义的正则表达式: digit [0-9]

number (\hexnumber \letter [a-zA-Z]

identifier ({letter}|_)({number}|{letter}|_)* newline [\\n] whitespace [ \\t]+ string \\\comment \

digit就不用说了,就是0-9的阿拉伯数字定义,第一篇文章中也举了这个例子.number就是digit的1到无限次的重复,再在其前面加上”+”和”-“符号. 注意:

“a”: 即使a是元字符,它仍是字符a \\a: 当a是元字符时候,为字符a

a?: 一个可选的a,也就是说可以是a,也可以没有a a|b: a或b (a): a本身

[abc]: 字符a,b或c中的任一个 [a-d]: a,b,d或者d中的任一个 [^ab]: 除了a或b外的任何一个字符 .: 除了新行之外的任一个字符 {xxx}: 名字xxx表示的正则表达式

这里需要特别说明的就是 newline [\\n]

newline就是新行,这里我使用了[]把\\n换行号括起来.因为如果我直接用\\n表示的话,那么按照上面的规则,那就会看成\\和n两个字符,所以我使用了[\\n].有些时候newline也被写成[\\n]|[\\r\\n].因为在文本文件中,一般换行一次,那么就是一个\\n(0xA),可是在二进制文件中,换行有时候又是\\r\\n(0xD,0xA)一共两个字符号.

第二部分就是定义扫描到正则表达式的动作.

这些动作其实就是C代码,它们将会被镶嵌在lex输出的C文件中的yylex()函数中.