.
PL/0 语言编译器分析实验报告
一、实验目的
通过阅读与解析一个实际编译器(PL/0语言编译器)的源代码, 加深对编译阶段(包括词法分析、语法分析、语义分析、中间代 码生成等)和编译系统软件结构的理解,并达到提高学生学习兴趣的目的。
二、实验要求
(1)要求掌握基本的程序设计技巧(C语言)和阅读较大规模程序 源代码的能力;
(2)理解并掌握编译过程的逻辑阶段及各逻辑阶段的功能;
(3)要求能把握整个系统(PL/0语言编译器)的体系结构,各功能 模块的功能,各模块之间的接口;
(4)要求能总结出实现编译过程各逻辑阶段功能采用的具体算法与技术。
三、实验步骤
(1) 根据PL/0语言的语法图,理解PL/0语言各级语法单位的结构,掌握PL/0语言合法程序的结构;
(2)从总体上分析整个系统的体系结构、各功能模块的功能、各模块之间的调用关系、各模块之间的接口;
(3)详细分析各子程序和函数的代码结构、程序流程、采用的主要算法及实现的功能;
(4)撰写分析报告,主要内容包括系统结构框图、模块接口、主要算法、各模块程序流程图等。
四、报告内容
pl/0语言是pascal语言的一个子集,我们这里分析的pl/0的编译程序包括了
对pl/0语言源程序进行分析处理、编译生成类pcode代码,并在虚拟机上解释运行生成的类pcode代码的功能。
pl/0语言编译程序采用以语法分析为核心、一遍扫描的编译方法。词法分析和代码生成作为的子程序供语法分析程序调用。语法分析的同时,提供了出错报告和出错恢复的功能。在源程序没有错误编译通过的情况下,调用类pcode
word 专业资料
.
解释程序解释执行生成的类pcode代码。
PL/0语言文法的EBNF表示 EBNF表示的符号说明。
〈 〉 用左右尖括号括起来的中文字表示语法构造成分,或称语法单位,为非终结符。 ∷= | { } 该符号的左部由右部定义,可读作“定义为”。 表示“或”,为左部可由多个右部定义。 花括号表示其内的语法成分可以重复。在不加上下界时可重复0到任意次数,有上下界时为可重复次数的。 PL/0编译程序过程与函数定义层次结构图
word 专业资料
.
PL/0的解释执行结构
PL/0编译程序结构
输入数据
输出数据
PL/0语言目标程序 PL/0语言解释执行程序 word 专业资料
.
PL/0源程序 词法分析程序 序表格管理程语法语义分析程序出错处理程代码生成程序 目标程序
编译程序总体流程图
启动置初值调用GETSYM取单词调用BLOCK过程当前单词是否为源程序结束符'.'?Y源程序中是否有错误?N调用解释过程INTERPRET解释执行目标程序YN出错打印错误结束 PL/0编译程序的语法分析
PL/0编译程序语法、语义分析是整个编译程序设计与实现的核心部分,要求学员努力学习掌握实现技术和方法。现分别说明语法分析实现的主要思想方法和语义分析的实现。
word 专业资料
.
语法分析的任务是识别由词法分析给出的单词符号序列在结构上是否符合给定的文法规则。PL/0语言的文法规则已在2.1节中给出。本节将以语法图描述的语法形式为依据,给出语法分析过程的直观思想。
PL/0编译程序的语法分析采用了自顶向下的递归子程序法。
可用下面简单的PL/0程序为例构造其语法分析树
语法调用关系图
word 专业资料
.
PL/0编译程序语法分析的设计与实现
〈表达式〉的递归子程序实现
procedure expr; begin
if sym in [ plus, minus ] then
begin getsym; term;
end
else term;
while sym in [plus, minus] do
begin
getsym; term; end
end;
〈因子〉∷=〈标识符〉|〈无符号整数〉|‘(’〈表达式〉‘)’ 〈因子〉的递归子程序实现
procedure factor; begin
if sym <> ident then begin
if sym <> number then begin
if sym = ‘(‘ then begin getsym; expr;
if sym = ‘)’ then getsym else error end else error end else getsym end else getsym end;
说明部分的分析与处理
word 专业资料
.
对每个过程(含主程序)说明的对象(变量,常量和过程)造符号表, 登录标识符的属性。标识符的属性:种类,所在层次,值和分配的相对位置。登录信息由ENTER过程完成。
常量定义语句的处理语法:<常量说明部分>: := const <常量定义>{, <常量定义>}; <常量定义>: := <标识符>=<无符号整数> <无符号整数>: := <数字>{ <数字>}
if sym = constsym then begin
getsym; (* 获取下一个token,正常应为用作常量名的标识符 *) repeat (* 反复进行常量声明 *)
constdeclaration; (* 声明以当前token为标识符的常量 *) while sym = comma do (* 如果遇到了逗号则反复声明下一常量*) begin
getsym; (* 获取下一个token,这里正好应该是标识符 *) constdeclaration (* 声明以当前token为标识符的常量 *) end;
if sym = semicolon then (* 如果常量声明结束,应遇到分号 *) getsym (* 获取下一个token,为下一轮循环做好准备 *) else
error(5) (*提示5号错误 *)
until sym <> ident (* 如果遇到非标识符,则常量声明结束 *) end;
常量说明处理
procedure constdeclaration; begin
if sym = ident then begin getsym;
if sym in [eql, becomes] then (* 如果是等号或赋值号 *)
if sym = becomes then (* 如果是赋值号(常量生明中应该是等号) *) error(1); (* 提示1号错误 *)
getsym; (* 获取下一个token,等号或赋值号后应接上数字 *) if sym = number then (* 如果的确是数字 *) begin
enter(constant); (* 把这个常量登陆到符号表 *) getsym (* 获取下一个token,为后面作准备 *) end
word 专业资料
.
else error(2) (* 如果等号后接的不是数字,提示2号错误 *) else error(3)(* 如常量标识符后不是等号或赋值号,提示3号错误 *) end
else error(4) end(* constdeclaration *);
变量定义语句的处理语法:<变量说明部分>: := var <标识符>{, <标识符>};
if sym=varsym then begin getsym; repeat
vardeclaration;(*变量说明处理*) while sym=comma do begin getsym; vardeclaration end;
if sym=semicolon then getsym else error(5) until sym<>ident; end;
变量说明处理procedure ardeclaration;
begin
if sym=ident then begin
enter(variable); getsym end else error(4) end(*vardeclaration*);
过程定义语句的处理程序:
while sym = procsym do (* 循环声明各子过程 *) begin
getsym; (* 获取下一个token,此处正常应为作为过程名的标识符 *) if sym = ident then (* 如果token确为标识符 *) begin
word 专业资料
.
enter(procedur); (* 把这个过程登录到名字表中 *) getsym (* 获取下一个token,正常情况应为分号 *) end else
error(4); (* 否则提示4号错误 *)
if sym = semicolon then (* 如果当前token为分号 *)
getsym (* 获取下一个token,准备进行语法分析的递归调用 *) else
word 专业资料
error(5); (* 否则提示5号错误 *)