词法分析器生成工具flex的简单使用
时间:2010-10-17 来源:osdba
2. LEX源文件的格式 LEX对源文件的格式要求非常严格,比如若将要求顶行书写的语句变成非顶行书写就会产生致命错误。而LEX本身的查错能力很弱,所以书写时一定要注意。 LEX的源文件由三个部份组成,每个部分之间用顶行的“%%”分割,其格式如下:
定义部份 |
下面以统计单词出现的次数的源程序count.l做说明,count.l的内容如下:
%{ |
2.1定义部分:
%{ |
模式 | 解 释 |
x | 配置单个字母x |
. | 匹配除换行符’\n’之外的任意字符 |
[xyz] | 匹配x、y或z |
[abj-oz] | 匹配a、b、z及j至o之间的字母 |
[^A-Z] | 除大写字母A-Z之外的其它字符 |
[^A-Z\n] | 除大写字母A-Z和换行符之外的其它字符 |
r* | 匹配0个或多个r |
r+ | 匹配1个或多个r |
r? |
匹配0个或1个r |
2.2规则部分 规则部份是LEX源文件的核心部份,它包括一组模式和在生成分析器识别相应模式后对相应模式进行处理的C语言动作(Action)。格式如下
C语言代码 |
2.3 用户附加C语言部份 LEX对此部份不作任何处理,仅仅将之直接拷贝到输出文件lex.yy.c的尾部。在些部份,可定义对模式进行处理的C语言函数、主函数和yylex要调用的函数yywrap()等。如果用户在其它C模块中提供这些函数,用户代码部份可以省略。
3.生成源代码和编译运行 flex count.l gcc -g lex.yy.c -o count 运行: osdba@osdba-laptop:~/tmp$ ./count <<EOF aaa bbb ccc 999 EOF
(id=aaa) (id=bbb) (id=ccc) (num=999) num=1,id=3 osdba@osdba-laptop:~/tmp$
4. 模式匹配说明 yylex()函数被调用之后,它首先检查全局文件指针变量yyin是否有定义,如有,则将之设置为将要扫描的文件指针。如无,则设置为标准输入文件stdin.同理,如全局文件指针变量yyout无定义,则将之设置为标准输出文件stdout。 若有多个模式与被扫描文件中的字符串相匹配,则yylex()执行能匹配最长字符串的模式,称为“最长匹配原则”;若还有多个模式匹配长度相同的字符串,则yylex()选择在LEX源文件中排列最前面的模式进行匹配,称为“最先匹配原则”。yylex()常通过超前搜索一个字符来实现这样的原则,如果使用超前搜索匹配了某一模式,则yylex()在进行下一次分析前,将回退一个字符。见下例: %% program {printf(“keyword:%s!\n”,yytext); /*模式一*/} procedure {printf(“keyword:%s!\n”,yytext); /*模式二*/} [a-z][a-z0-9]* {printf(“identifier:%s!\n”,yytext); /*模式三*/} %% 如输入串为”programming”,yylex()分析到子串”program”时,有模式一和三可以匹配,但根据最长搜索原则,发现在继续读入输入串时,还可匹配模式三。这样,将输出”identifier:programming!”。如输入串为”program”,则按最先匹配原则,模式一与之匹配,输出”keyword:program!”。注意,若将模式一和模式三在源文件中次序弄反,则模式一永远也得不到匹配。若无模式可匹配输入串,则使用缺省规则,即将输入串原样拷贝至输出文件yyout中。
5. 常用全局变量和宏 lex.yy.c中常用全局变量、函数和宏很多,在此仅指出一些最常用的,若需要更详细信息,请阅读源文件。 (1) FILE *yyin,*yyout:为指向字符输入和结果输出文件的指针。如用户未对其定义,则设为标准输入文件stdin和stdout。 (2) int yylex():为词法分析程序,它自动移动文件指针yyin和yyout。在定义模式动作时,用户可用return语句结束yylex(),return 必须返回一整数。由于yylex()的运行环境都是以全局变量的方式保存,因此,在下一次调用yylex()时,yylex()可从上次扫描的断点处继续扫描,在语法分析时,可利用这一特性。若用户未定义相应的return语句,则yylex()继续分析被扫描的文件,直到碰到文件结束标志EOF。在读到EOF时,yylex()调用int yywrap()函数(该函数用户必须提供),若该函数返回非0值,则yylex()返回0而结束。否则,yylex()继续对yyin指向的文件扫描。 (3) char *yytext:存放当前被识别的词形。 (4) int yyleng:存放字符串yytext的长度。 (5) int yywrap():参见(2) (6) yymore():将当前识别的词形保留在yytext中,分析器下次扫描时的词形将加追加在yytext中。例模式定义如下 …… hello {printf(“%s!”,yytext);yymore();} world {printf(“%s!”,yytext);} …… 当输入串为”helloworld”时,将输出”hello!helloworld!” (7) yyless(int n):回退当前识别的词形中n个字符到输入中 (8) unput(char c):回退字符c到输入,它将作为下一次扫描的开始字符 (9) input():让分析器从输入缓冲区中读取当前字符,并将yyin指向下一字符 (10)yyterminate():中断对当前文件的分析,将yyin指向EOF。 (11)yyrestart(FILE * file):重新设置分析器的扫描文件为file (12)ECHO:将当前识别的字符串拷贝到yyout (13)BEGIN:激活开始条件对应的模式 (14)REJECT:放弃当前匹配的字符串和当前的模式,让分析器重新扫描当前的字符串,并选择另一个最佳的模式再次进行匹配。
6. 条件模式 LEX提供控制模式在一定状态下使用的功能,称为条件模式。LEX首先在定义部份通过%start来定义条件句。在规则部份可通过宏 BEGIN 条件名 来激活条件。BEGIN INITIAL或BEGIN 0将休眠所有的条件模式,使分析器回到开始状态。 例:将输入文件中的单词”magic” 作如下处理:识别”magic”时,如”magic”所在行行首为字符’a’,则输出”first”;若为’b’,则输出”second”;否则,输出”magic”。如不用条件模式,LEX源文件可这样写:
%{int flag;}% |
%start AA BB CC |