第6章 语法制导翻译和中间代码生成Tsu版电.docx

上传人:b****4 文档编号:4379693 上传时间:2022-12-01 格式:DOCX 页数:16 大小:21.83KB
下载 相关 举报
第6章 语法制导翻译和中间代码生成Tsu版电.docx_第1页
第1页 / 共16页
第6章 语法制导翻译和中间代码生成Tsu版电.docx_第2页
第2页 / 共16页
第6章 语法制导翻译和中间代码生成Tsu版电.docx_第3页
第3页 / 共16页
第6章 语法制导翻译和中间代码生成Tsu版电.docx_第4页
第4页 / 共16页
第6章 语法制导翻译和中间代码生成Tsu版电.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

第6章 语法制导翻译和中间代码生成Tsu版电.docx

《第6章 语法制导翻译和中间代码生成Tsu版电.docx》由会员分享,可在线阅读,更多相关《第6章 语法制导翻译和中间代码生成Tsu版电.docx(16页珍藏版)》请在冰豆网上搜索。

第6章 语法制导翻译和中间代码生成Tsu版电.docx

第6章语法制导翻译和中间代码生成Tsu版电

第6章语法制导翻译和中间代码生成

㈠语法分析和语义分析的区别

㈡语义分析主要工作

①建立符号表和常数表。

②诊察和报告源程序中的语义错误。

③根据语言的语义产生中间代码(或机器指令),或直接解释执行。

6.1语法制导翻译概述

㈠语法制导翻译方法简介

为每一个产生式配一个语义子程序。

在语法分析过程中,当一个产生式获得匹配或用于归约时,此产生式相应的语义子程序进入工作,完成既定的翻译任务。

㈡实现方法(以SLR分析器为例)

①分析表不变

②改造工作栈

●状态栈

●符号栈

●单词值栈:

用于保存单词的值(字符串形式)。

●语义栈:

用于记录分析过程中需保留的语义值。

例,值(val)、地址(addr)、种属(cat)、类型(type)等。

③修改总控程序

●在移进时,除移进状态和单词的种别外,还需移进单词的值。

●在用某个产生式进行归约时,除需执行归约动作外,还需调用相应语义子程序。

㈢解释执行例

①文法及语义子程序

②SLR分析表

③手工计算

7+9*5

6.2符号表和常数表

㈠符号表

①引入符号表的意义

②符号表的结构(略有修改)

struct{

void*addr;//标号或变量的地址

charid[5];//标识符名

unsignedcat:

4;//种属(4个二进制位)

unsignedtype:

4;//类型(4个二进制位)

}sym_table[NS];//NS表示符号表长度

③符号表的使用

④符号表地址使用说明

㈡常数表

①常数表结构

unsignedshortconst_int_table[NI];//NI表示整常数表长度

floatconst_real_table[NR];//NR表示实常数表长度

②常数表使用

③常数表地址使用说明

6.3中间代码

6.3.1三元式

㈠格式

OPARG1ARG2

运算符

第一运算量

第二运算量

㈡优点

代码生成无需引进临时变量。

㈢缺点

调整困难。

6.3.2四元式

㈠格式

OPARG1ARG2RESULT

运算符

第一运算量

第二运算量

运算结果

㈡优点

调整方便。

㈢缺点

在生成中间代码时引进大量临时变量。

㈣临时变量的处理

①将Ti作为标识符存入符号表

②设置临时变量表

6.4说明语句(简单变量)的翻译

㈠文法及修改

<语句>→integer<标识符表>S→aV

<语句>→real<标识符表>S→cV

<标识符表>→<标识符表>,标识符V→V,i

<标识符表>→标识符V→i

为了避免使用队列,文法修改如下:

<语句>→<说明>S→V

<说明>→<说明>,标识符V→V,i

<说明>→integer标识符V→ai

<说明>→real标识符V→ci

用这个文法来制导翻译,每当读进一个标识符,就可把它的变量名及其性质填入符号表,没有必要集中起来成批处理。

㈡语义子程序

V→ai{

fill_sym_table(wval,0,0);//填写符号表(标识符名,简单变量,整型)

V.cat=0;//保存语义值(简单变量)

V.type=0;//保存语义值(整型)

}

V→ci{

fill_sym_table(wval,0,1);//填写符号表(标识符名,简单变量,整型)

V.cat=0;//保存语义值(简单变量)

V.type=1;//保存语义值(实型)

}

V→V

(1),i{

fill_sym_table(wval,V

(1).cat,V

(1).type);//继承V

(1)的语义信息

V.cat=V

(1).cat;

V.type=V

(1).type;

}

