编译原理课程设计报告算符优先分析法.docx
- 文档编号:24742255
- 上传时间:2023-06-01
- 格式:DOCX
- 页数:14
- 大小:38.61KB
编译原理课程设计报告算符优先分析法.docx
《编译原理课程设计报告算符优先分析法.docx》由会员分享,可在线阅读,更多相关《编译原理课程设计报告算符优先分析法.docx(14页珍藏版)》请在冰豆网上搜索。
编译原理课程设计报告算符优先分析法
编译原理课程设计报告_算符优先分析法
编译原理课程设计报告
选题名称:
算符优先分析法
系(院):
计算机工程学院
专业:
计算机科学与技术
班级:
姓名:
学号:
指导教师:
学年学期:
7>2012~2013学年第1学期
2012年12月04日
设计任务书
课题名称算符优先分析法
设计
目的
通过一周的课程设计,对算符优先分析法有深刻的理解,达到巩固理论知识、锻炼实践能力、构建合理知识结构的目的。
实验环境Windows2000以上操作系统,VisualC++6.0编译环境
任务要求
1.判断文法是否为算符优先文法,对相应文法字符串进行算符优先分析;
2.编写代码,实现算符优先文法判断和相应文法字符串的算符优先分析;
3.撰写课程设计报告;
4提交报告。
工作进度计划序号起止日期工作内容1理论辅导,搜集资料2~编写代码,上机调试3撰写课程设计报告4提交报告
指导教师(签章):
年月日
摘要:
编译原理是计算机专业重要的一门专业基础课程,内容庞大,涉及面广,知识点多。
本次课程设计的目的正是基于此,力求为学生提供一个理论联系实际的机会,通过布置一定难度的课题,要求学生独立完成。
我们这次课程设计的主要任务是编程实现对输入合法的算符优先文法的相应的字符串进行算符优先分析,并输出算符优先分析的过程。
算符优先分析法特别有利于表达式的处理,宜于手工实现。
算符优先分析过程是自下而上的归约过程,但这种归约未必是严格的规范归约。
而在整个归约过程中,起决定作用的是相继连个终结符之间的优先关系。
因此,所谓算符优先分析法就是定义算符之间的某种优先关系,并借助这种关系寻找句型的最左素短语进行归约。
通过实践,建立系统设计的整体思想,锻炼编写程序、调试程序的能力,学习文档编写规范,培养独立学习、吸取他人经验、探索前言知识的习惯,树立团队协作精神。
同时,课程设计可以充分弥补课堂教学及普通实验中知识深度与广度有限的缺陷。
关键字:
编译原理;归约;算符优先分析;最左素短语;
1课题综述1
1.1课题来源1
1.2课题意义1
1.3预期目标1
1.4面对的问题1
2系统分析2
2.1基础知识2
2.2解决问题的基本思路5
2.3总体方案5
3系统设计6
3.1算法实现6
3.2流程图7
4代码编写8
5程序调试11
6运行与测试12
总结13
致谢14
参考文献15
1课题综述
1.1课题来源
算符文法:
即它的任一产生式的右部都不含两个相继的非终结符的文法。
如果G是一个不含空字符的算法文法,那么只要它的任一对终结符都只满足,,的关系的一种,则称G是一个算符优先文法。
1.2课题意义
算符优先文法在规约过程中只考虑终结符之间的优先关系确定句柄,而与非终结符无关,只需知道把当前句柄规约为某一非终结符,不必知道该非终结符的名字是什么,这样也就去掉了单非终结符的规约,因为若只有一个非终结符时无法与句型中该非终结符的左部及右部的串比较优先关系。
也就无法确定该非终结符为句柄。
1.3预期目标
编写程序,实现文法的算符优先判断,并对输入的符合算符优先文法的字符串进行算符优先分析。
首先对输入的表达式求FIRSTVT集和LASTVT集,然后根据优先级关系构造算符优先关系表,最后进行算符优先分析的过程。
过实践,建立系统设计的整体思想,锻炼编写程序、调试程序的能力,学习文档编写规范,培养独立学习、吸取他人经验、探索知识的习惯。
1.4面对的问题
如何通过自底向上的方法分析表达式,构造文法的优先矩阵,以及如何运用该优先矩阵完成移入和归约的过程,从而完成整个文法的分析。
1.5需解决的关键技术
本次课程设计中的关键是:
扫描和语法分析函数,它使用一个用于存放文法符号的先进后出栈,并利用有限关系可以确定最左素短语是否已形成来决定分析器的动作。
如果当前栈顶的终结符号和带输入符号之间优先关系是或则表示栈顶符号串未形成最左素短语,此时分析器将移进输入符号。
如果当前栈顶的终结符号和待输入符号之间的优先关系是,则表示已找到最左素短语的尾,在从栈顶开始,按优先关系在栈内向左寻找最左素短语的头,然后分析器将归约最左素短语。
如果出现两个终结符号之间不存在优先关系,则表示存在语法错误。
以及如何编写、调试、修改代码。
还要了解一个题目有许多种解决方法。
锻炼我们的思维能力。
2系统分析
2.1基础知识
算符优先分析法的基本思想
仿照算术表达式的四则运算过程
算符优先分析的基本思想是只规定算符广义为终结符之间的优先关系,也就是只考虑终结符之间的优先关系,不考虑非终结符之间的优先关系。
在归约过程中只要找到可归约串就归约,并不考虑归约到那个非终结符名,算符优先分析的可归约串不一定是规范句型的句柄,所以算符优先归约不是规范归约。
算符优先分析的可归约串是当前符号栈中的符号和剩余的输入符号构成句型的最左素短语。
先关系的定义
设G是一个不含ε产生式的算符文法,a和b是任意两个终结符,A、B、C是非终结符,算符优先关系、、定义如下:
①ab当且仅当G中含有形如A→…ab…或A→…aBb…的产生式
②ab当且仅当G中含有形如A→…aB…的产生式,且Bb…或BCb…
③ab当且仅当G中含有形如A→…Bb…的产生式,且B…a或B…aC
以上三种关系也可由下列语法树来说明:
①ab则存在语法子树如图2.1a
其中δ为ε或为B,这样a,b在同一句柄中同时归约所以优先级相同。
②ab则存在语法子树如图2.1b
其中δ为ε或为C。
a,b不在同一句柄中,b先归约,所以a的优先级低于b。
③ab则存在语法子树如图2.1c。
图2.1由语法树结构决定优先性
先文法的定义
设有一文法G,如果G中没有形如A→…BC…的产生式,其中B和C为非终结符,则称G为算符文法OperaterGrammar也称OG文法。
例如:
表达式文法E→E+E|E*E|E|i
其中任何一个产生式中都不包含两个非终结符相邻的情况,因此该文法是算符文法。
设有一不含ε产生式的算符文法G,如果对任意两个终结符对a,b之间至多只有、和三种关系中的一种成立,则称G是一个算符优先文法。
OperatorPrecedenceGrammar即OPG文法。
由以上内容我们可计算出给定的算符文法中任何两个终结符对a,b之间的优先关系,其算法如下:
首先定义如下两个集合:
FIRSTVTBb|Bb…或BCb…
LASTVTBa|B…a或B…aC
三种优先关系的计算为
a关系:
可直接查看产生式的右部,对如下形式的产生式
A→…ab…,A→…aBb…
有ab成立。
b关系:
求出每个非终结符B的FIRSTVTB,在如下形式的产生式
A→…aB…中,对每一b∈FIRSTVTB,有ab成立。
c关系:
计算每个非终结符B的LASTVTB,在如下形式的产生式
A→…Bb…中,对每一a∈LASTVTB,有ab成立。
最左素短语的定义
设有文法G[S],其句型的素短语是一个短语,它至少包含一个终结符,并除自身外不包含其它素短语,最左边的素短语称最左素短语。
例如,若表达式文法G[E]为:
E→E+T|T
T→T*F|F
F→P↑F|P
P→E|i
图2.2句型T+T*F+i的语法树
若有句型#T+T*F+i#,它的语法树如图2.2。
其短语有:
T+T*F+i相对于非终结符E的短语
T+T*F相对于非终结符E的短语
T相对于非终结符E的短语
T*F相对于非终结符T的短语
i相对于非终结符P,F,T的短语
由以上内容知i和T*F为素短语,T*F为最左素短语。
也为算符优先分析的可归约串。
由算符优先分析算法可知一个算符优先文法的最左素短语满足如下条件:
ai-1aiai+1...ajaj+1
上述句型#T+T*F+i#写成算符分析过程的形式为:
#N1a1N2a2N3a3a4#其中a1+,a2*,a3+,a4i
a1a2因+*
a2a3因*+
由此N2a2N3即T*F为可归约串,也就是前面分析的最左素短语。
2.2解决问题的基本思路
根据课程设计的要求,程序应具有如下功能:
对输入的文法进行分析并判断是否为算符优先文法。
如果是算符优先分析文法则再进一步输入符合该算符优先文法的字符串,并对该字符串进行算符优先分析,同时输出算符优先分析的过程。
2.3总体方案
启动VC++,新建源程序并进行编程,程序的功能模块图如图2-1所示。
图2-1系统功能结构图
函数功能:
Main函数:
调用主函数,运行程序;
FIRSTVT函数:
构造FIRSTVT表;
LASTVT函数:
构造LASTVT表;
OpPrioTable函数:
构造算符优先关系表;
InputAnalyse函数:
分析输入串是否为文法中的句子,并给出规约过程。
3系统设计
3.1算法实现
算符优先分析法的具体过程如下:
1、首先先输入文件的路径,在readfilecharsen[][col]函数中,将需要分析的文法通过输入流文件打开函数open复制到sen[row][col]中。
2、然后利用FIRSTVT构造产生式sen[row][col]的FIRSTVT表。
先找出形如A-…a…(a为第一个终结符)的产生式,把(A,a)压入Operator栈中。
从Operator栈顶抛出项(A,a),填入first表相应位置。
在找出形如B-A…的产生式,把(B,a)压入Operator栈中。
循环直到Operator栈为空,此时FIRSTVT表构造完毕。
3、然后把产生式右部翻转,调用FIRSTVT函数求出LASTVT表。
4、接着调用OpPriotable()构造算符优先关系表opTable。
先把产生式中所有终结符填入opTable表第一行和第一列,然后利用产生式和FIRSTVT表LASTVT表分别找出满足关系、关系、关系的算符填表。
若相应位已有关系,说明两个终结符之间至少有两种优先关系,该文法不是算符优先文法。
5、最后调用InputAnalyse()对输入串进行分析。
初始化分析栈S,依次判断当前输入符a和分析栈中离栈顶最近的终结符S[j]的关系,若S[j]a,则a移近,若S[j]a,则往前找到第一个S[j]a,将S[j-1]到栈顶S[k]规约,若S[j]a,如果S[j]#,则接受,如果S[j]!
#,则移进。
直到接受或者出错,算符优先分析结束。
3.2流程图
图3-1程序流程图
4代码编写
在这次课程设计过程中,我主要负责的是FIRSTVT、LASTVT集的构造部分,代码如下。
//FIRSTVT表和LASTVT表中表项(非终结符)的初始化
voidItemInitcharsen[][col],charfirst[][col],charlast[][col],intsen_len,int&frist_len
inti;
frist_len1;
first[0][0]sen[0][0];
last[0][0]sen[0][0];
fori1;isen_len;i++
ifTerminalJudsen[i][0]false&&ItemJudfirst,frist_len,sen[i][0]false//k是当前first和last表的长度
first[frist_len][0]sen[i][0];
last[frist_len][0]sen[i][0];
frist_len++;
voidFirstVtcharsen[][col],charfirst[][col],intsen_len,intfrist_len//frist_len是first表的行数sen_len是产生式的个数
StackElementDFS,record[SIZE];
stackOperator;//创建存放(A,a)的栈
InitStackOperator;
inti,j,r0;
fori0;isen_len;i++//第一次扫描,将能直接得出的first(A,a)放进栈中
forj3;sen[i][j]!
'\0';j++
ifTerminalJudsen[i][j]true//遇到的第一个终结符压入
intexist0;
DFS.nontermsen[i][0];
DFS.termsen[i][j];
forinti10;ir;i++
ifrecord[i1].nontermsen[i][0]&&record[i1].termsen[i][j]
exist1;
break;
record[r].nontermsen[i][0];
record[r].termsen[i][j];
ifexist0
InsertOperator,DFS;//A-aBA-aCA,a压栈两次?
record[r].nontermsen[i][0];
record[r].termsen[i][j];
r++;
break;
intlocation[col];//辅助数组,用来记录first表中放入终结符的位置
fori0;ifrist_len;i++
location[i]1;
while!
ifEmptyOperator
intexist0;//标志位,记录即将入栈的元素是否已经存在
StackElementIDElement,DElement;
DElementPopOperator;//弹出栈顶元素
fori0;ifrist_len;i++
iffirst[i][0]DElement.nonterm
intnlocation[i];
first[i][n]DElement.term;//将终结符填入相应的first表中
location[i]++;
break;
forj0;jsen_len;j++
ifsen[j][3]DElement.nonterm//找出能推出当前非终结符的产生式的左部
IDElement.nontermsen[j][0];
IDElement.termDElement.term;
//判断将要放进栈里的元素曾经是否出现过,若没有,才压入栈
forintr00;r0r;r0++//r记录record数组中的元素个数
ifrecord[r0].nontermIDElement.nonterm&&record[r0].termIDElement.term
exist1;
break;
ifexist0
InsertOperator,IDElement;
record[r].nontermIDElement.nonterm;
record[r].termIDElement.term;
r++;
//if
//for
//while
voidLastVtcharsen[][col],charlast[][col],intsen_len,intfrist_len//firstvt表与lastvt表行数一样first_len表示last表的行数
inti,j,i1,j1;
charc,record[row][col]'\0';
fori0;isen_len;i++
forj0;sen[i][j]!
'\0';j++
record[i][j]sen[i][j];
jj-1;
fori13,j1j;i1j1;i1++,j1--//做翻转,就可以用求first的方法求last
crecord[i][i1];
record[i][i1]record[i][j1];
record[i][j1]c;
//for
FirstVtrecord,last,sen_len,frist_len;
5程序调试
程序中调用了许多函数,编写代码时会出现调用的错误,使在程序运行时无法正确判断以致程序运行出错。
在创建函数时会出现错误而无法得知,致使在程序运行时出错,需要很细心的去编写代码。
编程的时候一定要细心,对出现的错误要认真调整,反复修改,使函数前后相对应。
6运行与测试
运行界面如下:
图6-1运行结果图1图6-1运行结果图2
总结
编译原理旨在介绍编译程序构造的一般原理和基本方法:
包括语言和文法、词法分析、语法分析、语法制导翻译、中间代码生成、存储管理、代码优化和目标代码生成。
虽然只有少数人从事编译方面的工作,但是这门课在理论、技术、方法上都对学生提供了系统而有效的训练,有利于提高软件人员的素质和能力。
算符优先分析法是一种简单直观、特别方便于表达式分析,易于手式实现的方法。
算符优先法只考虑算符(广义为终结符号)之间的优先关系,它是一种自底向上的归约过程。
但这种归约未必严格按照句柄归约,它是一种不规范归约法。
算符优先分析法的关键是比较两个相继出现的终结符号的优先级而决定应采取的动作。
要完成算符间的优先级比较,就要先定义各种可能出相继出现的运算符的优先级,并将其表示成矩阵形式,在分析过程中通过查询矩阵元素而得算符间的优先关系。
谢
感谢淮阴工学院,计算机工程系陈宏明院长提供这次实践机会,是他的正确决策让我有了这次的实践机会,通过这次的课程设计使我在实践中得到了提高,锻炼了动手编程的能力。
同时也感谢实验室人员提供的给我方便的实验环境。
最后感谢08级几位同学对于我的帮助。
参考文献
1于永彦,于长辉,刘作军.C++程序设计《实践教学指导书》.淮安市淮海路小学印刷厂,2007
14
1
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 编译 原理 课程设计 报告 优先 分析