flexbison使用教程.docx

上传人:b****1 文档编号:23274379 上传时间:2023-05-15 格式:DOCX 页数:21 大小:22.82KB
下载 相关 举报
flexbison使用教程.docx_第1页
第1页 / 共21页
flexbison使用教程.docx_第2页
第2页 / 共21页
flexbison使用教程.docx_第3页
第3页 / 共21页
flexbison使用教程.docx_第4页
第4页 / 共21页
flexbison使用教程.docx_第5页
第5页 / 共21页
点击查看更多>>
下载资源
资源描述

flexbison使用教程.docx

《flexbison使用教程.docx》由会员分享,可在线阅读,更多相关《flexbison使用教程.docx(21页珍藏版)》请在冰豆网上搜索。

flexbison使用教程.docx

flexbison使用教程

使用说明

本文需要读者对C语言有一定的了解作为基础

本文中所涉及的例子可以用本站提供的‘全自动化Makefile’一文中提供的Makefile进行编译

读者如果在Linux下,可以直接使用,Windows用户需要Cygwin环境

本文中的工具,需要用户安装flex和bison软件包

1.介绍

编译器是软件开发中的核心部件,其作用是其他任何软件所不能取代的。

编译器在工作过程中,往往完成如下的任务:

1.读取源代码并且获得程序的结构描述

2.分析程序结构,并且生成相应的目标代码

在UNIX早期时代,编写一个编译器是一件非常耗时的工作。

人们为了简化开发过程,开发了Lex和YACC程序来解决第一个任务,根据用户描述的语言,生成能够解决问题的C/C++语言代码,供开发者使用。

1.将源代码文件分解为各种词汇(Lex)

2.找到这些词汇的组成方式(YACC)

GNU软件协会开发了Flex和BISON,其功能与LEX和YACC基本兼容,并且在Lex和YACC提供的功能的基础上进行了各种扩展。

入门

Lex能够用来编写那些输入数据流(字符串)能够用正则表达式描述的程序,它可以根据正则表达式的描述,将输入数据流分类为各类词汇,为后来的语法分析做准备。

.正则表达式

正则表达式是通过对各种词组类型所包含的字符类型的归纳,描述所需词组组成格式的方法,比如下面的例子描述了所有数字类型的字符串,表明无论在何时起,只要有0-9字符出现,就进入该状态,说明是字符,直到非0-9字符结束:

[09]+

为了简化书写起见,也可以写成如下的格式:

[0-9]+

对于任意单词,其中只能包含字母,所以单词的正则表达式为:

[a-zA-Z]+

Flex支持如下类型的正则表达式:

x     符合字符串"x"

.     除了换行以外的任何字符

[xyz]   一个字符类,在这个例子中,输入必须符合要么是'x’要么是'y'要么是'z'

[abj-oZ] 一个带范围的字符类,符合任何满足'a','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是一个'a','b','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,但是必须是在行末

r   一个r,但是之前字符串必须符合条件s

r

      同上,但是必须之前字符串符合s1或者s2或者s3

<*>r   不考虑开始字符串类型,只符合r

<>  文件末尾

<>

      前面符合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代码如下:

%{

#include<>

%}

%%

[a-zA-Z][a-zA-Z0-9]* printf("WORD");   /*字符串*/

[a-zA-Z0-9\/.-]+   printf("FILENAME"); /*文件名*/

\"          printf("QUOTE");   /*引号"*/

\{          printf("OBRACE");  /*左花括号*/

\}          printf("EBRACE");  /*右花括号*/

;          printf("SEMICOLON"); /*分号*/

\n          printf("\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);

    return0;

}

到这里,我们已经完全可以对一个包含各种类型词组的源代码文件进行分析,得出其中各类型词组的排列顺序。

在一个规范的基于语法的源代码中,词组的顺序从一定意义上来说,就是语法。

对于源代码,lex的处理能力也就到这里为止,但是我们并没有完全展示lex的所有功能,读者如果有兴趣,可以继续深入阅读本文提供的参考文献。

如何进行语法分析?

我们在下面的章节中讲开始讲述Bison的基本使用方法,以及如何使用Bison进行语法分析。

入门