S→V{;}//空

①语义变量.cat和.type

②fill_sym_table函数

㈢手工计算

intergera,b

6.5整型算术表达式及赋值语句的翻译

㈠文法

<语句>→标识符=<整型算术表达式>S→i=X

<整型算术表达式>→<整型算术表达式>+<项>X→X+Y

<整型算术表达式>→<项>X→Y

<项>→<项>*<因子>Y→Y*Z

<项>→<因子>Y→Z

<因子>→(<整型算术表达式>)Z→(X)

<因子>→-<因子>Z→-Z

<因子>→标识符Z→i

<因子>→无符号整常数Z→x

㈡语义子程序

S→i=X{

gen_code(=,X.addr,0,sym_entry(wval));//产生四元式。

}

X→X

(1)+Y{

X.addr=get_tmpvar(0);//申请临时变量(整型)

gen_code(+,X

(1).addr,Y.addr,X.addr);//产生四元式

}

X→Y{

X.addr=Y.addr;//传递语义值

}

Y→Y

(1)*Z{

Y.addr=get_tmpvar(0);//申请临时变量(整型)

gen_code(*,Y

(1).addr,Z.addr,Y.addr);//产生四元式

}

Y→Z{

Y.addr=Z.addr;//传递语义值

}

Z→(X){

Z.addr=X.addr;//传递语义值

}

Z→-Z

(1){

Z.addr=get_tmpvar(0);//申请临时变量(整型)

gen_code(-,Z

(1).addr,0,Z.addr)//产生四元式

}

Z→i{

Z.addr=sym_entry(wval);//wval表示单词的值

}

Z→x{

Z.addr=const_int_entry(atoi(wval));//wval表示单词的值,atoi为C语言系统函数。

}

①get_tmpvar函数

②sym_entry函数

③gen_code函数

④const_int_entry(wval)函数

㈢手工计算

a=-b*(c+2)

6.6混合型算术表达式及赋值语句的翻译

㈠概述

①拒绝接受混合运算,报错(如标准Fortran语言)。

②允许混合运算,在运算前将它们转换成同一类型(例Pascal语言、C语言)。

㈡引入定点、浮点和类型转换运算符

●运算符itr作用:

将整型量转换为实型量。

●运算符+r、+i、…,分别表示实数加、整数加、…。

设源程序为

inta,b;

realc,d;

c=d+a*b

符号表略,相应的四元式代码为

(*i,&a,&b,&T1)

(itr,&T1,0,&T2)

(+r,&d,&T2,&T3)

(=r,&T3,0,&c)

㈢文法

<语句>→标识符=<算术表达式>S→i=X

<算术表达式>→<算术表达式>+<项>X→X+Y

<算术表达式>→<项>X→Y

<项>→<项>*<因子>Y→Y*Z

<项>→<因子>Y→Z

<因子>→(<算术表达式>)Z→(X)

<因子>→-<因子>Z→-Z

<因子>→标识符Z→i

<因子>→无符号整常数Z→x

<因子>→无符号实常数Z→y

㈣语义子程序(X→X+Y)

void*t;

X→X

(1)+Y{

if(X

(1).type==Y.type)//类型相同

if(X

(1).type==0){//intopint

X.addr=get_tmpvar(0);

gen_code(+i,X

(1).addr,Y.addr,X.addr);//产生四元式

X.type=0;

}

else{//real=real

X.addr=get_tmpvar

(1);

gen_code(+r,X

(1).addr,Y.addr,X.addr);//产生四元式

X.type=1;

}

else{//类型不相同

X.type=1;//结果类型均为实型

t=get_tmpvar

(1);//申请临时变量(实型),用于类型转换。

X.addr=get_tmpvar

(1);

if(X

(1).type==0){//intopreal

gen_code(itr,X

(1).addr,0,t);

gen_code(+r,t,Y.addr,X.addr);

}

else{//realopint

gen_code(itr,Y.addr,0,t);

gen_code(+r,X

(1).addr,t,X.addr);

}

}

}

6.7布尔表达式的翻译

㈠布尔表达式作用

①控制语句的条件ifx+y<10gotoL

②计算逻辑值d=x>y

㈡程序设计语言的优先级和结合性

①标准Fortran语言(按表达式类别分级)

②Pascal语言(共分4级,同级运算优先性相同)

③C语言(共分17级,同级运算优先性相同)

㈢描述布尔表达式文法

以标准FORTRAN语言为基础,适当化简。

E→E∨E|E∧E|(E)|~E|XrX|X

X→X+X|X*X|(X)|-X|i|x

