第12章pl0代码生成
合集下载
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
在运行栈中为被调用的过程开辟a个单元的数据区
无条件跳转至a地址
条件跳转,当栈顶布尔值非真则跳转至a地址,否则顺序执行 过程调用结束后,返回调用点并退栈 栈顶元素取反 次栈顶与栈顶相加,退两个栈元素,结果值进栈 次栈顶减去栈顶,退两个栈元素,结果值进栈 次栈顶乘以栈顶,退两个栈元素,结果值进栈 次栈顶除以栈顶,退两个栈元素,结果值进栈 栈顶元素的奇偶判断,结果值在栈顶 次栈顶与栈顶是否相等,退两个栈元素,结果值进栈 次栈顶与栈顶是否不等,退两个栈元素,结果值进栈 次栈顶是否小于栈顶,退两个栈元素,结果值进栈 次栈顶是否大于等于栈顶,退两个栈元素,结果值进栈 次栈顶是否大于栈顶,退两个栈元素,结果值进栈 次栈顶是否小于等于栈顶,退两个栈元素,结果值进栈 栈顶值输出至屏幕 屏幕输出换行 从命令行读入一个输入置于栈顶
10
While B Do S
switch (SYM) { ……
CASE WHILESYM:
CX1
L1: B False CX2 S 转L1 L2 :
CX1=CX; GetSym(); //保留L1的地址 CONDITION(SymSetAdd(DOSYM,FSYS),LEV,TX); //生成B的代码 CX2=CX; GEN(JPC,0,0);//条件跳转, L2待定, if (SYM==DOSYM) GetSym(); else Error(18); STATEMENT(FSYS,LEV,TX);//生成S的代码 GEN(JMP,0,CX1); //无条件跳转, 转到L1 CODE[CX2].A=CX; //回填L2
PL/0编译程序的目标代码生成是由GEN过程完成的 ,当 语法分析正确,则调用目标代码生成过程以生成与PL/0 语句等价功能的目标代码,直到编译正常结束。 注意:过程说明部分,变量和常量的说明都不产生目 标代码。 对分程序体入口的处理(见程序文本P424页block 的过 程体) begin (*block*) dx:=3; tx0:=tx; (*保留当前table表指针值,实际为过程名在table表 中的位置*) table[tx].adr:=cx;(*保留当前code指针值到过程名 的adr域*) (jmp,0,0)指令,作为过程体入口指令,该指 gen(jmp,0,0); 令的第3区域的'0'需分析到过程体入口时才 7 返填。
table表格管理
code[table[tx0].adr].a:=cx;
table[tx0].adr=cx
tx0 tx
9
过程体入口时的处理 table表格管理
code[table[tx0].adr].a:=cx;(cx为过程入口地址) with table[tx0] do begin adr:=cx; (table[tx0].adr=cx) size:=dx; (table[tx0].size=dx) end; 请特别注意dx、 tx、 cx的作用和如何处理信息之 间的连接关系。
14
P426 do{ i=code[p]; p++; switch (i.f ) { …… case OPR: switch (i.a) { /*OPERATOR*/ { case 0: /*RETURN*/ t=b-1; p=S[t+3]; b=S[t+2]; break; case 1: S[t]=-S[t]; break; case 2: t--; S[t]=S[t]+S[t+1]; break; case 3: case 4: t--; S[t]=S[t]-S[t+1]; break; t--; S[t]=S[t]*S[t+1]; break;
层次差标识符引用层减去定义层根据不同的指令有所区别目标指令见下页见p23页将常数值取到栈顶a为常数值lod将变量值取到栈顶a为相对运行栈基址的偏移量l为层差sto将栈顶内容送入某变量单元中a为相对运行栈基址偏移量l为层差cal调用过程a为过程入口地址l为层差int在运行栈中为被调用的过程开辟a个单元的数据区jmp无条件跳转至a地址jpc条件跳转当栈顶布尔值非真则跳转至a地址否则顺序执行opr过程调用结束后返回调用点并退栈opr栈顶元素取反opr次栈顶与栈顶相加退两个栈元素结果值进栈opr次栈顶减去栈顶退两个栈元素结果值进栈opr次栈顶乘以栈顶退两个栈元素结果值进栈opr次栈顶除以栈顶退两个栈元素结果值进栈opr栈顶元素的奇偶判断结果值在栈顶opr次栈顶与栈顶是否相等退两个栈元素结果值进栈opr次栈顶与栈顶是否不等退两个栈元素结果值进栈opr10次栈顶是否小于栈顶退两个栈元素结果值进栈opr11次栈顶是否大于等于栈顶退两个栈元素结果值进栈opr12次栈顶是否大于栈顶退两个栈元素结果值进栈opr13次栈顶是否小于等于栈顶退两个栈元素结果值进栈opr14栈顶值输出至屏幕opr15屏幕输出换行opr16从命令行读入一个输入置于栈顶代码生成代码生成是由过程gen完成
case 5:
case 8: ……
t--; S[t]=S[t] % S[t+1]; break;
break; t--; S[t]=S[t]==S[t+1]; break;
case 6: S[t]=(S[t]%2!=0);
15
2
OPR 0 12 OPR 0 13 OPR 0 14 OPR 0 15 OPR 0 16
代码生成 代码生成是由过程GEN完成。P417 GEN有3个参数,分别代表目标代码的功能码, 层差和位移量。例如 gen(opr,0,16);从命令行读取值到栈顶 gen(sto,lev-level,adr) 将栈顶内容送到变量单元中, lev:当前处理的过程层次 level:被引用变量或过程所在层次
If B Then
0(false)
S1
。
Else L1:S2 L2
13
当源程序经过语法分析,如果未发现错误时,由编 译程序调用解释程序,对目标代码开始进行解释执行。 解释程序还定义了4个寄存器。 (1) I:指令寄存器。存放着当前正在解释的一条 目标指令。 (2) P:程序地址寄存器。指向下一条要执行的目 标程序的地址(目标程序CODE数组的 下标)。 (3) T:栈顶寄存器。 (4) B:基址寄存器。指向每个过程被调用时,在 数据区S中给它分配的数据段起始地址, 也称基地址。
录过程在code的入口到table中的adr域如下表所示:
tx0:=tx; table[tx].adr:=cx;
tx0 tx
(*生成转向过程体入口的指令,该指令的地址为cx已保留在过程名的adr域, 真正的过程体入口地址,等生成过程体入口的指令时,将过程体入口回填 (jmp,0,0)的第3区域,同时填到table[tx0].adr 中*) 8
break;
11
条件语句的一般形式: IF 条件B THEN 语句S1
[ ELSE
语句S2 ]
CX1
If B Then 0(false) S1
CX2
。
Else
L1:S2 L2
12
Switch(SYM) {…… case IFSYM: CX1 GetSym(); CONDITION(SymSetUnion(SymSetNew(THENSYM,DOSYM),F SYS),LEV,TX); {生成B的代码} if (SYM==THENSYM) GetSym(); else Error(16); CX2 CX1=CX; GEN(JPC,0,0);{条件跳转} STATEMENT(SymSetUnion(SymSetNew(ELSESYM),FSYS),LE V,TX); {生成S1的代码} If (SYM!=ELSE ) CODE[CX1].A=CX Else {CX2=CX; Gen(JMP,0,0) CODE[CX1].A=CX ; {转向S2} STATEMENT(FSYS,LEV,TX); {生成S2的代码} CODE[CX2].A=CX ;}break; ……}
转向主程序入口 转向过程p入口 过程p入口,为过程p开辟空间 取变量b的值到栈顶 取常数10到栈顶 次栈顶与栈顶相加 栈顶值送变量c中 退栈并返回调用点(16) 主程序入口开辟5个栈空间 从命令行读入值置于栈顶 将栈顶值存入变量b中 将变量b的值取至栈顶 将常数值0进栈 次栈顶与栈顶是否不等 等时转(24)(条件不满足转) 调用过程p 常数值2进栈 将变量c的值取至栈顶 次栈顶与栈顶相乘(2*c) 栈顶值输出至屏幕 换行 从命令行读取值到栈顶 栈顶值送变量b中 无条件转到循环入口(11) 6 结束退栈
CX:为目标代码code数组的下标指针
3
Code: array[0..cxmax] of instruction; p414 fct=(lit, opr, lod, sto, cal, int, jmp, jpc) P413 Instruction= packec record f: fct; P413
5Hale Waihona Puke 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
PL/0编译程序的目标代码结构和代码生成
见P23页
目标代码类pcode是一种假想栈式计算机的汇编语言。 指令格式:
f
f 功能码
l
a
l
a
层次差 (标识符引用层减去定义层)
根据不同的指令有所区别 目标指令见下页
1
指 令 功 能 表
LIT LOD STO CAL INT JMP JPC OPR OPR OPR OPR OPR OPR OPR OPR OPR OPR OPR OPR
l: 0..levmax
a: 0..amax;
end;
4
CODE为一维数组,数组元素为记录型数据。每 一个记录就是一条目标指令。 CX为指令的指针,由0开始顺序增加。
在block入口处生成一条(jmp,0,0)指令,作为过程 体入口指令,该指令的第3区域的'0'需分析到过 程体入口时才返填。
实际上目标代码的顺序是内层过程的排在前边, 主程序的目标代码在最后。 下面我们给出一个PL/0源程序和对应的目标程序 的清单。
0 l l l 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
a a a a a a a 0 1 2 3 4 5 6 7 8 9 10 11
将常数值取到栈顶,a为常数值
将变量值取到栈顶,a为相对运行栈基址的偏移量,l为层差 将栈顶内容送入某变量单元中,a为相对运行栈基址偏移量,l为层
调用过程,a为过程入口地址,l为层差
无条件跳转至a地址
条件跳转,当栈顶布尔值非真则跳转至a地址,否则顺序执行 过程调用结束后,返回调用点并退栈 栈顶元素取反 次栈顶与栈顶相加,退两个栈元素,结果值进栈 次栈顶减去栈顶,退两个栈元素,结果值进栈 次栈顶乘以栈顶,退两个栈元素,结果值进栈 次栈顶除以栈顶,退两个栈元素,结果值进栈 栈顶元素的奇偶判断,结果值在栈顶 次栈顶与栈顶是否相等,退两个栈元素,结果值进栈 次栈顶与栈顶是否不等,退两个栈元素,结果值进栈 次栈顶是否小于栈顶,退两个栈元素,结果值进栈 次栈顶是否大于等于栈顶,退两个栈元素,结果值进栈 次栈顶是否大于栈顶,退两个栈元素,结果值进栈 次栈顶是否小于等于栈顶,退两个栈元素,结果值进栈 栈顶值输出至屏幕 屏幕输出换行 从命令行读入一个输入置于栈顶
10
While B Do S
switch (SYM) { ……
CASE WHILESYM:
CX1
L1: B False CX2 S 转L1 L2 :
CX1=CX; GetSym(); //保留L1的地址 CONDITION(SymSetAdd(DOSYM,FSYS),LEV,TX); //生成B的代码 CX2=CX; GEN(JPC,0,0);//条件跳转, L2待定, if (SYM==DOSYM) GetSym(); else Error(18); STATEMENT(FSYS,LEV,TX);//生成S的代码 GEN(JMP,0,CX1); //无条件跳转, 转到L1 CODE[CX2].A=CX; //回填L2
PL/0编译程序的目标代码生成是由GEN过程完成的 ,当 语法分析正确,则调用目标代码生成过程以生成与PL/0 语句等价功能的目标代码,直到编译正常结束。 注意:过程说明部分,变量和常量的说明都不产生目 标代码。 对分程序体入口的处理(见程序文本P424页block 的过 程体) begin (*block*) dx:=3; tx0:=tx; (*保留当前table表指针值,实际为过程名在table表 中的位置*) table[tx].adr:=cx;(*保留当前code指针值到过程名 的adr域*) (jmp,0,0)指令,作为过程体入口指令,该指 gen(jmp,0,0); 令的第3区域的'0'需分析到过程体入口时才 7 返填。
table表格管理
code[table[tx0].adr].a:=cx;
table[tx0].adr=cx
tx0 tx
9
过程体入口时的处理 table表格管理
code[table[tx0].adr].a:=cx;(cx为过程入口地址) with table[tx0] do begin adr:=cx; (table[tx0].adr=cx) size:=dx; (table[tx0].size=dx) end; 请特别注意dx、 tx、 cx的作用和如何处理信息之 间的连接关系。
14
P426 do{ i=code[p]; p++; switch (i.f ) { …… case OPR: switch (i.a) { /*OPERATOR*/ { case 0: /*RETURN*/ t=b-1; p=S[t+3]; b=S[t+2]; break; case 1: S[t]=-S[t]; break; case 2: t--; S[t]=S[t]+S[t+1]; break; case 3: case 4: t--; S[t]=S[t]-S[t+1]; break; t--; S[t]=S[t]*S[t+1]; break;
层次差标识符引用层减去定义层根据不同的指令有所区别目标指令见下页见p23页将常数值取到栈顶a为常数值lod将变量值取到栈顶a为相对运行栈基址的偏移量l为层差sto将栈顶内容送入某变量单元中a为相对运行栈基址偏移量l为层差cal调用过程a为过程入口地址l为层差int在运行栈中为被调用的过程开辟a个单元的数据区jmp无条件跳转至a地址jpc条件跳转当栈顶布尔值非真则跳转至a地址否则顺序执行opr过程调用结束后返回调用点并退栈opr栈顶元素取反opr次栈顶与栈顶相加退两个栈元素结果值进栈opr次栈顶减去栈顶退两个栈元素结果值进栈opr次栈顶乘以栈顶退两个栈元素结果值进栈opr次栈顶除以栈顶退两个栈元素结果值进栈opr栈顶元素的奇偶判断结果值在栈顶opr次栈顶与栈顶是否相等退两个栈元素结果值进栈opr次栈顶与栈顶是否不等退两个栈元素结果值进栈opr10次栈顶是否小于栈顶退两个栈元素结果值进栈opr11次栈顶是否大于等于栈顶退两个栈元素结果值进栈opr12次栈顶是否大于栈顶退两个栈元素结果值进栈opr13次栈顶是否小于等于栈顶退两个栈元素结果值进栈opr14栈顶值输出至屏幕opr15屏幕输出换行opr16从命令行读入一个输入置于栈顶代码生成代码生成是由过程gen完成
case 5:
case 8: ……
t--; S[t]=S[t] % S[t+1]; break;
break; t--; S[t]=S[t]==S[t+1]; break;
case 6: S[t]=(S[t]%2!=0);
15
2
OPR 0 12 OPR 0 13 OPR 0 14 OPR 0 15 OPR 0 16
代码生成 代码生成是由过程GEN完成。P417 GEN有3个参数,分别代表目标代码的功能码, 层差和位移量。例如 gen(opr,0,16);从命令行读取值到栈顶 gen(sto,lev-level,adr) 将栈顶内容送到变量单元中, lev:当前处理的过程层次 level:被引用变量或过程所在层次
If B Then
0(false)
S1
。
Else L1:S2 L2
13
当源程序经过语法分析,如果未发现错误时,由编 译程序调用解释程序,对目标代码开始进行解释执行。 解释程序还定义了4个寄存器。 (1) I:指令寄存器。存放着当前正在解释的一条 目标指令。 (2) P:程序地址寄存器。指向下一条要执行的目 标程序的地址(目标程序CODE数组的 下标)。 (3) T:栈顶寄存器。 (4) B:基址寄存器。指向每个过程被调用时,在 数据区S中给它分配的数据段起始地址, 也称基地址。
录过程在code的入口到table中的adr域如下表所示:
tx0:=tx; table[tx].adr:=cx;
tx0 tx
(*生成转向过程体入口的指令,该指令的地址为cx已保留在过程名的adr域, 真正的过程体入口地址,等生成过程体入口的指令时,将过程体入口回填 (jmp,0,0)的第3区域,同时填到table[tx0].adr 中*) 8
break;
11
条件语句的一般形式: IF 条件B THEN 语句S1
[ ELSE
语句S2 ]
CX1
If B Then 0(false) S1
CX2
。
Else
L1:S2 L2
12
Switch(SYM) {…… case IFSYM: CX1 GetSym(); CONDITION(SymSetUnion(SymSetNew(THENSYM,DOSYM),F SYS),LEV,TX); {生成B的代码} if (SYM==THENSYM) GetSym(); else Error(16); CX2 CX1=CX; GEN(JPC,0,0);{条件跳转} STATEMENT(SymSetUnion(SymSetNew(ELSESYM),FSYS),LE V,TX); {生成S1的代码} If (SYM!=ELSE ) CODE[CX1].A=CX Else {CX2=CX; Gen(JMP,0,0) CODE[CX1].A=CX ; {转向S2} STATEMENT(FSYS,LEV,TX); {生成S2的代码} CODE[CX2].A=CX ;}break; ……}
转向主程序入口 转向过程p入口 过程p入口,为过程p开辟空间 取变量b的值到栈顶 取常数10到栈顶 次栈顶与栈顶相加 栈顶值送变量c中 退栈并返回调用点(16) 主程序入口开辟5个栈空间 从命令行读入值置于栈顶 将栈顶值存入变量b中 将变量b的值取至栈顶 将常数值0进栈 次栈顶与栈顶是否不等 等时转(24)(条件不满足转) 调用过程p 常数值2进栈 将变量c的值取至栈顶 次栈顶与栈顶相乘(2*c) 栈顶值输出至屏幕 换行 从命令行读取值到栈顶 栈顶值送变量b中 无条件转到循环入口(11) 6 结束退栈
CX:为目标代码code数组的下标指针
3
Code: array[0..cxmax] of instruction; p414 fct=(lit, opr, lod, sto, cal, int, jmp, jpc) P413 Instruction= packec record f: fct; P413
5Hale Waihona Puke 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
PL/0编译程序的目标代码结构和代码生成
见P23页
目标代码类pcode是一种假想栈式计算机的汇编语言。 指令格式:
f
f 功能码
l
a
l
a
层次差 (标识符引用层减去定义层)
根据不同的指令有所区别 目标指令见下页
1
指 令 功 能 表
LIT LOD STO CAL INT JMP JPC OPR OPR OPR OPR OPR OPR OPR OPR OPR OPR OPR OPR
l: 0..levmax
a: 0..amax;
end;
4
CODE为一维数组,数组元素为记录型数据。每 一个记录就是一条目标指令。 CX为指令的指针,由0开始顺序增加。
在block入口处生成一条(jmp,0,0)指令,作为过程 体入口指令,该指令的第3区域的'0'需分析到过 程体入口时才返填。
实际上目标代码的顺序是内层过程的排在前边, 主程序的目标代码在最后。 下面我们给出一个PL/0源程序和对应的目标程序 的清单。
0 l l l 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
a a a a a a a 0 1 2 3 4 5 6 7 8 9 10 11
将常数值取到栈顶,a为常数值
将变量值取到栈顶,a为相对运行栈基址的偏移量,l为层差 将栈顶内容送入某变量单元中,a为相对运行栈基址偏移量,l为层
调用过程,a为过程入口地址,l为层差