当前位置: 首页 > >

编译方法实验3—1

发布时间:

编译方法实验3
人民大学信息学院 陈文萍

PL/0 语言程序

PL/0编译程序

类 pcode 代吗

源语言(PL/0)

PL/0

类 pcode

目标语言(类 pcode)
实现语言(C)

C

语义和代码生成
? 语义:静态语义和动态语义 ? 静态语义分析
– 类型检查和作用域分析

? 代码生成:语法制导的翻译方法,在语法 分析的同时根据产生式进行翻译

目标代码类pcode
目标代码类pcode是一种栈式机的汇编语言。 栈式机系统结构:没有累加器和寄存器,只有存储栈 指针所有运算都在栈顶 指令格式:
f l a

f

l

a

功能码 层次差 (标识符引用层减去定义层) 根据不同的指令有所区别

LIT 0 a LOD l a STO l a CAL l a INT 0 a JMP 0 a JPC 0 a OPR 0 0 OPR 0 1 OPR 0 2 OPR 0 3 OPR 0 4 OPR 0 5 OPR 0 6 OPR 0 7 OPR 0 8 OPR 0 9 OPR 0 10 OPR 0 11 OPR 0 12 OPR 0 13 OPR 0 14 OPR 0 15 OPR 0 16

将 常 数 值 取 到 栈 顶 , a为 常 数 值 将 变 量 值 取 到 栈 顶 , a为 偏 移 量 , l为 层 差 将 栈 顶 内 容 送 入 某 变 量 单 元 中 , a为 偏 移 量 , l为 层 差 调 用 过 程 , a为 过 程 地 址 , l为 层 差 在 运 行 栈 中 为 被 调 用 的 过 程 开 辟 a个 单 元 的 数 据 区 无 条 件 跳 转 至 a地 址 条 件 跳 转 , 当 栈 顶 布 尔 值 非 真 则 跳 转 至 a地 址 , 否 则 顺 序执行 过 程 调 用 结 束 后 ,返 回 调 用 点 并 退 栈 栈顶元素取反 次栈顶与栈顶相加,退两个栈元素,结果值进栈 次栈顶减去栈顶,退两个栈元素,结果值进栈 次栈顶乘以栈顶,退两个栈元素,结果值进栈 次栈顶除以栈顶,退两个栈元素,结果值进栈 栈顶元素的奇偶判断,结果值在栈顶 次栈顶与栈顶是否相等,退两个栈元素,结果值进栈 次栈顶与栈顶是否不等,退两个栈元素,结果值进栈 次栈顶是否小于栈顶,退两个栈元素,结果值进栈 次栈顶是否大于等于栈顶,退两个栈元素,结果值进栈 次栈顶是否大于栈顶,退两个栈元素,结果值进栈 次栈顶是否小于等于栈顶,退两个栈元素,结果值进栈 栈顶值输出至屏幕 屏幕输出换行 从命令行读入一个输入置于栈顶

指 令 功 能 表

语义分析
? 说明部分的分析与处理
–对每个过程(含主程序)说明的对象(变量,常量和 过程)造符号表 – 登录标识符的属性 – 标识符的属性:种类,所在层次,值和分配的相对位置

语义分析示例
? 例如: var a, b; varstat
SVAR varlist SEMICOLON vardefine
在符号表 中登入变量b IDENT(b)

varlist COMMA vardefine
在符号表中登入变量a
IDENT(a)

符号表
例程序说明部分为:CONST A=35,B=49; VAR C,D,E; PROCEDURE P; VAR G ;…
dx: 计算每个变量在运行栈中相对本过程基地址的偏移量 ,放在表中的adr 域,生成目标代码时再放在code中的a域

NAME: A NAME: B NAME: C NAME: D NAME: E NAME: P NAME: G ……

KIND: CONSTANT KIND: CONSTANT KIND: VARIABLE KIND: VARIABLE KIND: VARIABLE KIND: PROCEDUR KIND: VARIABLE ……