㈣布尔表达式计算方法

①根据优先性和结合性按步计算

②优化计算法

㈤布尔表达式的第一种翻译法

同算术表达式

㈥布尔表达式的第二种翻译法

①概述

②实例引入

③问题的提出

④解决办法

1)修改文法

2)引进语义变量.tc和.fc保存未填转移目标的四元式地址

3)变量和函数

●nxq指示器

●链合并函数merg(p1,p2)

●回填函数backpatch(p,t)

⑤语义子程序

E→X{

E.tc=nxq;

gen_code(jnz,X.addr,0,0);

E.fc=nxq;

gen_code(jmp,0,0,0);

}

Er→XrX

(1){

E.tc=nxq;

E.tc:

=nxq+1;

gen_code(jr,X.addr,X

(1).addr,0);

gen_code(jmp,0,0,0)

}

E→~E

(1){//真假出口链链首互换

E.tc=E

(1).fc;E.fc=E

(1).tc;

}

E→(E

(1)){//传递真假出口链链首

E.tc=E

(1).tc;E.fc=E

(1).fc;

}

EA→E∧{

backpatch(E.tc,nxq);//可填真出口(下一个四元式地址)

EA.fc=E.fc;//传递假出口链链首

}

E→EAE

(2){

E.tc=E

(2).tc;//传递真出口链链首

E.fc=merge(EA.fc,E

(2).fc);//合并假出口链

}

EO→E

(1)∨{

EO.tc=E

(1).tc;//传递真出口链链首

backpatch(E

(1).fc,nxq);//可填假出口(下一个四元式地址)

}

E→EOE

(2){

E.tc=merge(EO.tc,E

(2).tc);//合并真出口链

E.fc=E

(2).fc;//传递假出口链链首

}

X→i{

X.addr=sym_entry(wval);//wval表示单词的值。

}

X→x{

X.addr=const_int_entry(atoi(wval));//wval表示单词的值。

}

⑥手工计算

a∨b∨c

6.8标号和无条件转移语句的翻译

㈠标号和goto语句

①向后转移(程序首部方向)

②向前转移(程序尾部方向)

㈡文法及修改

<语句>→标识符:

<语句>S→i:

S

<语句>→goto标识符S→gi

标号用于标领一个语句,为了能及时填写标号的地址,将文法修改如下:

<语句>→<标号><语句>S→FS

<标号>→标识符:

F→i:

<语句>→goto标识符S→gi

㈢问题的提出和解决办法

①gotoL99是一个向后转移语句

②gotoL99是一个向前转移语句

●L99第一次出现

●L99非第一次出现

㈣语义子程序(不考虑出错情况)

F→i:

{

if(sym_entry(wval)==0){//标号未进入符号表,属先定位后使用。

fill_sym_table(wval,1,1);//将标号名填入符号表且标记已定位

(*sym_entry(wval)).addr=nxq;//nxq为标号i标领的语句第一个四元式地址

}

else{//标号已进入符号表,属先使用后定位,此时应回填。

backpatch((*sym_entry(wval)).addr,nxq);//回填

(*sym_entry(wval)).addr=nxq;

(*sym_entry(wval)).type=1;//标号已定位

}

}

S→gi{

if(sym_entry(wval)==0){/*标号未进入符号表,属先使用后定位且是第一个向前转移语句,此时产生新链,链中仅有一个四元式。

*/

fill_sym_table(wval,1,0);//将标号名填入符号表且标记为未定位

(*sym_entry(wval)).addr=nxq;//下一个无条件转移四元式地址(编号)

gen_code(jmp,0,0,0);//产生不完全四元式

}

else{//标号已进入符号表

if((*sym_entry(wval)).type==1)//标号已进入符号表且定位,直接产生四元式。

gen_code(jmp,0,0,(*sym_entry(wval)).addr);

else{/*标号已进入符号表,但未定位,即有以该标号为转移目标的单向链存在,将新产生的四元式插入单向链。

*/

void*t;

t=(*sym_entry(wval)).addr;

(*sym_entry(wval)).addr=nxq;

gen_code(jmp,0,0,t);

}

}

}

S→FS{;}//暂时可认为是空

6.9控制语句的翻译

㈠概述

㈡语义变量E.fc的传递

㈢引进语义变量.chain

6.9.1if-then语句的翻译

㈠文法及修改

<语句>→if<布尔表达式>then<语句>endifS→fEtS

(1)j

<语句>→标识符=<算术表达式>S→i=X

为了能及时回填真出口,文法修改如下:

C→if<布尔表达式>thenC→fEt

