您的位置:首页 > 其它

Lex和Yacc从入门到精通(7)-筛选信息(容错处理)

2009-07-31 23:39 281 查看



Lex和Yacc从入门到精通(7)-筛选信息(容错处理)

收藏

document.body.oncopy=function(){
if(window.clipboardData){
setTimeout(function(){
vartext=clipboardData.getData("text");
if(text&&text.length>300){
text=text+"/r/n/n本文来自CSDN博客,转载请标明出处:"+location.href;
clipboardData.setData("text",text);
}
},100);
}
}

functionStorePage(){d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();}

#if0


在通常的情况下,我们只关心文本中的一部分信息,但是为了编写词法和语法分析程

序,又不得不将所有的结构信息全部描写出来,例如:我们仅仅关心C++源文档中的类名字

信息,而不关心类是否有成员变量,是否有成员函数以及是否有其它的一些C++内容。将结

构信息全部描述出来的做法是费时费力的,通常的情况往往导致项目的不可完成或者延期

完成。另外,作为程序设计者和代码编写者,都希望将功能局域化而不扩散难度,也非常

希望编写的代码能够简单的不予理睬还没有理解的内容,专心处理自己关心的内容。本篇

文档就以着重考虑处理C/C++类名称信息为例,忽略其它的一切没有进行语法描述的C/C++

信息。这就是Lex和Yacc的错误(error)处理的一个应用:)我非常喜欢:)


下面给出词法和语法分析器的源代码,因为这么简单的程序,看源代码是学习的最好

方法:)


#endif


////////////////////////////////////////////////////////////////////////////////

//
词法扫描器文件:lex.l

%{

#include
<string>


//
将yylval的值类型由默认的int修改为std::string类型,实际上可以修改为你认为的任

//
何类型,仅仅只是需要定一个这样YYSTYPE宏即可,特别注意,这个宏定义必须在后面

//
的标记文件yacc.tab.h之前定义,并且在yacc文件中也要有这个YYSTYPE定义,并且必

//
须和这里的保持一致。实际上YYSTYPE的定义在生成的标记文件yacc.tab.h中有一个宏

//
判断,如果用户也就是我们定义了YYSTYPE宏,那么就用我们定义的YYSTYPE,否则就用

//
默认的YYSTYPE,也就是int类型:)


#defineYYSTYPEstd::string

#include
"yacc.tab.h"


#defineLEX_RETURN(arg)yylval=yytext;
return

arg

%}

d[
0
-9
]

l[a-z]

u[A-Z]

a{l}|{u}

%%

[;{}

]
{

LEX_RETURN(yytext[0
]);}

"class"

{

LEX_RETURN(CLASS);}


(_|{

a}

)(_|{

a}

|{

d}

)*
{

LEX_RETURN(IDENTIFIER);}


[/t/n]
/*
忽略空白*/

.
/*
忽略其它一切没有被处理的文本*/

%%

int

yywrap()

{

return

1
;

}

////////////////////////////////////////////////////////////////////////////////



////////////////////////////////////////////////////////////////////////////////

//
语法分析器文件:yacc.y

%{

#include
<iostream>

#defineYYSTYPEstd::string

extern

int

yylex();

void

yyerror(const

char

*msg);

%}

%tokenCLASSIDENTIFIER

%%

program

:/*
空*/

|program
class

//处理C++类

|programerror
';'
//一旦出现错误直接跳到最近的分号处,回复正常的扫描过程

//
特别注意这里的标记符号error,它是由yacc自动生成的标记

//
和上面的CLASS和IDENTIFIER标记一样都可以直接应用到语法

//
描述中

;

class

://
特别注意一下下面的class语法描述又调用了program,这是一种嵌套结构的常见做法

CLASSIDENTIFIER
'{'
program'}'
';'
{std::cout<<"
发现类名:"
<<$2
<<std::endl;}

;

%%

void

yyerror(const

char

*msg)

{

//
错误处理,仅仅是简单的输出一个错误标记,在具体应用中应当能够分析出这种错

//
误是否已经被处理了,这里为了说明上面的错误信息过滤没有进行这种识别

std::cerr<<
"
发现错误"
<<std::endl;

}

int

main()

{

yyparse();

return

0
;

}

////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////

//Makefile
文件

CC=g++

CFLAGS=

LEX=flex

YACC=bison

YACCFLAGS=-d

TARGET=lexyacc


$(TARGET):lex.yy.cyacc.tab.hyacc.tab.c

$(CC)$(CFLAGS)lex.yy.cyacc.tab.c-o$(TARGET)

lex.yy.c:lex.l

$(LEX)lex.l

yacc.tab.cyacc.tab.h:yacc.y

$(YACC)$(YACCFLAGS)yacc.y


clean

:

rm-flex.yy.cyacc.tab.hyacc.tab.c

////////////////////////////////////////////////////////////////////////////////


//
从上面的代码中可以看出,通过容错处理之后,我们就可以专心于特定的功能代码编写

//
而不需要考虑其它的信息,这样就可以极大的降低解决问题的难度。在后续的文档中都

//
会采用这种技巧来实现特定的功能。如果对上面的一些描述还不是很清晰的话,可以参

//
见我之前已经写出来的系列文档,在本章中值得说明的只有两点:

//1
:yacc自动生成的error标记的使用

//2
:改变默认的yylval的int类型为std::string类型

//
其实我是在尽可能的使用C++库,目的当然是降低编写代码的难度,减少代码,便于说

//
明问题;)

//

//好了,本篇文档到此就已经说明了本文开始所提出的问题:D,后续的文档正在努力给出

//。其实编写Lex和Yacc程序非常简单,只需要注意几个常见错误就可以完成一般的任务

//了,在下一篇里面将会讲解常见的错误及其处理方法:)敬请关注:)


//下面是实例应用

////////////////////////////////////////////////////////////////////////////////

//测试文件:sample.cpp

class

Point

{

int

x;

int

y;

int

GetX();

int

GetY();

};


class

Rect

{

int

x;

int

y;

int

w;

int

h;

int

GetX();

int

GetY();

int

GetW();

int

GetH();

};


class

Wrapper

{

class

Inner1{};

class

Inner2{

class

InnerInner1{float

f;};

class

InnerInner2{};

std::stringname;

};

bool

sex;

};

////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////

//编译并运行过程

D

:/home/blog/lexyacc>make

flexlex.l

bison-dyacc.y

g++lex.yy.cyacc.tab.c-olexyacc


D

:/home/blog/lexyacc>lexyacc.exe<sample.cpp

发现错误

发现类名:Point

发现错误

发现类名:Rect

发现类名:Inner1

发现错误

发现类名:InnerInner1

发现类名:InnerInner2

发现错误

发现类名:Inner2

发现错误

发现类名:Wrapper


D

:/home/blog/lexyacc>

////////////////////////////////////////////////////////////////////////////////
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: