编译原理课程设计.docx
- 文档编号:26182604
- 上传时间:2023-06-17
- 格式:DOCX
- 页数:27
- 大小:907.84KB
编译原理课程设计.docx
《编译原理课程设计.docx》由会员分享,可在线阅读,更多相关《编译原理课程设计.docx(27页珍藏版)》请在冰豆网上搜索。
编译原理课程设计
课程设计报告
设计题目:
一个简单文法的编译器前端的设计与实现
班级:
计算机1206
组长学号:
201239
组长姓名:
闫智宣
指导教师:
李晓华
设计时间:
2014年12月
设计分工
组长学号及姓名:
20123974闫智宣
分工:
语法分析,四元式生成,目标代码优化及生成
组员1学号及姓名:
20123977廖峭
分工:
词法分析,错误处理
组员2学号及姓名:
20123959郭天龙
分工:
符号表生成,语义动作插入,操作界面
摘要
编译原理课程设计是通过C语言编译器相关子系统的设计,进一步加深对编译器构造的理解;第一部分词法分析,设计各单词的状态转换图,并为不同的单词设计种别码,制作扫描器识别一个个单词,返回值为识别码的序号,返回Token序列。
将词法分析器设计成供语法分析器调用的子程序。
词法分析器具备预处理功能。
将不翻译的注释等符号先滤掉,只保留要翻译的符号串,即要求设计一个供词法分析调用的预处理子程序;第二部分,语法分析,用递归下降法,实现对表达式、各种说明语句、控制语句进行语法分析。
若语法正确,则用语法制导翻译法进行语义翻译;生成并打印出语法树;若语法错误,要求指出出错性质和出错位置(行号)。
我们还做了附加功能,即编译后端,有中间代码优化,生成目标代码汇编语言。
通过此次课程设计,提高了我们的独立分析问题、解决问题的能力,以及系统软件设计的能力;提高程序设计能力、程序调试能力,团结协作能力
关键词:
词法分析,语法分析,四元式生成,错误处理,符号表生成,语义动作插入,中间代码优化,生成目标代码
目录
摘要
1.概述
2.课程设计任务及要求
2.1设计任务
2.2设计要求
3.算法及数据结构
3.1算法的总体思想(流程)
3.2词法分析模块
3.2.1功能
3.2.2数据结构
3.2.3算法
3.3语法分析模块
3.3.1功能
3.3.2数据结构
3.3.3算法
3.4符号表模块
3.4.1功能
3.4.2数据结构
3.4.3算法
3.5四元式模块
3.5.1功能
3.5.2数据结构
3.5.3算法
3.6语义动作分析模块
3.6.1功能
3.6.2数据结构
3.6.3算法
3.7错误处理模块
3.7.1功能
3.7.2数据结构
3.7.3算法
3.8目标代码模块
3.8.1功能
3.8.2数据结构
3.8.3算法
4.程序设计与实现
4.1程序流程图
4.2程序说明
4.3实验结果
5.结论
6.参考文献。
7.收获、体会和建议。
1.概述
编译器是将C语言翻译为汇编语言代码的计算机程序。
编译器将源程序(sourcelanguage)编写的程序作为输入,翻译产生目标语言(targetlanguage)机器代码的等价程序。
通常地,源程序为高级语言(high-levellanguage),C语言程序,而目标则是机器语言的目标代码(objectcode),也就是可以在计算机硬件中运行的机器代码软件程序。
这一过程可以表示为:
源程序→编译器→目标机器代码程序
2.课程设计任务及要求
2.1设计任务
学生在学习《编译原理》课程过程中,结合各章节的构造编译程序的基本理论,要求用C#语言描述及上机调试,实现一个C编译程序(包括词法分析,语法分析等重要子程序),使学生将理论与实际应用结合起来,受到软件设计等开发过程的全面训练,从而提高学生软件开发的能力。
2.2设计要求
要求:
(1)设计词法分析器
设计各单词的状态转换图,并为不同的单词设计种别码。
将词法分析器设计成供语法分析器调用的子程序。
功能包括:
a.具备预处理功能。
将不翻译的注释等符号先滤掉,只保留要翻译的符号串,即要求设计一个供词法分析调用的预处理子程序;
b.能够拼出语言中的各个单词;
c.返回(种别码,属性值,行号)。
(2)语法分析
要求用学习过的自底向上或自顶向下的分析方法等,实现对表达式、各种说明语句、控制语句进行语法分析。
若语法正确,则用语法制导翻译法进行语义翻译;生成并打印出语法树;若语法错误,要求指出出错性质和出错位置(行号)。
3.算法及数据结构
3.1算法的总体思想(流程)
本节主要分析程序的代码结构和代码工程文件的划分。
(程序由几个类组成:
Token类和Variable类SymbolTable类ObjectCode类Lexical类Grammar类Four_Yuan类Action类ErrorItem类,分别为词法分析和语法分析类。
工程分为几个文件:
Form1.cs,Token.cs,Variable.cs,SymbolTable.cs,ObjectCode.cs,Lexical.cs,Grammar.cs,Four_Yuan,cs,Action.cs,ErrorItem.cs分别对应Token类和Variable类SymbolTable类ObjectCode类Lexical类Grammar类Four_Yuan类Action类ErrorItem类的声明和实现文件)。
本程序采用C#语言以面向对象的思想编写,程序分为几部分:
词法分析(Lexical),语法分析(Grammer),目标代码生成(ObjectCode)。
Lexical类主要的工作是词法分析获取Token。
Grammer类的主要工作是根据Lexical类词法分析之后的Token进行语法分析,生成语法树,最后并输出语法树。
在处理过程中,Token类的对象作为Lexical类的一个成员变量,配合Grammer类进行语法分析。
工程文件总体上是按照九个类的格局分为十个文件,分别是九个类的声明文件和实现文件。
十个文件为Form1.cs,Token.cs,Variable.cs,SymbolTable.cs,ObjectCode.cs,Lexical.cs,Grammar.cs,Four_Yuan,cs,Action.cs,ErrorItem.cs,他们分别是Lexical类声明文件、Lexical类实现文件、Grammer类声明文件、Grammer类实现文件。
程序流程
在程序中,Lexical类的对象(Token)作为Grammer类中的一个成员变量,配合Grammer类进行语法分析。
它们的关系是这样的:
Grammer类的一个成员变量temp首先对源程序删除注释,然后进行词法分析获取所有Token,并将获取的Token存储在Token对象的tokenList(List类型)中。
然后Grammer类的语法分析程序就根据tokenList中的Token进行语法分析,生成语法树,最后打印语法树。
同时,这也是程序的流程。
3.2词法分析模块
3.2.1功能
Lexical类主要的工作是词法分析获取Token序列。
3.2.2数据结构
词法分析阶段的代码被封装成一个类——Lexical,Token中主要是Lexical类的声明代码,Lexical.cs中主要是Lexical类的实现代码。
Lexical类对外提供的函数主要有:
staticpublicintRecogId(stringstr,inti),
staticpublicintRecogDig(stringstr,inti),
staticpublicintRecogOperator(stringstr,inti),
staticpublicintRecogBound(stringstr,inti),
以上几个函数构成了词法分析的骨架,在Lexical类中还有其他成员变量和函数,主要作为这三个函数处理过程的中间步骤,为这三个函数服务。
Lexical类的代码结构和主要的成员变量和函数及其含义如下图所示:
3.2.3算法
算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。
主程序示意图:
主程序示意图如图3-1所示。
⑴关键字表的初值。
关键字作为特殊标识符处理,把它们预先安排在一张表格中(称为关键字表),当扫描程序识别出标识符时,查关键字表。
如能查到匹配的单词,则该单词为关键字,否则为一般标识符。
(2)程序中需要用到的主要变量为type和number
扫描子程序的算法思想:
首先设置3个变量:
①token用来存放构成单词符号的字符串;
②number用来整型单词;
③type用来存放单词符号的种别码。
Token定义
Token定义:
Token类型(TokenType):
3.3语法分析模块
3.3.1功能
语法分析是编译过程的一个逻辑阶段。
语法分析的功能是在词法分析的基础上将单词序列组合成各类语法短语,如“程序”,“语句”,“表达式”等等.语法分析程序判断源程序在结构上是否正确.源程序的结构由上下文无关文法描述.
3.3.2数据结构
下图为实现语法分析的类Grammar,属性与方法的作用都已说明
3.3.3算法
1.文法
下面终结符与非终结符意义
B程序开始
Z数据类型,如int,char,float等
V标识符
S语句
P语句块
E加减算术表达式
D逗号表达式
T乘除算术表达式
C关系表达式
L逻辑表达式
Q标识符或圆括号
e表示空
i表示标识符
a)函数文法
B----ZV()S
b)语句块文法
P----SP|e
S----{P}
c)语句文法
表达式语句文法
S----V=E
goto语句文法
S----i:
S
S----gotoi
if语句文法
S----if(E)S[elseS]
while语句文法
S----while(E)S
声明语句文法
S----ZVD
D----,VD|=ED|e
d)表达式文法
E----T|E+T|E-T
T----F|T*F|T/F
C----C|C
L----Q|L&&Q|L||Q
Q----i|(E)|!
Q
2.递归下降程序流程图
对应于每个文法编写如下递归下降子程序
主程序(B)
3.4符号表模块
3.4.1功能
进行符号表的储存,添加,更新,查找,保存标识符活跃信息以及输出。
3.4.2数据结构
3.4.3算法
3.5四元式模块
3.5.1功能
四元式为中间代码,编译程序进行完语义分析后,先生成中间代码作为过渡,此时中间代码与目标代码已经比较相似
3.5.2数据结构
3.5.3算法
3.6语义动作分析模块
3.6.1功能
在语法分析中嵌入相应的语义动作,生成四元式
3.6.2数据结构
3.6.3算法
GEQ(+)(-)(*)(/)(+,i1,i2,t)
PUSH(i)
ASSI(=)(=,t,_,POP)
LABER(i)(lb,_,_,i)
GOTO(i)(gt,_,_,i)
IF(if)(if,a,_,_)
EL(el)(el,_,_,_)
IE(ie)(ie,_,_,_)
WH()(wh,_,_,_)
DO()(do,a,_,_)
WE(we)(we,_,_,_)
3.7错误处理模块
3.7.1功能
保存运行时发现的错误,储存行号已经详细信息并输出。
3.7.2数据结构
3.7.3算法
publicstaticvoidAddErrorMessage(intlineno,stringcontent)函数用作在发现错误时保存错误信息以及行号。
publicstaticstringPrintErrorList()把所有发现的错误格式化后统一输出。
错误信息在语法分析,语义分析,符号表检错中添加。
3.8目标代码模块
3.8.1功能
目标代码生成把优化后的中间代码变换成目标代码,此处的目标代码为汇编代码,采用单寄存器生成目标代码
3.8.2数据结构
3.8.3算法
对于一个基本块有如下流程图
W:
操作符,B:
第一操作数,C:
第二操作数,R:
寄存器
5.结论
网上找一段话抄上
6.测试
测试打开文件
测试保存文件
如果没打开文件,直接敲代码,点保存时会弹出另存为窗口
测试错误检测,程序缺少main函数的类型,错误列表中显示第一行函数缺少错误类型。
测试错误检测,程序缺少分号,错误列表中显示该行缺少语句结束标志';'
单击错误列表,会自动选定错误行
编译成功,生成并显示token串、符号表、四元式与目标代码
测试if与while语句,而且while嵌套在if当中
测试goto语句,结果正确。
测试优化,输入课件中的代码,结果与课件一样
6.参考文献。
1、陈火旺.《程序设计语言编译原理》(第3版).北京:
国防工业出版社.2000.
2、美AlfredV.AhoRaviSethiJeffreyD.Ullman著.李建中,姜守旭译.《编译原理》.北京:
机械工业出版社.2003.
3、美KennethC.Louden著.冯博琴等译.《编译原理及实践》.北京:
机械工业出版社.2002.
4、金成植著.《编译程序构造原理和实现技术》.北京:
高等教育出版社.2002.
7.收获、体会和建议。
直接拷贝好歹也检查一下错误
对于编译原理的这次课程设计,自己经历了从刚开始的不懂明白任务的要求和内容理论知识的了解开始着手写代码完成基本功能根据DFA及自顶向下等理论修改完善代码等这些过程。
自己着手写词法分析的时候还不清楚词法分析的任务内容,还不知道词法分析的结果是什么,词法分析出错的情况和类型有哪些,也总是将词法分析和语法分析混在一起,不明白哪些错误在词法分析中报,哪些错误在语法分析中判断,后来经过查书、网上资料、请教同学等途径逐步清晰了词法分析的工作内容是从源代码文件中获取出Token,供语法分析使用。
在充分了解了语法分析需要哪些信息时,我才真正了解了词法分析的工作内容和目标,才知道词法分析需要完成哪些任务获取到哪些信息。
充分了解了词法分析的任务之后,就开始理论知识的学习。
经过揣摩书上的例子,自己理解和掌握了怎么设计过滤注释和分析程序中Token的DFA,于是开始根据设计好的DFA进行编码,最后经过调试已经可以正确地完成词法阶段的任务了。
这只是词法分析的原始代码,在之后还进行了两次彻底的改动。
虽然之前写的词法分析的代码已经完成了词法分析的需求,也是根据DFA的原理编写的,但是在代码结构上却难以体现,在对书上的根据已知DFA写代码的例子进行了详细的研究之后,发现自己的代码并没有像书上那样完全按照所依据的DFA各状态转移的关系进行编写,所以对代码进行了重写,像书上一样严格按照状态之间转移的方式进行编写,将状态划分成11个状态,状态分别按1~11进行标注,程序也按照DFA来编写,也实现了词法分析的功能。
再后来写报告的时候,发现分析出Token的那个DFA并不是最简的,有很多多余的状态,完全可以用一个flag标志来标识,从而简化代码结构,于是又重写了一次词法分析函数scan()的代码,将状态缩减为5个,且不再用1-5来表示,而是像书上那样分别取了名字(START、INNUM、INID、INDBSYM、DONE),同时为了简化代码将输出Token到文件的部分从scan()中剥离开来,而在Lexical类中加了一个printToken()的函数,使scan()函数逻辑更加清晰,使读者能够容易地将代码与DFA进行查看比照。
在写语法分析的时候,已经对编译器的语法分析的内容有了一定的了解,所以直接进行了理论的学习。
首先自己对递归向下分析法进行了学习,将书上的几个递归向下分析的伪代码看过之后,自己对递归向下的分析方法的原理有了初步的认识,大概知道了根据文法怎么分析,但是对于如何编写代码却还是难以下手,于是就对照TINY语言的文法看了几遍书后面的TINY语言的递归向下分析的语法分析程序,这样就基本知道了C-语言的语法分析程序怎么写。
由于C-语言给出的文法有左递归存在,于是自己将存在左递归的文法改写成EBNF的形式,并据此进行代码编写。
由于在编写代码的过程中需要确定分析是否正确或选择多个文法中的某一个文法进行分析,有时必须探测需要的或下一个Token的类型,在这种情况下需要求First集合,在推导中若存在empty,又需要求Follow集合,所以这样又需要我了解First集合和Follow集合,自己在程序中也根据求出的First集合和Follow集合进行判断,以确定程序的走向。
在编写过程中,还有一类问题,就是存在公共左因子,如文法expression→var=expression|simple-expression,左因子为ID,在分析过程中,由于已经取出了一个ID的Token,且生成了一个IdK的节点,但是在当前状态无法确定是哪一个推导,然而IdK节点已经生成,又无法回退,并且是使用自顶向下的分析方法,已经生成的IdK在程序上方无法使用,自己通过查阅资料等途径的学习确定了在这种情形下的处理方式:
将已经生成的IdK节点传到下方的处理程序,所以TreeNode*simple_expression(TreeNode*k)、TreeNode*additive_expression(TreeNode*k)等函数都被设计成有节点类型参数的函数,目的就是将已经生成的节点传到下面的分析函数中去。
通过这次的编译原理课程的学习和实践,自己获益良多。
首先最基本的成果是完成了课程设计的任务,实现了编译器的词法分析和语法分析阶段的功能,词法分析主要能过滤注释、分析出语法分析阶段需要的Token并满足语法阶段的所有要求,能够判别词法分析阶段是否出错和出错类型和位置。
语法分析主要能根据递归向下的分析思想和C-文法对词法分析获取的Token进行语法分析,能够构造出语法树,能够判别语法分析过程中是否出错以及出错位置和错误类型。
由于在编写程序过程中,涉及到了正则表达式、DFA、提取公共左因子、消除左递归、EBNF、求First集合和Follow集合、递归向下分析方法以及编程语言方面的知识,所以,通过本次的课程设计的实践,使得自己对编译原理这门课的许多知识点有了更加深刻和具体的理解,而不再只限制于做题。
此外,对以前那些已掌握的知识有了温习和动手锻炼的机会。
如:
以前在编译原理课上虽然知道First集合和Follow集合怎么求的,却不知道First集合和Follow集合到底是干什么的,通过编写程序自己明白了他们的实际作用,使得自己不仅知其然还知其所以然,从而使得自己加深了对知识点的理解和掌握。
由于以前编写代码都是使用JAVA语言,所以C/C++很多内容都忘记了,通过本次的实践,自己又重新拾起了以前的知识。
此外,由于在做报告的时候,需要描绘DFA和程序流程图,使得自己初步掌握了使用visio和word画图的能力。
此外,对于文档的编写和美化自己也获得了许多有用的经验。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 编译 原理 课程设计