FLEX 中文手册Word文档格式.docx

上传人:b****1 文档编号:921376 上传时间:2023-04-29 格式:DOCX 页数:27 大小:31.62KB
下载 相关 举报
FLEX 中文手册Word文档格式.docx_第1页
第1页 / 共27页
FLEX 中文手册Word文档格式.docx_第2页
第2页 / 共27页
FLEX 中文手册Word文档格式.docx_第3页
第3页 / 共27页
FLEX 中文手册Word文档格式.docx_第4页
第4页 / 共27页
FLEX 中文手册Word文档格式.docx_第5页
第5页 / 共27页
FLEX 中文手册Word文档格式.docx_第6页
第6页 / 共27页
FLEX 中文手册Word文档格式.docx_第7页
第7页 / 共27页
FLEX 中文手册Word文档格式.docx_第8页
第8页 / 共27页
FLEX 中文手册Word文档格式.docx_第9页
第9页 / 共27页
FLEX 中文手册Word文档格式.docx_第10页
第10页 / 共27页
FLEX 中文手册Word文档格式.docx_第11页
第11页 / 共27页
FLEX 中文手册Word文档格式.docx_第12页
第12页 / 共27页
FLEX 中文手册Word文档格式.docx_第13页
第13页 / 共27页
FLEX 中文手册Word文档格式.docx_第14页
第14页 / 共27页
FLEX 中文手册Word文档格式.docx_第15页
第15页 / 共27页
FLEX 中文手册Word文档格式.docx_第16页
第16页 / 共27页
FLEX 中文手册Word文档格式.docx_第17页
第17页 / 共27页
FLEX 中文手册Word文档格式.docx_第18页
第18页 / 共27页
FLEX 中文手册Word文档格式.docx_第19页
第19页 / 共27页
FLEX 中文手册Word文档格式.docx_第20页
第20页 / 共27页
亲,该文档总共27页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

FLEX 中文手册Word文档格式.docx

《FLEX 中文手册Word文档格式.docx》由会员分享,可在线阅读,更多相关《FLEX 中文手册Word文档格式.docx(27页珍藏版)》请在冰点文库上搜索。

FLEX 中文手册Word文档格式.docx

/*needthisforthecalltoatof()below*/

#include<

math.h>

%}

DIGIT[0-9]ID[a-z][a-z0-9]*

%%