.基础理论

Bison采用与YACC相同的描述语言,这种语言是BNF语法(BackusNaurForm)的一种,最早被JohnBackus和PeterNaur用于ALGOL60语言的开发工作。

BNF语法可以用来表达与内容无关的,基于语法的语言,几乎所有的现代编程语言都可以用BNF进行描述。

作为一个例子,一个进行加法和乘法的数学表达式语法可以如下表达:

E:

E'+'E

E:

E'*'E

E:

id

在这三句中,E在Bison语言中代表表达式,一个表达式可以是一个数字,也可以是一个变量名称,也可以是几个变量名称的组合,比如:

1

1+2

a

a+b*c

而以上三句Bison语言就能够表达这些语法结构。

初探

我们在下面作一个计算器,通过这个实例让大家明白Flex和Bison的相互关系和如何共同工作。

首先,建立文件,并输入以下内容:

/*计算器的词法分析器描述,Flex语言*/

%{            /*直接翻译为C语言*/

#include<>   /*包含标准库文件*/

voidyyerror(char*);  /*这是我们上面用到的错误报告函数*/

#include""   /*这个头文件由Bison自动生成*/

%}

%%

[0-9]+  {

       yylval=atoi(yytext);  /*yytext是flex内部用于指向当前词汇的字符串指针*/

       returnINTEGER;     /*INTEGER是从中包含过来的,在Bison中定义*/

     }

[-+\n]  return*yytext;

[\t]  ;/*跳过空白字符*/

.    yyerror("invalidcharacter");/*产生一个错误,说明是无效字符*/

%%

intyywrap(void)

{

  return1;             /*文件结束时退出*/

}

以上就是计算器使用的Flex语言,描述了我们将会遇到的各种词汇的格式,比如[0-9]+说明了,只有连续的从'0'到'9'的字符串,才被分析为INTEGER类型,如果遇到制表符、空格等,直接忽略,遇到加减符号则返回字符指针,其它的则报告语法错误。

下面是我们的Bison语法文件:

/*注:

您先抄写,注解见下文*/

%{

#include<>

intyylex(void);

voidyyerror(char*);

%}

%tokenINTEGER             /*Flex语言中INTEGER定义在此*/

%%

program:

    programexpr'\n'  {printf("%d\n",$2);}

    |

    ;

expr:

    INTEGER       {$$=$1;}

    |expr'+'expr   {$$=$1+$3;} /*

(1)*/

    |expr'-'expr   {$$=$1-$3;} /*

(2)*/

    ;

%%

voidyyerror(char*s)

{

  fprintf(stderr,"%s\n",s);

}

intmain(void)

{

  yyparse();

  return0;

}

编译过程:

flex

bison-d   #注意-d,用于产生对应的头文件

gcc-otest2

在这个例子中,我们遇到了许多没有见过的用法,Bison的书写格式基本与Flex的相同,只是规则的定义语法不同。

其中,$N(N为数字)代表语法描述中,第N个词汇的内容,比如

(1)中的$1代表'+'左边的expr,$3代表右边expr的内容,其中的N是指当前语法的词汇顺序,从1开始计数。

而$$则代表这一段语法处理完后的结果,每一个语法对应的处理都有输入$N和输出$$。

该例子中还有一个特殊的地方,就是第归调用,在Bison中,语法规则可以是第归的,这也是Bison之处(或者说是YACC的强大之处)。

举个例子:

program:

    programexpr'\n'  {printf("%d\n",$2);}

    |

    ;

这里,program的定义就是任何符合program的表达式后面紧接着expr和'\n',扫描到该表达式后,将expr处理的结果打印到屏幕。

最后的|是“或者”的意思,也就是说program也可以是空的,什么都不写,分号代表该语义定义结束。

有了第归之后,Bison才可以说是一个能够应对任何状况的语法分析器,当然,这里还需要读者对以上所提供代码进行深入的研究和分析,考虑清楚后,会发现无论是C语言,还是Bison,第归永远是一个神奇的解决方案。

.计算器程序的深入研究

以上我们设计的计算器只能进行加减计算,并且里面还有一些软件缺陷,对于一个实用的计算器来说,我们必须能够支持:

