1、编译原理课程设计报告MiniC 编译分组序号:27设计地点:微机 101电子邮件:分组成绩: 指导教师:李村合专业班级 计算机 08-4 班姓名 孟庆刚 刘红伟 闫广 黄永强 秦洪卿 许少雷学号 08081421 08081426 08081412 08081410 08081411 08081433成绩比例成绩2010 年 11 月 26 日目录1 课程设计目的 .12 课程设计内容 .13 课程设计原理 .14 系统需求分析 .24.1 MiniC 编译程序的结构图 .24.2 MiniC 编译程序总体流程图 .34.3 功能需求 .34.4 主要用到的关键词、虚拟机代码等: .44.5
2、虚拟机代码格式 .44.6 MiniC 语言的 BNF 文法 .55 系统设计与实现 .55.1 MiniC 编译程序主要模块功能 .55.2 词法分析子程序 .65.3 语法语义分析子程序 .75.3.1 分程序处理过程 .85.3.2 常量定义过程 .125.3.3 变量定义过程 .135.3.4 语句处理过程 .135.3.5 赋值语句的处理 .135.3.6 read 语句的处理 .155.3.7 write 语句的处理 .155.3.8 call 语句的处理 .155.3.9 if 语句的处理 .155.3.10 begin/end 语句的处理 .165.3.11 while 语句的
3、处理 .165.3.12 表达式、项、因子处理 .165.3.13 逻辑表达式的处理 .165.3.14 判断单词合法性与出错恢复过程分析: .165.3.15 类 PCODE 代码解释执行过程分析 .176 系统测试与运行结果分析 .186.1.1 测试程序: .186.1.2 测试结果 .197 心得体会 .2201 课程设计目的1. 编写一个 MiniC编译程序,掌握编译原理课程的基本知识;2. 加强编写和读程序的能力;3. 理解词法分析、语法分析和语义分析在编译程序中的作用;4. 掌握词法分析、语法分析和语义分析程序的实现方法和技术。5. 编制一个递归下降分析程序,实现对词法分析程序所
4、提供的单词序列的语法检查和结构分析。2 课程设计内容(1)仔细阅读 PL/0编译程序文本(编译原理(第二版) 张素琴 吕映芝 蒋维杜 戴桂兰 主编 清华大学出版社) ,并上机调试通过。(2)根据 PL/0的基本原理用 C语言实现具有部分 C语言编译功能的编译器,有 C到pcode码的翻译执行。1:具体实现功能如下:类型:void int;函数:主函数 main和其他函数;语句:赋值语句,运算语句,输入输出语句,循环语句,条件语句,调用函数语句;运算符:+ - * / =逻辑运算符 = != = grtm“dquotwhwhns# 结 束 符 号 bg附 加 符 号 ero$空 empty2:转
5、换后的 PCODE码:虚拟机代码格式即中间代码表示如下:1f L a其中 f代表功能码,l 表示层次差,也就是变量或过程被引用的分程序与说明该变量或过程 的分程序之间的层次差.a 的含意对不同的指令有所区别,见下面对每条指令解释说明.目标指令有 8条:1、lit:将常量值取到运行栈顶.a 域为常数值.2、lod:将变量放到运行栈顶.a 域为变量在所说明层中的相对位置,l 为调用层与说明层的层差值.3、sto:将栈顶的内容送入某变量单元中.a,l 域的含意同 LOD指令.4、cal:调用过程的指令.a 为被调用过程 的目标程序入口地址,l 为层差.5、int:为被调用的过程(或主程序)在运行栈中
6、开辟数据区.a 域为开辟的单元个数.6、jmp:无条件转移指令,a 为转向地址.7、jpc:条件转移指令,当栈顶的布尔值为非真时,转向 a域的地址,否则顺序执行.8、opr:关系运算符和算术运算指令.将栈顶和次栈顶的内容进行运算,结果存放栈顶.具体操作由 a域值给出.3 课程设计原理MIniC 语言可以看成 C 语言的子集,它的编译程序是一个编译解释执行系统。MIniC的目标程序为假想栈式计算机的汇编语言,与具体计算机无关。 (后面内容没具体实现)MiniC 的编译程序和目标程序的解释执行程序都是用 C 语言书写的, 。其编译过程采用一趟扫描方式,以语法分析程序为核心,词法分析和代码生成程序都
7、作为一个独立的过程,当语法分析需要读单词时就调用词法分析程序,而当语法分析正确需要生成相应的目标代码时,则调用代码生成程序。 用数组以及类建立变量、常量和过程表示符的说明与引用之间的信息联系。 当源程序编译正确时,MiniC 编译程序自动调用解释执行程序,对目标代码进行解释执行,并按用户程序的要求输入数据和输出运行结果。 3.1 MiniC 编译程序的结构图语法语义分析程序表格管理程序出错处理程序目标程序代码生成程序程序词法分析程序程序MiniC源程序23.2 MiniC 编译程序总体流程图图 2 PL/0编译程序总体流程图3.3 功能需求1、用 C语言实现了类 PASCAL语言,称为扩展的
8、PL/0语言,即 EPL/0语言的编译器。2、文法是 LL(1)文法,采用递归子程序法实现语法分析,并用 C语言实现了词法分析器、语法分析器、代码生成器和解释器。3、在声明中实现了对静态常量、变量、数组和过程的声明支持;在赋值语句中实现了+=、+、-=、-、*=、/=、%=、:=(赋值);数学运算支持+、-、*、/、%。4、使用 call实现了对过程的调用。5、使用 beginend实现了复合语句。6、使用 read()来同时读入一个到多个数据,使用 write()来同时输出一个到多个数据。7、在循环分支语句中实现了 ifthenelse语句,caseofend 语句,forto/downto
9、do语句,whiledo和 repeatuntil语句。8、条件语句包括奇偶判断、=(等于)、#(不等于)、=。启动置初值调用 getsym 取单词调用 block 过程是否为源程序结束符源程序是否有错误调用解释过程 interpret 解释执行目标执行目标程序结束出错打印错误NNYY34 系统设计与实现4.1 MiniC 语言的文法4.2 词法分析子程序词法分析子程序名为 getsym,功能是从源程序中读出一个单词符号(token) ,把它的信息放入全局变量 sym、id 和 num中,语法分析器需要单词时,直接从这三个变量中获得。(注意!语法分析器每次用完这三个变量的值就立即调用 gets
10、ym子程序获取新的单词供下一次使用。而不是在需要新单词时才调用 getsym过程。 )getsym 过程通过反复调用 getch子过程从源程序过获取字符,并把它们拼成单词。getch 过程中使用了行缓冲区技术以提高程序运行效率。词法分析器的分析过程:调用 getsym时,它通过 getch过程从源程序中获得一个字符。如果这个字符是字母,则继续获取字符或数字,最终可以拼成一个单词,查保留字表,如果查到为保留字,则把 sym变量赋成相应的保留字类型值;如果没有查到,则这个单词应是一个用户自定义的标识符(可能是变量名、常量名或是过程的名字) ,把 sym置为ident,把这个单词存入 id变量。查保
11、留字表时使用了二分法查找以提高效率。如果getch获得的字符是数字,则继续用 getch获取数字,并把它们拼成一个整数,然后把 sym置为 number,并把拼成的数值放入 num变量。如果识别出其它合法的符号(比如:赋值号、大于号、小于等于号等) ,则把 sym则成相应的类型。如果遇到不合法的字符,把 sym置成nul。getsym函数: 4getch 获得字符辨别字符类型单词保留字sym被赋保留字值Y sym置为identN单词存入 id数字sym 置为number数值放入num其它合法字符置sym为相应类型非法字符sym置成 nul图 3 PL/0词法分析过程 getsym判断单词合法性
12、与出错恢复过程分析:本过程有三个参数,s1、s2 为两个符号集合,n 为出错代码。本过程的功能是:测试当前符号(即 sym变量中的值)是否在 s1集合中,如果不在,就通过调用出错报告过程输出出错代码 n,并放弃当前符号,通过词法分析过程获取一下单词,直到这个单词出现在s1或 s2集合中为止。这个过程在实际使用中很灵活,主要有两个用法:在进入某个语法单位时,调用本过程,检查当前符号是否属于该语法单位的开始符号集合。若不属于,则滤去开始符号和后继符号集合外的所有符号。在语法单位分析结束时,调用本过程,检查当前符号是否属于调用该语法单位时应有的后继符号集合。若不属于,则滤去后继符号和开始符号集合外的
13、所有符号。通过这样的机制,可以在源程序出现错误时,及时跳过出错的部分,保证语法分析可以继续下去。行可以正常的结束55 系统测试与运行结果分析 5.1.1测试程序:5.1.2 测试结果:6 心得体会这次课程设计的过程我遇到了很多的困难,不过由于有七个星期的时间,所以有足够的时间给我看书和查资料,从这次课程设计的过程我也看到了自己学习的理论知识的不足。通过这次课程设计我对于编译原理有了更加深入的了解,也懂得了构造一种语言的编译器所要考虑的过程,还有锻炼了我看别人写的大型的程序的能力。进一步加强了我写程序和读程序的能力。这次实验用是 C语言,对此并不熟练,所以在修改的过程中遇到了一些比较难的问题,但
14、在老师与同学们的讨论后才得以解决。同时,也就此机会熟悉和回忆了了 C语言,为今后进行 C+设计积累了不少的经验。这次实验我做了五个内容,其中在增加一些语句的时候遇到的困难比较大,不过通过查资料和与同学讨论我最后解决了这个问题,也学到了很多的东西,在这次实验中充分理解了团结就是力量。在编译程序实现的过程中反复使用了递归调用的思想,且也使用了模块化处理问题的思想,使用模块化的思想关键是在抽象阶段要抽象出对应的模块,且模块的层次必须是清晰的。在实现此程序中,由于要实现关键字和符号表中字段的搜索,实现中就必须注意快速查找的方法,而在实现的过程中多次用到了二分搜索的方法,这是个比较快的搜索方法。由于此程序的实现相对比较复杂,且不方便调试,改进时可以把此程序的词法分析,语法分析和执行原代码作为单独的测试程序来测试,这样也方便大家来调试。通过本次的课设我知道了一个算法的设计是需要静下心来仔细的研究的,且实现中必须先了解程序的整个流程,也就是说在编程中首先必须看懂那些对应的 UML 图,只有在图的指导下,编程中才不会盲目,也有一定的方向性。同样在编程中必须注意代码的规范,多写一些对应的注释是很必要的,要时刻想这代码并不是给你自己看的,而是必须要给别人看,因此我觉得代码的规范是相当重要的。