编译原理 词法分析.docx
- 文档编号:23049357
- 上传时间:2023-04-30
- 格式:DOCX
- 页数:22
- 大小:25.24KB
编译原理 词法分析.docx
《编译原理 词法分析.docx》由会员分享,可在线阅读,更多相关《编译原理 词法分析.docx(22页珍藏版)》请在冰豆网上搜索。
编译原理词法分析
实验报告
学院(系)名称:
计算机与通信工程学院
姓名
建坤
学号
专业
计算机科学与技术
班级
2010级2班
实验项目
实验一:
词法分析
课程名称
编译原理
课程代码
0668056
实验时间
2013年3月22日第5~8节
2013年3月26日第1、2节
实验地点
软件实验室7-215
批改意见
成绩
教师签字:
实验内容:
实现标准C语言词法分析器
实验目的:
1.掌握程序设计语言词法分析的设计方法;
2.掌握DFA的设计与使用方法;
3.掌握正规式到有限自动机的构造方法;
实验要求:
1.单词种别编码要求
基本字、运算符、界符:
一符一种;
标识符:
统一为一种;
常量:
按类型编码;
2.词法分析工作过程中建立符号表、常量表,并以文本文件形式输出;
3.词法分析的最后结果以文本文件形式输出;
4.完成对所设计词法分析器的功能测试,并给出测试数据和实验结果;
5.为增加程序可读性,请在程序中进行适当注释说明;
6.整理上机步骤,总结经验和体会;
7.认真完成并按时提交实验报告。
【实验过程记录(源程序、测试用例、测试结果及心得体会等)】
符号对照:
种类
标识
正则表达式
关键字
KEY
[_A-Za-z][0-9_A-Za-z]
标识符
ID
[_A-Za-z][0-9_A-Za-z]
整型常量
INT
[0-9]+
浮点常量
FLOAT
[0-9](\.[0-9]+)?
(E[+-]?
[0-9]+)?
界符
DELIM
[,;\[\]\{\}\(\)]
运算符
OPT
[!
%\^&\*\+\-<>?
/]|&&|<=|>=|==|\|\|
字符常量
CHAR
^\'$\'
字符串常量
STR
^\"$\"
源程序:
#include
#include
#include
#include
#include
#defineKEY0
#defineID1
#defineINT2
#defineFLOAT3
#defineCHAR4
#defineSTR5
#defineDELIM6
#defineOPT7
char*TYPE[]={"KEY","ID","INT","FLOAT","CHAR","STR","DELIM","OPT"};
charfilename[256];//要处理的文件名
longlength;//文件长度
char*key[]={"auto","break","case","char","const","continue",
"default","do","double","else","enum","extern",
"float","for","goto","if","int","long",
"register","return","short","signed","sizeof","static",
"struct","switch","typedef","union","unsigned","void",
"volatile","while",NULL};
constintKEYCOUNT=32;
char*source;//源码的内存缓冲区
longpos=0;//指向源码的指针
longline=1;//行号
longcolumn=0;//列号
chartoken[1024];//临时存放标识符
voiderror(constchar*error,...){
va_listarglist;
va_start(arglist,error);
vfprintf(stderr,error,arglist);
va_end(arglist);
exit(EXIT_FAILURE);
}
voidwarning(constchar*error,...){
va_listarglist;
va_start(arglist,error);
vfprintf(stderr,error,arglist);
va_end(arglist);
}
//判断是否为分隔符,是的话返回1,否则返回0
intisdelim(constcharch){
switch(ch){
case'(':
case')':
case'[':
case']':
case'{':
case'}':
case',':
case';':
case':
':
return1;
}
return0;
}
intisoperator(constcharch){
switch(ch){
case'+':
case'-':
case'*':
case'/':
case'<':
case'>':
case'?
':
case'=':
case'&':
case'!
':
case'~':
case'%':
case'|':
case'^':
case'.':
return1;
}
return0;
}
intiskey(constchar*str){
for(inti=0;i if(strcmp(key[i],str)==0) returni+1; } return0; } //读入源码的一个字符 charreadSource(){ if(pos charch=source[pos++]; if(ch=='\n'){ line++; column=0; } else column++; returnch; } else{ error("未预料的EOF\n"); return0; } } //回退源码指针 voidback(){ if(pos==0){ error("errorinback(): posnowis0\n"); } else pos--; } longgetFileLength(FILE*fp){ longpos=ftell(fp); longlength; fseek(fp,0,SEEK_END); length=ftell(fp); fseek(fp,pos,SEEK_SET); returnlength; } voidpreprocess(){ for(charch;ch=readSource();){ if(ch=='#'){ inti=0; token[i++]=ch; while((ch=readSource())! ='\n') token[i++]=ch; token[i]='\0'; if(token[0]=='#') printf("%d\t%s\n",line,token); } else{ if(ch! ='\n') back(); break; } } } voidgetOperator(charch){ token[0]=ch; ch=readSource(); token[1]=ch; token[2]='\0'; switch(token[0]){ case'<': case'>': if(token[0]==token[1]||token[1]=='=') break; case'|': case'&': case'+': case'-': case'=': if(token[0]==token[1]) break; case'! ': if(token[1]=='=') break; default: token[1]='\0'; back(); break; } printf("%ld\t%s\t%s\n",line,TYPE[OPT],token); } voidcomment(){ charch=readSource(); if(ch=='*'){ while (1){ ch=readSource(); if(ch=='*'){ ch=readSource(); if(ch=='/') break; } } } elseif(ch=='/'){ while (1){ ch=readSource(); if(ch=='\n') break; } } else{ back(); getOperator('/'); } } voidgetChar(charch){ inti=0; for(;(ch=readSource())! ='\'';i++){ token[i]=ch; if(ch=='\\'){ ch=readSource(); token[++i]=ch; } } token[i]='\0'; if(token[0]! ='\\'&&strlen(token)>1){ error("字符常量字符多余1个\n"); } printf("%ld\t%s\t\'%s\'\n",line,TYPE[CHAR],token); } voidgetString(charch){ inti=0; for(;(ch=readSource())! ='"';i++){ token[i]=ch; if(ch=='\\'){ ch=readSource(); if(ch=='\n') i--; else token[++i]=ch; } } token[i]='\0'; printf("%ld\t%s\t\"%s\"\n",line,TYPE[STR],token); } voidgetIdentify(charch){ inti=1; token[0]=ch; for(;! isspace(ch=readSource());i++){ if(isalpha(ch)||isdigit(ch)||ch=='_'){ token[i]=ch; } elseif(isoperator(ch)||isdelim(ch)||ch=='.'){ back(); break; } else{ error("非法标识符字符\n",filename,line,column); } } token[i++]='\0'; if(iskey(token)) printf("%ld\t%s\t%s\n",line,TYPE[KEY],token); else printf("%ld\t%s\t%s\n",line,TYPE[ID],token); } voidgetNum(charch){ inti=0; inthasDot=0; inttype=0;//0isint1isfloat intafterE=0; if(ch=='.'){ hasDot=1; type=1; } token[0]=ch; for(i=1;i<256;i++){ ch=readSource(); if(token[0]=='.'&&i==1){ if(! isdigit(ch)){ getOperator('.'); back(); return; } } if(ch=='.'){ if(! hasDot){ hasDot=1; type=1; } else error("数字中小数点多于1个\n"); } elseif(ch=='E'||ch=='e'){ afterE=1; type=1; } elseif(ch=='+'||ch=='-'){ if(afterE){ afterE=0; } else{ back(); break; } } elseif(! isdigit(ch)){ back(); break; } token[i]=ch; } token[i]='\0'; if(token[0]=='.'&&strlen(token)==1){ //error("未预料的符号.\n"); getOperator(ch); return; } if(type==0){ printf("%ld\t%s\t%s\n",line,TYPE[INT],token); } elseif(type==1){ printf("%ld\t%s\t%s\n",line,TYPE[FLOAT],token); } } //获得界符与运算符 voidgetDelim(charch){ printf("%ld\t%s\t%c\n",line,TYPE[DELIM],ch); } voidlexer(){ pos=0; line=1; column=0; preprocess(); for(;pos charch=readSource(); //printf("%ld%ld%c\n",line,column,ch); if(isalpha(ch)||ch=='_'){ getIdentify(ch); } elseif(isdigit(ch)||ch=='.'){ getNum(ch); } elseif(isspace(ch)){ } elseif(ch=='\''){ getChar(ch); } elseif(ch=='"'){ getString(ch); } elseif(ch=='/'){ comment(); } elseif(isoperator(ch)){ getOperator(ch); } elseif(isdelim(ch)){ getDelim(ch); } else{ printf("%ld\tPRE\t%c\n",line,ch); } } } /*命令行参数 *lexerfilename */ intmain(intargc,char**argv){ if(argc! =2){ error("Usage: %sfilename\n",argv[0]); } strcpy(filename,argv[1]); FILE*file; if(NULL==(file=fopen(argv[1],"r"))){ error("Cannotopen%s.\n",filename); } longfileLength=getFileLength(file); source=(char*)malloc(fileLength+1); fseek(file,0,SEEK_SET); inthasRead; for(hasRead=0;! feof(file);){ intcount=fread(source+hasRead,1,1024,file); hasRead+=count; } source[hasRead]=0; length=hasRead; lexer();//调用词法处理器 fclose(file); return0; } 测试程序: #include intgetSum(intnum){ inti=0; intsum=0; while(i<=num){ sum+=i; i++; } returnsum; } /*Thisfunctionistogettwonumandcalculatetheresum *andprintthesumof12...to10 */ intmain(){ intt=10; floata=10E-5,b=5.2; scanf("%f%f",&a,&b); printf("a=%f,b=%f\n",a,b); if(a==b) printf("aisequaltob\n"); elseif(a printf("a<=b\n"); else printf("a>b\n"); //invokeafunction printf("sum=%d\n",sum(t)); return0; } 测试结果: 2#include 3KEYint 3IDgetSum 3DELIM( 3KEYint 3IDnum 3DELIM) 3DELIM{ 4KEYint 4IDi 4OPT= 4INT0 4DELIM; 5KEYint 5IDsum 5OPT= 5INT0 5DELIM; 6KEYwhile 6DELIM( 6IDi 6OPT<= 6IDnum 6DELIM) 6DELIM{ 7IDsum 7OPT+= 7IDi 7DELIM; 8IDi 8OPT++ 8DELIM; 9DELIM} 10KEYreturn 10IDsum 10DELIM; 11DELIM} 17KEYint 17IDmain 17DELIM( 17DELIM) 17DELIM{ 18KEYint 18IDt 18OPT= 18INT10 18DELIM; 19KEYfloat 19IDa 19OPT= 19FLOAT10E-5 19DELIM, 19IDb 19OPT= 19FLOAT5.2 19DELIM; 21IDscanf 21DELIM( 21STR"%f%f" 21DELIM, 21OPT& 21IDa 21DELIM, 21OPT& 21IDb 21DELIM) 21DELIM; 22IDprintf 22DELIM( 22STR"a=%f,b=%f\n" 22DELIM, 22IDa 22DELIM, 22IDb 22DELIM) 22DELIM; 23KEYif 23DELIM( 23IDa 23OPT== 23IDb 23DELIM) 24IDprintf 24DELIM( 24STR"aisequaltob\n" 24DELIM) 24DELIM; 25KEYelse 25KEYif 25DELIM( 25IDa 25OPT< 25IDb 25DELIM) 26IDprintf 26DELIM( 26STR"a<=b\n" 26DELIM) 26DELIM; 28KEYelse 28IDprintf 28DELIM( 28STR"a>b\n" 28DELIM) 28DELIM; 31IDprintf 31DELIM( 31STR"sum=%d\n" 31DELIM, 31IDsum 31DELIM( 31IDt 31DELIM) 31DELIM) 31DELIM; 32KEYreturn 32INT0 32DELIM; 33DELIM} 实验感想: 1.开始时的程序整体无框架,所有程序都写在了一个函数里,写到中间发现不宜维护,可读性差,后来就整体重新写了一遍,把不相关的功能剥离,提高模块性及可读性。 。 2.开始时注释处理在符号处理后面,后来发现处理不了注释,经过排查后发现把注释处理放到最前面就行了。 3.本程序添加了许多错误处理,使代码更加健壮。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 编译原理 词法分析 编译 原理 词法 分析