编译原理课程设计终结版.docx
- 文档编号:4379633
- 上传时间:2022-12-01
- 格式:DOCX
- 页数:26
- 大小:418.52KB
编译原理课程设计终结版.docx
《编译原理课程设计终结版.docx》由会员分享,可在线阅读,更多相关《编译原理课程设计终结版.docx(26页珍藏版)》请在冰豆网上搜索。
编译原理课程设计终结版
基于算符优先分析方法
的表达式语法分析器
年级:
2007
班级:
级计算机科学与技术4班
组长:
刘思佳
组员:
欧垚毛群晖袁小仨徐碧红
邓文杰孙苗苗顿硕伍小军
曾洁孙梁吉顺昌
指导老师:
段明秀
二〇一八年九月二十四日
前言
1.摘要
编译原理是计算机专业的一门重要专业课,旨在介绍编译程序构造的一般原理和基本方法。
内容包括语言和文法、词法分析、语法分析、语法制导翻译、中间代码生成、存储管理、代码优化和目标代码生成。
编译原理是计算机专业设置的一门重要的专业课程。
虽然只有少数人从事编译方面的工作,但是这门课在理论、技术、方法上都对学生提供了系统而有效的训练,有利于提高软件人员的素质和能力。
算符优先分析法是一种简单直观、特别方便于表达式分析,易于手式实现的方法。
算符优先法只考虑算符(广义为终结符号)之间的优先关系,它是一种自底向上的归约过程,但这种归约未必严格按照句柄归约。
它是一种不规范归约法。
算符优先分析法的关键是比较两个相继出现的终结符号的优先级而决定应采取的动作。
要完成算符间的优先级比较,就要先定义各种可能出相继出现的运算符的优先级,并将其表示成矩阵形式,在分析过程中通过查询矩阵元素而得出算符间的优先关系。
2.问题描述
给出该文法
E’→#E#
E→E+Q|Q
Q→Q-T|T
T→T*F|F
F→F/M|M
M→M^P|P
P→(E)|i
用算符优先分析法实现对表达式的计算。
3.项目开发平台
语言:
Java
开发平台:
MyEclipse
第1章课程设计计划
1.1组员与工作分配
组长:
刘思佳
资料组:
毛群晖,邓文杰,曾洁
代码组:
刘思佳,孙梁,孙苗苗,顿硕
测试组:
欧垚,吉顺昌,徐碧红,袁小仨,伍小军
1.2课程计划
表1.2.1课程设计计划清单
序号
内容
需求
计划时间
实际时间
状态
1
问题定义
对课程设计要求分析
6月15日
6月15日
已完成
2
查询资料
对课程设计做必要的资料查询
6月16日-6月17日
6月17日
已完成
3
概要设计
确定课程设计的总体框架与分包
6月18日
6月18日
已完成
4
详细设计
具体分析设计每个类与接口
6月19日-6月20日
6月20日
已完成
5
编码
实现程序
6月21日
6月21日
已完成
6
测试并修改
测试程序BUG并进行修改
6月22日-6月26日
6月26日
已完成
1.3资源需求
表1.3.1开发资源
序号
资源
作用
占用时间
当前可用状态
获得途径
1
MyEclipse平台
设计平台
贯穿整个设计阶段
可用
网上下载
第2章功能需求分析
2.1功能需求清单
表2.1.1需求清单
功能编号
功能名称
备注
1
键盘输入
用户能从键盘输入字符串
2
表达式切分
切分算术表达式,结果存入字符串数组,如:
字符串:
1.5+3*2#将被切分为{1.5,+,3,*,2,#}
3
扫描表达式
检测是否符合给定的文法
4
出错处理
不符合文法的给出错误提示
5
计算表达式
合法的算术表达式将计算出结果
6
输出
将计算结果输出给用户
第3章设计、分析与编码
3.1总体设计
3.1.1模块划分
该语法分析器可分为以下几个主要模块:
1.词法分析并计算模块
其中应有一个操作符栈和一个操作数栈,用于分析输入的文法和句子,并提供方法检验该表达式是否为给出的文法,如果是则运算出结果,否则提示错误
2.算符优先表构建模块
用于构建输入文法的算符优先表,并对其中的算符优先表进行各种操作。
3.输入功能模块
提供从键盘输入功能。
3.1.2程序分包
com.op.core该包下为核心类,完成核心功能
com.op.util该报为工具包,包含一些输入,字符串处理等
程序之间应该保持低耦合,高内聚。
包之间的依赖关系为core->util,核心包依赖于util,util不依赖其他包。
3.2详细设计
3.2.1类图
com.op.core.OperatorPrority类:
该类为核心类,实现所有核心功能。
com.op.core.ProrityTable类:
该类为存放算符优先级表,以及对算符优先级表查询等操作。
com.op.core.StringUtil类:
该类实现必要的字符串操作。
com.op.core.IOUtil类:
该类实现输入输出等常用操作
类之间的依赖关系:
OperatorPriority将依赖于其他三个类,而其他的类互不依赖。
3.3程序流程图
3.4分析与编码实现
3.4.1表达式文法G[E’]构造算符优先关系表
计算算符优先只针对于终结符,终结符之间的优先关系有三种,在计算优先关系之前我们先定义两个集合,对于任意两个终结符(a,b)FIRSTVT(B)={b|B=>b…或B=>Cb…},其中…表示V*中的符号串。
LASTVT(B)={a|B=>…a或B=>…aC}
三种优先关系:
(1)等于关系:
可直接查看产生式的右部,对如下形式的产生式A->…ab…A->…aBb…则有a=b成立。
(2)小于关系:
求出每个非终结符B的FIRSTVT(B),观察如下形式的产生式A->…aB…对每一b∈FIRSTVT(B)有a≮b成立
(3)大于关系:
计算每个非终结符B的LASTVT(B),观察如下形式的产生式A->…Bb…对每一a∈LASTVT(B)有a≯b成立
关系表:
通常用矩阵的形式存放文法中各种可能的优先关系。
大小:
矩阵是n×n的,其中n是文法中终结符的个数。
表达式文法G[E’]:
E’→#E#
E→E+Q|Q
Q→Q-T|T
T→T*F|F
F→F/M|M
M→M^P|P
P→(E)|i
根据上面的规则手工构造上述文法的算符优先表如下:
+
-
*
/
^
(
)
i
#
+
≯
≮
≮
≮
≮
≮
≯
≮
≯
-
≯
≯
≮
≮
≮
≮
≯
≮
≯
*
≯
≯
≯
≮
≮
≮
≯
≮
≯
/
≯
≯
≯
≯
≮
≮
≯
≮
≯
^
≯
≯
≯
≯
≯
≮
≯
≮
≯
(
≮
≮
≮
≮
≮
≮
=
≮
)
≯
≯
≯
≯
≯
≯
≯
i
≯
≯
≯
≯
≯
≯
≯
#
≮
≮
≮
≮
≮
=
代码清单
packagecom.op.core;
publicclassPriorityTable{
privatestaticchartable[][]={
//+*/i()#^
{'>','<','<','<','<','>','>','<'},//+
{'>','>','>','<','<','>','>','<'},//*
{'>','>','>','<','<','>','>','<'},///
{'>','>','>','$','$','>','>','>'},//i
{'<','<','<','<','<','=','$','<'},//(
{'>','>','>','$','$','>','>','>'},//)
{'<','<','<','<','<','$','=','<'},//#
{'>','>','>','<','<','>','>','<'},//^
};//算符优先表
/****************************************************************
*判断一个符号在算符优先表中位置
*
*@paramc
*@return
*/
privatestaticintjudgePriority(charc){
intpriority=0;
switch(c){
case'+':
priority=0;
break;
case'*':
priority=1;
break;
case'/':
priority=2;
break;
case'i':
priority=3;
break;
case'(':
priority=4;
break;
case')':
priority=5;
break;
case'#':
priority=6;
break;
case'^':
priority=7;
break;
}
returnpriority;
}
/**
*判断两个算术符的优先级
*
*@paramm
*为符号栈的栈顶元素
*@paramn
*为当前输入算术符
*@return
*/
publicstaticchargetPriority(charm,charn){
returnPriorityTable.table[judgePriority(m)][judgePriority(n)];
}
}
3.4.2根据算符优先表用栈结构来实现算符优先分析
设置两个栈:
存放运算符的OPTR栈和存放操作数或运算结果的OPND栈。
具体算法描述如下:
(1)首先置操作数OPND栈为空栈,将#入运算符OPTR栈。
(2)依次读入表达式中每个单词,若是操作数则进OPND栈,若是运算符则转(3)。
(3)当前设读入的运算符为θ2,查找算符优先关系表,比较θ2与OPTR栈顶元素θ1:
若θ1<θ2,则θ2进OPTR栈,转
(2);
若θ1=θ2,如θ2为#,则分析成功,否则OPTR栈顶元素θ1出栈,并转
(2);
若θ1>θ2,则出栈OPND栈顶元素存放到b,又出栈其新栈顶元素存放到a,再出栈OPTR栈顶元素至t,进行运算r=atb(t为运算符),并将结果r存入栈OPND后转
(2);
(4)若θ1和θ2之间无优先关系,则报错。
分析归约流程图
在分析过程中,利用分析栈存放已识别的那部分句型,而句型的其余部分由剩余输入串组成,通过比较栈顶符号和下一个输入符号之间的关系,如果是小于或等于则将输入串一次逐个存入符号栈中,直到遇到栈顶符号的优先关系大于下一个待输入符号为止,此时可以判别栈顶符号是否为句柄尾符号。
如果是句柄尾,则沿栈顶向下,在栈内寻找句柄头(利用文法的某条规则),然后把它们弹出栈,并代之以归约后的非终结符。
这样就完成了一次归约过程。
代码清单
packagecom.op.core;
importjava.math.BigDecimal;
importjava.util.Stack;
importcom.op.util.StringUtil;
importcom.op.util.IOUtil;
publicclassOperatorPriority{
privateStack
privateStack
privateStringinput;//待分析的算术表达式
/*
*构造函数
*@paraminput
*/
publicOperatorPriority(Stringinput){
super();
optrStack=newStack
opndStack=newStack
optrStack.push('#');
this.input=input;
}
/***
*操作两个数
*@parama操作数1
*@paramb操作数2
*@paramop操作符
*@return运算结果
*/
publicfloatoperateTwoNum(floata,floatb,charop){
BigDecimalda=newBigDecimal(Float.toString(a));
BigDecimaldb=newBigDecimal(Float.toString(b));
switch(op){
case'*':
returnda.multiply(db).floatValue();
case'+':
returnda.add(db).floatValue();
case'-':
returndb.subtract(da).floatValue();
case'/':
returndb.divide(da,7,BigDecimal.ROUND_HALF_UP).floatValue();//除不尽的情况取7位精确值。
case'^':
returndb.pow((int)a).floatValue();
}
return0;
}
/***
*判断是否为操作符
*@paramch被判断字符
*@return布尔值
*/
publicbooleanisOperator(charch){
if(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='('
||ch==')'||ch=='#'||ch=='^')
returntrue;
else
returnfalse;
}
/***
*扫描字符串,判断是否对应文法,并计算出结果
*@return计算结果
*@throwsException如果不符合文法,或者除数等于0,都将抛出异常
*/
publicStringscanner()throwsException{
intpostion=0;//字符串上指示的指针
charoperator=0;//操作符
floata=0,b=0;//操作数
String[]exp=StringUtil.splitExp(input);
while(true){
//判断是否为运算符
if(exp[postion].length()==1&&isOperator(exp[postion].charAt(0))){
//需要进行运算符的比较
if(!
optrStack.isEmpty()){
if(PriorityTable.getPriority(optrStack.peek().charValue(),
exp[postion].charAt(0))=='<')
optrStack.push(exp[postion].charAt(0));
elseif(PriorityTable.getPriority(optrStack.peek()
.charValue(),exp[postion].charAt(0))=='>'){
a=opndStack.pop();
b=opndStack.pop();
operator=optrStack.pop().charValue();
opndStack.push(operateTwoNum(a,b,operator));
continue;
}elseif(PriorityTable.getPriority(optrStack.peek()
.charValue(),exp[postion].charAt(0))=='='){
optrStack.pop();
if(exp[postion].charAt(0)=='#'){
returnopndStack.pop().toString();
}
}
}else
optrStack.push(exp[postion].charAt(0));
}
//为运算数时
else{
opndStack.push(Float.valueOf((exp[postion])).floatValue());
}
postion++;
if(postion>=exp.length)
break;
}
thrownewException();
}
/***
*程序入口,启动函数
*@paramargs
*/
publicstaticvoidmain(String[]args){
OperatorPriorityop=newOperatorPriority(IOUtil
.getStringFromKeyBoard());//实例化构造函数参数从键盘获得
try{
System.out.println("您输入的表达式:
"+op.input+"="+op.scanner());
}catch(Exceptione){
//TODOAuto-generatedcatchblock
//e.printStackTrace();
System.out.println("您输入的表达式"+op.input+"有误!
");
}
}
}
3.4.3辅助工具类设计
a.通过键盘输入表达式。
程序清单
packagecom.op.util;
importjava.io.BufferedReader;
importjava.io.IOException;
importjava.io.InputStreamReader;
publicclassIOUtil{
/***
*得到从键盘输入的字符串
*@return字符串
*/
publicstaticStringgetStringFromKeyBoard()
{
try
{
BufferedReaderreader=newBufferedReader(newInputStreamReader(System.in));
System.out.print("请输入一个表达式以#号结束:
");
Stringstr=reader.readLine();//获取字符串
//System.out.println("您输入的字符串是:
"+str);
returnstr;
}catch(IOExceptione)
{
e.printStackTrace();
}
returnnull;
}
}
b.字符串处理类
将从键盘输入的字符串表达式进行简单的切分,存入字符串数组。
这个类是为了在扫描表达式时能对其中的操作数与操作符进行方便的操作。
程序清单
packagecom.op.util;
importjava.util.Vector;
publicclassStringUtil{
/***
*切分算术表达式,结果存入字符串数组,如:
字符串:
1.5+3*2#将被切分为{1.5,+,3,*,2,#}
*@paramstr
*@return
*/
publicstaticString[]splitExp(Stringstr){
Vector
intbeginIndex=0;
for(inti=0;i if((str.charAt(i)>32&&str.charAt(i)<48&&str.charAt(i)! =46)||str.charAt(i)==94){ if(beginIndex! =i) v.add(str.substring(beginIndex,i)); v.add(String.valueOf(str.charAt(i))); beginIndex=i+1; } } if(beginIndex! =str.length()) v.add(str.substring(beginIndex,str.length())); Stringresult[]=newString[v.size()]; for(inti=0;i { result[i]=v.get(i); } returnresult; } } 第4章测试用例及程序截图 本次设计经过三次测试形成最终版本 4.1第一版测试 1、如果正确输入表达式应能正确得出结果 当输入10+15*4#后,预计结果为70,实际结果为: 70.0 之所以会出现70.0是因为输出结果的精度不一样。 提示“请按任意键继续…”,当按下任意键时,退出了程序。 程序应该跳到开始处,提醒用户再次输入表达式并以#号结束。 2、如果输入一个错误的表达式应能给出错误信息 从图中所输入的表达式跟文法进行分析可以得出10不是文法的句子,故输出的结果为: 您输入的表达式10+*15+有误! 3、对负号的处理 经过对文法的分析并没有对负数的处理,在这里他会认为是减号,而在减号的左边缺少一个元素,故输出的结果为: 您输入的表达式(-10)*2有误! 4、对于单个的整数 5、测试除法优先操作 测试结果与预计的结果不符合,经过分析得出,之所
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 编译 原理 课程设计 终结
![提示](https://static.bdocx.com/images/bang_tan.gif)