编译原理FOR循环语句的翻译程序设计LL1法输出四元式附源代码.docx
《编译原理FOR循环语句的翻译程序设计LL1法输出四元式附源代码.docx》由会员分享,可在线阅读,更多相关《编译原理FOR循环语句的翻译程序设计LL1法输出四元式附源代码.docx(76页珍藏版)》请在冰豆网上搜索。
编译原理FOR循环语句的翻译程序设计LL1法输出四元式附源代码
学号:
课程设计
题目
FOR循环语句的翻译程序设计
(LL
(1)法、输出四元式)
学院
计算机科学与技术
专业
计算机科学与技术
班级
计算机0901班
姓名
指导教师
2012
年
01
月
03
日
课程设计任务书
学生姓名:
专业班级:
计算机0901班
指导教师:
工作单位:
计算机科学与技术学院
题目:
FOR循环语句的翻译程序设计(LL
(1)法、输出四元式)
初始条件:
理论:
学完编译课程,掌握一种计算机高级语言的使用。
实践:
计算机实验室提供计算机及软件环境。
如果自己有计算机可以在其上进行设计。
要求完成的主要任务:
(包括课程设计工作量及其技术要求,以及说明书撰写等具体要求)
(1)写出符合给定的语法分析方法的文法及属性文法。
(2)完成题目要求的中间代码四元式的描述。
(3)写出给定的语法分析方法的思想,完成语法分析和语义分析程序设计。
(4)编制好分析程序后,设计若干用例,上机测试并通过所设计的分析程序。
(5)设计报告格式按附件要求书写。
课程设计报告书正文的内容应包括:
1系统描述(问题域描述);
2文法及属性文法的描述;
3语法分析方法描述及语法分析表设计;
4按给定的题目给出中间代码形式的描述及中间代码序列的结构设计;
5编译系统的概要设计;
6详细的算法描述(流程图或伪代码);
7软件的测试方法和测试结果;
8研制报告(研制过程,本设计的评价、特点、不足、收获与体会等);
9参考文献(按公开发表的规范书写)。
时间安排:
设计安排一周:
周1、周2:
完成系统分析及设计。
周3、周4:
完成程序调试及测试。
周5:
撰写课程设计报告。
设计验收安排:
设计周的星期五第1节课开始到实验室进行上机验收。
设计报告书收取时间:
设计周的次周星期一上午10点。
指导教师签名:
2011年11月18日
系主任(或责任教师)签名:
2011年11月18日
FOR循环语句的翻译程序设计
——LL
(1)法、输出四元式
1.系统描述
1.1问题描述
用LL
(1)法设计、编制、调试一个FOR(表达式1;表达式2;表达式3)〈赋值语句〉的语法及语义分析程序,输出四元式。
1.2功能描述
(1)能够识别出单词、单词类型、单词位置
(2)能够用LL
(1)方法识别单词序列是否符合FOR循环文法
(3)能够完成对FOR循环中3个表达式的翻译
(4)能够完成对FOR循环中赋值语句(含复杂表达式)的翻译
(5)能够对FOR循环3个表达式中有表达式1或3缺少时翻译
(6)能够用标准化的四元式进行翻译结果输出
(7)能够用四元式清晰、正确地反映FOR循环的执行流程
(8)能够用文本输入FOR语句循环,再用txt文本输出分析结果
2文法及属性文法的描述
2.1文法的语言描述
A->for(条件){赋值语句}
条件->语句1语句2语句3
语句1->i=表达式;//i表示标识符
语句1->;
语句2->i>表达式;
语句2->i<表达式;
语句3->i=表达式;
语句3->
赋值语句->m=表达式//m表示标识符,作为左值出现
赋值语句->
表达式->表达式+表达式
表达式->表达式-表达式
表达式->表达式*表达式
表达式->表达式/表达式
表达式->(表达式)
表达式->i//i表示标识符、常数、字符、或字符串
2.2属性文法描述
2.2.1FOR语句
FOR(CDG)
nC
n+1ifD==truegotoY.start
n+2gotoY.end+3
Y.start...................//赋值语句的开始
.........................
Y.end...................//赋值语句结束
Y.end+1G
Y.end+2goton+1
Y.end+3//跳出循环体后第一条语句
2.2.2赋值语句
Y->m=E;{m.value=E.Value}
E->E1opE2(op:
+,-,*,/,>或<)
{
E.place=newtemp;//生成新的变量
E.value=E1.valueopE2.value
}
N->(E){N.value=E.value}
N->i{N.value=i.value}
3.语法分析方法描述及语法分析表设计
3.1对LL
(1)分析的描述
LL
(1):
第1个L表明自顶向下分析是从左向右扫描输入串,第2个L表明分析过程中将用最左推导,1表明只需向右看一个符号便可决定如何推导即选择哪个产生式(规则)进行推导。
从文法的开始符号出发企图推导出与输入的单词串完全相匹配的句子,若输入串是文法给定的句子,则必能推出,反之必然出错。
LL
(1)优点:
实现方法简单、直观,便于手工构造或自动生成语法分析器。
文法很容易写出。
LL
(1)缺点:
对文法有一定得限制,要求推导过程中紧跟在飞终结符右边可能出现的终结符集不相交。
另外在做语法制导翻译时中间代码的输出方案相对于LR法比较复杂。
LR分析法的句柄即体现了算符的优先级,出现句柄即做相应的归约动作,中间代码很容易写出,实现很简单。
LL
(1)是做自顶向下推导,因此设计LL
(1)的语法制导翻译输出中间代码很需要技巧,涉及到了判断符号的优先级。
3.2语法分析表设计
文法(消除了左递归)及相应的选择符集
NO.
文法
SELECT集
0
A->f(B){Y}
{f}
1
B->CDG
{;,i}
2
Y->
{}}
3
Y->m=E
{m}
4
C->;
{;}
5
C->i=E
{i}
6
D->iF;
{i}
7
F->{<}
8
F->>E
{>}
9
G->
{)}
10
G->i=E
{i}
11
E->LM
{(,i}
12
M->+LM
{+}
13
M->-LM
{-}
14
M->
{),;}
15
L->NP
{(,i}
16
P->*NP
{*}
17
P->/NP
{/}
18
P->
{+,-,),;}
19
N->i
{i}
20
N->(E)
{(}
3.3预测分析表设计
表达式文法的预测分析表
f
i
m
;
<
>
+
-
*
/
(
)
{
}
=
A
0
-1
-1
-1
-1
-1
-1
-1
-1
-1
-1
-1
-1
-1
-1
B
-1
1
-1
1
-1
-1
-1
-1
-1
-1
-1
-1
-1
-1
-1
C
-1
5
-1
4
-1
-1
-1
-1
-1
-1
-1
-1
-1
-1
-1
D
-1
6
-1
-1
-1
-1
-1
-1
-1
-1
-1
-1
-1
-1
-1
E
-1
11
-1
-1
-1
-1
-1
-1
-1
-1
11
-1
-1
-1
-1
F
-1
-1
-1
-1
7
8
-1
-1
-1
-1
-1
-1
-1
-1
-1
G
-1
10
-1
-1
-1
-1
-1
-1
-1
-1
-1
9
-1
-1
-1
L
-1
15
-1
-1
-1
-1
-1
-1
-1
-1
15
-1
-1
-1
-1
M
-1
-1
-1
14
-1
-1
12
13
-1
-1
-1
14
-1
-1
-1
N
-1
19
-1
-1
-1
-1
-1
-1
-1
-1
20
-1
-1
-1
-1
P
-1
-1
-1
18
-1
-1
18
18
16
17
-1
18
-1
-1
-1
Y
-1
-1
3
-1
-1
-1
-1
-1
-1
-1
-1
-1
-1
2
-1
说明:
1.第1列为终结符,第1行为非终结符
2.非终结符与终结符的交点出表示将要选择哪个产生式做预测分析进行推导
3.-1表示出错,其余数字为产生式的序号NO,表示选择相应的产生式
4.间代码形式的描述及中间代码序列的结构设计
4.1四元式描述
四元式是一种比较普遍采用的中间代码形式。
四元式的四个组成部分是:
算符op,第一和第二运算对象ARG1和ARG2及运算结果RESULT,运算对象和运算结果有时指用户自己定义的变量,有时指编译程序引进的临时变量。
例如a=b*c+b*d的四元式表示如下:
(1)(*,b,c,t1)
(2)(*,b,d,t2)
(3)(+,t1,t2,t3)
(4)(=,t3,-,a)
四元式表示很类似于三地址指令,有时把这类中间表示称为“三地址代码”,因为这种表示可以看成一种虚拟三地址机的通用汇编码,即这种虚拟机的每条“指令”包含操作符和三个地址,两个是为运算对象的,一个为结果的。
有时为了更直观,也把四元式写成简单赋值形式。
(1)t1=b*c
(2)t2=b*d
(3)t3=t1+t2
(4)a=t3
把(jump,—,—,L)写成gotoL
把(jrop,B,C,L)写成ifBropCgotoL
我采用的是更直观的形式。
4.2中间代码序列的结构设计
以for(i=0;i中间代码序列的结构应如下:
1.i=0
2.ifi3.goto11
4.t1=n-1
5.t2=t1/5
6.t3=3*2
7.t4=t2-t3
8.m=t4
9.i=i+1
10.goto2
11.
我的中间代码结构是这样设计的:
第1条语句输出表达式1,表达式为空时输出空行;
第2条输出条件判断;
第3条输出gototemp+7;
第4条至第4+temp条输出赋值语句的四元式;
第5+temp条输出条件表达式3;
第6+temp条输出"goto2"
第7+temp条输出空
说明:
其中temp表示最终生成的中间变量个数,例如上例中,生成了t1,t2,t3,t4共4个中间变量,所以temp=4.
由于临时变量的产生个数是未知的,在语法制导翻译中要先对语句进行保存,等临时变量temp产生完后在对相应中间代码语句进行回填,最后输出。
以便达到输出的中间代码跳转出入口及顺序是正确的。
5.编译系统的概要设计
5.1问题分析
在该阶段严格按照设计指导书,分析要完成什么功能。
词法分析提取单词,写出正确的文法,语法分析检查输入单词串是否符合文法,语义分析完成中间代码的输出,使用LL
(1)法语法分析。
5.2LL
(1)分析
根据平时课程对LL
(1)分析方法的学习,把握好分析方法的实质。
即从左向右扫描输入串,自顶向下最左推导。
推导时非终结符面临剩余输入串串头采用相应的推导产生式,产生式右边进分析栈,栈顶为首符。
若首符为非终结符,则继续推导;
若首符为终结符,则匹配,匹配不成功报错,匹配成功栈顶下移,剩余串串头右移。
重复该过程,直至结束。
5.3符合for循环的文法
过程非常重要,文法写不好,就会产生推导时面临相同选择符的推导冲突,并且文法往往决定了你能够分析的语句有哪些格式,哪些能够处理,哪些不能够处理。
对于for循环语句,要考虑到表达1可以为空,表达式3也可以为空,这样根据是否有表达式1,3有4种情况。
对于赋值语句,赋值语句,应该考虑到赋值语句为空的特殊情况,因为在采用for循环延时的时候,赋值语句就是空的。
对于赋值语句,不能是简简单单的m=b;还应该有m=b+c*d(e-f)/n这样的复杂的赋值语句。
5.4语义动作
语义分析,其实关键还是在于赋值语句上。
因为赋值语句是有优先级的,而语法分析时LL
(1)只是自左向右扫描,推导,匹配,并没涉及到优先级。
因此在写出文法后要给出恰当的语义动作。
我在设计时使用了算符栈和操作数栈。
当输入串串头为算符时,用算符栈栈顶算符与输入串串头算符进行比较。
若大于,栈顶算符退栈,操作数栈退出两个操作数,执行运算,产生中间变量,再中间变量进栈;若小于,则串头算符进算符栈;若等于,表明是(和)匹配,将(退栈。
6.详细的算法描述
6.1伪代码概述
(1)扫描输入的字符char_input[],将字符根据构词规则截取出一个个单词word_input[]。
根据不同类型的单词有不同的构词规则进行单词类型分类word_tyep[],并记录其出现的位置word_position[]。
(2)#进分析栈,开始符A进分析栈
(3)取符号栈顶元素a和剩余输入串队头元素b,
若a为非终结符,那么以(a,b)在预测分析表找到对应的数字i,根据i找到产生式。
若i为-1则出错,报出错误。
找到产生式后,a退栈,产生式入栈,按照产生式从右向左对应分析栈从底向顶的对应顺序入栈。
重复(3)
若a为终结符,则根据(a==b),匹配成功,则a出栈,串头后移。
若a不为"#",重复(3)。
a为"#",执行(4)。
匹配失败则报错。
(4)输出“匹配成功!
”
6.2语义动作方案
6.2.1赋值语句动作
while(c_get!
=";"||GetTop(OPTR,OPTR_i)!
=';')
{
if(!
In(c_get,OP))
{PushND(OPND,c_get,OPND_i);l++;c_get=a[l];}
else
switch(Precede(GetTop(OPTR,OPTR_i),c_get))//运算优先级的比较
{
case'<':
PushTR(OPTR,c_get,OPTR_i);
l++;
c_get=a[l];
break;
case'=':
x=PopTR(OPTR,OPTR_i);
l++;
c_get=a[l];
break;
case'>':
optr=PopTR(OPTR,OPTR_i);
opnd2=PopND(OPND,OPND_i);
opnd1=PopND(OPND,OPND_i);
PushND(OPND,Operate(opnd1,optr,opnd2,temp_i),OPND_i);
break;
}
}
(1)如果c_get为是标识符,PushND(OPND,c_get,OPND_i);将C_get入操作数栈OPND
(2)如果c_get是算符,Precede(GetTop(OPTR,OPTR_i),c_get),将OPTR这个运算符栈的栈顶运算符与c_get比较,出现>,<,或=
(3)若<,则PushTR(OPTR,c_get,OPTR_i),将c_get算符入栈OPTR
若=,则c_get为),栈顶算符为(,x=PopTR(OPTR,OPTR_i),将(退栈。
若>,则可以运算了:
optr=PopTR(OPTR,OPTR_i)运算符出栈
opnd2=PopND(OPND,OPND_i)先出操作数栈的是第2操作数
opnd1=PopND(OPND,OPND_i)后出操作数栈的是第1操作数
PushND(OPND,Operate(opnd1,optr,opnd2,temp_i),OPND_i)计算结果作为临时变量压入操作数栈。
temp_i记录临时变量的个数
执行Operated()时,将运算四元式保存到expression[]中,作为将来输出标准的四元式使用。
expression[temp_i]=temp[temp_i]+"="+opnd1+optr+opnd2;temp_i++
6.2.2FOR句动作
以FOR语句中的2个;和1个)为界,在语法分析时截取表达式:
Quaternion[1]中存储语法分析截取的第1个表达式
Quaternion[2]中存储语义分析截取的第2个表达式
Quaternion[3]中存储语义分析截取的第3个表达式
cout<<1<<"."<cout<<2<<"."<<"if"<cout<<3<<"."<<"goto"<<3+4+temp_i<temp_i记录在语法分析制导中赋值表达式产生中间变量的个数,因此goto语句的地址入口要等赋值语句做完产生所有的临时变量后才能知道。
...........赋值语句动作...............
cout<<5+temp_i<<"."<cout<<6+temp_i<<"."<<"goto2"<cout<<7+temp_i<7.软件的测试方法和测试结果
7.1测试方法
根据自己当初的设计思想,设计了测试用例。
包括没有for中第1个表达式的情况,没有第3个表达式的情况,没有赋值语句的情况,赋值语句比较复杂等情况。
用文本输入for循环语句,用txt文本输出分析出的四元式。
7.2测试用例
在文本文件中输入源程序:
for(i=0;i输入测试文件:
词法分析结果:
其中第一列为位置序号;第二列为截取的单词;第三列为类型
类型1:
关键字类型2:
标识符类型3:
常数类型4:
运算符类型5:
界符
语法分析结果:
语义分析结果:
输出四元式,txt文档记录:
8研制报告
8.1研制过程
8.1.1分析过程
本次课程设计在思考阶段花费了两天多的时间,开始时做过赋值语句的词法分析、语法分析和语义分析,不过使用LR方法做的。
感觉LR方法比较简单一些。
但是实验题目要求我要用LL
(1)方法来做,开始时不知如何下手,有一些担心自己做不出来的情绪。
后来就从LL
(1)的思想着手,从代表性的例题看起,按部就班的来。
感觉LL
(1)方法做语法分析比LR法要简单。
但是LL
(1)方法做语法制导翻译比LR法要复杂一些。
我的观点是:
LL
(1)方法单纯的做语法分析很简单,从左向右,自顶向下,没有优先级可言,语法分析匹配了则成功,不匹配则失败,但是对于语义动作要通过优先级来考虑,例如如a-b*c+d,a匹配,-匹配,b匹配,总不能做a-b,而是要a入操作数栈,-入算符栈,b入操作数栈,-优先级小于*,所以不做a-b,而*优先级大于+,可以做b*c,在比较-和+优先级;LR法在做语法分析时,要画识别文法活前缀的DFA,这点比较繁琐,但它把优先级的思想通过句柄来体现,句柄出现则进行归约,在把含*短语归约之前,绝不会把含-短语先归约,这样就很容易通过非常简单语义动作产生后缀式。
虽然用LL
(1)做语义动作困难一些,我想不妨先易后难,先把语法分析作出来,在做语义动作的时候因为是用语法制导,可以在写程序时加入语义动作。
因为以前做LR法分析赋值语句的时候我就是这么做的。
8.1.2写文法的过程
写文法的时候,因为要考虑到for循环的3个表达式,一般来说第2个表达式条件控制是必须的,而第1个和第3个可以为空的。
对于赋值语句,可以有,也可以是空的。
因此在考虑时要有推出为空的情况。
同时要保证所写文法不能含有左递归,相同非终结符所用产生式的select集不能有交集。
我的思想是尽量让右边的产生式以终结符作为开头。
这样会减少交集情况,减少左递归。
但是事实最后证明,这种方法有缺陷,进一步限制了文法。
由于开始没有考虑循环嵌套,所以没有实现for循环的嵌套的语法语义分析。
8.2本设计的评价特点、不足
本设计的优点在于能够将词法分析结果、语法分析结果清晰的展现出来,词法分析输出了单词、类型,位置,语法分析过程的每一步都输出了分析栈和剩余串,可以对照文法验证推导的正确性。
能够输出正确的四元式,找到正确的出口和入口。
能够对for循环中缺少表达式1或表达式3的情况进行相应处理,能够处理赋值语句为空的情况,能够处理复杂的赋值语句。
不足之处是,没有考虑到循环的嵌套,不能对嵌套的for循环进行语义分析,没有进行赋值时的类型分析,如不同类型变量之间的赋值。
8.3收获体会
本次编译课程设计收获到很多东西,最大的收获在于认识到了自己的不足,对编译原理的基本方法有了初步了解。
结合相关书籍以及互联网上的资料,实现了本次程序的研制。
在确定了所要设计的for语句属性文法之后,对程序整体划分了几个部分进行分析。
在这几天的课程设计里,暴露出了个人能力需要很大提高这个缺陷,在txt文档输出中,有时候会出现文件名弄错导致不能文档输出的现象,进过改进和不断地测试,最终完成了该课程设计,达到了基本的课设要求。
在今后的学习中,我会多多向他人学习,多借鉴他人优秀的编程方法和思想,并且多做练习,达到学以致用,有时间的话我会把这个程序做的更加完美。
9.参考文献
[1]殷人昆.数据结构(用面向对象方法与C++语言).清华大学出版社.2003.02
[2]闵联营,何克右.C++程序设计教程(第二版).武汉理工大学出版社.2005.07
[3]张素琴,吕映芝,蒋维杜,戴桂兰.编译原理(第2版).清华大学出版社.2002.06
[4]李文生.编译程序设计原理与技术.北京邮电大学出版社.2006.05
本科生课程设计成绩评定表
班级:
姓名:
学号:
序号
评分项目
满分
实得分
1
学习态度认真、遵守纪律
10
2
设计分析合理性
10
3
设计方案正确性、可行性、创造性
20
4
设计结果正确性
40
5
设计报告的规范性
10
6
设计验收
10
总得分/等级
评语:
注:
最终成绩以五级分制记。
优(90-100分)、良(80-89分)、中(70-79分)、
及格(60-69分)、60分以下为不及格
指导教师签名:
200年 月 日
源程序:
/////////////////////////////////处理空格问题如inta;intb;处理数值问题,整数,小数等;处理读入读出问题,文件
//;处理报错、纠错问题;处理格式类问题;
#include
#include
#include
#include
#include
usingnamespacestd;
intpredictor[12][15]=
{
//0