<语句>→C<语句>endifS→CS

(1)j

<语句>→标识符=<算术表达式>S→i=X

㈡语义子程序

C→fEt{

backpatch(E.tc,nxq);//回填真出口

C.chain=E.FC;//假出口是离开if-then语句

}

S→CS

(1)j{

S.chain=merge(C.chain,S

(1).chain);//S

(1)中可能含有离开if_then的四元式

}

S→i=X{//赋值语句按顺序执行,它的四元式代码中不存在需回填转移目标的四元式。

S.chain=0;

gen_code(=,X.addr,0,sym_entry(wval));

}

㈢手工计算

ifathenb=dendif

6.9.2if-then-else语句的翻译

㈠文法及修改

<语句>→if<布尔表达式>then<语句>else<语句>S→fEtS

(1)eS

(2)

当扫描到then可填真出口,当扫描到else可填假出口,当S

(1)执行完毕,应离开if-then-else语句。

为了能及时回填四元式,修改如下:

<语句>→TP<语句>S→TPS

(2)

TP→C<语句>elseTP→CS

(1)e

C→if<布尔表达式>thenC→fEt

㈡语义子程序

TP→CS

(1)e{//TP可理解为then-processed

void*t;

t=nxq;//t为下一条四元式地址,即(jmp,0,0,0)的地址(编号)。

gen_code(jmp,0,0,0);//执行完S

(1)后,离开if-then-else语句。

backpatch(C.chain,nxq);//回填假出口,这里C.chain相当于E.FC,此时nxq=t+1。

TP.chain=merge(S

(1).chain,t);//S

(1)中可能含有离开if_then-else的四元式

}

S→TPS

(2){

S.chain=merge(TP.chain,S

(2).chain);//S

(2)中可能含有离开if_then-else的四元式

}

C→fEt{…}//见6.9.1

㈢手工计算

ifathenb=celseb=d

6.9.3while-do语句的翻译

㈠文法及修改

<语句>→while<布尔表达式>do<语句>S→wEdS

(1)

为了便于语义分析,修改如下:

W→whileW→w

Wd→W<布尔表达式>doWd→WEd

<语句>→Wd<语句>S→WdS

(1)

㈡语义子程序

W→w{

W.quad=nxq;//记录E的第一个四元式编号

}

Wd→WEd{//Wd可理解为while-do

backpatch(E.TC,nxq);//回填真出口

Wd.chain=E.fc;//传递假出口、即while-do的出口。

Wd.quad=W.quad;//传递E的第一个四元式地址

}

S→WdS

(1){

backpatch(S

(1).chain,Wd.quad);/*回填S

(1).chain链,因S

(1)可能是控制语句,离开S

(1)的四元式的转移目标是E的第一个四元式。

*/

gen_code(jmp,0,0,Wd.quad);//生成转向E首址的无条件转移指令

S.chain=Wd.chain;//传递假出口、即while-do的出口。

}

㈢手工计算

whileadoifbthenc=dendif

6.9.4复合语句的翻译

㈠文法及修改

<语句>→begin<语句串>endS→{L}

<语句串>→<语句串>;<语句>L→L

(1);S

<语句串>→<语句>L→S

分号意味着一个语句的结束,当扫描到分号,就可回填转移目标。

为了能及时回填chain链,文法修改如下:

<语句>→begin<语句串>endS→{L}

<语句串>→LS<语句>L→LSS

LS→<语句串>;LS→L;

<语句串>→<语句>L→S

㈡语义子程序

L→S{

L.chain=S.chain;//传递

}

Ls→L;{

backpatch(L.chain,nxq);//回填

}

L→LsS{//LS表示L-S

L.chain=S.chain//因前一语句L已回填,而当前语句S尚未回填,故需传递。

}

S→{L}{

S.chain=L.chain;//传递

}

P→{L}{

backpatch(L.chain,nxq);//填写最后一个语句的chain链

gen_code(halt,0,0,0);//产生停机指令

}

㈢例子

设源程序为

begin

ifathenb=10endif;

whilec>ddo

begin

c=c-1;d=d+1

end

end

根据上述语义子程序,其相应四元式序列为:

⑴(jnz,&a,0,03)//if

⑵(jmp,0,0,04)

⑶(=,&10,0,&b)

⑷(j>,&c,&d,06)//while

⑸(jmp,0,0,011)

⑹(-,&c,&1,&T1)

⑺(=,&T1,0,&c)

⑻(+,&d,&1,&T2)

⑼(=,&T2,0,&d)

⑽(jmp,0,0,4)

⑾(halt,0,0,0)

6.10小结

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1