{DIGIT}+{

printf("

Aninteger:

%s(%d)\n"

yytext,

atoi(yytext));

{DIGIT}+"

."

{DIGIT}*{

Afloat:

%s(%g)\n"

atof(yytext));

if|then|begin|end|procedure|function{

Akeyword:

%s\n"

yytext);

{ID}printf("

Anidentifier:

"

+"

|"

-"

*"

/"

Anoperator:

{"

[^}\n]*"

}"

/*eatupone-linecomments*/

[\t\n]+/*eatupwhitespace*/

.printf("

Unrecognizedcharacter:

intmain(intargc,char**argv)

++argv,--argc;

/*skipoverprogramname*/

if(argc>

0)

yyin=fopen(argv[0],"

r"

);

else

yyin=stdin;

这是一个类似Pascal语言的简单扫描器的初始部分,用来识别不同类型的标志(tokens)并给出报告。

这个例子的详细介绍将在后面的章节中给出。

二、输入文件的格式

flex输入文件包括三个部分,通过“%%”行来分开:

definitions(定义)%%rules(规则)%%usercode(用户代码)

定义部分,包含一些简单的名字定义(namedefinitions),用来简化扫描器的规范,还有一些开始状态

(startconditions)的声明,将会在后面的章节中说明。

名字定义的形式如下:

namedefinition

“name”由字母或者下划线(“_”)起始,后面跟字母,数字,“_”或者“-”(破折号)组成。

定义由名字

后面的一个非空白(non-white-space)字符开始,直到一行的结束。

可以在后面通过“{name}”来引用定

义,并展开为“(definition)”。

例如,

定义了“DIGIT”为一个正规表达式用来匹配单个数字,“ID”为一个正规表达式用来匹配一个字母,后面

跟零个或多个字母和数字。

后面的引用如下,

{DIGIT}*

等同于

([0-9])+"

([0-9])*

用来匹配一个或多个数字,后面跟一个“.”,然后是零个或者多个数字。

flex输入的规则部分包括一系列的规则,形式如下:

patternaction

模式(pattern)不能有缩进,动作(action)必须在同一行。

参见后面对模式和动作的进一步描述。

最后,用户代码部分将被简单的逐字复制到“lex.yy.c”中,作为随同程序用来调用扫描器或者被扫描器

调用。

该部分是可选的,如果没有,输入文件中第二个“%%”也可以省略掉。

在定义部分和规则部分,任何缩进的文本或者包含在“%{”和“%}”中的文本,都会被逐字的复制到输出中(并去掉“%{}”)。

“%{}”本身不能有缩进。

在规则部分,在第一个规则之前的任何缩进的或者%{}中的文本,可以用来声明扫描程序的局部变量。

其它在规则部分的缩进或者%{}中的文本也会被复制到输出,但是它的含义却不好定义,而且可能会产生编译时错误(这一特点是为了与POSIX相同;

参见后面的其它特点)。

在定义部分(但不是在规则部分),一条未缩进的注释(即,由“/*”起始的行)也会被逐字的拷贝到输出,直到下一个“*/”。

三、模式

输入中的模式,使用的是扩展的正规表达式集。

它们是:

'

x'

匹配字符'

.'

除了换行符以外的任意字符(字节)

[xyz]'

一个字符类别(characterclass);

在这个例子中,该模式匹配一个'

,或者一个'

y'

,或者一

个'

z'

'

[abj-oZ]'

一个带有范围的字符类别;

匹配一个'

a'

b'

,或者从'

j'

到'

o'

的任意字母,或者一个'

Z'

[^A-Z]'

一个反选的字符类别(negatedcharacterclass),即任意不属于这些的类别。

在这个例子中,

表示任意一个非大写字母的字符。

[^A-Z\n]'

任意一个非大写字母的字符,或者一个换行符

r*'

零个或者多个r,其中r是任意的正规表达式

r+'

一个或者多个r

r?

零个或者一个r(也就是说,一个可选的r)

r{2,5}'

两个到五个r

r{2,}'

两个或者更多个r

r{4}'

确切的4个r

{name}'

“name”定义的展开(参见前面)

"

[xyz]\"

foo"

(这里单引号和双引号之间没有空格)

文字串:

[xyz]"

foo'

\x'

如果x是一个'

,'

f'

n'

r'

t'

或者'

v'

,则为ANSI-C所解释的\x。

否则,为一个文字'

用来转义操作符,例如'

*'

)。

\0'

一个NUL字符(ASCII代码0)

\123'

八进制值为123的字符

\x2a'

十六进制值为2a的字符

(r)'

匹配一个r;

括号用来改变优先级(参见后面)

rs'

正规表达式r,后面跟随正规表达式s;

称作“concatenation”

r|s'

或者r,或者s

r/s'

一个r,但是后面要跟随一个s。

在文本匹配时,s会被包含进来,以判断该规则是否是最长的匹配,但是在动作执行前会被返回给输入。

因此,动作只会看到匹配r的文本。

这种模式称作trailingcontext。

(有些'

组合,flex会匹配错误;

参见后面的不足和缺陷章节中,关于“危险的尾部相关”的注解)

^r'

一个r,但是只在一行的开始(即,刚开始扫描,或者一个换行符刚被扫描之后)

r$'

一个r,但是只在一行的结尾(即,正好在换行符之前)。

等同于“r/\n”。

注意,flex中对换行符的概念跟用来编译flex的C编译器中对'

\n'

的解释是一模一样的。

特别的是,在一些DOS系统上,必须在输入中自己过滤出'

\r'

,或者显示的使用r/\r\n来表示r$。

<

s>

一个r,但是只在起始条件(startcondition)s(参见下面关于起始条件的讨论)下匹配。

s1,s2,s3>

相同,但是在任意起始条件s1,s2,s3下都可以。

*>

一个r,在任意的起始条件下,甚至是互斥的(exclusive)起始条件。

EOF>

>

文件结尾

s1,s2>

文件结尾,当在起始条件s1或s2下匹配。

注意,在字符类别里面,除了转义符(‘\’),字符类别操作符‘-’,‘]’和类别开始处的‘^’,所有其它的

正规表达式操作符不再具有特殊的含义。

上面列出的正规表达式,是按照优先级由高到低排列的。

同一级别的具有相同的优先级。

foo|bar*

(foo)|(ba(r*))

因为,‘*’操作符的优先级比串联高,串联的优先级比间隔符高(‘|’),所以,该模式匹配字符串“foo”

或者字符串“ba”后面跟随零个或多个r。

如果要匹配“foo”或者零个或多个“bar”,可以使用:

foo|(bar)*

如果要匹配零个或者多个“foo”,或者零个或多个“bar”:

(foo|bar)*

除了字符和序列字符,字符类别也可以包含字符类别表达式。

这些表达式由‘[:

’和‘:

]’分隔符封装(并且

必须在字符类别的分隔符‘[’和‘]’之中)。

有效的表达式包括:

[:

alnum:

][:

alpha:

blank:

cntrl:

digit:

graph:

lower:

print:

punct:

space:

upper:

xdigit:

]

这些表达式都指定了与标准C中‘isXXX’函数相对应的字符类别。

例如,‘[:

]’指定了‘isalnum()’返

回值为真的字符集,即,任意的字母或者数字。

一些系统没有提供‘isblank()’,则flex定义‘[:

bland:

]’为

一个空格符(blank)或者一个制表符(tab)。

例如,下面的字符类别是等同的:

[[:

][:

][[:

]0-9][a-zA-Z0-9]

如果你的扫描器是大小写无关的(使用‘-i’命令行选项),则‘[:

]’和‘[:

]’等同于‘[:

]’。

关于模式的一些注意事项:

一个反选的字符类别例如上面的“[^A-Z]”将会匹配一个换行符,除非“\n”(或者等同的转义序

列)在反选字符类别中显示的指出(如“[^A-Z\n]”)。

这一点不像许多其它正规表达式工具,但不幸的

是这种不一致是由历史造成的。

匹配换行符意味着像[^"

]*这样的模式能够匹配整个的输出直到遇到另

一个引号。

一条规则中只能最多有一个尾部相关的情况(‘/’操作符或者‘$’操作符)。

起始条件,‘^’和

“<

”只能出现在模式的开始处,并且和‘/’,‘$’一样,都不能包含在圆括号中。

‘^’如果不出现在

规则的开始处,或者‘$’不出现在规则的结尾,将会失去它的特殊属性,并且被作为普通字符。

下面的

例子是非法的:

foo/bar$<

sc1>

foo<

sc2>

bar

注意,第一个可以写作“foo/bar\n”。

下面的例子中,‘$’和‘^’将会被作为普通字符:

foo|(bar$)foo|^bar

如果想匹配一个“foo”,或者一个“bar”并且后面跟随一个换行符,可以使用下面的方式(特殊动作‘|’,

将在下面介绍):

foo|bar$/*actiongoeshere*/

类似的技巧可以用来匹配一个foo,或者一个bar并且在一行的起始处。

四、如何匹配输入

当生成的扫描器运行时,它会分析它的输入,来查找匹配任意模式的字符串。

如果找到多个匹配,则采取最长文本的匹配方式(对于尾部相关规则,也包括尾部的长度,虽然尾部还要返回给输入)。

如果找到两个或者更多的相同长度的匹配,则选择列在flex输入文件中的最前面的规则。

一旦匹配确定,则所匹配的文本(称作标识,token)可以通过全局字符指针yytext来访问,文本的长度存放在全局整形yyleng中。

与匹配规则相应的动作(action)将被执行(后面会有关于动作的详细描述),然后剩余的输入再被继续扫描匹配。

如果没有找到匹配,则执行默认的规则:

紧接着的输入字符被认为是匹配的,并且复制到标准输出。

因此,最简单合法的flex输入是:

生成的扫描器只是简单的将它的输入(一次一个字符的)复制到它的输出。

注意,yytext可以通过两种方式来定义:

作为一个字符指针,或者作为一个字符数组。

可以在flex输入的第一部分(定义部分)通过专门的指令‘%pointer’或者‘%array’来控制flex使用哪种定义。

缺省的为‘%pointer’,除非使用‘-l’lex兼容选项,使得yytext为一个数组。

使用‘%pointer’的优点是能够进行足够快的扫描,并且当匹配非常大的标识时不会有缓冲溢出(除非是动态内存耗尽)。

缺点是在动作中对yytext的修改方式将会有所限制(参见下一章节),并且调用‘unput()’函数将会破坏yytext的现有内容,在不同lex版本中移植时,这将是一个非常头痛的事情。

使用‘%array’的优点是,可以按照自己的意愿来修改yytext,并且调用‘unput()’也不会破坏yytext(参见下面)。

而且,已有的lex程序有时可以通过如下的声明方式,在外部访问yytext:

externcharyytext[];

这种定义在使用‘%pointer’时是错误的,但是对于‘%array’却可以。

‘%array’定义了yytext为一个YYLMAX个字符的数组,缺省情况下,YYLMAX是一个相当大的值。

可以在flex输入的第一部分简单的通过#defineYYLMAX来改变大小。

正如上面提到的,‘%pointer’指定的yytext是通过动态增长来适应大的标识的。

这也意味着‘%pointer’的扫描器能够接受非常大的标识(例如匹配整个的注释块),不过要记住,每次扫描器都要重新设定yytext的长度,而且必须从头扫描整个标识,所以匹配这样的标识时速度会很慢。

目前,如果调用‘unput()’并且返回太多的文本,yytext将不会动态增长,而只是产生一个运行时错误。

而且要注意,不能在C++扫描器类(c++选项,参见下面)中使用‘%array’。

五、动作

规则中的每一个模式都有一个相应的动作,它可以是任意的C语句。

模式结束于第一个非转义的空白字符;

该行的剩余部分便是它的动作。

如果动作是空的,则当模式匹配时,输入的标识将被简单的丢弃。

例如,下面所描述的程序,是用来删除输入中的所有“zapme”:

%%"

zapme"

(输入中的所有其它字符,会被缺省规则匹配,并被复制到输出。

下面的程序用来将多个空格和制表符压缩为单个空格,并且丢弃在一行尾部的所有空格:

%%[\t]+putchar('

[\t]+$/*ignorethistoken*/

如果动作包括‘{’,则动作的范围直到对称的‘}’,并且可以跨过多行。

flex可以识别C字符串和注释,因此字符串和注释中的大括号不会起作用。

但是,也允许动作由‘%{’开始,并且将直到下一个‘%}’之间的动作看作是文本(包括在动作里面出现的普通大括号)。

只包含一个垂直分割线(‘|’)的动作意味着“与下一个规则相同”。

参见下面的例子。

动作能够包含任意的C代码,包括return语句来返回一个值给调用‘yylex()’的程序。

每次调用‘yylex()’,它将持续不断的处理标识,直到文件的结尾或者执行了return。

动作可以自由的修改yytext,除了增加它的长度(在尾端增加字符的,将会覆盖输入流中后面的字符)。

不过这种情形不会发生在使用‘%array’时(参见前面);

在那种情况下,yytext可以任意修改。

动作可以自由修改yyleng,除非他们不应该这么做,比如动作中也使用了‘yymore()’(参见下面)。

在动作中可以包含许多特殊指令:

*‘ECHO’将yytext复制到扫描器的输出。

*BEGIN后面跟随起始状态的名字,使扫描器处于相应的起始状态下(参见下面)。

*REJECT指示扫描器继续采用“次优”的规则匹配输入(或者输入的前面一部分)。

规则根据前面在“如何匹配输入”一节中描述的方式来选择,并且yytext和yyleng也被设为适当的值。

它可能是和最初选择的规则匹配相同多的文本,但是在flex输入文件中排在后面的规则,也可能是匹配较少的文本的规则。

例如,下面的将会计算输入中的单词,并且还在“frob”出现时调用程序special():

intword_count=0;

%%

frobspecial();

REJECT;

[^\t\n]+++word_count;

如果没有REJECT,输入中任何“frob”都不会被计入单词个数,因为扫描器在通常情况下只是对每一个标识执行一个动作。

可以使用多个REJECT,对于每一个,都将查找当前活动规则的下一个最优选择。

例如,当下面的扫描器扫描标识“abcd”时,它将往输出写入“abcdabcaba”:

a|

ab|

abc|

abcdECHO;

.|\n/*eatupanyunmatchedcharacter*/

(前三个规则都执行第四个的动作,因为他们使用了特殊的动作‘|’。

)对于扫描器执行效率来说,REJECT是一种相当昂贵的特征;

如果在扫描器的任意动作中使用了它,它将使得扫描器的所有匹配速度降低。

而且,REJECT不能和‘-Cf’或‘-CF’选项一起使用(参见下面)。

还要注意的是,不像其它特有动作,REJECT是一个分支跳转;

在动作中紧接其后面的代码将不会被执行。

*‘yymore()’告诉扫描器在下一次匹配规则时,相应的标识应该被追加到现在的yytext的值中,而不是替代它。

例如,假设有输入“mega-kludge”,下面的将会向输出写入“mega-mega-kludge”:

mega-ECHO;

yymore();

kludgeECHO;

首先是“mega-”被匹配,并且回显到输出。

然后是“kludge”被匹配,但是先前的“mega-”还保留在yytext的起始处,因此“kludge”规则中的‘ECHO’实际将会写出“mega-kludge”

使用‘yymore()’时,有两点需要注意的。

首先,‘yymore’依赖于yyleng的值能够正确地反映当前标识的长度,所以在使用‘yymore()’时,一定不要修改yyleng。

其次,在扫描器的动作中使用‘yymore()’,会给扫描器的匹配速度稍微有些影响。

*‘yyless(n)’将当前标识的除了前n个字符之外的都回送给输入流,扫描器在查找接下来的匹配时,会重新扫描它们。

yytext和yyleng会相应做适当的调整(例如,yyleng将会等于n)。

例如,在输入“foobar”时,下面的规则将会输出“foobarbar”:

foobarECHO;

yyless(3);

[a-z]+ECHO;

如果yyless的参数为0,则会使当前整个输入字符串被重新扫描。

除非已经改变扫描器接下来如何处理它的输入(例如,使用BEGIN),否则将会产生一个无限循环。

注意,yyless是一个宏,并且只能用在flex输入文件中,其它源文件则不可以。

*‘unput(c)’将字符c回放到输入流,并将其作为下一次扫描的字符。

下面的动作将会接受当前的标识,并使它封装在括号中而被从新扫描。

inti;

/*Copyyytextbecauseunput()trashesyytext*/

char*yycopy=strdup(yytext);

unput('

)'

for(i=yyleng-1;

i>

=0;

--i)

unput(yycopy[i]);

('

free(yycopy);

注意,由于‘unput()’每次都将字符放回到输入流的起始处,因此如果要回放字符串,则必须从后往前操作。

在使用‘unput()’时,一个重要的潜在问题是如果使用‘%pointer’(缺省情况),调用‘unput()’会破坏yytext的内容,将会从最右面的字符开始,每次向左吞并一个。

如果需要保留yytext的值直到调用‘unput()’之后(如上面的例子),必须将其复制到别处,或者使用‘%array’来构建扫描器(参见如何匹配输入)。

最后,注意不能将EOF放回来标识输入流出去文件结尾。

*‘input()’从输入流中读取下一个字符。

例如,下面的方法可以去掉C注释:

/*"

registerintc;

for( 

;

 

while((c=input()) 

!

='

&

&

=EOF)

 

/*eatuptextofcomment*/

if(c=='

while((c=input())=='

/'

break;

/*foundtheend*/

if(c==EOF)

error("

EOFincomment"

(注意,如果扫描器是用‘C++编译的’,则‘input()’由‘yyinput()’代替,为了避免与‘C++’流input的名字冲突。

*YY_FLUSH_BUFFER刷新扫描器内部的缓存,以至于扫描器下次匹配标识时,将会首先使用YY_INPUT重新填充缓存(参见下面的生成的扫描器)。

这个动作是较为常用的函数`yy_flush_buffer()'

的特殊情况,将在下面的多输入缓存章节介绍。

*‘yyterminate()’可

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 总结汇报 > 学习总结

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2