4.4 表达式及赋值语句的翻译
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
T E(1) ∨ E(2) F F (a) T
“真”出口 “假”出口
T E(1) F
T
∧ E(2)
F (b)
“真”出口 “假”出口
2016/6/23
12
在自下而上的分析过程中,一个布尔式的真假出 口往往不能在产生四元式的同时就填上,我们只 好把这种未完成的四元式的地址 (编号)作为E的语 义值暂存起来,待到整个表达式的四元式产生完 毕之后,再来填写这个未填入的转移目标。
简单变量:指普通变量和常数,但不含数 组元素及结构引用等复合型数据结构;
简单算术表达式:一种仅含简单变量的算 术表达式。 简单算术表达式的计值顺序与四元式出现 的顺序相同,因此容易将其翻译成四元式 形式,这些翻译方法稍加修改也可用于产 生三元式或间接三元式。
3
2016/6/23
考虑以下文法G[A]: A→i=E E→E+E∣E*E∣−E∣(E)∣i 在此,非终结符A代表“赋值语句”。 文法 G[A] 虽然是一个二义文法,但通过 确定运算符的结合性及规定运算符的优 先级就可避免二义性的发生。 为了实现由表达式到四元式的翻译,需 要给文法加上语义子程序,以便在进行 归约的同时执行对应的语义子程序。
例4.2 试给出布尔表达式a∧b∨c≥d作为控 制条件的四元式中间代码。 [解答] 设四元式序号从100开始,则布尔 表达式 a∧b∨c≥d 的分析过程如图 4–7 所示。 顺序执行相应的语义子动作。
提示:先画出相应的语法树,再根据归约
2016/6/23
22
即: 100(jnz,a,_,102) 101(j,_,_,104) 102(jnz,b,_,106) 103(j,_,_,104) 104(j≥,c,d,106) 105(j,_,_,q) T: 106
2016/6/23 4
语义子程序所涉及的语义变量、语义过程及函数说明:
(1) 语义变量E.place:即用E.place表示存放E值的变 量名在符号表中的入口地址或临时变量名的整数码。 (2) 语义函数newtemp( ):即每次调用newtemp( )时 都将回送一个代表新临时变量的整数码;临时变量名 按产生的顺序可设为T1、T2、……。 (3) 语义过程 emit(op,arg1,arg2,result) : emit 的功 能是产生一个四元式并填入四元式表中。
编 译 原 理 Principle of Compiling
郭 一 晶
厦门大学嘉庚学院 2008 年 9 月
2016/6/23 1
4.4 表达式及赋值语句的翻译
4.4.1 简单算术表达式和赋Fra Baidu bibliotek语句的翻译 4.4.2 布尔表达式的翻译
2016/6/23
2
4.4.1 简单算术表达式和赋值语句的翻译
2016/6/23 6
(5) E→(E(1)) { E.place= E(1) .place ; } (6) E→i { p=lookup(i.name); if (p!=NULL) E.place = p; /*另一种表示为E.place= entry(i)*/ else error( );}
(jrop,X,Y,0) /*X、Y为关系运算符两侧的变量或值*/ ( j,_,_,0)
2016/6/23 25
作业:
参考P105图4-7和P106例4.4,写出 a ∨ (m ≠ n) ∧ (x > y)对应的语法树,给出详细的 分析过程,写出相应的四元式代码 (注意: ∧的优先级大于∨)。 [ Q:例4.4的代码101、103存在冗余现象, 如何改进? A:参考P127习题4.7。 ]
– 布尔运算符: ┐、∧、∨,或为not、and和or (注:
C语言中为!、&& 和 ||)。 – 运算对象:布尔变量、常量或关系表达式。 – 布尔运算符的运算顺序一般为┐、∧、∨,且∧ 和∨服从左结合,布尔算符的运算优先级低于任 何关系运算符。
2016/6/23 8
关系表达式: – 关系运算符: <、<=、==、!=、>=、>等 – 运算对象:算术表达式 – 关系运算符的优先级相同但不得结合,其运算 优先级高于布尔运算符,低于任何算术运算符。 算术表达式: – 算术运算符: +、-、*、/、^等 – 运算对象:操作数 – 算术运算符的运算顺序一般为^、 *、/、 +、-, 且满足左结合,其运算优先级高于布尔运算符, 且高于任何关系运算符。
为了便于实现布尔表达式的语法制导翻译,并 在扫描到“∧”与“∨”时能及时回填一些已 经确定了的待填转移目标,我们将前述文法 G[E]改写为下面的文法G‘[E],以利于编制相应 的语义子程序: G'[E]: E→EAE∣EBE∣┐E∣(E)∣i∣i rop i
EA→E∧
EB→E∨
注意: EA 、EB是与E不同的非终结符。
例如,假定E的四元式需要回填“真”出口的有p、 q、r这三个四元式,则它们可链接成如图4–6所示 的一条真值链(记作tc)。
(p)
(x, x, x,0) …
(x , x, x,p) …
0是链尾标志
(q)
(r)
2016/6/23
(x, x, x,q)
地址(r)是E.tc的链首
14
为了处理E.tc和E.fc这两项语义值,我们 需要引入如下的语义变量和函数: (1) nxq :始终指向下一条将要产生 的四元式的地址 ( 序号 ) ,其初值为 1 。每 当执行一次emit语句后,nxq自动增1。 (2) merge(p1,p2) :把以 p1 和 p2 为链首 的两条链合并为一条以 p2 为链首的链 ( 即 返回链首值p2)。 (3) Backpatch(p,t) :把链首 p 所链接 的每个四元式的第四区段 ( 即 result) 都改 写为地址t。
2016/6/23 11
如何确定一个表达式的真假出口呢? 考虑表达式E(1)∨E(2),若E(1)为真,则立即知道E也 为真,因此,E(1)的真出口也就是整个E的真出口; 若E(1)为假,则E(2)必须被计值,此时E(2)的第一个四 元式就是E(1)的假出口。当然,E(2)的真假出口也就 是整个E的真假出口。类似的考虑适用于对E(1)∧E(2) 的翻译。
…
2016/6/23
F: q
23
当然,我们也可以通过下图的分析得到上 述四元式序列。
2016/6/23
24
由例4.2可知,每一个布尔变量a都对应一真 一假两个四元式,并且格式是固定的,即
(jnz,a,_,0)
( j,_,_,0)
/*a为布尔变量*/
而每一个关系表达式同样对应一真一假两 个四元式,其格式也是固定的,即
2016/6/23 18
文法G'[E]的每个产生式和相应的语义子程序: (1) E→i {E.tc=nxq; E.fc=nxq+1; emit(jnz,entry(i),_,0); emit(j,_,_,0);} (2) E→i(1) rop i(2) {E.tc=nxq; E.fc=nxq+1; emit(jrop, entry(i(1)), entry(i(2)),0); emit(j,_,_,0);} (3) E→(E(1) ) {E.tc = E(1).tc;E.fc = E(1).fc;} (4) E→┐E(1) {E.tc = E(1).fc;E.fc = E(1).tc;}
对于每个非终结符E,我们需要为它赋予两个语义 值E.tc和E.fc,以分别记录E所对应的四元式需要 回填“真”、“假”出口的四元式地址所构成的 链。这是因为在翻译过程中,常常会出现若干转 移四元式转向同一个目标但目标位置又未确定的 情况,此时可用“拉链”的方法将这些四元式链 接起来,待获得转移目标的四元式地址时再进行 返填。 2016/6/23 13
2016/6/23 15
merge( )函数如下: merge(p1,p2) { if(p2= = 0) return(p1); else { p = p2; while (四元式p的第四区段内容不为0) p = 四元式p的第四区段内容; 把p1填进四元式p的第四区段; return (p2); } }
注意: EA 、EB是与E不同的非终结符,
E(1) 、E(2)是与E相同的非终结符。
2016/6/23 20
注
意:
整个布尔表达式所对应的四元式全部产 生之后,作为整个表达式的真假出口(转 移目标)仍尚待回填。
由产生式(2)也可看出关系表达式的优先 级高于布尔表达式。
2016/6/23
21
2016/6/23 19
(5) EA→E(1)∧ {Backpatch(E(1).tc,nxq); EA.fc = E(1).fc;} (6) E→EAE(2) {E.tc = E(2).tc; E.fc =merge( EA.fc,E(2).fc);} (7) EB→E(1)∨ {Backpatch(E(1).fc,nxq); EB.tc = E(1).tc; } (8) E→EBE(2) {E.fc = E(2).fc; E.tc = merge(EB.tc,E(2).tc);}
16
2016/6/23
Backpatch( )函数如下: Backpatch( p , t ) { Q = p; while (Q != 0) { q = 四元式Q的第四区段内容; 把t填进四元式Q的第四区段; Q = q; } }
2016/6/23 17
2016/6/23 9
为简单起见,我们遵循以上运算约定讨论下 述文法G[E]生成的布尔表达式: G[E]:E→E∧E∣E∨E∣┐E∣(E)∣i∣i rop i
注意: rop 代表六个关系运算符,即 < 、 <= 、 ==、!=、>=、>等。
2016/6/23
10
计算布尔表达式通常有两种方法: 1. 仿照计算算术表达式的文法,按布尔表 达式的运算顺序一步步地计算出真假值, 如1 ∨ (┐0∧0) ∨0。 2. 根据布尔运算的特点实施某种优化,省 略不影响运算结果的运算。例如,在计算 A∨B时,若计算出的A值为1,则B值就 无需再计算了;同样,在计算A∧B时若 发现A值为0,则B值也无需计算,A∧B 的值一定为0。 注 意:假定函数过程的工作不出现P102 的副作用情况。
P101 例4.1试分析赋值语句X= −B*(C+D) 的语法制导翻译过程。
2016/6/23
7
4.4.2 布尔表达式的翻译
程序设计语言中的布尔表达式有两个作用, 一是计算逻辑值,更多的情况是二,用作改 变控制语句中的条件表达式,如在if-then, if-then-else或while-do语句中。 表达式:由运算符与运算对象组成。 布尔表达式:
2016/6/23 26
2016/6/23
27
(4) 语义函数lookup(i.name):其功能是审查i.name 是否出现在符号表中,是则返回i.name在符号表的入 口指针,否则返回NULL。
2016/6/23 5
文法G[A]中的每一个产生式的语义子程序: (1) A→i=E {p = lookup(i.name); if(p==NULL) error( ); else emit(=, E.place, _, P); } (2) E→E(1)+E(2) {E.place=newtemp( ); emit(+, E(1) .place, E(2).place, E.place);} (3) E→E(1)*E(2) {E.place=newtemp( ); emit(*, E(1) .place, E(2).place, E.place);} (4) E→−E(1) {E.place=newtemp( ); emit(uminus, E(1).place, _, E.place);}
“真”出口 “假”出口
T E(1) F
T
∧ E(2)
F (b)
“真”出口 “假”出口
2016/6/23
12
在自下而上的分析过程中,一个布尔式的真假出 口往往不能在产生四元式的同时就填上,我们只 好把这种未完成的四元式的地址 (编号)作为E的语 义值暂存起来,待到整个表达式的四元式产生完 毕之后,再来填写这个未填入的转移目标。
简单变量:指普通变量和常数,但不含数 组元素及结构引用等复合型数据结构;
简单算术表达式:一种仅含简单变量的算 术表达式。 简单算术表达式的计值顺序与四元式出现 的顺序相同,因此容易将其翻译成四元式 形式,这些翻译方法稍加修改也可用于产 生三元式或间接三元式。
3
2016/6/23
考虑以下文法G[A]: A→i=E E→E+E∣E*E∣−E∣(E)∣i 在此,非终结符A代表“赋值语句”。 文法 G[A] 虽然是一个二义文法,但通过 确定运算符的结合性及规定运算符的优 先级就可避免二义性的发生。 为了实现由表达式到四元式的翻译,需 要给文法加上语义子程序,以便在进行 归约的同时执行对应的语义子程序。
例4.2 试给出布尔表达式a∧b∨c≥d作为控 制条件的四元式中间代码。 [解答] 设四元式序号从100开始,则布尔 表达式 a∧b∨c≥d 的分析过程如图 4–7 所示。 顺序执行相应的语义子动作。
提示:先画出相应的语法树,再根据归约
2016/6/23
22
即: 100(jnz,a,_,102) 101(j,_,_,104) 102(jnz,b,_,106) 103(j,_,_,104) 104(j≥,c,d,106) 105(j,_,_,q) T: 106
2016/6/23 4
语义子程序所涉及的语义变量、语义过程及函数说明:
(1) 语义变量E.place:即用E.place表示存放E值的变 量名在符号表中的入口地址或临时变量名的整数码。 (2) 语义函数newtemp( ):即每次调用newtemp( )时 都将回送一个代表新临时变量的整数码;临时变量名 按产生的顺序可设为T1、T2、……。 (3) 语义过程 emit(op,arg1,arg2,result) : emit 的功 能是产生一个四元式并填入四元式表中。
编 译 原 理 Principle of Compiling
郭 一 晶
厦门大学嘉庚学院 2008 年 9 月
2016/6/23 1
4.4 表达式及赋值语句的翻译
4.4.1 简单算术表达式和赋Fra Baidu bibliotek语句的翻译 4.4.2 布尔表达式的翻译
2016/6/23
2
4.4.1 简单算术表达式和赋值语句的翻译
2016/6/23 6
(5) E→(E(1)) { E.place= E(1) .place ; } (6) E→i { p=lookup(i.name); if (p!=NULL) E.place = p; /*另一种表示为E.place= entry(i)*/ else error( );}
(jrop,X,Y,0) /*X、Y为关系运算符两侧的变量或值*/ ( j,_,_,0)
2016/6/23 25
作业:
参考P105图4-7和P106例4.4,写出 a ∨ (m ≠ n) ∧ (x > y)对应的语法树,给出详细的 分析过程,写出相应的四元式代码 (注意: ∧的优先级大于∨)。 [ Q:例4.4的代码101、103存在冗余现象, 如何改进? A:参考P127习题4.7。 ]
– 布尔运算符: ┐、∧、∨,或为not、and和or (注:
C语言中为!、&& 和 ||)。 – 运算对象:布尔变量、常量或关系表达式。 – 布尔运算符的运算顺序一般为┐、∧、∨,且∧ 和∨服从左结合,布尔算符的运算优先级低于任 何关系运算符。
2016/6/23 8
关系表达式: – 关系运算符: <、<=、==、!=、>=、>等 – 运算对象:算术表达式 – 关系运算符的优先级相同但不得结合,其运算 优先级高于布尔运算符,低于任何算术运算符。 算术表达式: – 算术运算符: +、-、*、/、^等 – 运算对象:操作数 – 算术运算符的运算顺序一般为^、 *、/、 +、-, 且满足左结合,其运算优先级高于布尔运算符, 且高于任何关系运算符。
为了便于实现布尔表达式的语法制导翻译,并 在扫描到“∧”与“∨”时能及时回填一些已 经确定了的待填转移目标,我们将前述文法 G[E]改写为下面的文法G‘[E],以利于编制相应 的语义子程序: G'[E]: E→EAE∣EBE∣┐E∣(E)∣i∣i rop i
EA→E∧
EB→E∨
注意: EA 、EB是与E不同的非终结符。
例如,假定E的四元式需要回填“真”出口的有p、 q、r这三个四元式,则它们可链接成如图4–6所示 的一条真值链(记作tc)。
(p)
(x, x, x,0) …
(x , x, x,p) …
0是链尾标志
(q)
(r)
2016/6/23
(x, x, x,q)
地址(r)是E.tc的链首
14
为了处理E.tc和E.fc这两项语义值,我们 需要引入如下的语义变量和函数: (1) nxq :始终指向下一条将要产生 的四元式的地址 ( 序号 ) ,其初值为 1 。每 当执行一次emit语句后,nxq自动增1。 (2) merge(p1,p2) :把以 p1 和 p2 为链首 的两条链合并为一条以 p2 为链首的链 ( 即 返回链首值p2)。 (3) Backpatch(p,t) :把链首 p 所链接 的每个四元式的第四区段 ( 即 result) 都改 写为地址t。
2016/6/23 11
如何确定一个表达式的真假出口呢? 考虑表达式E(1)∨E(2),若E(1)为真,则立即知道E也 为真,因此,E(1)的真出口也就是整个E的真出口; 若E(1)为假,则E(2)必须被计值,此时E(2)的第一个四 元式就是E(1)的假出口。当然,E(2)的真假出口也就 是整个E的真假出口。类似的考虑适用于对E(1)∧E(2) 的翻译。
…
2016/6/23
F: q
23
当然,我们也可以通过下图的分析得到上 述四元式序列。
2016/6/23
24
由例4.2可知,每一个布尔变量a都对应一真 一假两个四元式,并且格式是固定的,即
(jnz,a,_,0)
( j,_,_,0)
/*a为布尔变量*/
而每一个关系表达式同样对应一真一假两 个四元式,其格式也是固定的,即
2016/6/23 18
文法G'[E]的每个产生式和相应的语义子程序: (1) E→i {E.tc=nxq; E.fc=nxq+1; emit(jnz,entry(i),_,0); emit(j,_,_,0);} (2) E→i(1) rop i(2) {E.tc=nxq; E.fc=nxq+1; emit(jrop, entry(i(1)), entry(i(2)),0); emit(j,_,_,0);} (3) E→(E(1) ) {E.tc = E(1).tc;E.fc = E(1).fc;} (4) E→┐E(1) {E.tc = E(1).fc;E.fc = E(1).tc;}
对于每个非终结符E,我们需要为它赋予两个语义 值E.tc和E.fc,以分别记录E所对应的四元式需要 回填“真”、“假”出口的四元式地址所构成的 链。这是因为在翻译过程中,常常会出现若干转 移四元式转向同一个目标但目标位置又未确定的 情况,此时可用“拉链”的方法将这些四元式链 接起来,待获得转移目标的四元式地址时再进行 返填。 2016/6/23 13
2016/6/23 15
merge( )函数如下: merge(p1,p2) { if(p2= = 0) return(p1); else { p = p2; while (四元式p的第四区段内容不为0) p = 四元式p的第四区段内容; 把p1填进四元式p的第四区段; return (p2); } }
注意: EA 、EB是与E不同的非终结符,
E(1) 、E(2)是与E相同的非终结符。
2016/6/23 20
注
意:
整个布尔表达式所对应的四元式全部产 生之后,作为整个表达式的真假出口(转 移目标)仍尚待回填。
由产生式(2)也可看出关系表达式的优先 级高于布尔表达式。
2016/6/23
21
2016/6/23 19
(5) EA→E(1)∧ {Backpatch(E(1).tc,nxq); EA.fc = E(1).fc;} (6) E→EAE(2) {E.tc = E(2).tc; E.fc =merge( EA.fc,E(2).fc);} (7) EB→E(1)∨ {Backpatch(E(1).fc,nxq); EB.tc = E(1).tc; } (8) E→EBE(2) {E.fc = E(2).fc; E.tc = merge(EB.tc,E(2).tc);}
16
2016/6/23
Backpatch( )函数如下: Backpatch( p , t ) { Q = p; while (Q != 0) { q = 四元式Q的第四区段内容; 把t填进四元式Q的第四区段; Q = q; } }
2016/6/23 17
2016/6/23 9
为简单起见,我们遵循以上运算约定讨论下 述文法G[E]生成的布尔表达式: G[E]:E→E∧E∣E∨E∣┐E∣(E)∣i∣i rop i
注意: rop 代表六个关系运算符,即 < 、 <= 、 ==、!=、>=、>等。
2016/6/23
10
计算布尔表达式通常有两种方法: 1. 仿照计算算术表达式的文法,按布尔表 达式的运算顺序一步步地计算出真假值, 如1 ∨ (┐0∧0) ∨0。 2. 根据布尔运算的特点实施某种优化,省 略不影响运算结果的运算。例如,在计算 A∨B时,若计算出的A值为1,则B值就 无需再计算了;同样,在计算A∧B时若 发现A值为0,则B值也无需计算,A∧B 的值一定为0。 注 意:假定函数过程的工作不出现P102 的副作用情况。
P101 例4.1试分析赋值语句X= −B*(C+D) 的语法制导翻译过程。
2016/6/23
7
4.4.2 布尔表达式的翻译
程序设计语言中的布尔表达式有两个作用, 一是计算逻辑值,更多的情况是二,用作改 变控制语句中的条件表达式,如在if-then, if-then-else或while-do语句中。 表达式:由运算符与运算对象组成。 布尔表达式:
2016/6/23 26
2016/6/23
27
(4) 语义函数lookup(i.name):其功能是审查i.name 是否出现在符号表中,是则返回i.name在符号表的入 口指针,否则返回NULL。
2016/6/23 5
文法G[A]中的每一个产生式的语义子程序: (1) A→i=E {p = lookup(i.name); if(p==NULL) error( ); else emit(=, E.place, _, P); } (2) E→E(1)+E(2) {E.place=newtemp( ); emit(+, E(1) .place, E(2).place, E.place);} (3) E→E(1)*E(2) {E.place=newtemp( ); emit(*, E(1) .place, E(2).place, E.place);} (4) E→−E(1) {E.place=newtemp( ); emit(uminus, E(1).place, _, E.place);}