1.变量定义

2.变量赋值

3.变量与数字立即处理

于是我们假想设计出来的计算器能有如下的操作过程(输入和输出):

输入:

3*(4+5)

结果:

27

输入:

x=3*(4+5)

输入:

y=5

输入:

x

结果:

27

输入:

y

结果:

5

输入:

x+2*y

结果:

37

这样看,这个计算器的功能已经相当强大了,下面我们着手实现,首先修改上面例子的Flex文件为如下:

%{

  #include<>

  voidyyerror(char*);

  #include""

%}

%%

[a-z]    {              /*变量类型词汇,限制:

变量只能用一个字符*/

         yylval=*yytext-'a';

         returnVARIABLE;

       }

[0-9]+   {              /*整数*/

         yylval=atoi(yytext);

         returnINTEGER;

       }

[+-()=/*\n] {return*yytext;}     /*数学计算符号*/

[\t]    ;              /*跳过空白符号*/

%%

intyywrap(void)

{

  return1;

}

下面是我们新的Bison文件:

%tokenINTEGERVARIABLE

%left'+''-'

%left'*''/'

%{

  voidyyerror(char*);

  intyylex(void);

  intsym[26];

%}

%%

program:

  programstatement'\n'

  |

  ;

statement:

  expr           {printf("%d\n",$1);}

  |VARIABLE'='expr    {sym[$1]=$3;}

  ;

expr:

  INTEGER

  |VARIABLE        {$$=sym[$1];}

  |expr'+'expr      {$$=$1+$3;}

  |expr'-'expr      {$$=$1-$3;}

  |expr'*'expr      {$$=$1*$3;}

  |expr'/'expr      {$$=$1/$3;}

  |'('expr')'      {$$=$2;}

  ;

%%

voidyyerror(char*s)

{

  fprintf(stderr,"%s\n",s);

  return0;

}

intmain(void)

{

  yyparse();

  return0;

}

现在我们对该例子中引入的新功能介绍,%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;

}

例子中得到的输出结果如下:

0

1

2

首先是我们的全局头文件:

typedefenum{

    typeCon,

    typeId,

    typeOpr

}nodeEnum;

/*constants*/

typedefstruct{

    intvalue;   /*valueofconstant*/

}conNodeType;

/*identifiers*/

typedefstruct{

    inti;     /*subscripttosymarray*/

}idNodeType;

/*operators*/

typedefstruct{

    intoper;   /*operator*/

    intnops;   /*numberofoperands*/

    structnodeTypeTag*op[1];   /*operands(expandable)*/

}oprNodeType;

typedefstructnodeTypeTag{

    nodeEnumtype; /*typeofnode*/

    /*unionmustbelastentryinnodeType*/

    /*becauseoperNodeTypemaydynamicallyincrease*/

    union{

        conNodeTypecon;    /*constants*/

        idNodeTypeid;     /*identifiers*/

        oprNodeTypeopr;    /*operators*/

    };

}nodeType;

externintsym[26];

下面是Flex语言文件:

%{

#include<>

#include""

#include""

voidyyerror(char*);

%}

%%

[a-z]     {

            =*yytext-'a';

            returnVARIABLE;

        }

[0-9]+     {

            =atoi(yytext);

            returnINTEGER;

        }

[-()<>=+*/;{}.]{

            return*yytext;

        }

">="      returnGE;

"<="      returnLE;

"=="      returnEQ;

"!

="      returnNE;

"while"    returnWHILE;

"if"      returnIF;

"else"     returnELSE;

"print"    returnPRINT;

[\t\n]+    ;   /*ignorewhitespace*/

.       yyerror("Unknowncharacter");

%%

intyywrap(void)

{

    return1;

}

然后是我们的Bison文件:

%{

#include<>

#include<>

#include<>

#include""

/*prototypes*/

nodeType*opr(intoper,intnops,...);

nodeType*id(inti);

nodeType*con(intvalue);

voidfreeNode(nodeType*p);

intyylex(void);

voidyyerror(char*s);

intsym[26];

%}

%union{

    int

展开阅读全文
相关搜索

当前位置:首页 > PPT模板 > 动物植物

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

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