BISONFlexWord文件下载.docx
- 文档编号:20090744
- 上传时间:2023-01-16
- 格式:DOCX
- 页数:31
- 大小:39.20KB
BISONFlexWord文件下载.docx
《BISONFlexWord文件下载.docx》由会员分享,可在线阅读,更多相关《BISONFlexWord文件下载.docx(31页珍藏版)》请在冰豆网上搜索。
{DIGIT}+"
."
{DIGIT}*
就等价于:
([0-9])+"
([0-9])*
定义段中还可以加入启动条件(startconditions)的声明。
顾名思义,启动条件就如同C语言中的条件编译一样,根据指定的启动条件去激活一条规则,并用这条规则去匹配读入的字符。
关于启动条件,后面还有更详细的介绍。
规则段(rulessection)
规则由模式(pattern)和动作(action)两个部分组成。
模式就是一个正则表达式,FLEX加入了一些自己的扩展。
而动作一般就是一些C语句。
模式指出了一个单词是如何构成的,当分析出一个符合该规则的单词时,就执行相应的动作。
模式一定要位于一行的开头处,不能有缩进。
而动作的开头一定要与模式在同一行。
当动作是用一对花括号{}括起来时,可以将左花括号放在与规则相同的行,而其余部分则可以从下一行开始。
所有用户代码都被原样拷贝到文件lex.yy.c中。
在这里可以定义一些辅助函数或代码,供扫描器yylex()调用,或者调用扫描器(一般来说就是main()了)。
这一部分是可有可无的。
如果没有的话,Flex文件中第二个%%是可以省略的。
在定义段或者规则段中,任何一行有缩进的文本或者包含在一对%{和%}之间的文本,都被原样拷贝到最后生成的C代码文件中(当然%{和%}会被移走)。
在书写时%{和%}都必须在一行的开始处,不能缩进。
在规则段中,第一条规则之前的任何未缩进的文本或者在%{和%}之间的文本,可以用来为扫描器声明一些本地变量和代码。
一旦进入扫描器的代码,这些代码就会被执行。
规则段内其他的缩进的文本或者%{和%}之间的文本还是被原样拷贝输出,但是他们的含义是尚未有明确定义,很可能引起编译时(compile-time)错误(这一特性是为了与POSIX兼容而提供的)。
在定义段中,没有缩进的注释也会被原样拷贝到最后生成的C代码文件中,例如以/*开始的一行注释,直到遇到*/,这中间的文本会被原样拷贝输出。
模式及其分类
模式采用正则表达式来书写。
正则表达式大致可以分为如下几类(从上到下,优先级依次递减):
(1)单字符匹配
*‘x’匹配字符x。
*‘.’匹配任意一个字符(字节),除了换行符。
*‘[xyz]’匹配单个字符,这个字符是方括号中给出的字符类(characterclass)中的一个。
*‘[abj-oZ]’匹配单个字符,这个字符是方括号中给出的字符类中的一个。
与上一方式的区别是指定字符类时用到了一个范围表示法:
j-o,这表示按照26个英文字母的顺序,从字母j开始一直到字母o共6个字母。
这里减号(-)表示范围。
如果减号本身也要作为一个匹配字符时,最好用转义字符(\)去除其特殊含义。
由于花括号({})在模式中用来引用名字,以及作为模式定义之后的动作(Action)定义块的首尾界定符,因此如果要在字符类中匹配花括号,必须用转义字符(\)去除其特殊含义。
下面这个例子定义了一个所有可打印字符的字符类:
[[:
alnum:
][:
blank:
]]\t+\-*/&
!
_'
?
@^`~$\\()%|.;
[\]\{\}:
#<
>
=]
*‘[^A-Z]’匹配单个字符,这个字符必须是方括号中给定字符类以外的字符。
在方括号内开始处的特殊符号(^)表示否定。
当字符^不在字符类的开始处时,并不具有特殊含义,而是一个普通字符。
*‘[^A-Z\n]’匹配单个字符,这个字符不可以是方括号中给出的字符类中的字符。
与上一方式的不同在于,这里多了一个换行符,也就是说所匹配的字符不能是26个大写字母,也不能是换行符。
根据上面的描述,在表达字符分类时,除了直接用字符以及字符范围来表达外,还有一种叫做字符类表达式的,也有同样的作用,常见的一些表达式如下:
[:
][:
alpha:
cntrl:
digit:
graph:
]
lower:
print:
punct:
space:
upper:
xdigit:
每一个表达式都指示了一个字符分类,而且其名称与标准C函数isXXXX的名字对应。
例如,[:
]就指示了那些经由函数isalnum()检查后返回true的字符,也就是任何的字母或者数字。
注意,有些系统上没有给出C函数isblank()的定义,所以flex自己定义了[:
]为一个空格或者一个tab。
下面所举的几个例子,都是等价的:
]]
]0-9]
[a-zA-Z0-9]
应该注意字符类表达式的写法。
一个字符类表达式是由一对[:
和:
]包住的,作为一个整体,在书写时不可与外层的[]混淆。
(2)重复模式的匹配
*‘r*’r是一个正则表达式,特殊字符`*'
表示0个或多个。
因此这个模式表示匹配0个或多个r。
*‘r+’r是一个正则表达式,特殊字符`+'
表示1个或多个。
因此这个模式表示匹配1个或多个r。
*‘r?
’r是一个正则表达式,特殊字符`?
'
表示0个或1个。
因此这个模式表示匹配0个或1个r。
(从另一个角度看,就是说模式r是可选的)
*‘r{2,5}’r是一个正则表达式,{2,5}表示2个到5个。
因此这个模式表示匹配2个到5个r。
也就是说可以匹配`rr'
,`rrr'
,`rrrr'
,`rrrrr'
四种重复的模式。
*‘r{2,}’r是一个正则表达式,{2,}省略了第二个数字,表示至少2个,不设上限。
因此这个模式表示匹配2个及以上个r。
也就是说至少可以匹配`rr'
,还可以匹配`rrr'
等无限多种重复的模式。
*‘r{4}’r是一个正则表达式,{4}只有一个数字,表示4个。
因此这个模式确切地匹配4个r,即`rrrr'
。
(3)名字替换
*‘{name}’这里name就是在前面的定义段给出的名字。
这个模式将用这个名字的定义来匹配。
(4)平凡(plain)文本串的匹配
*‘“[xyz]\″foo”’这个模式用来确切地匹配文本串:
[xyz]\″foo。
注意最外层的单引号所包含的是整个模式表达式,也就是说,当希望匹配字串[xyz]\″foo时,在书写规则时该字串必须用双引号括住。
(5)特殊单字符的匹配
*‘\x’当x是一个`a'
,`b'
,`f'
,`n'
,`r'
,`t'
或`v'
时,它就解释为ANSI-C中的\x。
否则就仍然作为一个普通字符x(一般用于诸如`*'
字符的转义字符)。
*‘\0’匹配一个NUL字符(ASCII码值为0)。
*‘\123’匹配一个字符,其值用八进制表示为123。
*‘\x2a’匹配一个字符,其值用十六进制表示为2a。
(6)组合模式的匹配
*‘(r)’匹配规则表达式r,圆括号可以提高其优先级。
*‘rs’匹配规则表达式r,其后紧跟着表达式s。
这称为联接(concatenation)。
*‘r|s’或者匹配规则表达式r,或者匹配表达式s。
*‘r/s’匹配模式r,但是要求其后紧跟着模式s。
当需要判断本次匹配是否为“最长匹配(longestmatch)时,模式s匹配的文本也会被包括进来,但完成判断后开始执行对应的动作(action)之前,这些与模式s相配的文本会被返还给输入。
所以动作(action)只能看到模式r匹配到的文本。
这种模式类型叫做尾部上下文(trailingcontext)。
(有些‘r/s’组合是flex不能识别的;
请参看后面deficiencies/bugs一节中的dangeroustrailingcontext的内容。
)
*‘^r’匹配模式r,但是这个模式只出现在一行的开始处。
也就是说,刚开始扫描时遇到的,或者说在刚扫描完一个换行字符后紧接着遇到的。
*‘r$’匹配模式r,但是这个模式只在一行的尾部。
也就是说,该模式就出现在换行之前。
这个模式等价于r/\n。
注意,flex中的换行(newline)的概念,就是C编译器中所使用的\n,flex也采用同样的符号和解释。
在DOS系统中,可能必须由你自己滤除输入中的\r,或者明确地在模式中写成r/\r\n来代替r$。
(在unix系统中换行是用一个字节\n表示的,而DOS/Windows则采用两个字节\r\n来表示换行。
(7)有启动条件(StartCondition)的模式匹配
*‘<
s>
r’匹配模式r,但需要启动条件s(后面后关于启动条件的讨论)。
模式‘<
s1,s2,s3>
r’是类似的,匹配模式r,只要有三个启动条件s1,s2,s3中的任一个即可。
(启动条件简单来说,类似于C语言中的条件编译,满足了某个条件才启动这个模式参与匹配,否则不会启动该模式参与匹配。
*>
r’匹配模式r,在任何启动条件下都参与匹配,即使是排斥性的条件。
[上述还需要从实践中体会其含义]
(8)文件尾匹配
<
EOF>
’匹配文件尾,即遇到了文件尾部。
一般说来,都应该在模式中加入文件尾模式。
这样可以有机会在文件扫描完成时增加一些额外的处理。
s1,s2>
’在有启动条件s1或者s2的情况下,匹配文件尾部。
一些常见规则的编写(待续)
(1)双引号字符串。
[\"
]({SAFECHAR}|{RESTCHAR}|[_])*[\"
这里需要注意的地方是中间的重复模式的写法:
(r)*。
r可以是一个组合模式。
中间的两个名称SAFECHAR和RESTCHAR是在定义段给出的两个字符类。
[此处应在实用中不断添加]
=========================================
创建一个简单的扫描器
下列例子来自于Flex的手册。
并在Windows+Cygwin+bison+flex+gcc的环境下编译运行。
(1)
编辑Flex语法文件。
/*name:
example.flex*/
intnum_lines=0,num_chars=0;
\n++num_lines;
++num_chars;
.++num_chars;
intmain()
{
yylex();
printf("
#oflines=%d,#ofchars=%d\n"
num_lines,num_chars);
return0;
}
(2)
生成扫描器的C文件。
Theoutputislex.yy.c
(3)
编译生成的C文件。
编译时失败,出现了如下的问题:
#gcc-g-Wall-lfl-oscanlex.yy.c
lex.yy.c:
959:
warning:
'
yyunput'
definedbutnotused
/cygdrive/c/DOCUME~1/ADMINI~1.78B/LOCALS~1/Temp/ccHwCWNb.o:
Infunction`main'
:
/cygdrive/c/home/sandbox/flex_exam_1/example.l:
9:
multipledefinitionof`_main'
/usr/lib/gcc/i686-pc-cygwin/3.4.4/../../../libfl.a(libmain.o):
(.text+0x0):
firstdefinedhere
Infunction`yylex'
/cygdrive/c/home/sandbox/flex_exam_1/lex.yy.c:
692:
undefinedreferenceto`_yywrap'
Infunction`input'
1041:
collect2:
ldreturned1exitstatus
上述消息指出两个问题:
(1)函数yywrap没有定义。
(2)自定义函数main与连接库fl中的定义冲突了。
第一个问题的解决办法是在第一段(定义段)中加上一个选项指令:
%optionnoyywrap
第二个问题的解决办法就是用gcc编译时不连接fl库,如下所示:
#flexexample.flex
#ls
example.flexlex.yy.c
#gcc-g-Wall-oscanlex.yy.c
977:
example.flexlex.yy.cscan.exe
#./scan.exe
789
234
345#oflines=2,#ofchars=11
修改过的代码如下:
%optionnoyywrap<
====防止出现yywrap的问题
%{
%}
num_lines,num_chars);
更改扫描器yylex()的名字
我们还可以更改Flex自动生成的词法分析函数yylex()的名字、参数以及返回值,也就是说yylex这个名字仅仅是一个默认的名称,是可以改成其他名称的。
方法很简单,只需要对宏YY_DECL做一个重定义即可:
#defineYY_DECLfloatlexscan(floata,floatb)
上述的宏定义就表明:
当运行Flex生成C代码时,词法分析函数的名字叫做lexscan(不再是yylex了),有两个浮点型参数a和b,函数的返回值是浮点型。
如果与Bison联用的话,还是不要更改的好,因为Bison要求词法分析函数的名称是yylex。
[应该也是可以改的,但其实际的方法还需在实践中得来。
词法分析函数yylex()会使用全局变量yyin读取字符。
一些思考
(1)在H248协议的BNF文本中,需要分析很多的数字,有十六进制的,有十进制的,有长的数字也有短的数字。
虽然在H248协议看来,各种不同的数字有着不同的意义,但是在Flex词法扫描器看来,它们有什么不同呢?
特别是同样的一个0xab这样的只有两位数字的十六进制数,在H248协议和BISON看来,其有不同的含义和类型,但是在Flex看来却没有什么不同。
假设Bison分别将其定义为Token_A和Token_B,那么当Flex分析出这么一个单词时,返回给Bison的数字类型是A还是B?
(2)在H248协议中,有一种表达式是由多个参数组成的,其中每个参数至多出现一次,且参数间次序是任意的。
此外其中有两个参数是必须的。
这种情况下如何给出Bison文法规则定义呢?
文法分析概览
利用BNF写出的文法规则,可以用来对输入的文本进行文法分析。
一条BNF文法规则,左边是一个非终结符(Symbol或者non-terminal),右边则定义该非终结符是如何构成的,也称为产生式(Production),产生式中可能包含非终结符,也可能包含终结符(terminal),也可能二者都有。
在所有文法规则中,必有一个开始的规则,该规则左边的部分叫做开始符号(startsymbol)。
一个规则的写法如下:
Symbol:
=Production
下面是一个BNF文法定义的例子。
FN是fractionalnumber的意思,DL是digitlist的意思,S是startsymbol。
S:
='
-'
FN|FN
FN:
=DL|DL'
.'
DL
DL:
=D|DDL
D:
0'
|'
1'
2'
3'
4'
5'
6'
7'
8'
9'
一个非终结符可能有多个产生式,相互间用竖线(|)隔开。
每一条BNF产生式,都有自己的启动集(startset)。
启动集里的元素就是每个Production中的第一个部分,比如上例S规则的启动集就是{'
}以及{FN}。
利用BNF文法来分析目标文本,其分析方法比较流行的有几种,下面作一概述[Garshol03]。
LL(k)分析
LL分析又称为自顶向下的分析(top-downparsing),也有叫递归下降分析(recursive-descentparsing)。
也是最简单的一种分析方式。
它工作的方式类似于找出一个产生式可以从哪一个终结符开始。
当分析时,从起始符号开始,比较输入中的第一个终结符和启动集,看哪一个产生式规则被使用了。
当然,两个启动集之间不能拥有同一个终结符。
如果有的话,就没有办法决定选择哪个产生式规则了。
Ll文法通常用数字来分类,比如LL
(1),LL(0)等。
这个数字告诉你,在一个文法规则中的任何点可以允许一次察看的终结符的最大数量。
LL(0)就不需要看任何终结符,分析器总是可以选择正确的产生式规则。
它只适用于所有的非终结符都只有一个产生规则。
只有一个产生规则意味着只有一个字符串。
[不用看当前的终结符是什么就可以决定是哪一个产生规则,说明这个规则是为一个固定的字符串所写的。
]这种文法是没有什么意义的。
最常见也是比较有用的事LL
(1)文法。
它只需要看一个终结符,然后就可以决定使用哪一个产生规则。
而LL
(2)则可以查看两个终结符,还有LL(k)文法等等。
对于某个固定的k值,也存在着根本不是LL(k)的文法,而且还很普遍。
下面来分析一下本章开头给出的例子。
首先看下面这条规则:
上述规则有十个产生式,每个产生式的启动集是一个数字终结符构成的集合{'
}、{'
}、……、{'
}。
这是一个很好的LL
(1)文法,因为我们只要看一个终结符,就可以选择一个正确的产生式。
例如,如果看到一个终结符,其内容是3,那么就采用上面第四个产生式,即D:
接下来分析DL规则。
上述规则有两个产生式,启动集是{D},{D}。
很不幸,两个产生式的启动集相同。
这就表示只看第一个输入中的第一个终结符不能选择正确的产生式。
然而可以通过欺骗来绕过这个问题:
如果输入中第二个终结符不是一个数字,那么就选择第一个产生式,但如果两者都是数字就必须选择第二个产生式。
换句话说,这意味着这是一条好的LL
(2)文法规则。
实际上这里有些东西被简化了。
再分析下FN规则吧。
它的情况更糟糕。
它有两条产生式,而且启动集相同,均为{DL}。
然而这次不像DL规则那么幸运了。
咋一看,似乎通过LL
(2)可以分辨应该使用哪一个产生式。
但是很不幸,我们无法确定在读到终结符('
)之前,需要读多少个数字才算是DL符号的最后一个数字。
[想想吧,分析器这么工作着:
读入第一个终结符,一看是相同的DL符号,那么就读第二个终结符吧;
读入第二个终结符,两者合起来一看,还是一样的DL符号;
读入第三个终结符,前三个终结符合起来看,仍然是相同的DL符号。
但是DL符号表指示数字表示没有长度限制的。
]没有任何一个给定的k值,这都不符合LL(k)文法,因为数字表总能突破这个k的长度。
最后看看启动符号规则。
有点意外,它产生规则的选择很简单。
它有两个产生规则,两者的启动集是{'
}和{FN}。
因此,如果输入中第一个终结符是'
,那么就选择第一个产生式,否则选择第二个产生式。
所以这是一个LL
(1)文法。
从上述的LL分析看,只有FN和DL规则引起了问题。
但是不必绝望。
大部分的非LL(k)文法都可以容易地转换为LL
(1)文法。
下面以当前的这个例子来看看如何转换有问题的FN和DL。
对于FN符号来说,它的两个产生式都开始于DL,但是第二个产生式其后续的是一个小数点终结符('
),以及另外一个数字表。
那么这很容易解决:
可以将FN改变为一个产生式,其以DL开始,后跟一个FP(fractionalpart)符号。
而FP符号则定义成或者为空,或者为小数点后跟着一个数字表,如下所示:
=DLFP
FP:
=@|'
上述@符号表示为空。
现在FN文法没有任何问题了,因为它现在只有一个产生式。
而FP也不会有问题,因为它的两个产生式的启动集是不同的:
前者是输入的尾端,后者是小数点终结符。
DL符
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- BISONFlex
![提示](https://static.bdocx.com/images/bang_tan.gif)