当前位置:文档之家› 编译原理实验报告——词法分析器

编译原理实验报告——词法分析器

编译原理实验报告姓名:关海超学号:200807010209专业:计算机科学与技术班级:08—02班一、实验目的通过设计调试词法分析程序,实现从源程序中分出各种单词的方法;加深对课堂教学的理解;提高词法分析方法的实践能力。

二、词法分析器的实现1、词法分析过程的考虑词法分析器的任务是将程序源代码看做一个字符串,只需从中分离出一个个具有独立意义的单词(包括标识符,符号和常量)即可,而无需考虑其在上下文环境中的正确性。

基于此认识,词法分析的过程可如下描述:本程序中用户源程序存储在文件“E:\prog.txt”文件中,程序首先调用readFromFile()函数将源程序代码从文件中读出,放到数组中暂存,然后主函数调用scaner()函数对其进行逐个扫描,分离出的每个独立单词进行分类判断,构成二元组形式,再将其输出的文件“E:\result.txt”中进行保存。

2、各种单词符号对应的种别码0 标识符21 ret 42 ++ 63 ||1 整型常量22 sho 43 -- 64 ?:2 auto 23 sig 44 - 65 =3 brea 24 siz 45 * 66 +=4 case 25 sta 46 & 67 -=5 char 26 str 47 / 68 *=6 cons 27 swi 48 % 69 /=7 cont 28 typ 49 + 70 %=8 defa 29 uni 50 - 71 >>=9 do 30 uns 51 << 72 <<=10 dou 31 voi 52 >> 73 &=11 els 32 vol 53 < 74 ^=12 enu 33 whi 54 <= 75 |=13 ext 34 ( 55 > 76 ,14 flo 35 ) 56 >= 77 '15 for 36 [ 57 == 78 ;16 got 37 ] 58 != 79 :17 if 38 -> 59 & 80 \{18 int 39 . 60 ^ 81 }19 lon 40 ! 61 | 82 //20 reg 41 ~ 62 &&3、关键数据结构的描述计数器count:将二元组写入文件时通过count判断是否是首次写入,若是则清空文件,否则追加写入;字符串常量endStr:其值为“end”,在分析判断每一单词的种类时,该字符串作为rwtab表的结束标志;数组prog[200]:暂存从文件中读取的源程序代码,该词法分析器约定源代码长度不超过199;数组token[20]:暂存每次分离出的单个具有独立意义的单词,该词法分析器约定每个单词的长度不超过19;结构体result:存放一个单词的种别码和单词本身的值,在写入文件时以结构体中的元素为单位依次写入;4、程序结构的描述本程序采用结构化设计方法,共有两个文件,六个模块,分别介绍如下:rwtab.h文件包含一个模块,即各种单词符号对应的种别码,作为外部文件被main.cpp文件引用。

main.cpp文件包含以下五个平行模块:1)main()函数:程序入口,控制整个程序的执行流程;2)scanner()函数:词法扫描程序;3)print()函数:由main()函数调用,判别每一个已识别单词的种类,并将其以结构体形式标准化;4)readFromFile()函数:由main()函数调用,将源程序代码读出,并暂存至数组prog[200]中;5)writeToFile()函数:由main()函数调用,把标准的二元组写入文件中。

三、程序运行截屏1、待扫描的程序源代码(prog.txt文件)2、程序执行过程3、程序执行结果(result.txt文件)四、源代码由于源代码较长,故附于文档最后。

五、心得体会这个词法分析器,加深了我对有穷自动机的理解,在编写词法分析器的过程中,我不断将程序算法和自动机的概念相对比,逐步理解了初态、终态、状态转换、接受、拒绝等概念在实际编程中的应用。

这个词法分析程序,能识别大部分的C语言单词,并能指出错误的位置。

对分析出的单词也能够以二元组的形式存储到文件中。

但该程序依然存在一些问题,比如,不能对字符串常量进行有效识别,不能识别汉字等。

词法分析器是编译器与外部交互的接口,是进行后续工作的基础,因此,词法分析程序健壮性和正确性十分重要,掌握词法分析程序的设计技术是学好编译技术的第一步,也是极为重要的一步。

