词法分析器flex中文手册.docx

上传人:b****4 文档编号:888186 上传时间:2022-10-13 格式:DOCX 页数:21 大小:30.22KB
下载 相关 举报
词法分析器flex中文手册.docx_第1页
第1页 / 共21页
词法分析器flex中文手册.docx_第2页
第2页 / 共21页
词法分析器flex中文手册.docx_第3页
第3页 / 共21页
词法分析器flex中文手册.docx_第4页
第4页 / 共21页
词法分析器flex中文手册.docx_第5页
第5页 / 共21页
点击查看更多>>
下载资源
资源描述

词法分析器flex中文手册.docx

《词法分析器flex中文手册.docx》由会员分享,可在线阅读,更多相关《词法分析器flex中文手册.docx(21页珍藏版)》请在冰豆网上搜索。

词法分析器flex中文手册.docx

词法分析器flex中文手册

FLEX中文手册

这是flex手册的部分中文翻译,仅供参考

∙一些简单的例子

∙输入文件的格式

∙模式

∙如何匹配输入

∙动作

∙生成的扫描器

∙开始条件

∙文件结尾规则

∙与yacc一起使用

一些简单的例子

首先给出一些简单的例子,来了解一下如何使用flex。

下面的flex输入所定义的扫描器,用来将所有的“

username”字符串替换为用户的登陆名字:

%%usernameprintf("%s",getlogin());

默认情况下,flex扫描器无法匹配的所有文本将被复制到输出,所以该扫描器的实际效果是将输入文件

复制到输出,并对每一个“username”进行展开。

在这个例子中,只有一个规则。

“username”是模式

(pattern),“printf”是动作(action)。

“%%”标志着规则的开始。

这里是另一个简单的例子:

intnum_lines=0,num_chars=0;

%%\n++num_lines;++num_chars;.++num_chars;

%%intmain(void)

{

yylex();

printf("#oflines=%d,#ofchars=%d\n",num_lines,num_chars);

}

该扫描器计算输入的字符个数和行数(除了最后的计数报告,并未产生其它输出)。

第一行声明了两

个全局变量,“num_lines”和“num_chars”,可以在yylex()函数中和第二个“%%”后面声明的main()函数中

使用。

有两个规则,一个是匹配换行符(“\n”)并增加行数和字符数,另一个是匹配所有不是换行符的

其它字符(由正规表达式“.”表示)。

一个稍微复杂点的例子:

/*scannerforatoyPascal-likelanguage*/

%{

/*needthisforthecalltoatof()below*/

#include

%}

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

%%

{DIGIT}+{

printf("Aninteger:

%s(%d)\n",yytext,

atoi(yytext));

}

{DIGIT}+"."{DIGIT}*{

printf("Afloat:

%s(%g)\n",yytext,

atof(yytext));

}

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

printf("Akeyword:

%s\n",yytext);

}

{ID}printf("Anidentifier:

%s\n",yytext);

"+"|"-"|"*"|"/"printf("Anoperator:

%s\n",yytext);

"{"[^}\n]*"}"/*eatupone-linecomments*/

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

.printf("Unrecognizedcharacter:

%s\n",yytext);

%%

intmain(intargc,char**argv)

{

++argv,--argc;/*skipoverprogramname*/

if(argc>0)

yyin=fopen(argv[0],"r");

else

yyin=stdin;

yylex();

}

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

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

输入文件的格式

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

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

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

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

名字定义的形式如下:

namedefinition

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

定义由名字

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

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

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

例如,

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

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

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

后面的引用如下,

{DIGIT}+"."{DIGIT}*

等同于

([0-9])+"."([0-9])*

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

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

patternaction

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

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

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

调用。

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

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

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

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

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

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

模式

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

它们是:

'x'

匹配字符'x'

'.'

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

'[xyz]'

一个字符类别(characterclass);在这个例子中,该模式匹配一个'x',或者一个'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是一个'a','b','f','n','r','t'或者'v',则为ANSI-C所解释的\x。

否则,为一个文字'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。

(有些'r/s'组合,flex会匹配错误;参见后面的不足和缺陷章节中,关于“危险的尾部相关”的注解)

'^r'

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

'r$'

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

等同于“r/\n”。

注意,flex中对换行符的概念跟用来编译flex的C编译器中对'\n'的解释是一模一样的。

特别的是,在一些DOS系统上,必须在输入中自己过滤出'\r',或者显示的使用r/\r\n来表示r$。

'r'

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

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

'<*>r'

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

'<>'

文件结尾

'<>'

文件结尾,当在起始条件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’函数相对应的字符类别。

例如,‘[:

alnum:

]’指定了‘isalnum()’返

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

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

bland:

]’为

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

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

alnum:

[[:

alpha:

][:

digit:

][[:

alpha:

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

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

upper:

]’和‘[:

lower:

]’等同于‘[:

alpha:

]’。

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

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

展开阅读全文
相关搜索

当前位置:首页 > 小学教育 > 语文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1