您好,欢迎来到九壹网。
搜索
您的当前位置:首页哈尔滨工程大学--编译原理实验--词法分析程序

哈尔滨工程大学--编译原理实验--词法分析程序

来源:九壹网
word格式-可编辑-感谢下载支持

编译原理实验报告

学 号 2011061618 实验名称 词法分析程序 实验目的 1、基本掌握计算机语言的词法分析程序的开发方法。 2、实现一个词法分析程序,将字符串流分解成终结符流供语法分析使用。 3、通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解。并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。 姓 名 唐宗林 实验方案 1、设计功能分析 程序能够从左到右一个字符一个字符地读入源程序,并对构成的源程序的字符流进行扫描和分解,从而识别出一个个单词,并给出单词的种别和属性。 2、设计思路 主函数main()的思想: 先输入一串字符,将字符串用空格打断,若是分隔出的单元不为空,则对此单元继续分析,根据所输入的字符串判断出是标识符、八进制数、十进制数、十六进制数、运算符、分隔符还是关键字,然后赋予那单词的种别和属性。 3、正规文法 对于十进制数: A1——>B1C1 B1——>D1B1|ε C1——>E1B1 E1——> ε|. D1——>0|1|2|3|4|5|6|7|8|9 对于八进制数: A2——>0B2 B2——>C2D2 C2——>E2F2 E2——>1|2|3|4|5|6|7 F2——>GF|ε D2——>H2F2 H2——> ε|. D2——>1|2|3|4|5|6|7 G2——>0|1|2|3|4|5|6|7 对于十六进制: A3——>0xB3 B3——>C3D3 C3——>E3C3|ε E3——> 0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f D3——>F3C3 F3——> ε|. 对于运算符和分隔符: A4——>+|-|*|/|>|<|=|(|)|; 对于标识符和关键字: word格式-可编辑-感谢下载支持 A5——>B5C5 B5——>D5E5 D5——>a|b|……|y|z E5——>F5E5|ε F5——>a|b|……|y|z|0|1|2|3|4|5|6|7|8|9 C5——>G5E5 G5——> ε|. 综上正规文法为: S——>A1|A2|A3|A4|A5 A1——>B1C1 B1——>D1B1|ε C1——>E1B1 E1——> ε|. D1——>0|1|2|3|4|5|6|7|8|9 A2——>0B2 B2——>C2D2 C2——>E2F2 E2——>1|2|3|4|5|6|7 F2——>GF|ε D2——>H2F2 H2——> ε|. D2——>1|2|3|4|5|6|7 G2——>0|1|2|3|4|5|6|7 A3——>0xB3 B3——>C3D3 C3——>E3C3|ε E3——> 0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f D3——>F3C3 F3——> ε|. A4——>+|-|*|/|>|<|=|(|)|; A5——>B5C5 B5——>D5E5 D5——>a|b|……|y|z E5——>F5E5|ε F5——>a|b|……|y|z|0|1|2|3|4|5|6|7|8|9 C5——>G5E5 G5——> ε|. 4、状态图 word格式-可编辑-感谢下载支持 空白 开始 0….9/a…z/A…Z 0 a….z/ A…Z 0…9 1…9 1 其他 其他 2 3 4 0…9 。 5 0 * 非数字 6 7 。 0…7 0…7 非o..7且8 0…7 09 。 12 1…9/a….f/ x/X 。 10非o..7 11 13 非1….9且非a...f且非14 0….9/a...f/A...F 。 非0….9且非a...f且非15 。 0 17 16 +/-/ …/; 18 If/while/then/do 19 实验记录 1、 程序源代码 #include #include //#include \"stdafx.h\" union chars{ //联合,可存储字符串,整型和浮点型 char pro_char[15]; int pro_number; float real; word格式-可编辑-感谢下载支持 }; struct data{ //将每个单元用一个结构来存储,其内容包括:类型,所属的具体类型,以及属性值 char kind[7]; int id; union chars pro; }; int scan(char *a); //对每个用空格打断的单元进行进一步的分析,对其进行进一步的分类 void Prints(char a[15],int id,int a_long); //将分析后的每个token输出 void save(char *a,int id,int x,float y); //将分析后的结果保存到一个结构数组中 char nowChar[15]; //临时的存储单元,用来存储被空格打断以后单元 char kinds[11][8]={\" \\\\//单词的不同种别 struct data link[100]; //用来存放词法分析以后的结果的结构数组 int link_long=0; //全局变量 int scan(char *a) { int id; int a_long=0; int doc=0; while(*a!=NULL){ nowChar[0]='\\0'; a_long=0; doc=0; //对数值的判断及处理 if('0'<=*a&&*a<='9'){ //如果第一个字符为数值 nowChar[a_long]=*a; *a++; a_long++; //对十六进制的判断及处理 if(nowChar[0]=='0'&&(*a=='x'||*a=='X')){ //如果第一个字符为0且第二个字符为x,则为十六进制数 nowChar[a_long]=*a; *a++; a_long++; while(*a!=NULL&&(('0'<=*a&&*a<='9')||('a'<=*a&&*a<='f')||('A'<=*a&&*a<='F')||*a=='.')){ nowChar[a_long]=*a; //一直将此十六进制数完全读入,若为浮点型的,则加以标记 if(*a=='.') doc=1; word格式-可编辑-感谢下载支持 *a++; a_long++; } nowChar[a_long]='\\0'; //判断输入的十六进制数是否合法 if(a_long==2){ //输入的只有0x,则输入错误 Prints(nowChar,7,a_long); return 0; } if(doc) //输入的十六进制数是浮点型的 Prints(nowChar,10,a_long); //则将其具体的类型属性定为10 else //输入的十六进制数是整型的 Prints(nowChar,3,a_long); //则将其具体的类型属性定义为3 continue; } //对八进制的判断及处理 if(nowChar[0]=='0'&&'0'<=*a&&*a<='7'){ //如果第一个字符为0且第二个字符为0~7,则为八进制数 nowChar[a_long]=*a; *a++; a_long++; while(*a!=NULL&&(('0'<=*a&&*a<='7')||*a=='.')){ nowChar[a_long]=*a; //一直将此八进制数完全读入,若为浮点型的,则加以标记 if(*a=='.') doc=1; *a++; a_long++; } nowChar[a_long]='\\0'; if(doc) //输入的八进制数是浮点型的 Prints(nowChar,9,a_long); //则将其具体的类型属性定为9 else //输入的十六进制数是整型的 Prints(nowChar,2,a_long); //则将其具体的类型属性定义为2 continue; } //对十进制数的判断及处理 else{ while(*a!=NULL&&(('0'<=*a&&*a<='9')||*a=='.')){ nowChar[a_long]=*a; //一直将此十进制数完全读入,若为浮点型的,则加以标记 if(*a=='.') doc=1; *a++; a_long++; } nowChar[a_long]='\\0'; if(doc) //输入的十进制数是浮点型的 word格式-可编辑-感谢下载支持 Prints(nowChar,8,a_long); //则将其具体的类型属性定为8 else //输入的十进制数是整型的 Prints(nowChar,1,a_long); //则将其具体的类型属性定义为1 continue; } } //完成了对数值的判断及处理 //对字符的判断及处理 else{ nowChar[a_long]=*a; *a++; a_long++; //判断输入的字符是否为运算符或其他的分隔符 switch(nowChar[0]) { case'+':case'-':case'*':case'/':case'<':case'>': case'(':case')':case'=':case';': nowChar[a_long]='\\0'; Prints(nowChar,5,a_long); //将其具体的类型属性定义为5 continue; default: break; } //判断输入的第一个字符是否为字母 if(('a'<=nowChar[0]&&nowChar[0]<='z')||('A'<=nowChar[0]&&nowChar[0]<='Z')){ while(*a!=NULL&&(('a'<=*a&&*a<='z')||('A'<=*a&&*a<='Z')||('0'<=*a&&*a<='9')||(*a=='.')||(*a=='_'))) { //一直将此字符串完全读入 nowChar[a_long]=*a; *a++; a_long++; } nowChar[a_long]='\\0'; //判断输入的字符串是否为特殊的标识符,若是,则将其具体类型值定义为6 //判断输入的字符串是否为特殊的字符串if if(a_long==2&&strcmp(nowChar,\"if\")==0){ Prints(nowChar,6,a_long); continue; } //判断输入的字符串是否为特殊的字符串then if(a_long==4&&strcmp(nowChar,\"then\")==0){ Prints(nowChar,6,a_long); continue; } //判断输入的字符串是否为特殊的字符串else if(a_long==4&&strcmp(nowChar,\"else\")==0){ word格式-可编辑-感谢下载支持 Prints(nowChar,6,a_long); continue; } //判断输入的字符串是否为特殊的字符串while if(a_long==5&&strcmp(nowChar,\"while\")==0){ Prints(nowChar,6,a_long); continue; } //判断输入的字符串是否为特殊的字符串do if(a_long==2&&strcmp(nowChar,\"do\")==0) { Prints(nowChar,6,a_long); continue; } //若输入的字符串不符合以上几种情况,则输入的为变量 //若输入的字符串为变量,则将其具体属性值定义为4 Prints(nowChar,4,a_long); continue; } //如果输入的既不是数值也不是字符串,则输入错误,将其具体类型之定义为7 else { Prints(nowChar,7,a_long); return 0; } } } return 1; } main() { printf(\"请输入句子:\"); char buf[100]; //用来存储从键盘上输入一串字符 char *tokenPtr; //用来存储用空格打断后的单元 int id=1; //用来存储具体的类型号 link_long=0; while(id){ link_long=0; gets(buf); //从键盘上输入一串字符 tokenPtr=strtok(buf,\" \"); //用空格将字符串打断 while(id&&*tokenPtr!=NULL) { //分割出来的单元不为空 id=scan(tokenPtr); //将此单元进行继续分析,并返回其具体的类型值 tokenPtr=strtok(NULL,\" \"); //将字符串继续用空格进行分割 } word格式-可编辑-感谢下载支持 } printf(\"\\n\\n\"); getchar(); return 0; } //将所分解后的单元存入结构数组中 void save(char *a,int id,int x,float y) { int i; if(link_long<100){ link[link_long].id=id; //将具体的类型值存入 if(id>=5){ if(id>=8){ //id=8,9,10 //若为浮点型的数值,则将浮点型的y值(转换后的)存入其属性当中且存入单词的种别 for(i=0;i<9&&kinds[id][i]!='\\0';i++) link[link_long].kind[i]=kinds[id][i]; link[link_long].pro.real=y; } //id=5,6,7 else{ //若为标识符,则将单词种别定为自身,属性值定为空 for(i=0;i<15&&a[i]!='\\0';i++) link[link_long].kind[i]=a[i]; link[link_long].pro.pro_char[0]='-'; link[link_long].pro.pro_char[1]='\\0'; } link_long++; } //id=1,2,3,4 else{ for(i=0;i<8&&kinds[id][i]!='\\0';i++) link[link_long].kind[i]=kinds[id][i]; //若分解后的token为变量或者整型数值,则将其单词种别直接输出 if(id==4){ //若token为变量,则将其属性值设为自身 for(i=0;i<15&&a[i]!='\\0';i++) link[link_long].pro.pro_char[i]=a[i]; link[link_long].pro.pro_char[i]='\\0'; } else //若token为整型数值,则将其相应的十进制数值赋给其属性值 link[link_long].pro.pro_number=x; } link_long++; //继续存入下一个token } else printf(\"Full 100\\n\"); //结构数组已经存满 word格式-可编辑-感谢下载支持 return; } //将词法分析器分解后的结果输出出来 void Prints(char a[15],int id,int a_long){ int i; int x=0; float y=0; //int float1; //char *c; if(id==1){ //若为十进制整数 for(i=1;i=0&&a[i]!='.';i--) y=(y+(a[i]-48))/10; y=y+x; //整数部分与小数部分换算后相加 printf(\"REAL10\%f\\n\save(a,id,x,y); //存入结构数组 return; } if(id==9){ //若为八进制浮点型 for(i=1;i=0&&a[i]!='.';i--) y=(y+(a[i]-48))/8; y=y+x; //整数部分与小数部分换算后相加 printf(\"REAL8\%f\\n\save(a,id,x,y); //存入结构数组 return; } if(id==10){ //若为十六进制浮点型 for(i=2;i=0&&a[i]!='.';i--) y=(y+(a[i]-48))/16; y=y+x; //整数部分与小数部分换算后相加 printf(\"REAL16\%f\\n\存入结构数组 save(a,id,x,y); return; } printf(\"Wrong Enter\"); //所得的具体类型值为7,则输入有错误 return ; } 2、 运行截图 输入:98 00 –> tyy while word格式-可编辑-感谢下载支持 实验总结 本次的实验使我对词法分析的过程有了全新的了解,同时也明白了词法分析何时可以采用空格来区分单词,明白了程序设计中影响词法分析的效率的环节。比如,关键字的识别过程。因为当词法分析器识别出一个标识符时,就去和保留字表中的关键字进行比较,以确定它是否是关键字。如果关键字和标识符比较少,标识符在表中采取顺序比较的时间还可以接受,但如果关键字和标识符都比较多,那么查询比较的平均时间就会比较长,就会影响到词法分析的效率。且每一次比较都是字符串之间的比较,也很耽误时间。因此,我们讨论出了采取比较好的预选方式,如对标识符先进行筛选,有些不可能是关键字的标识符就可以不再与保留字表中的关键字进行比较了。如某种语言的关键字最长为8个字符,那么对于长度大过8的标识符被“筛下”了。当然进行“筛选” ,也要付出一定的代价。 对于这次的实验,从中积累了很多的经验,同时也总结了一些编程出现的问题。1、在调试的过程中添加语句时经常忘记加分号。2、在编写时对于多层括号的,时常少一边的括号,这个可以采用在编写时直接将完整的括号编写上去,不要只先写一边的括号。3、经常未经定义便使用该变量。4、注意前后的函数名的大小写,保持前后一致,避免出现原本前后是同一个函数,但由于字母的大小写,而导致是表示两个不同的函数 。5、要判断好某个函数是否需要返回其函数值。6、判断好该代码需要在什么环境先实现的,是C还是C++。

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- 91gzw.com 版权所有 湘ICP备2023023988号-2

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务