VAL: 35 VAL: 49 LEVEL: LEV LEVEL: LEV LEVEL: LEV LEVEL: LEV L E V E L :L E V + 1 …… ADR: DX ADR: DX+1 ADR: DX+2 ADR: ADR: DX …… SIZE: 4

代码生成
? 可由过程GEN完成 GEN有3个参数,分别代表目标代码的功能码, 层差和位移量。例如
gen(opr,0,16); gen(sto,lev-level,adr)

lev:当前处理的过程层次 level:被引用变量或过程所在层次

语义分析示例
E T F
lod 0,3
opr 0,2
var a, b, c; begin a+b*c;

+ F

T
opr 0,4

end.

*

F
lod 0,5

lod 0,4

lod lod lod opr opr

0,3 0,4 0,5 0,4 0,2

a

b

c

const a=10; var b,c; procedure p; begin c:=b+a; end; begin read(b); while b#0 do begin call p; write(2*c); read(b); end end.

( 0) ( 1) ( 2) ( 3) ( 4) ( 5) ( 6) ( 7) ( 8) ( 9) (10) (11) (12) (13) (14) (15) (16) (17) (18) (19) (20) (21) (22) (23) (24)

jmp jmp int lod lit opr sto opr int opr sto lod lit opr jpc cal lit lod opr opr opr opr sto jmp opr

0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

8 2 3 3 10 2 4 0 5 16 3 3 0 9 24 2 2 4 4 14 15 16 3 11 0

转向主程序入口 转向过程p入口 过程p入口,为过程p开辟空间 取变量b的值到栈顶 取常数10到栈顶 次栈顶与栈顶相加 栈顶值送变量c中 退栈并返回调用点(16) 主程序入口开辟5个数据栈空间 从命令行读入值置于栈顶 将栈顶值存入变量b中 将变量b的值取至栈顶 将常数值0进栈 次栈顶与栈顶是否不等 等时转(24)(条件不满足转) 调用过程p 常数值2进栈 将变量c的值取至栈顶 次栈顶与栈顶相乘(2*c) 栈顶值输出至屏幕 换行 从命令行读取值到栈顶 栈顶值送变量b中 无条件转到循环入口(11) 结束退栈

类pcode解释器的结构
? 目标代码存放在数组CODE中。 ? 解释程序定义
–一维整型数组S作为运行数据区 –指令寄存器I:存放当前正在解释的目标指令 –栈顶寄存器t:每个过程执行时,给它分配的数据区最 新分配的单元地址 –基址寄存器b:每个过程被调用时,在数据区给它分配 的数据段起始地址 –指令地址寄存器p:指向下一条要执行的目标程序的地 址

类pcode解释器的结构
? 目标代码解释执行时数据栈的布局(运行栈的存 储分配) ? 在每个过程调用时在栈顶分配3个联系单元:
–SL: 静态链,指向定义该过程的直接外过程(或主程 序)运行时数据段的基地址。 –DL: 动态链,指向调用该过程前正在运行过程的数据 段基地址。 –RA: 返回地址,记录调用该过程时目标程序的断点, 即调用过程指令的下一条指令的地址。

目标代码的解释执行
? 几条特殊指令在code中的位置和功能
– INT 0 A 在过程目标程序的入口处,开辟A个单元的数据段。A为局部变量 的个数+3。(多3个单元存储动态链,静态链,返回地址) – OPR 0 0 在过程目标程序的出口处,释放数据段(退栈),恢复调用该过 程前正在运行的过程的数据段基址寄存器B和栈顶寄存器T的值, 并将返回地址送到指令地址寄存器P中,以使调用前的程序从断点 开始继续执行。 – CAL L A 调用过程,还完成填写静态链、动态链、返回地址,给出被调用 过程的基地址值,送入基址寄存器B中,目标程序的入口地址A的 值送指令地址寄存器P中,使指令从A开始执行。

interpret

三个寄存器赋初值 t:=0; b:=1; p:=0;

解 释 执 行 的 流 程 图

主程序的SL,DL,RA赋初值 s[1]:=0; s[2]=0; s[3]=0;

i:=code[p]; p:=p+1;

执行指令i

P=0? Y 返回

N

主程序 的RA s[3]=0




友情链接: