编译原理-分析中间代码生成程序
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验报告
课程名称编译原理
实验学期至学年第学期学生所在系部
年级专业班级
学生姓名学号
任课教师
实验成绩
计算机学院制
开课实验室:年月日
实验题目分析中间代码生成程序
一、实验目的
分析PL/0编译程序的总体结构、代码生成的方法和过程;具体写出一条语句的中间代码生成过程。
二、设备与环境
PC兼容机、Windows操作系统、Turbo Pascal软件等。
三、实验内容
1.分析PL/0程序的Block子程序,理清PL/0程序结构和语句格式。
画出Block
子程序的流程图,写出至少两条PL/0程序语句的语法格式。
2.分析PL/0程序的Block子程序和Gen子程序,了解代码生成的方法和过程。
使用概要算法来描述语句的代码生成过程。
3.自己编写一个简单的PL/0程序,能够正确通过编译,得到中间代码。
列出
自己编写的源程序和编译后得到的中间代码。
4.从中选择一个语句或表达式,写出代码生成的过程。
要求从自己的源程序中
选择一条语句,结合这条语句写出语义分析和代码生成过程。
在描述这个过
程中,要说清楚每个功能有哪个子程序的哪条语句来完成,说清楚语句和参
数的含义和功能。
四、实验结果及分析
(一)程序标注
levmax = 3; { max depth of block nesting } { 最大允许的块嵌套层数}
{ 语法分析过程block }
{ 参数:lev:这一次语法分析所在的层次}
{ tx:符号表指针}
{ fsys:用于出错恢复的单词集合}
procedure block(lev, tx: integer; fsys: symset);
var
dx: integer; { data allocation index } { 数据段内存分配指针,指向下一个被分配空间在数据段中的偏移位置}
tx0: integer; { initial table index } { 记录本层开始时符号表位置}
cx0: integer; { initial code index } { 记录本层开始时代码段分配位置}
{ 登陆符号表过程enter }
procedure enter(k: object1);
begin { enter object into table } { 参数:k:欲登陆到符号表的符号类型}
tx := tx + 1; { 符号表指针指向一个新的空位}
with table[tx] do { 开始登录}
begin
name := id; { name是符号的名字,对于标识符,这里就是标识符的名字}
kind := k; { 符号类型,可能是常量、变量或过程名}
case k of { 根据不同的类型进行不同的操作}
constant: { 如果是常量名}
begin
if num > amax then { 在常量的数值大于允许的最大值的情况下}
begin
error(31); { 抛出31号错误}
num := 0; { 实际登陆的数字以0代替}
end;
val := num { 如是合法的数值,就登陆到符号表}
end;
variable: { 如果是变量名}
begin
level := lev; { 记下它所属的层次号}
adr := dx; { 记下它在当前层中的偏移量}
dx := dx+1; { 偏移量自增一,为下一次做好准备}
end;
procedur: { 如果要登陆的是过程名}
level := lev { 记录下这个过程所在层次}
End
End
end { enter };
{ 登录符号过程没有考虑到重复的定义的问题。
如果出现重复定义,则以最后一次的定义为准。
}
{ 在符号表中查找指定符号所在位置的函数position }
{ 参数:id:要找的符号}
{ 返回值:要找的符号在符号表中的位置,如果找不到就返回0 }
function position (id: alfa): integer;
var
i: integer;
begin { find identifier in table }
table[0].name := id; { 先把id放入符号表0号位置}
i := tx; { 从符号表中当前位置也即最后一个符号开始找}
while table[i].name <> id do { 如果当前的符号与要找的不一致}
i := i –1; { 找前面一个}
position := i { 返回找到的位置号,如果没找到则一定正好为0 }
end{ position };
(二)过程说明
说明入口参数,返回值和过程的功能
1、入口参数:
过程体入口时的处理
code[table[tx0].adr].a:=cx;(cx为过程入口地址,填写在code 中)
with table[tx0] do
begin
adr:=cx; (过程的入口填写在table表的过程名中)
size:=dx; (过程需要的空间填写在table中)
end;
cxo:=cx; (保留过程在code中的入口地址在输出目标代码时用)
gen(int,0,dx);(生成过程入口指令)
2、返回值:
(* 通过静态链求出数据区基地址的函数base *)
(* 参数说明:l:要求的数据区所在层与当前层的层差*)
(* 返回值:要求的数据区基址*)
function base(l: integer): integer;
var
b1: integer;
begin
b1 := b; (* find base 1 level down *) (* 首先从当前层开始*)
while l > 0 do (* 如果l大于0,循环通过静态链往前找需要的数据区基址*)
begin
b1 := s[b1]; (* 用当前层数据区基址中的内容(正好是静态链SL数据,为上一层的基址)的作为新的当前层,即向上找了一层*)
l := l - 1 (* 向上了一层,l减一*)
end;
base := b1 (* 把找到的要求的数据区基址返回*)
end(* base *);
(三)程序静态结构图
BLOCK 开始
置DX,TX 的初值,并将CODE 的下标
指针CX值保存到TABLE 中
当前TOKEN 是常量保留字
进行常量声明处理
当前TOKEN 是变量保留字
进行变量声明处理
当前TOKEN 是过程保留字
SYM 是语句开始符?
ERROR
向TABLE 回填过程入口
新建数据段
调用语句处理过程
退出数据段
向TABLE 表填写新的过程名
递归调用BLOCK ,参数
LEV+1
获取单词
SYM 为语句后继符?
ERROR
PCODE 码输出
结束
N
Y
N
Y
Y
N
N
Y
N
Y
(四)PL0文法描述
在计算机科学中,文法是编译原理的基础,是描述一门程序设计语言和实现其编译器的方法。
文法的描述多用BNF(巴克斯范式),而另一个重要的概念:正则表达式,也是文法的另一种形式。
PL/0文法的表示: <程序>::= <分程序>.
<分程序>::= [<常量说明部分>][<变量说明部分>][<过程说明部分>]<语句>
<常量说明部分>::= const<常量定义>{,<常量定义>};
<常量定义>::= <标识符>=<无符号整数>
<无符号整数>::= <数字>{<数字>}
<标识符>::= <字母>{<字母>|<数字>}
<变量说明部分>::= var<标识符>{, <标识符>};
<过程说明部分>::= <过程首部><分程序>{;<过程说明部分>}
<过程首部>::= procedure<标识符>;
<语句> ::= <赋值语句>|<条件语句>|<当循环语句>|<过程调用语句> |<复合语句>|<读语句>|<写语句>|<空>
<赋值语句>::= <标识符> := <表达式>
<表达式> ::= [+|-]<项>{<加法运算符><项>}
<项>::= <因子>{<乘法运算符><因子>}
<因子>::= <标识符>|<无符号整数>| ‘ ( ’ <表达式> ‘ ) ’
<加法运算符>::= +|-
<乘法运算符>::= *|/
<条件>::= <表达式><关系运算符><表达式>|odd<表达式>
<关系运算符>::= =|<>|<|<=|>|>=
<条件语句>::= if<条件>then<语句>
<当循环语句>::= while<条件>do<语句>
<过程调用语句>::= call<标识符>
<复合语句>::= begin<语句>{;<语句>}end
<读语句>::= read ‘ ( ’<标识符>{, <标识符>} ‘ ) ’
<写语句>::= write ‘ ( ’<表达式>{, <表达式>} ‘ ) ’
<字母>::= a|b|c|d…..x|y|z
<数字>::= 0|1|2|3…...8|9
(五)代码生成程序说明
对分程序体人口的处理(见程序文本block 的过程体) begin (*block*)
dx:=3;
tx0:=tx; (*保留当前table表指针值,实际为过程名在table 表中的位置*)
table[tx].adr:=cx;(*保留当前code指针值到过程名的adr 域*)
gen(jmp,0,0);
(*生成转向过程体入口的指令,该指令的地址为cx已保留在过程名的adr域,真正的过程体入口地址,等生成过程体入口的指令时,再由table[tx].adr中取出 cx 将过程体入口返填到cx所指目标代码,即:(jmp,0,0)的第3区域,同时填到table[tx].adr 中*)
②过程体入口时的处理
code[table[tx0].adr].a:=cx;(cx为过程入口地址,填写在code 中)
with table[tx0] do
begin
adr:=cx; (过程的入口填写在table表的过程名中)
size:=dx; (过程需要的空间填写在table中)
end;
cxo:=cx; (保留过程在code中的入口地址在输出目标代码时用)
gen(int,0,dx);(生成过程入口指令)
table表格管理
(六)代码生成程序实例
给出pl0源程序,中间代码和过程说明
编写代码:
program abc(input,output);
var
i : integer;
begin
i := 10;
writeln(i);
end.
运行程序如图:
五、实验总结
这次实验加深了我对编译过程的理解,无论是整体还是细节都有了更深入的体
会,强化了基础知识的进一步学习,如活动记录、符号表、中间过程生成等。
这次实验让我更深的认识到只是学习课本是远远不够的,我们还需要从实际的操作中体会所学知识。
这次实验让我更好的理解了词法分析语法分析过程的区别。
同时,这次实验我也存在着很多的不足,比如我不能完全靠自己的能力理解PL0程序的全部内容,自身知识的不足督促我们通过书籍、网络等途径完善对于知识的认知,扩展自身知识面,提升自身能力,让我们能更好的利用计算机以及编译原理这门课程的知识。
教师评价
评定项目 A B C D 评定项目 A B C D 算法正确流程图正确
语句语法格式正确源程序正确
中间代码正确分析过程正确
报告规范回答问题正确
实验结果正确题解正确
其他:
评价教师签名:
年月日。