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中。
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;}% %% ^a {flag=’a’;ECHO;} ^b {flag=’b’;ECHO;} \n {flag=0;ECHO;} magic { switch(flag) { case ‘a’:printf(“first”);break; case ‘b’:printf(“second”);break; default :ECHO;break; } } %%
|
如使用条件模式,则上述源文件可简化为