编译原理词法分析课程设计报告.docx
- 文档编号:10854945
- 上传时间:2023-02-23
- 格式:DOCX
- 页数:25
- 大小:346.42KB
编译原理词法分析课程设计报告.docx
《编译原理词法分析课程设计报告.docx》由会员分享,可在线阅读,更多相关《编译原理词法分析课程设计报告.docx(25页珍藏版)》请在冰豆网上搜索。
编译原理词法分析课程设计报告
编译原理课程设计报告
题目名称
实现C/C++语言的词法分析器
班
学
姓
级
号
名
计算机二班
2402090206
蒋阳斌
指导教师
编写时间
宁航
2011.12.26—2011.12.30
一、课程设计题目名称
实现C/C++语言词法分析器
二、课程设计目的与任务
(1)输入:
C/C++源代码文件,即后缀为c/cpp的文件。
(2)输出:
后缀为tok的文本性文件。
(3)实现功能:
完成C/C++语言的词法分析器
(C语言词法记号及其含义详见附件一)
词法记号
含义
LB
“{”
LP
“(”
RB
“}”
RP
“)”
PLUS
“+”
…
…
三、设计思想和实现方法
(一)、Lex是一种生成扫描器的工具,(我是在Lunix 操作系统下安装flex,进行编程的)
Lex程序编程分为以下四步:
1.Lunix下用vi命令编写lex程序,我的文件是lex.l,编写好后,保存并退出。
2.使用命令flexlex.l,编译系统自动生成了lex.yy.c的C文件。
3.使用命令gcclex.yy.c-ll,生成可执行的扫描器a.out文件。
4.使用命令a.outfile1.c,其中file1.c为要进行此法扫描的C文件。
我要做的就是编写C语言词法的正则表达式,以及需要识别的各种词法记号和匹配后需要执行的动作即可,其他的操作都可以交给Lex来执行。
(二)、词法分析器的作用如下:
1.词法分析器的主要任务是读入源程序的输入字符
2
2.过滤掉源程序中的注释、空白(空格、换行符、制表符以及输入中用于分割词法单元的其他字符)
3.对源程序进行预处理,如对源程序的宏展开
4.将编译器生成的错误消息与与源程序的位置对应起来;
(三)、对于此题,我使用Lex编程来自动生成词法分析器。
使用Lex编程的重点与难点是正则式的定义,对于容易产生二义性的正则表达式,我们要借助与辅助函数来解决。
以下为一个二义性的解决;
plus({Int}|{Float}|{id}){blank}?
\+//加号的正则定义
{plus}{install(yytext,PLUS);}//转换规则里的模式{动作}
需要说明的是:
当‘+’左边为一个标示符(id)或数字(num)时,我们才认为它是加号;否则为正号。
但匹配到plus正则式时,我们调用intinstall()辅助函数,intinstall()函数再把“+”前面的标示符(id)或数字(num)与“+”分离开来,其余三个容易产生歧义的符号,也采用同种处理方法,install()辅助函数的定义,将在本报告的第四部分<程序说明>中给出。
四、程序说明
Lex是一种生成扫描器的工具,我们可以通过编写Lex文件来实现识别文本中的词汇模式的程序。
一个Lex程序可具有如下形式:
声明、定义部分
%%
转换规则
%%
辅助函数
1、声明部分包括变量和明示常量(被声明的表示一个常数标示符,如一个此法单元的
名字)的声明,本程序声明部分包括:
C语言的头文件,及为每个关键字定义一个宏常量,为避免与ASCII冲突,数值从257开始。
定义部分同时给出了正则表达式。
第一段的部分如下,详细见附件二
声明部分
%{
#include
#include
#include
intyywrap();
#defineLB257
#defineLP258
….
….
#defineREAL_LITERAL367
#defineSTRING368
3
#defineCHARACTER369
#defineNUM370
%}
正则表达式
blank\0
delim[\t\n]
ws{delim}+
FloatE?
{digit}+(\.{digit}+)+(e{E}?
{digit}+)?
[Ff]
id{letter}({letter}|{digit})*
incom(\/\*[^*]*\*+([^/*]*\*+)*\/)|(\/\/(.)*)
mul({Int}|{Float}|{id}){blank}?
\*//乘号的正则定义
Bit({Int}|{Float}|{id}){blank}?
\&//按位与的正则定义
plus({Int}|{Float}|{id}){blank}?
\+//加号的正则定义
sub({Int}|{Float}|{id}){blank}?
\-//减号的正则定义
2.LEX程序的每个转换规则具有如下形式:
模式{动作}
其中,每个模式是一个正则表达式,我的程序的正则表达式的定义全部在声明部分给出。
动作部分是代码片段。
以下为转换规则部分
{plus}{install(yytext,PLUS);}
{sub}{install(yytext,MINUS);}
{mul}{install(yytext,MULT);}
"+="{printf("<%s,%d>\n",yytext,PLUSA);}
"-="{printf("<%s,%d>\n",yytext,MINUSA);}
"*="{printf("<%s,%d>\n",yytext,MULA);}
"/="{printf("<%s,%d>\n",yytext,DIVA);}
Lex机器经过此法扫描。
通过模式匹配产生一个动作,其形式为<词素,属性值>,其中词素为当前匹配到的最长字符串,属性值为该词素对应的属性值,这里我们通过lex程序的声明部分的宏声明,给出每个词素对应的属性值,每个词素的属性值是唯一的。
3.Lex程序的第三个部分包括各个动作需要的所有辅助函数,其中int
yywrap() 函数,这里作者定义了一个用于消除“+、—、*、&”二义性的辅助函数
intinstall(constchar*y,intb)
{
intlen=strlen(y);
charid[len];
inti;
for(i=0;i { id[i]=*(y+i); } 4 id[len-1]='\0'; if(! sdigit(id))printf("<%s,%d>\n",id,IDENTIFIER); elseprintf("<%s,%d>\n",id,NUM); printf("<%c,%d>\n",y[len-1],b); return0; }; 五、程序运行结果 在lunix中用vi编辑器,编辑一个名叫lex.l的lex程序文件; lex编译器产生lex.yy.c文件: (如下图) 用gcclex.yy.c–ll命令产生a.out文件: (如下图) 执行a.out文件,其中goods.c为要进行词法分析的C程序源文件, 使用: ./a.outgoods.c>goods.tok通过命令行传递文件,并把分析器产生的词素通过重定向符‘>’输入goods.tok文件中(操作如下图) 通过分屏操作符more 打开goods.tok文件(如下图) 5 其中good.c文件的部分如下图: 六、测试报告 1、现在用写好的lex程序,用来扫描一个li.c文件,程序的重点在于二义性的处理,简单起见,我的li.c文件的内容不会太多,具体如下图: 图 (一) 6 2、我们用命令 ./a.outli.c>li.tok对li.c文件进行词法分析,得到的结果输入到li.tok文件 中,我们打开li.tok文件,其结果如下图: 图 (二) 在lex程序的声明部分我们定义了如下宏: #definePLUS261//“+”为加号 #defineMINUS262//“-”为减号 #defineMULT263//“*”为乘号 #defineBITAND276//“&”为按位与操作 #defineUNARYMINUS297//“-”为正号 #defineUNARYPLUS298//“+”为负号 #defineDEREFERECE299//“*”为指针号 #defineADDRESS300//“&”为引用符号 #defineIDENTIFIER303 我们由第一部可知a、b、c都为标示符(id),所以a、b、c其属性指都是303,第一个表达式a+b,扫描结果理论为<+,261>表示其为加号,由图二可知此法扫描实际结果与理论匹配;第二表达式+a中的“+”理论上是正号,对应的是<+,298>,图二中的实际结果也是<+,298>,其他表达式,同理也可分析出。 7 七、存在问题及分析 词法分析的正则表达式编写有些不是很全面简洁,比如说char和income的正则式。 宏定义部分显得冗余,没有把握住词法分析的程序关键要处理的词素, 识别某些词法记号的正则表达式编写的不是很严谨,比如说在识别C语言预处理定 义语句的正则表达式仅仅只能识别出预处理语句,而无法进行预处理包含的头文件的词法分析。 程序存在一个瑕疵,在处理”+、—、*、&”时,扫描id+id、id*id、id-id、id&id, 时,把这四个符号当成加、减、乘、与符号,但当扫描遇到 num+、num*、num&、num-时,分不出mun是int还是float类型,只是笼统的把它归为数字。 这个问题是在设计辅助函数,及在正则式定义是出现的最大漏洞。 对Lex编程还不是很了解,对词法分析器的作用以及工作原理的理解还有待提高 八、总结及体会 在拿到本次课程设计题目后,对是用C/C++还是lex进行了分析,用C/C++语言直接编写词法分析程序从思路上来说会比较容易些,但在写代码的过程中,慢慢地就暴露出直接编写词法分析程序的一些问题,比如说代码里充斥着大量的if…switch…语句,也频繁些读写语句,极大地增加了代码的复杂度,从而促使我选择使用unix下的Lex编程来自动生成词法分析器的方案。 使用Lex编程就简化了代码的编写,但是Lex编程的重点是正则表达式的定义。 本次课程设计也暴露了我在编译原理学习中的一些不足,比如对正规式的含义和编写还有一些疑问,对辅助函数的编写显得不严谨,对词法分析器的作用和工作原理理解的不是很清等等,通过课程设计很好的复习了编译原理课程中的词法分析部分,对自己理解词法分析有很大的帮助 参考文献 AlfredV.AhoMonicaS.LamRaviSethiJeffreyD.Ullman《编译原理》,机械工程出版社 8 附录: 附录一 C语言词法记号及其含义表 词法记号 含义 LB “{” LP “(” RB “}” RP “)” PLUS “+” MINUS “-” MULT “*” DIV “/” MOD “%” PLUSA “+=” MINUSA “-=” MULA “*=” DIVA “/=” MODA “%=” LS “<<” RS “>>” LSA “<<=” RSA “>>=” NOT “! ” BITAND "&" BITOR "|" XOR "^" COMPL "~" 9 词法记号 含义 AND “&&” OR “||” LT “<” LE “<=” GT “>” GE “>=” EQ “==” NE “! =” ASSIGN “=” DOT “.” MS "->" LA "[" RA "]" POSINC "++" POSDEC "--" PREINC "++" PREDEC "--" UNARYMINUS "-" 附件二程序源代码: %{ /************************************************************************** ** Filename: lex.l ProductLexfileinunix Author: 蒋阳斌学号: 2402090206**************************************************************************/ #include #include #include intyywrap(); #defineLB257 10 #defineLP258 #defineRB259 #defineRP260 #definePLUS261 #defineMINUS262 #defineMULT263 #defineDIV264 #defineMOD265 #definePLUSA266 #defineMINUSA267 #defineMULA268 #defineDIVA269 #defineMODA270 #defineLS271 #defineRS272 #defineLSA273 #defineRSA274 #defineNOT275 #defineBITAND276 #defineBITOR277 #defineXOR278 #defineCOMPL279 #defineAND280 #defineOR281 #defineLT282 #defineLE283 #defineGT284 #defineGE285 #defineEQ286 #defineNE287 #defineASSIGN288 #defineDOT289 #defineMS290 #defineLA291 #defineRA292 #definePOSINC293 #definePOSDEC294 #definePREINC295 #definePREDEC296 #defineUNARYMINUS297 #defineUNARYPLUS298 #defineDEREFERECE299 #defineADDRESS300 #defineCOMMA301 11 #defineSC302 #defineIDENTIFIER303 #defineASM304 #defineAUTO305 #defineBOOL306 #defineBREAK307 #defineCASE308 #defineCATCH309 #defineCHAR310 #defineCLASS311 #defineCONST312 #defineCONST_CAST313 #defineCONTINUE314 #defineDEFAULT315 #defineDELETE316 #defineDO317 #defineDOUBLE318 #defineDYNAMIC_CAST319 #defineELSE320 #defineENUM321 #defineEXPLICIT322 #defineEXTERN323 #defineFALSE324 #defineFLOAT325 #defineFOR326 #defineFRIEND327 #defineGOTO328 #defineIF329 #defineINLINE330 #defineINT331 #defineLOG332 #defineLONG333 #defineMUTABLE334 #defineNAMESPACE335 #defineNEW336 #defineOPERATOR337 #definePRIVATE338 #definePROTECTED339 #definePUBLIC340 #defineREGISTER341 #defineREINTERPRET_CAST342 #defineRETURN343 #defineSHORT344 #defineSIGNED345 12 #defineSIZEOF346 #defineSTATIC347 #defineSTATIC_CAST348 #defineSTRUCT349 #defineTEMPLATE350 #defineTHIS351 #defineTHROW352 #defineTRUE353 #defineTRY354 #defineTYPEDEF355 #defineTYPRID356 #defineTYPENAME357 #defineUNION358 #defineUNSIGNED359 #defineUSING360 #defineVIRTUAL361 #defineVOID362 #defineVOLATITLE363 #defineWCHAR_T364 #defineWHILE365 #defineINTEGER_LITERAL366 #defineREAL_LITERAL367 #defineSTRING368 #defineCHARACTER369 #defineNUM370 %} /*正则式的定义*/ blank\0 delim[\t\n] ws{delim}+ letter[A-Za-z] digit[0-9] E[+-] Int{E}? {digit}+ Float{E}? {digit}+(\.{digit}+)[Ff] id{letter}({letter}|{digit})* incom(\/\*[^*]*\*+([^/*]*\*+)*\/)|(\/\/(.)*) Oct0(E? )[0-7]+ UNSIGN[0-9]+[uU] HEX0[xX](E? )[a-fA-F0-9]+ string\"[^"]*\" char(\\(([ntbrf\\'"])|([0-7]{1,3})|([xX][A-Fa-f0-9]{1,2})))|\'[^']\' headfile#include\<[A-Za-z]+(.h)? \> mul({Int}|{Float}|{id}){blank}? \* 13 Bit({id}|{Int}|{Float}){blank}? \& plus({id}|{Int}|{Float}){blank}? \+ sub({id}|{Int}|{Float}){blank}? \- %% /*转换规则*/ {ws}{/*noaction*/} "{"{printf("<%s,%d>\n",yytext,LB);} "("{printf("<%s,%d>\n",yytext,LP);} "}"{printf("<%s,%d>\n",yytext,RB);} ")"{printf("<%s,%d>\n",yytext,RP);} {plus}{install(PLUS);}//匹配加号 {sub}{install(MINUS);}//匹配减号 {mul}{install(MULT);}//匹配乘号 {Bit}{install(BITAND);}//匹配按位与操作符 "/"{printf("<%s,%d>\n",yytext,DIV);} "%"{printf("<%s,%d>\n",yytext,MOD);} "+="{printf("<%s,%d>\n",yytext,PLUSA);} "-="{printf("<%s,%d>\n",yytext,MINUSA);} "*="{printf("<%s,%d>\n",yytext,MULA);} "/="{printf("<%s,%d>\n",yytext,DIVA);} "%="{printf("<%s,%d>\n",yytext,MODA);} "<<"{printf("<%s,%d>\n",yytext,LS);} ">>"{printf("<%s,%d>\n",yytext,RS);} "<<="{printf("<%s,%d>\n",yytext,LSA);} ">>="{printf("<%s,%d>\n",yytext,RSA);} "! "{printf("<%s,%d>\n",yytext,NOT);} "~"{printf("<%s,%d>\n",yytext,COMPL);} "&&"{printf("<%s,%d>\n",yytext,AND);} "||"{printf("<%s,%d>\n",yytext,OR);} "<"{printf("<%s,%d>\n",yytext,LT);} "<="{printf("<%s,%d>\n",yytext,LE);} ">"{printf("<%s,%d>\n",yytext,GT);} ">="{printf("<%s,%d>\n",yytext,GE);} "=="{printf("<%s,%d>\n",yytext,EQ);} "! ="{printf("<%s,%d>\n",yytext,NE);} "="{printf("<%s,%d>\n",yytext,ASSIGN);} "."{printf("<%s,%d>\n",yytext,DOT);} "->"{printf("<%s,%d>\n",yytext,MS);} "["{printf("<%s,%d>\n",yytext,LA);} "]"{printf("<%s,%d>\n",yytext,RA);} "++"{printf("<%s,%d>\n",yytext,POSINC);} "--"{printf("<%s,%d>\n",yytext,POSDEC);} "-"{p
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 编译 原理 词法 分析 课程设计 报告