六、附录(程序源代码,仅扫描函数)void scaner(){int i, j;char ch; // 暂存源程序代码中的一个字符int len = strlen(prog); // 源程序代码长度int scanedChars = -1; // 已扫描过的字符(不包括本行)的下标,计算列数时使用int line = 1; // 记录当前行数, 初始化为1int row = 1; // 记录当前列数, 初始化为1for (i=0; i<len; i++){ch = prog[i];j = 0;if ((ch == ' ') || (ch == '\t')) // 空格或水平制表(即tab键){continue;}if (ch == '\n'){line++;scanedChars = i;continue;}if (isalpha(ch)) // ch 是字母{while (isalpha(prog[i]) || isdigit(prog[i])){token[j++] = prog[i];i++;}token[j] = '\0';i--;print(token);//continue;}else{if (isdigit(ch)) // ch 是数字{while (isdigit(prog[i])){token[j++] = prog[i];i++;}token[j] = '\0';i--;print(token);continue;}else // ch 是符号{char t;switch (ch){case '*' :token[j++] = ch;t = prog[++i];if (t == '=')token[j++] = t;elsei--;token[j] = '\0';print(token);break;case '/' :token[j++] = ch;t = prog[++i];if (t == '=')token[j++] = t;else ////////////////////////////////////////////////////////////////////if (t == '/') // 双斜杠注释符{while (prog[++i] != '\n');continue;}elseif (t == '*') // "/* */"注释符{int flag = 0;while (i+2 < len){if ( (prog[i+1]=='*') && (prog[i+2]=='/') ){flag = 1;i += 2;break;}i++;}if (flag){continue;}else // 注释符作用至文件尾{i = len;continue;} /////////////////////////////////////////////////////////////}elsei--;token[j] = '\0';print(token);break;case '=' :token[j++] = ch;t = prog[++i];if (t == '=')token[j++] = t;elsei--;token[j] = '\0';print(token);break;case '!' :token[j++] = ch;t = prog[++i];if (t == '=')token[j++] = t;elsei--;token[j] = '\0';print(token);break;case '?' :token[j++] = ch;t = prog[++i];if (t == '=')token[j++] = t;elsei--;token[j] = '\0';print(token);break;case '%' :token[j++] = ch;t = prog[++i];if (t == '=')token[j++] = t;elsei--;token[j] = '\0';print(token);break;case '^' :token[j++] = ch;t = prog[++i];if (t == '=')token[j++] = t;elsei--;token[j] = '\0';print(token);break;case '+' :token[j++] = ch;t = prog[++i];if (t == '+')token[j++] = t;elseif (t == '=')token[j++] = t;elsei--;token[j] = '\0';print(token);break;case '-' :token[j++] = ch;t = prog[++i];if (t == '>')token[j++] = t;elseif (t == '-')token[j++] = t;elseif (t == '=')token[j++] = t;elsei--;token[j] = '\0';print(token);break;case '&' :token[j++] = ch;t = prog[++i];if (t == '&')token[j++] = t;elseif (t == '=')token[j++] = t;elsei--;token[j] = '\0';print(token);break;case '|' :token[j++] = ch;t = prog[++i];if (t == '|')token[j++] = t;elseif (t == '=')token[j++] = t;elsei--;token[j] = '\0';print(token);break;case '<' :token[j++] = ch;t = prog[++i];if (t == '=')token[j++] = t;else{if (t == '<'){token[j++] = t;t = prog[++i];if (t == '=')token[j++] = t;elsei--;}elsei--;}token[j] = '\0';print(token);break;case '>' :token[j++] = ch;t = prog[++i];if (t == '=')token[j++] = t;else{if (t == '>'){token[j++] = t;t = prog[++i];if (t == '=')token[j++] = t;elsei--;}elsei--;}token[j] = '\0';print(token);break;case '(':token[j++] = ch;token[j] = '\0';print(token);break;case ')':token[j++] = ch;token[j] = '\0';print(token);break;case '{':token[j++] = ch;token[j] = '\0';print(token);break;case '}':token[j++] = ch;token[j] = '\0';print(token);break;case '[':token[j++] = ch;token[j] = '\0';print(token);break;case ']':token[j++] = ch;token[j] = '\0';print(token);break;case '.':token[j++] = ch;token[j] = '\0';print(token);break;case '_':token[j++] = ch;token[j] = '\0';print(token);break;case '~':token[j++] = ch;token[j] = '\0';print(token);break;case ',':token[j++] = ch;token[j] = '\0';print(token);break;case 34:token[j++] = ch;token[j] = '\0';print(token);break;case '\'':token[j++] = ch;token[j] = '\0';print(token);break;case ';':token[j++] = ch;token[j] = '\0';print(token);break;case ':':token[j++] = ch;token[j] = '\0';print(token);break;case '\\':token[j++] = ch;token[j] = '\0';print(token);break;default :printf("Error at line: %d\n", line);printf("Error at row : %d\n", i - scanedChars);printf("Error is : %c\n", prog[i]);exit(-1) ;} // switch} // else} // else} // for//printf("Total lines: %d\n", line);} // scaner method。

相关主题