ImageVerifierCode 换一换
格式:DOCX , 页数:27 ,大小:31.62KB ,
资源ID:921376      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bingdoc.com/d-921376.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(FLEX 中文手册Word文档格式.docx)为本站会员(b****1)主动上传,冰点文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰点文库(发送邮件至service@bingdoc.com或直接QQ联系客服),我们立即给予删除!

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

1、 /* need this for the call to atof() below */ #include % DIGIT 0-9 ID a-za-z0-9* % DIGIT+ printf( An integer: %s (%d)n, yytext, atoi( yytext ) );DIGIT+.DIGIT* A float: %s (%g)n atof( yytext ) );if|then|begin|end|procedure|function A keyword: %sn, yytext );ID printf( An identifier:+|-*/An operator:n*

2、 /* eat up one-line comments */ tn+ /* eat up whitespace */ . printf( Unrecognized character:int main(int argc, char *argv) +argv, -argc; /* skip over program name */ if ( argc 0 ) yyin = fopen( argv0, r ); else yyin = stdin;这是一个类似Pascal语言的简单扫描器的初始部分,用来识别不同类型的标志(tokens)并给出报告。这个例子的详细介绍将在后面的章节中给出。二、输入

3、文件的格式flex输入文件包括三个部分,通过“%”行来分开:definitions(定义) % rules(规则) % user code(用户代码) 定义部分,包含一些简单的名字定义(name definitions),用来简化扫描器的规范,还有一些开始状态 (start conditions)的声明,将会在后面的章节中说明。名字定义的形式如下:name definition “name”由字母或者下划线(“_”)起始,后面跟字母,数字,“_”或者“-”(破折号)组成。定义由名字 后面的一个非空白(non-white-space)字符开始,直到一行的结束。可以在后面通过“name”来引用定

4、义,并展开为“(definition)”。例如, 定义了“DIGIT”为一个正规表达式用来匹配单个数字,“ID”为一个正规表达式用来匹配一个字母,后面 跟零个或多个字母和数字。后面的引用如下, DIGIT* 等同于 (0-9)+(0-9)* 用来匹配一个或多个数字,后面跟一个“.”,然后是零个或者多个数字。flex输入的规则部分包括一系列的规则,形式如下:pattern action 模式(pattern)不能有缩进,动作(action)必须在同一行。参见后面对模式和动作的进一步描述。最后,用户代码部分将被简单的逐字复制到“lex.yy.c”中,作为随同程序用来调用扫描器或者被扫描器 调用。该

5、部分是可选的,如果没有,输入文件中第二个“%”也可以省略掉。在定义部分和规则部分,任何缩进的文本或者包含在“%”和“%”中的文本,都会被逐字的复制到输出中(并去掉“%”)。“%”本身不能有缩进。在规则部分,在第一个规则之前的任何缩进的或者%中的文本,可以用来声明扫描程序的局部变量。其它在规则部分的缩进或者%中的文本也会被复制到输出,但是它的含义却不好定义,而且可能会产生编译时错误(这一特点是为了与POSIX相同;参见后面的其它特点)。在定义部分(但不是在规则部分),一条未缩进的注释(即,由“/*”起始的行)也会被逐字的拷贝到输出,直到下一个“*/”。三、模式输入中的模式,使用的是扩展的正规表达

6、式集。它们是:x 匹配字符. 除了换行符以外的任意字符(字节)xyz 一个字符类别(character class);在这个例子中,该模式匹配一个,或者一个y,或者一个z abj-oZ 一个带有范围的字符类别;匹配一个ab,或者从j到o的任意字母,或者一个ZA-Z 一个反选的字符类别(negated character class),即任意不属于这些的类别。在这个例子中,表示任意一个非大写字母的字符。A-Zn 任意一个非大写字母的字符,或者一个换行符r* 零个或者多个r,其中r是任意的正规表达式r+ 一个或者多个rr? 零个或者一个r(也就是说,一个可选的r)r2,5 两个到五个rr2, 两个

7、或者更多个rr4 确切的4个rname “name”定义的展开(参见前面) xyzfoo (这里单引号和双引号之间没有空格) 文字串:xyzfoox 如果x是一个,fnrt或者v,则为ANSI-C所解释的x。否则,为一个文字(用来转义操作符,例如*)。0 一个NUL字符(ASCII代码0)123 八进制值为123的字符x2a 十六进制值为2a的字符(r) 匹配一个r;括号用来改变优先级(参见后面)rs 正规表达式r,后面跟随正规表达式s;称作“concatenation”r|s 或者r,或者sr/s 一个r,但是后面要跟随一个s。在文本匹配时,s会被包含进来,以判断该规则是否是最长的匹配,但是

8、在动作执行前会被返回给输入。因此,动作只会看到匹配r的文本。这种模式称作trailing context。(有些组合,flex会匹配错误;参见后面的不足和缺陷章节中,关于“危险的尾部相关”的注解)r 一个r,但是只在一行的开始(即,刚开始扫描,或者一个换行符刚被扫描之后)r$ 一个r,但是只在一行的结尾(即,正好在换行符之前)。等同于“r/n”。注意,flex中对换行符的概念跟用来编译flex的C编译器中对n的解释是一模一样的。特别的是,在一些DOS系统上,必须在输入中自己过滤出r,或者显示的使用r/rn来表示r$。 一个r,但是只在起始条件(start condition)s(参见下面关于起

9、始条件的讨论)下匹配。s1, s2, s3相同,但是在任意起始条件s1,s2,s3下都可以。* 一个r,在任意的起始条件下,甚至是互斥的(exclusive)起始条件。EOF 文件结尾s1, s2 文件结尾,当在起始条件s1或s2下匹配。注意,在字符类别里面,除了转义符(),字符类别操作符-,和类别开始处的,所有其它的 正规表达式操作符不再具有特殊的含义。上面列出的正规表达式,是按照优先级由高到低排列的。同一级别的具有相同的优先级。foo|bar* (foo)|(ba(r*) 因为,*操作符的优先级比串联高,串联的优先级比间隔符高(|),所以,该模式匹配字符串“foo” 或者字符串“ba”后面

10、跟随零个或多个r。如果要匹配“foo”或者零个或多个“bar”,可以使用:foo|(bar)* 如果要匹配零个或者多个“foo”,或者零个或多个“bar”:(foo|bar)* 除了字符和序列字符,字符类别也可以包含字符类别表达式。这些表达式由:和:分隔符封装(并且 必须在字符类别的分隔符和之中)。有效的表达式包括::alnum: :alpha:blank:cntrl:digit:graph:lower:print:punct:space:upper:xdigit: 这些表达式都指定了与标准C中isXXX函数相对应的字符类别。例如,:指定了isalnum()返 回值为真的字符集,即,任意的字母

11、或者数字。一些系统没有提供isblank(),则flex定义:bland:为 一个空格符(blank)或者一个制表符(tab)。例如,下面的字符类别是等同的: : :0-9 a-zA-Z0-9 如果你的扫描器是大小写无关的(使用-i命令行选项),则:和:等同于:。关于模式的一些注意事项: 一个反选的字符类别例如上面的“A-Z”将会匹配一个换行符,除非“n”(或者等同的转义序列)在反选字符类别中显示的指出(如“A-Zn”)。这一点不像许多其它正规表达式工具,但不幸的 是这种不一致是由历史造成的。匹配换行符意味着像*这样的模式能够匹配整个的输出直到遇到另 一个引号。 一条规则中只能最多有一个尾部相

12、关的情况(/操作符或者$操作符)。起始条件,和“”只能出现在模式的开始处,并且和/,$一样,都不能包含在圆括号中。如果不出现在 规则的开始处,或者$不出现在规则的结尾,将会失去它的特殊属性,并且被作为普通字符。下面的 例子是非法的:foo/bar$ foobar 注意,第一个可以写作“foo/barn”。下面的例子中,$和将会被作为普通字符:foo|(bar$) foo|bar 如果想匹配一个“foo”,或者一个“bar”并且后面跟随一个换行符,可以使用下面的方式(特殊动作|, 将在下面介绍):foo | bar$ /* action goes here */ 类似的技巧可以用来匹配一个foo

13、,或者一个bar并且在一行的起始处。四、如何匹配输入当生成的扫描器运行时,它会分析它的输入,来查找匹配任意模式的字符串。如果找到多个匹配,则采取最长文本的匹配方式(对于尾部相关规则,也包括尾部的长度,虽然尾部还要返回给输入)。如果找到两个或者更多的相同长度的匹配,则选择列在flex输入文件中的最前面的规则。一旦匹配确定,则所匹配的文本(称作标识,token)可以通过全局字符指针yytext来访问,文本的长度存放在全局整形yyleng中。与匹配规则相应的动作(action)将被执行(后面会有关于动作的详细描述),然后剩余的输入再被继续扫描匹配。如果没有找到匹配,则执行默认的规则:紧接着的输入字符

14、被认为是匹配的,并且复制到标准输出。因此,最简单合法的flex输入是:生成的扫描器只是简单的将它的输入(一次一个字符的)复制到它的输出。注意,yytext可以通过两种方式来定义:作为一个字符指针,或者作为一个字符数组。可以在flex输入的第一部分(定义部分)通过专门的指令%pointer或者%array来控制flex使用哪种定义。缺省的为%pointer,除非使用-llex兼容选项,使得yytext为一个数组。使用%pointer的优点是能够进行足够快的扫描,并且当匹配非常大的标识时不会有缓冲溢出(除非是动态内存耗尽)。缺点是在动作中对yytext的修改方式将会有所限制(参见下一章节),并且调

15、用unput()函数将会破坏yytext的现有内容,在不同lex版本中移植时,这将是一个非常头痛的事情。使用%array的优点是,可以按照自己的意愿来修改yytext,并且调用unput()也不会破坏yytext(参见下面)。而且,已有的lex程序有时可以通过如下的声明方式,在外部访问yytext:extern char yytext;这种定义在使用%pointer时是错误的,但是对于%array却可以。%array定义了yytext为一个YYLMAX个字符的数组,缺省情况下,YYLMAX是一个相当大的值。可以在flex输入的第一部分简单的通过#define YYLMAX来改变大小。正如上面提

16、到的,%pointer指定的yytext是通过动态增长来适应大的标识的。这也意味着%pointer的扫描器能够接受非常大的标识(例如匹配整个的注释块),不过要记住,每次扫描器都要重新设定yytext的长度,而且必须从头扫描整个标识,所以匹配这样的标识时速度会很慢。目前,如果调用unput()并且返回太多的文本,yytext将不会动态增长,而只是产生一个运行时错误。而且要注意,不能在C+扫描器类(c+选项,参见下面)中使用%array。五、动作规则中的每一个模式都有一个相应的动作,它可以是任意的C语句。模式结束于第一个非转义的空白字符;该行的剩余部分便是它的动作。如果动作是空的,则当模式匹配时,

17、输入的标识将被简单的丢弃。例如,下面所描述的程序,是用来删除输入中的所有“zap me”:% zap me(输入中的所有其它字符,会被缺省规则匹配,并被复制到输出。) 下面的程序用来将多个空格和制表符压缩为单个空格,并且丢弃在一行尾部的所有空格:% t+ putchar( t+$ /* ignore this token */ 如果动作包括,则动作的范围直到对称的,并且可以跨过多行。flex可以识别C字符串和注释,因此字符串和注释中的大括号不会起作用。但是,也允许动作由%开始,并且将直到下一个%之间的动作看作是文本(包括在动作里面出现的普通大括号)。只包含一个垂直分割线(|)的动作意味着“与下

18、一个规则相同”。参见下面的例子。动作能够包含任意的C代码,包括return语句来返回一个值给调用yylex()的程序。每次调用yylex(),它将持续不断的处理标识,直到文件的结尾或者执行了return。动作可以自由的修改yytext,除了增加它的长度(在尾端增加字符的,将会覆盖输入流中后面的字符)。不过这种情形不会发生在使用%array时(参见前面);在那种情况下,yytext可以任意修改。动作可以自由修改yyleng,除非他们不应该这么做,比如动作中也使用了yymore()(参见下面)。在动作中可以包含许多特殊指令: * ECHO将yytext复制到扫描器的输出。 * BEGIN后面跟随起

19、始状态的名字,使扫描器处于相应的起始状态下(参见下面)。 * REJECT指示扫描器继续采用“次优”的规则匹配输入(或者输入的前面一部分)。规则根据前面在“如何匹配输入”一节中描述的方式来选择,并且yytext和yyleng也被设为适当的值。它可能是和最初选择的规则匹配相同多的文本,但是在flex输入文件中排在后面的规则,也可能是匹配较少的文本的规则。例如,下面的将会计算输入中的单词,并且还在“frob”出现时调用程序special(): int word_count = 0; % frob special(); REJECT; tn+ +word_count; 如果没有REJECT,输入中任

20、何“frob”都不会被计入单词个数,因为扫描器在通常情况下只是对每一个标识执行一个动作。可以使用多个REJECT,对于每一个,都将查找当前活动规则的下一个最优选择。例如,当下面的扫描器扫描标识“abcd”时,它将往输出写入“abcdabcaba”: a | ab | abc | abcd ECHO; .|n /* eat up any unmatched character */ (前三个规则都执行第四个的动作,因为他们使用了特殊的动作|。)对于扫描器执行效率来说,REJECT是一种相当昂贵的特征;如果在扫描器的任意动作中使用了它,它将使得扫描器的所有匹配速度降低。而且,REJECT不能和-C

21、f或-CF选项一起使用(参见下面)。还要注意的是,不像其它特有动作,REJECT是一个分支跳转;在动作中紧接其后面的代码将不会被执行。 *yymore()告诉扫描器在下一次匹配规则时,相应的标识应该被追加到现在的yytext的值中,而不是替代它。例如,假设有输入“mega-kludge”,下面的将会向输出写入“mega-mega-kludge”: mega- ECHO; yymore(); kludge ECHO; 首先是“mega-”被匹配,并且回显到输出。然后是“kludge”被匹配,但是先前的“mega-”还保留在yytext的起始处,因此“kludge”规则中的ECHO实际将会写出“m

22、ega-kludge”使用yymore()时,有两点需要注意的。首先,yymore依赖于yyleng的值能够正确地反映当前标识的长度,所以在使用yymore()时,一定不要修改yyleng。其次,在扫描器的动作中使用yymore(),会给扫描器的匹配速度稍微有些影响。 * yyless(n)将当前标识的除了前n个字符之外的都回送给输入流,扫描器在查找接下来的匹配时,会重新扫描它们。yytext和yyleng会相应做适当的调整(例如,yyleng将会等于n)。例如,在输入“foobar”时,下面的规则将会输出“foobarbar”: foobar ECHO; yyless(3); a-z+ EC

23、HO; 如果yyless的参数为0,则会使当前整个输入字符串被重新扫描。除非已经改变扫描器接下来如何处理它的输入(例如,使用BEGIN),否则将会产生一个无限循环。注意,yyless是一个宏,并且只能用在flex输入文件中,其它源文件则不可以。 * unput(c)将字符c回放到输入流,并将其作为下一次扫描的字符。下面的动作将会接受当前的标识,并使它封装在括号中而被从新扫描。 int i; /* Copy yytext because unput() trashes yytext */ char *yycopy = strdup( yytext ); unput( ) for ( i = yy

24、leng - 1; i = 0; -i ) unput( yycopyi );( free( yycopy ); 注意,由于unput()每次都将字符放回到输入流的起始处,因此如果要回放字符串,则必须从后往前操作。在使用unput()时,一个重要的潜在问题是如果使用%pointer(缺省情况),调用unput()会破坏yytext的内容,将会从最右面的字符开始,每次向左吞并一个。如果需要保留yytext的值直到调用unput()之后(如上面的例子),必须将其复制到别处,或者使用%array来构建扫描器(参见如何匹配输入)。最后,注意不能将EOF放回来标识输入流出去文件结尾。 * input()

25、从输入流中读取下一个字符。例如,下面的方法可以去掉C注释:/* register int c; for (; ) while ( (c = input()!= & c= EOF ) /* eat up text of comment */ if ( c = while ( (c = input() = / break; /* found the end */ if ( c = EOF ) error( EOF in comment (注意,如果扫描器是用C+编译的,则input()由yyinput()代替,为了避免与C+流input的名字冲突。) * YY_FLUSH_BUFFER 刷新扫描器内部的缓存,以至于扫描器下次匹配标识时,将会首先使用YY_INPUT重新填充缓存(参见下面的生成的扫描器)。这个动作是较为常用的函数 yy_flush_buffer()的特殊情况,将在下面的多输入缓存章节介绍。 * yyterminate()可

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

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