flexbison使用教程Word文档下载推荐.docx
《flexbison使用教程Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《flexbison使用教程Word文档下载推荐.docx(26页珍藏版)》请在冰点文库上搜索。
b'
从'
j'
到'
o'
还有'
Z'
[^A-Z]
一个取反的字符类,比如任何字母除了大写字母。
[^A-Z\n]
任何字符除了大写字母和换行
r*
零个或更多r,r可以是任意正则表达式
r+
一个或更多r
r
零个或最多一个r
r{2,5}
任何2到5个r
r{2,}
2个或更多r
r{4}
正好4个r
{name}
对name的扩展
"
[xyz]\"
foo"
符合正则表达式[xyz]"
foo的字符串
\X
如果X是一个'
f'
n'
r'
t'
或者'
v'
则按照ASCII码\x转义符进行处理,否则,其他的'
X'
将用来做取消处理符处理
\0
一个ASCII码空字符
\123
内容为八进制123的char型
\x2a
内容为十六进制0x2a的char型
(r)
符合一个r,括号是用来越过优先级的
rs
正则表达式r,紧跟着一个
r|s
要么是r要么是s
^r
一个r,但是必须是在一行的开始
r$
一个r,但是必须是在行末
<
s>
一个r,但是之前字符串必须符合条件s
s1,s2,s3>
r
同上,但是必须之前字符串符合s1或者s2或者s3
*>
不考虑开始字符串类型,只符合r
EOF>
>
文件末尾
s1,s2>
前面符合s1或者s2的文件末尾
.第一个Lex代码
按照上一节我们讲述的正则表达式例子,我们尝试第一次使用Lex来产生我们所需要的程序,实践一遍Lex的使用以及gcc编译器如何编译和生成所需的二进制。
Flex甚至Bison代码都有如下的编写格式:
/*定义段*/
%%
/*Flex、Bison代码段(规则)*/
/*辅助代码段,C语言*/
首先,使用vi编译器,输入以下代码():
文件
#include<
%}
test
#运行刚刚生成的二进制
下面我们来对刚生成的二进制进行试验,以弄清楚flex到底是做什么的,在test程序中输入以下内容,按下Ctrl-D可以退出test程序:
3505
hello
whatis3505
通过这些试验,相信您已经明白了Flex的用途,每当一个正则表达式符合时,flex生成的代码就会自动调用对应的函数,或者运行对应的程序。
下面我们对这个例子进行一些深入研究,处理一个类似C语言的程序配置脚本代码。
首先,一个演示脚本如下:
logging{
categorylame-servers{null;
};
categorycname{null;
};
zone"
."
{
typehint;
file"
/etc/bind/"
;
}
在这个脚本中,我们可以看到一系列的词汇类型:
单词(WORD),比如'
zone'
type'
文件名(FILENAME),比如'
/etc/bind/'
引号(QUOTE),比如文件名两边的
左花括号(OBRACE),'
{'
右花括号(EBRACE),'
}'
分号(SEMICOLON),'
'
我们修改后的Lex代码如下:
%{
[a-zA-Z][a-zA-Z0-9]*
printf("
WORD"
);
/*字符串*/
[a-zA-Z0-9\/.-]+
FILENAME"
/*文件名*/
\"
QUOTE"
/*引号"
*/
\{
OBRACE"
/*左花括号*/
\}
EBRACE"
/*右花括号*/
printf("
SEMICOLON"
/*分号*/
\n
\n"
/*换行*/
[\t]+
/*忽略空白字符*/
intyywrap(void)
/*当词法分析器到了文件末尾做什么*/
{
return1;
/*返回1,说明停止前进,0则继续*/
voidyyerror(char*s)/*错误信息打印函数*/
fprintf(stderr,"
%s\n"
s);
return0;
intmain(intargc,char*argv[])
FILE*fp;
fp=fopen(argv[1],"
r"
/*首先打开要被处理的文件(参数1)*/
yyin=fp;
/*yyin是lex默认的文件输入指针,则不处理控制台输入*/
yylex();
/*调用lex的工作函数,从这里开始,lex的词法分析器开始工作*/
fclose(fp);
到这里,我们已经完全可以对一个包含各种类型词组的源代码文件进行分析,得出其中各类型词组的排列顺序。
在一个规范的基于语法的源代码中,词组的顺序从一定意义上来说,就是语法。
对于源代码,lex的处理能力也就到这里为止,但是我们并没有完全展示lex的所有功能,读者如果有兴趣,可以继续深入阅读本文提供的参考文献。
如何进行语法分析我们在下面的章节中讲开始讲述Bison的基本使用方法,以及如何使用Bison进行语法分析。
.基础理论
Bison采用与YACC相同的描述语言,这种语言是BNF语法(BackusNaurForm)的一种,最早被JohnBackus和PeterNaur用于ALGOL60语言的开发工作。
BNF语法可以用来表达与内容无关的,基于语法的语言,几乎所有的现代编程语言都可以用BNF进行描述。
作为一个例子,一个进行加法和乘法的数学表达式语法可以如下表达:
E:
E'
+'
E
*'
id
在这三句中,E在Bison语言中代表表达式,一个表达式可以是一个数字,也可以是一个变量名称,也可以是几个变量名称的组合,比如:
1
1+2
a
a+b*c
而以上三句Bison语言就能够表达这些语法结构。
初探
我们在下面作一个计算器,通过这个实例让大家明白Flex和Bison的相互关系和如何共同工作。
首先,建立文件,并输入以下内容:
/*计算器的词法分析器描述,Flex语言*/
%{
/*直接翻译为C语言*/
/*包含标准库文件*/
voidyyerror(char*);
/*这是我们上面用到的错误报告函数*/
#include"
/*这个头文件由Bison自动生成*/
[0-9]+
yylval=atoi(yytext);
/*yytext是flex内部用于指向当前词汇的字符串指针*/
returnINTEGER;
/*INTEGER是从中包含过来的,在Bison中定义*/
}
[-+\n]
return*yytext;
[\t]
;
/*跳过空白字符*/
yyerror("
invalidcharacter"
/*产生一个错误,说明是无效字符*/
intyywrap(void)
/*文件结束时退出*/
以上就是计算器使用的Flex语言,描述了我们将会遇到的各种词汇的格式,比如[0-9]+说明了,只有连续的从'
0'
9'
的字符串,才被分析为INTEGER类型,如果遇到制表符、空格等,直接忽略,遇到加减符号则返回字符指针,其它的则报告语法错误。
下面是我们的Bison语法文件:
/*注:
您先抄写,注解见下文*/
intyylex(void);
%tokenINTEGER
/*Flex语言中INTEGER定义在此*/
program:
programexpr'
\n'
{printf("
%d\n"
$2);
|
expr:
INTEGER
{$$=$1;
|expr'
expr
{$$=$1+$3;
}
/*
(1)*/
-'
{$$=$1-$3;
/*
(2)*/
voidyyerror(char*s)
intmain(void)
yyparse();
编译过程:
flex
bison-d
#注意-d,用于产生对应的头文件
gcc-otest2
在这个例子中,我们遇到了许多没有见过的用法,Bison的书写格式基本与Flex的相同,只是规则的定义语法不同。
其中,$N(N为数字)代表语法描述中,第N个词汇的内容,比如
(1)中的$1代表'
左边的expr,$3代表右边expr的内容,其中的N是指当前语法的词汇顺序,从1开始计数。
而$$则代表这一段语法处理完后的结果,每一个语法对应的处理都有输入$N和输出$$。
该例子中还有一个特殊的地方,就是第归调用,在Bison中,语法规则可以是第归的,这也是Bison之处(或者说是YACC的强大之处)。
举个例子:
这里,program的定义就是任何符合program的表达式后面紧接着expr和'
,扫描到该表达式后,将expr处理的结果打印到屏幕。
最后的|是“或者”的意思,也就是说program也可以是空的,什么都不写,分号代表该语义定义结束。
有了第归之后,Bison才可以说是一个能够应对任何状况的语法分析器,当然,这里还需要读者对以上所提供代码进行深入的研究和分析,考虑清楚后,会发现无论是C语言,还是Bison,第归永远是一个神奇的解决方案。
.计算器程序的深入研究
以上我们设计的计算器只能进行加减计算,并且里面还有一些软件缺陷,对于一个实用的计算器来说,我们必须能够支持:
1.变量定义
2.变量赋值
3.变量与数字立即处理
于是我们假想设计出来的计算器能有如下的操作过程(输入和输出):
输入:
3*(4+5)
结果:
27
x=3*(4+5)
y=5
x
y
5
x+2*y
37
这样看,这个计算器的功能已经相当强大了,下面我们着手实现,首先修改上面例子的Flex文件为如下:
#include<
voidyyerror(char*);
#include"
[a-z]
{
/*变量类型词汇,限制:
变量只能用一个字符*/
yylval=*yytext-'
returnVARIABLE;
{
/*整数*/
yylval=atoi(yytext);
returnINTEGER;
[+-()=/*\n]
{return*yytext;
/*数学计算符号*/
/*跳过空白符号*/
下面是我们新的Bison文件:
%tokenINTEGERVARIABLE
%left'
'
/'
intyylex(void);
intsym[26];
programstatement'
statement:
{printf("
$1);
|VARIABLE'
='
{sym[$1]=$3;
INTEGER
|VARIABLE
{$$=sym[$1];
{$$=$1*$3;
{$$=$1/$3;
|'
('
expr'
)'
{$$=$2;
现在我们对该例子中引入的新功能介绍,%left,%right,%token都是用来声明词汇的,区别在于,%token声明的词汇与左右优先级无关,而%left的处理时,先处理左边的,%right先处理右边的,例如遇到字符串"
1-2-5"
,到底是处理为"
(1-2)-5"
,还是处理为"
1-(2-5)"
%left处理为前者,而%right处理为后者(注:
第一个计算器代码中就有这个缺陷,比如执行1-2+3,得到的结果就是-4,作为一个练习,读者可以使用这里讲解的%left自行更正)。
和Bison高级应用
在下面的例子中,我们便写了一个更高级的计算器程序,其操作实例如下:
x=0;
while(x<
3){
print(x);
x=x+1;
例子中得到的输出结果如下:
2
首先是我们的全局头文件:
typedefenum{
typeCon,
typeId,
typeOpr
}nodeEnum;
/*constants*/
typedefstruct{
intvalue;
/*valueofconstant*/
}conNodeType;
/*identifiers*/
inti;
/*subscripttosymarray*/
}idNodeType;
/*operators*/
intoper;
/*operator*/
intnops;
/*numberofoperands*/
structnodeTypeTag*op[1];
/*operands(expandable)*/
}oprNodeType;
typedefstructnodeTypeTag{
nodeEnumtype;
/*typeofnode*/
/*unionmustbelastentryinnodeType*/
/*becauseoperNodeTypemaydynamicallyincrease*/
union{
conNodeTypecon;
idNodeTypeid;
oprNodeTypeopr;
}nodeType;
externintsym[26];
下面是Flex语言文件:
=*yytext-'
returnVARIABLE;
=atoi(yytext);
[-()<
=+*/;
{}.]{
return*yytext;
="
returnGE;
returnLE;
=="
returnEQ;
!
returnNE;
while"
returnWHILE;
if"
returnIF;
else"
returnELSE;
print"
returnPRINT;
[\t\n]+
/*ignorewhitespace*/
Unknowncharacter"
然后是我们的Bison文件:
/*prototypes*/
nodeType*opr(intoper,intnops,...);
nodeType*id(inti);
nodeType*con(intvalue);
voidfreeNode(nodeType*p);
voidyyerror(char*s);
intsym[26];
%union{
intiValue;
/*integervalu