??xml version="1.0" encoding="utf-8" standalone="yes"?>
在网上搜?/span>flexQ安?/span>flexQ先下蝲flexQ原本打放上来的,但是考虑到版权的问题Q还是不要了。需要的朋友Q我可以发给你)Q然后按照默认的步骤逐步安装?/span>
安装后,讄环境变量Q将Path指向flex.exe所在的文g夹(本机上ؓQ?/span>C:\Program Files\GnuWin32\binQ一般按默认方式安装?/span>flex.exe都在该文件夹内)Q具体步骤:
→?#8220;我的电脑”图标按右?#8594;选择“属?#8221;→选择“高”→单击“环境变量”→?#8220;pȝ变量”中查?/span>Path,q择?#8594;?#8220;~辑”→?#8220;变量?#8221;的最后一Ҏ?#8220;;C:\Program Files\GnuWin32\bin”Q按定完成?/span>
最q我是先从课?/span>TINY语言开始,TINY语言?/span>lex文g在源代码?/span>LEX文g夹内
1. ?/span>tiny.l的最后添加:
int yywrap()
{
return 1;
}
用来l束扫描
2. ?/span>console上输?/span>flex tiny.lQ生?/span>lex.yy.cQ将其替?/span>scan.cQ编译链接生?/span>tiny的编译器?/span>
参考文献:
http://course.cugnc.com/bianyi/shiyan/CHAPTER/f1.htm
http://blog.csdn.net/litchh/archive/2004/07/14/40983.aspx
http://www.cnscn.org/read.php?tid-10862.html
我们往往只是生的lex.yy.c直接d?/span>MFC工程完事,但是~译Ӟ׃各种各样的原因,而生大量的语法错误Q难以修攏V本人最q在MFC下构造一个扩?/span>TINY语言的词法分析也是遇C一些问题,查阅了大量资料(已经主要的参考资料放?/span>lex学习栏目上,LQ?a href="http://www.shnenglu.com/Plator/category/7159.html">http://www.shnenglu.com/Plator/category/7159.htmlQ,耗费了我两天的时间解册些问题。因此我惛_本文Q将把一些注意问题叙q如下,希望对一些朋友有所帮助?/span>
1. 要将lex.yy.c改ؓCPP文gQ?/span>lex.yy.cpp。因?/span>MFC?/span>C++工程Q若不修改则会出现错误;
2. ?/span>#include <stdio.h>改ؓ#include <stdafx.h>Q不然会出现如下错误Q?/span>unexpected end of file while looking for precompiled header directiveQ?/span>
3. ?/span>flex安装目录?/span>include文g夹的unistd.hd?/span>MFC工程内,q修?/span>#include <unistd.h>Qؓ#include "unistd.h"。因?/span>unistd.h文g中定义了词法分析需要用C些头文g?/span>
4. 如果lex源文仉要用inputd字符Q则应该换用yyinputQ因?/span>input会与C++中的名词重复,会出现编译错误;
5. 注意一?/span>I/O例程的应用,具体误Q?a href="http://www.shnenglu.com/Plator/archive/2008/05/24/50940.html">http://www.shnenglu.com/Plator/archive/2008/05/24/50940.html
只是短短几个错误Q但是解决的q程参考了大量资料Q虽然不知道q些资料何h之手Q但是在此感谢这些作者!
定义
%%
规则
%%
用户代码
一?Lex E序分ؓ三个D:W一D| C ?Lex 的全局声明Q第二段包括模式QC 代码Q,W三D|补充?C 函数?q些D以%%来分界?下面是一个行C字数的统计工兗?/p>
int num_lines = 0, num_chars = 0;
%%
\n ++num_lines; ++num_chars;
. ++num_chars;
%%
main()
{
yylex();
printf( "# of lines = %d, # of chars = %d\n",
num_lines, num_chars );
}
Second!
对First内容的回?
C ?Lex 的全局声明
q一D中我们可以增加 C 变量声明。这里我们将为字数统计程序声明一个整型变量,来保存程序统计出来的字数。我们还进?Lex 的标记声明?
字数l计E序的声?/p>
%{
int wordCount = 0;
%}
chars [A-za-z\_\'\.\"]
numbers ([0-9])+
delim [" "\n\t]
whitespace {delim}+
words {chars}+
%%
两个癑ֈh记指Z Lex E序中这一D늚l束和三D中W二D늚开始?
Lex 的模式匹配规?
让我们看一?Lex 描述我们所要匹配的标记的规则。(我们?C 来定义标记匹配后的动作。)l箋看我们的字数l计E序Q下面是标记匚w的规则?
字数l计E序中的 Lex 规则
{words} { wordCount++; /*
increase the word count by one*/ }
{whitespace} { /* do
nothing*/ }
{numbers} { /* one may
want to add some processing here*/ }
%%
C 代码
Lex ~程的第三段Q也是最后一D覆盖了 C 的函数声明(有时是主函数Q。注意这一D必d?yywrap() 函数?Lex 有一套可供用的函数和变量?其中之一是 yywrap。一般来_yywrap() 的定义如下例。我们将?高 Lex 中探讨这一问题?
字数l计E序?C 代码D?/p>
void main()
{
yylex(); /* start the
analysis*/
printf(" No of words:
%d\n", wordCount);
}
int yywrap()
{
return 1;
}
Lex ~程的基本元素就q样搞定了,它将帮助你编写简单的词法分析E序?
Third
高Lex
Lex 有几个函数和变量提供了不同的信息Q可以用来编译实现复杂函数的E序。下表中列出了一些变量和函数Q以及它们的使用?详尽的列表请参?Lex 手册?
Lex 变量
yyin FILE* cd?它指?lexer 正在解析的当前文件?br> yyout FILE* cd?它指向记?lexer 输出的位|?~省情况下,yyin ?yyout 都指向标准输入和输出?br> yytext 匚w模式的文本存储在q一变量中(char*Q?br> yyleng l出匚w模式的长度?br> yylineno 提供当前的行C息。(lexer不一定支持。)
Lex 函数
yylex() q一函数开始分析?它由 Lex 自动生成?br> yywrap() q一函数在文Ӟ或输入)的末调用。如果函数的q回值是1Q就停止解析?因此它可以用来解析多个文件。代码可以写在第三段Q这p够解析多个文件?Ҏ是?yyin 文g指针Q见上表Q指向不同的文gQ直到所有的文g都被解析。最后,yywrap() 可以q回 1 来表C析的l束?br> yyless(int n) q一函数可以用来送回除了?n? 个字W外的所有读出标记?br> yymore() q一函数告诉 Lexer 下一个标记附加到当前标记后?
到此为止Q可能你看到lexE序q会范晕Q没关系Q下面我们接着来,分析一个类pascal语法的极析器Q?
/* q个是注释?/
/* scanner for a toy Pascal-like language */
x部分开?br>%{ 内的东西会原不动地出现在输出文件中 }%
%{
/* need this for the call to atof() below */
#include <math.h>
%}
DIGIT [0-9]
ID [a-z][a-z0-9]*
%%
模式部分开?
{DIGIT}+ {
printf( "An integer: %s (%d)\n", yytext,
atoi( yytext ) );
}
{DIGIT}+"."{DIGIT}* {
printf( "A float: %s (%g)\n", yytext,
atof( yytext ) );
}
if|then|begin|end|procedure|function {
printf( "A keyword: %s\n", yytext );
}
{ID} printf( "An identifier: %s\n", yytext );
"+"|"-"|"*"|"/" printf( "An operator: %s\n", yytext );
"{"[^}\n]*"}" /* eat up one-line comments */
[ \t\n]+ /* eat up whitespace */
. printf( "Unrecognized character: %s\n", yytext );
%%
补充部分开?
main( argc, argv )
int argc;
char **argv;
{
++argv, --argc; /* skip over program name */
if ( argc > 0 )
yyin = fopen( argv[0], "r" );
else
yyin = stdin;
yylex();
}
惌真正了解lex, [[正则表达式]] 是关?
Four
yytext 匚w模式的文本存储变? 可以通过在申明阶D?pointer?array来控制是一个字W指针还是一个字W数l。指针模式与数组模式各有特点Q导致在yytexx上也不一P具体请参考lex手册Q?
在模式阶D中
模式 动作
[ \t]+ putchar( ' ' );
[ \t]+$ /* ignore this token */
模式部分是正则表辑ּQ动作部分是处理ҎQ动作部分如果时{开_那么Q动作将会持l到},如果动作中出C括号{},开始采?%{ %}来表C动作去区段。动作部分如果时 |,pCZ下一条规则执行相同的动作?
好的Q我们来看一个更为实用一点的lexE序?br>我们先定义三个动?
ECHO yytext输出
BEGIN 开始一个条件处理块
REJECT 指示析器对当前规则不做处理,而是采用W二匚w规则?
int word_count = 0;
%%
frob special(); REJECT;
[^ \t\n]+ ++word_count;
如果frob没有REJECT动作Qfrob不会被计数Q因析器在通常情况下,每个被匹配的对象只会对一个动作生效,多个REJECT也是允许的,会寻找下一个最配的规则来做处理。所以,下面的规则会把输入的"abcd"处理后输?abcdabcaba".
%%
a |
ab |
abc |
abcd ECHO; REJECT;
.|\n /* eat up any unmatched character */
`yymore()' 告诉解析器下一ơ匹配的规则Q满的部分会d到当前yytext值得后面而不是替换它?例如Q指定的输入"mega-kludge"l过下面的程序处理后会输出"mega-mega-kludge"?
%%
mega- ECHO; yymore();
kludge ECHO;
W一?"mega-" 被满_ƈ且输? 然后 "kludge" 满, 但是q没有替换之前的"mega-"而是"kludge"附加C的后面,然后输出的其实是"mega-kludge".
yymore()需要两件事情需要注意。第一Qyymnore()依赖于表现当前匹配项的长度yyleng的|所以用yymore不允许改变yyleng的倹{第二,yymore()的用会使解析器付出一点点性能的代仗?
有yymore()有yyless()
yyless(n) q回当前匚ww了开始的n个字W内的所有的内容到输入缓存区Q解析器处理下一个匹配时Q它们将会被重新解析。yyless会Dyytext与yyleng的调整。(yyleng会{于=nQ?如输?foobar"被下面的E序处理后,会输出"boobarbar". 因ؓ前n=3个字Wfoo外的字符bar被重新返回到输入~存Z?
%%
foobar ECHO; yyless(3);
[a-z]+ ECHO;
参数0对于yyless会D整个当前匚w会被重新解析。除非你改变了解析器本来的处理流E?如用begin),q将会导致@环结束。需要注意的是,yyless是一个宏Qƈ且在flex输入文g中用,不能在其他源文g中用?
unput(c) 字Wc攑֛到输入流中,该字W可以重新被解析。下面的动作当前的匚w值附上括号后重新q行匚w?
{
int i;
/* Copy yytext because unput() trashes yytext */
char *yycopy = strdup( yytext );
unput( ')' );
for ( i = yyleng - 1; i >= 0; --i )
unput( yycopy[i] );
unput( '(' );
free( yycopy );
}
注意: ׃每次unput()指定的字符d到输入源的开_所以将字符串添加到输入源开头必M后道前处理。一个比较重要的潜在问题是用unput()的时候,如果采用?pointer指针模式保存yytext,unput会破坏yytext的内容,从最双的字W开始将会破坏左边的一个字W。如果在unput()后要用到yytext,你首先必d制一份yytext,或者用%array模式来保存yytext. 最后你不能放一个EOF去试图标志输入流的结束?
input 从输入源中读取下一个字W。例如,下面有的例子会吃掉C语言注释
%%
"/*" {
register int c;
for ( ; ; )
{
while ( (c = input()) != '*' &&
c != EOF )
; /* eat up text of comment */
if ( c == '*' )
{
while ( (c = input()) == '*' )
;
if ( c == '/' )
break; /* found the end */
}
if ( c == EOF )
{
error( "EOF in comment" );
break;
}
}
}
注意: 如果析器采用用C++~译Qinput()被yyinput()的替代,因ؓinput()与C++中的名Uinput冲突?
YY_FLUSH_BUFFER h解析器内部缓存以便于下一ơ的匚w工作Q首先它会用YY_INPUT填充~存区。这是通用yy_flush_buffer()的一个特例,会在多输入~存中描q?
yyterminate()可以在动作内部返回描q区域中使用Q它终止解析器q返?l解析器调用者,表示操作完成。缺省情况下Q到达文件结束位|也会被调用Q它是一个宏Qƈ且可能重定义?/p>
Lexq阶
模式
模式在第一阶段或第二个阶段使用Q也是在申明或规则阶段中出玎ͼ模式定义了匹配的目标Q目标被匚w后将会执行动作?br>对于模式不想做太多说明,使用正则表达式定义,可以参看 regex ?pcre.
开始条?br>lex提供了根据条件激z规则的机制。在<sc>前缀的规则将会在解析器在"sc"的开始条件下被匹配?/p>
<STRING>[^"]* { /* eat up the string body ... */ ... }
会在启动条?STRING"的情况下被激zR?/p>
<INITIAL,STRING,QUOTE>\. { /* handle an escape ... */ ... }
会?"INITIAL", "STRING", "QUOTE"三者之一的条件下被激zR?/p>
开始条件在输入源的定义(W一Q部分被xQ在‘%s' ?’%x'后跟随着名字列表?%sx了包含的开始条Ӟ%xx了排他的开始条件。开始条件被BEGIN动作ȀzR直C一个BEGIN动作Q满_始条件名U的规则会被规则,不满_动条件的规则不会被执行?/p>
如果是包含条Ӟ没有开始条件的规则也会被激zL行,如果时排他条Ӟ只有满开始条件的规则才会被执行?/p>
h相同排他条g的规则的集合可以使解析器独立于其他的规则。因此,排他条g可以Ҏ地创建微型解析器处理输入源中的独立与其他部分的一部分Q如Q注释)。如果对于包含与排他条gq有hQ可以看下面的例子?/p>
%s example%%<example>foo do_something();bar something_else();
{同?/p>
%x example%%<example>foo do_something();<INITIAL,example>bar something_else();
上面的程序中如果没有<INITIAL,example>Q在example条g下bar规则永q不会被ȀzR如果?lt;example>Q将会导致只能在exmaple开始条件下Ȁz,而INITIAL条g下不会被ȀzR而第一个程序中在Q何条件下bar都被会激zR因为第一个程序用example?sQ时包含条g。页可以通过Ҏ开始条?lt;*>来配|Q何开始条Ӟ上面的程序还可以写ؓQ?/p>
%x example%%<example>foo do_something();<*>bar something_else();
~省规则Q显CZQ何未被匹配的字符Q在开始条件下仍然生效。等同于Q?/p>
<*>.|\\n ECHO;
‘BEGIN(0)’在无开始条件的规则ȀzL件下q回原始状态,q个状态同于开始条件下?INITIAL',所?#8216;BEGIN(INITIAL)'{同?#8217;BEGIN(0)'?br>BEGIN行ؓ在规则部分的开头是默认的代码(BEGIN actions can also be given as indented code at the beginning of the rules section.L译)例如Q下面的代码会仅需SPECIAL开始条Ӟ不管合适yylex()被调用ƈ且全局变量enter_special是true?/p>
int enter_special;%x SPECIAL%% if ( enter_special ) BEGIN(SPECIAL);<SPECIAL>blahblahblah...more rules follow...
Z说明开始条Ӟ我们用两U方法处?123.456".~省会被解析ؓ '123','.','456'三个标记Q如果expect-floats后面会被解析ؓ点?123.456
%{#include <math.h>%}%s expect%%expect-floats BEGIN(expect);<expect>[0-9]+"."[0-9]+ { printf( "found a float, = %f\n", atof( yytext ) ); }<expect>\n { /* that's the end of the line, so * we need another "expect-number" * before we'll recognize any more * numbers */ BEGIN(INITIAL); }[0-9]+ { printf( "found an integer, = %d\n", atoi( yytext ) ); }"." printf( "found a dot\n" );
下面的代码能够是被C语言注释q且l计行数?/p>
%x comment%% int line_num = 1;"/*" BEGIN(comment);<comment>[^*\n]* /* eat anything that's not a '*' */<comment>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */<comment>\n ++line_num;<comment>"*"+"/" BEGIN(INITIAL);
实际上,~写高速解析程序的办法时在每个规则中做可能多的匹配?/p>
This scanner goes to a bit of trouble to match as much text as possible with each rule. In general, when attempting to write a high-speed scanner try to match as much possible in each rule, as it's a big win.
注意: 开始条件的名字实际上时一个整形值ƈ且能够被保存Q所以,上面的代码可以扩展ؓQ?/p>
%x comment foo%% int line_num = 1; int comment_caller;"/*" { comment_caller = INITIAL; BEGIN(comment); }...<foo>"/*" { comment_caller = foo; BEGIN(comment); }<comment>[^*\n]* /* eat anything that's not a '*' */<comment>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */<comment>\n ++line_num;<comment>"*"+"/" BEGIN(comment_caller);
而且Q可能易使用YY_START宏来讉K当前的开始条件。如上面的赋值条件可以改写ؓ
comment_caller = YY_START
YYSTATE是YY_START的别名(因ؓAT&T lex使用了YYSTATEQ?br>注意 开始条件没有他们的名字I间; %s ?%x x?#define形式一栗?/p>
到这里,时一个用排他开始条件如何匹配C风格的引用字W串的处理。包含的扩展的{义,但不包括查,因ؓ代码太长?/p>
%x str%% char string_buf[MAX_STR_CONST]; char *string_buf_ptr;\" string_buf_ptr = string_buf; BEGIN(str);<str>\" { /* saw closing quote - all done */ BEGIN(INITIAL); *string_buf_ptr = '\0'; /* return string constant token type and * value to parser */ }<str>\n { /* error - unterminated string constant */ /* generate error message */ }<str>\\[0-7]{1,3} { /* octal escape sequence */ int result; (void) sscanf( yytext + 1, "%o", &result ); if ( result > 0xff ) /* error, constant is out-of-bounds */ *string_buf_ptr++ = result; }<str>\\[0-9]+ { /* generate error - bad escape sequence; something * like '\48' or '\0777777' */ }<str>\\n *string_buf_ptr++ = '\n';<str>\\t *string_buf_ptr++ = '\t';<str>\\r *string_buf_ptr++ = '\r';<str>\\b *string_buf_ptr++ = '\b';<str>\\f *string_buf_ptr++ = '\f';<str>\\(.|\n) *string_buf_ptr++ = yytext[1];<str>[^\\\n\"]+ { char *yptr = yytext; while ( *yptr ) *string_buf_ptr++ = *yptr++; }
通常Q如上面的例子中所看到你,会有许多相同开始条件的处理。开始条件范围可以简化重复操作?/p>
<SCs>{}
SCs 是一个或开始条件的列表。在q个开始条件范围内Q每个规则将会自动具有前~ `<SCs>' 直到 `}' 与开始的 `{' 匚w. 例如
<ESC>{ "\\n" return '\n'; "\\r" return '\r'; "\\f" return '\f'; "\\0" return '\0';}
{h?
<ESC>"\\n" return '\n';<ESC>"\\r" return '\r';<ESC>"\\f" return '\f';<ESC>"\\0" return '\0';
开始条仉可以嵌套Q下面时三个理开始条件堆栈的参数?
`void yy_push_state(int new_state)'
当前的开始条件压栈,切换?new_state 与?`BEGIN new_state'cM?
`void yy_pop_state()'
从栈弹出,cM?BEGIN.
`int yy_top_state()'
q回栈顶|不改变栈内容?
开始条件栈动态增长,没有固定限制Q如果内容用,E序竟会l止?
Z使用开始条件栈Q需要?`%option stack' 指o?
多输入缓存区
一些允许include文g解析器的解析器要求从几个输入中d内容。YY_INPUT只在l束~存时被调用Q碰?include 后需要切换输入源Q而解析一个描qC讔R要很长时间。ؓ了解xc问题,解析器提供了创徏q在多个输入~存中创建的机制。输入缓存可以通过下面的方式创?
YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
参数Z~存兌的输入文件指针,以及_的可l持size字符Q如果不定Qsize可以使用YY_BUF_SIZE)。返回一个YY_BUFFER_STATE,可以传递到其他的处理过E。YY_BUFFER_STATE是一个不可见l构yy_buffer_state的指针,所以可以安全地使用`((YY_BUFFER_STATE) 0)'来初始化YY_BUFFER_STATEQ如果你愿意Q你可以在解析器之外的源E序中引用这个不透明l构来正的x输入~存。可以通过下面的参数来选择一个缓存区?
void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
切换解析器的输入~存会D记接下来的匹配项来自于新的缓存中。yy_switch_to_buffer可能出现在yywrap中ؓl箋解析做准备,替换打开一个新的文件ƈ执行yyin. 通过yy_switch_to_buffer ?yywrap切换输入源不改变开始条件?
void yy_delete_buffer( YY_BUFFER_STATE buffer )
用于收回与缓存关联的I间。你可以使用下面的函数清I当前内?
void yy_flush_buffer( YY_BUFFER_STATE buffer )
此函数废弃缓存内容,下一个解析器试图匚w一个内Ҏ会使用YY_INPUT来更新缓存区?/p>
`yy_new_buffer()' ?`yy_create_buffer()' 的一个别名,用于提供C++使用new ?delete操作创徏与销毁动态对象的兼容性?/p>
最? YY_CURRENT_BUFFER 宏返?YY_BUFFER_STATE 指针Q表C当前的~存?/p>
q里是一个扩展include使用的一个解析器 (`<<EOF>>' Ҏ将会在以后讨论):
/* "incl" 状态用于获取include的文件名 */
%x incl
%{
#define MAX_INCLUDE_DEPTH 10
YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
int include_stack_ptr = 0;
%}
%%
include BEGIN(incl);
[a-z]+ ECHO;
[^a-z\n]*\n? ECHO;
<incl>[ \t]* /* eat the whitespace */
<incl>[^ \t\n]+ { /* got the include file name */
if ( include_stack_ptr >= MAX_INCLUDE_DEPTH )
{
fprintf( stderr, "Includes nested too deeply" );
exit( 1 );
}
include_stack[include_stack_ptr++] =
YY_CURRENT_BUFFER;
yyin = fopen( yytext, "r" );
if ( ! yyin )
error( ... );
yy_switch_to_buffer(
yy_create_buffer( yyin, YY_BUF_SIZE ) );
BEGIN(INITIAL);
}
<<EOF>> {
if ( --include_stack_ptr < 0 )
{
yyterminate();
}
else
{
yy_delete_buffer( YY_CURRENT_BUFFER );
yy_switch_to_buffer(
include_stack[include_stack_ptr] );
}
}
提供三个q程来实现内存字W串而不是文件输入缓存的解析。它们都要创Z个输入缓存来解析字符Ԍq且q回YY_BUFFER_STATE (可以在完成解析后?`yy_delete_buffer()' 删除).Q也可以通过`yy_switch_to_buffer()'来切? 下一ơ调用`yylex()' 会解析字符丌Ӏ?/p>
`yy_scan_string(const char *str)' 解析0l尾字符丌Ӏ?br>`yy_scan_bytes(const char *bytes, int len)' 解析bytes开始的len个字W?可能包含 0 字符)
注意Q上面的两个函数会创建字W串或字节串的副本?q也许时期望的,因ؓ`yylex()' 会修改被解析~存的内? 可以使用下面的方式来拒绝使用副本:
`yy_scan_buffer(char *base, yy_size_t size)'
会从base开始解析,包含size个字? 最后的两个字节必须?YY_END_OF_BUFFER_CHAR (ASCII NUL)。他们不会被解析, 解析范围?`base[0]' ?`base[size-2]'Q包含)。如果你没能按照q种规定使用baseQ如Q忘C最后的两个YY_END_OF_BUFFER_CHAR字节), `yy_scan_buffer()' 会q回I指针而不创徏YY_BUFFER_STATE。yy_size_tcd是个整型Q可以{化ؓ整数来反映buffer的长度?/p>
文gl束规则
Ҏ规则 "<<EOF>>" 只是规则在文件结束位|发生且yywrap()q回?倹{?如,没有更多的文件要处理). q个动作必须完成下面四g事情之一:
赋值给yyin一个新的文?(早期版本的flex, 此操作后必须调用Ҏ动作 YY_NEW_FILE; q个操作已经不需要了);
执行一个返回申?
执行一个特D的`yyterminate()' 动作;
或者用`yy_switch_to_buffer()' 切换C个新的输入缓存区.
<<EOF>> 不能与其他模式一起用;它也总在开始条件列表申明。如果指定了不合?<<EOF>> 规则, 它将会应用到所有的开始条件而不仅是 <<EOF>> 动作. 指定 <<EOF>> 规则仅在 initial 开始条件下匚wQ就是用:
<INITIAL><<EOF>>
下面的规则可以发现象不关闭的注释cȝ问题?/p>
%x quote
%%
...other rules for dealing with quotes...
<quote><<EOF>> {
error( "unterminated quote" );
yyterminate();
}
<<EOF>> {
if ( *++filelist )
yyin = fopen( *filelist, "r" );
else
yyterminate();
}
q些例程都有默认的宏定义Q但是用户可以重写它们以适应不同的需求。这些例E定义了外部文g和内部字W之间的关系Qƈ且只能同时存在或更改。它们可以被重写使得输入或者输定向到特D的位置Q包括其他的E序或者内存;但是字符集的使用必须在整个例E中保持l一Q?strong>input必须q回0以表C文件结束;unput?strong>input之间的关pdM留,否则Lex不能完成向前搜烦的操作。Lex在不需要的时候不会向前搜索,但是每一个以+*?$l尾的、或者含?的规则需要这个功能。同P当一个表辑ּ是另一个的前缀Ӟ向前搜烦也是必不可少的。参阅下文中有关Lex使用的字W集的讨论。默认的Lex库?00个字W作为备用限制?