490 likes | 645 Views
第七章 语义分析和 中间代码的产生. 属性文法( P136 ) 属性文法 是进行语义分析和处理的重要工具。. 属性文法 —— 在属性文法是在 上下文无关文法 的基础上为每个 文法符号 (终结符或非终结符)配备若干个相关的 “ 值 ” (称为 属性 )。这些属性代表与文法符号相关的信息,例如它的类型、值、代码序列、符号表内容等等。属性和变量一样,可以进行 计算 和 传递 。 属性分类 :综合属性 和 继承属性。 简单的说,综合属性用于 “ 自下而上 ” 传递信息,而继承属性用于 “ 自上而下 ” 传递信息。
E N D
第七章 语义分析和 中间代码的产生 第七章 语义分析和中间代码产生
属性文法(P136) 属性文法是进行语义分析和处理的重要工具。 • 属性文法——在属性文法是在上下文无关文法的基础上为每个文法符号(终结符或非终结符)配备若干个相关的“值”(称为属性)。这些属性代表与文法符号相关的信息,例如它的类型、值、代码序列、符号表内容等等。属性和变量一样,可以进行计算和传递。 • 属性分类:综合属性和继承属性。简单的说,综合属性用于“自下而上”传递信息,而继承属性用于“自上而下”传递信息。 • 语义规则——属性加工加工的过程即是语义处理的过程,对于文法的每一个产生式都配备了一组属性的计算规则,则称为语义规则。主要包括:属性计算、静态语义检查、符号表操作、代码生成等。在一个属性文法中,对应于每个产生式都有一套与之相关联的语义规则。 第七章 语义分析和中间代码产生
语义规则所描述的工作可以包括属性计算、静态语义检查、符号表操作、代码生成等。语义规则通常写成过程调用,或过程段。语义规则所描述的工作可以包括属性计算、静态语义检查、符号表操作、代码生成等。语义规则通常写成过程调用,或过程段。 综合属性: 在语法树中,一个结点的综合属性的值由其子结点的属性值确定。因此,通常使用自底向上的方法在每一个结点处使用语义规则计算综合属性的值。 继承属性: 在语法树中,一个结点的继承属性由此结点的父结点和/或兄弟结点的某些属性确定。用继承属性来表示程序语言结构中的上下文依赖关系很方便。 第七章 语义分析和中间代码产生
引 言 紧接在词法分析和语法分析之后,编译程序要做的工作是进行静态语义检查和翻译。(图7.1) • 静态语义检查 1、类型检查。 2、控制流检查。 3、一致性检查。 4、相关名字检查。 • 翻译(中间语言): (1)便于进行与机器无关的代码优化; (2)使编译程序改变目标机更容易; (3)使编译程序的结构在逻辑上更为简单明确,以中间语言为界面,编译前端和后端的接口更清晰。 第七章 语义分析和中间代码产生
语法制导翻译P139 基于属性文法的处理方法 (语法制导翻译法) 从概念上讲,基于属性文法的处理过程通常是这样的:对单词符号串进行语法分析,构造语法分析树,然后根据需要遍历语法树,并在语法树的各结点处按语义规则进行计算。 输入串 语法树 依赖图 语义规则计算次序 这种由源程序的语法结构所驱动的处理办法就是语法制导翻译法。语义规则的计算可能产生代码、在符号表中存放信息、给出错误信息或执行任何其它动作。对输入串的翻译也就是根据语义规则进行计算得出结果。(常以中间代码形式表示。) 第七章 语义分析和中间代码产生
7.1 中间语言 主要掌握几种常见的中间语言表达形式: • 逆波兰表示(后缀式); • 三地址代码(四元式、三元式、间接三元式); • 图表示法(DAG 和抽象语法树); 第七章 语义分析和中间代码产生
7.1.1 后缀式 • 后缀式表示法又称逆波兰表示法。 • 逆波兰式(Reverse Polish Notation)。逆波兰式最早于1920年由 Jan Lukasiewicz 发明,作为一种无需括号的数学表达式。 • 特点:把运算量(操作数)写在前面,把算符写在后面(后缀)。 • 例如:a + b 写为ab+;a*b写为ab*; 第七章 语义分析和中间代码产生
后缀式定义 • 一个表达式的后缀式可以如下定义: (1)如果E是一个变量或常量,则E的后缀式是E自身。 (2)如果E是E1 op E2形式的表达式,这里op是任何二元操作符,则E的后缀式为 E1’ E2’op,这里E1’和E2’分别为E1和E2的后缀式。 (3)如果E是(E1)形式的表达式,则E1的后缀式就是E的后缀式。(后缀式无括号) 第七章 语义分析和中间代码产生
例子:写出表达式“-a+b*(-c+d)”的逆波兰式 后缀式的求法:对单目运算符,直接将其放到变量后面,得到(a-)+b*((c-)+d),此处括号为清楚起见而加 然后按照运算优先顺序,对双目运算符进行转换: 第一步得到:(a-)+b*((c-)d+) 第二步得到:(a-)+(b((c-)d+)*) 第三步得到:(a-)(b((c-)d+)*)+ 最后去掉所有括号:a-bc-d+*+ 第七章 语义分析和中间代码产生
a+b*c abc * + x / y ^ z – d * e x y z ^ d e * – 只要我们知道每个算符的目数,对于后缀式,不论从哪一端进行扫描,都能对它正确进行唯一分解。把一般表达式翻译为后缀式是很容易的(栈)。 表7.1给出了把表达式翻译为后缀式的语义规则描述,其中||表示后缀式的连接。 第七章 语义分析和中间代码产生
7.1.2 图表示法 • 图表示法包括: DAG与抽象语法树(P144)。 语法树可以作为一种合适的中间语言形式。 第七章 语义分析和中间代码产生
If_then_else B S2 S1 抽象语法树的每个结点上都可带上一定的属性。语法制导翻译可以基于语法树分析,也可以基于抽象语法树进行。 (1)抽象语法树: 定义:在语法树中去掉那些对翻译不必要的信息,从而获得更有效的源程序中间表示,经过这种变换的语法树就是抽象语法树。在抽象语法树中,操作数和关键字都不作为叶子结点出现,而是作为内部结点,即这些节点的父结点。 产生式:S → if B then S1 else S2的抽象语法树 第七章 语义分析和中间代码产生
* -- b a b * c d d • 建立抽象语法树的方法:通过为每一个运算分量或运算符号建立一个结点来为表达式建立子树。运算符号结点的各个子结点分别表示的是该运算符号的各个运算分量的子表达式组成的子树的根。 表达式:a+a*(b-c)+ (b-c)*d 的抽象语法树为 + + a -- 第七章 语义分析和中间代码产生
(2)无循环有向图: • 无循环有向图(Directed Acyclic Graph , 简称 DAG ).与抽象语法树一样,对于表达式中的每个子表达式,DAG图中都有一个结点。一个内部结点代表一个操作符,它的孩子代表操作数。两者不同的是,在DAG图中代表公共子表达式的结点具有多个父结点,而在一棵抽象语法树中公共子表达式被表示为重复的子树。 第七章 语义分析和中间代码产生
+ + * b * d d a -- 表达式:a+a*(b-c)+ (b-c)*d 的DAG图 第七章 语义分析和中间代码产生
7.1.3三地址代码 三地址代码是由下面一般形式的语句构成的序列: x := y op z • x、y、z——名字、常数或编译时产生的临时变量; • op—运算符号如定点运算符、浮点运算符、逻辑运算符等。 “三地址代码“是每条语句通常包含3个地址,2个表示操作数,1个存放结果。(类似于汇编语言代码) 注意:每个语句的右边只能有一个运算符。 例如:表达式 x+y*z翻译为三地址代码是: T1:= y*z T2:= x+ T1 (T1、T2为临时变量) 第七章 语义分析和中间代码产生
三地址代码可以看成是DAG或抽象语法树的一种线性表示。三地址代码可以看成是DAG或抽象语法树的一种线性表示。 • P170 图7.5给出了图7.3(P168)的三地址代码形式 a:=b * - c + b * - c T1 := - c T2 := b* T1 T3 := - c T4 := b* T3 T5 := T2 + T4 a := T5 第七章 语义分析和中间代码产生
本书常用的三地址语句P170: x := y op z(二元运算,如T1:= y*z) x := op y(单元运算,如T1 := - c) x := y Goto L(无条件转移到标号为L的三地址语句) If x relop y goto L或If a goto L(条件转移语句) (6~8不要求掌握) 生成三地址码时,临时变量的名字对应抽象语法树的内部结点。一般来说,赋值语句id:=E的三地址码包括:对表达式E求值并置于变量T中,然后进行赋值id:= T。 第七章 语义分析和中间代码产生
四元式、三元式、间接三元式 三地址码语句可看成中间代码的一种抽象形式。编译程序中,三地址代码语句的具体实现可以用记录表示,记录中包含表示运算符和操作数的域。通常有三种表示方法: 四元式、三元式、间接三元式。 第七章 语义分析和中间代码产生
四元式——一个带四个域的记录结构。 • (op,arg1,arg2,result) • (OP包含一个代表运算符的内部码,单目运算只用arg1 ) • 例如:x := y op z( :=, y, z , x ) • 三元式 • (op,arg1,arg2)(arg2有时是指针) • 例如:x := y op z( :=, y, z ) • 间接三元式 • 用一张间接码表(表示执行的顺序)辅以三元式的方法表示中间代码。 第七章 语义分析和中间代码产生
间接代码 1 2 3 1 4 5 第七章 语义分析和中间代码产生
四元式、三元式的比较 四元式之间的联系通过临时变量实现;这与三元式不同,要更改一张三元表是比较困难的;但要更改四元式表是很容易的。因此当需要对中间代码进行优化处理时,四元式比三元式要方便得多。这一点,四元式和间接三元式同样方便。 第七章 语义分析和中间代码产生
练 习 写出表达式:A+B*(C-D)-E/F↑G的三元式表示, 四元式表示形式。 四元式表示: ①( - , C , D , T1 ) ② ( * , B , T1 , T2 ) ③ ( + , A , T2 , T3 ) ④ ( ↑, F , G , T4 ) ⑤ ( / , E , T4 , T5 ) ⑥ ( - , T3, T5 , T6 ) 三元式表示: ① ( - , C , D) ②( * , B , ①) ③( + , A , ②) ④( ↑, F , G) ⑤( / , E , ④) ⑥( - , ③, ⑤) 第七章 语义分析和中间代码产生
7.3 赋值语句的翻译 在本节中赋值语句中的表达式的类型可以是整型、实型、数组和纪录。我们将讨论如何翻译赋值语句,并用三地址代码的形式来表示中间结果。 第七章 语义分析和中间代码产生
赋值语句产生三地址代码 的属性文法 表7.3(P171)是为赋值语句生成三地址代码的属性文法定义。 • Gen(x ‘ := ’ y ‘ op ‘ z) ——表示生成三地址语句x := y op z。用单引号括起来的运算符原样保留。 • 把生成的三地址语句序列放在code属性里。 • Id:=E 的三地址代码包括:对表达式E求值并置于临时变量T中,然后进行赋值id.place:=T。 ( E.place表示存放E值的名字, E.code表示对E 求值的三地址语句序列) 第七章 语义分析和中间代码产生
赋值语句X:=A+B*C的翻译 第七章 语义分析和中间代码产生
四元式: (1)(*,B,C,T1) (2)(+,A,T1,T2) (3)(:=, T2, __,X) 第七章 语义分析和中间代码产生
id id id id E.place : = T2 Gen(: = ,T2,__,X) Newtemp (T2 ) E.place : = T2 Gen( +,A,T1, T2) Newtemp (T1 ) E.place : = T1 Gen( *,B,C,T1) E.place : = X E.place : =A E.place : =B E.place : =C X := A + B * C 第七章 语义分析和中间代码产生
7.4 布尔表达式的翻译 1.什么是布尔表达式? 布尔表达式是用布尔运算符号(and、 or、not )作用到布尔变量或关系表达式上而组成的。 关系表达式形式如E1 relop E2, 其中E1和E2是算术表达式, relop为关系运算符 ( < ,<=, > =, > , =, ≠)。 2. 布尔表达式的两个基本作用: • 计算逻辑值; • 控制流语句,如 if-then、if-then-else和 while-do等之中的条件表达式。 第七章 语义分析和中间代码产生
在本节中我们考虑由下列文法产生的布尔表达式:在本节中我们考虑由下列文法产生的布尔表达式: E→E or E | E and E | not E | (E) | id relop id |id 用relop的属性relop.op来确定relop所指的六种关系中的哪一种。 按惯例,我们假定or和and是左结合的,并且规定的优先级顺序为: or < and < not 第七章 语义分析和中间代码产生
布尔表达式的2种求值方法: 1、顺序计算 2、优化计算 1、顺序计算 • 一步步从表达式各部分的值计算出整个布尔表达式的值 例如:1 or ( not 0 and 0 ) or 0 = 1 or ( 1 and 0 ) or 0 = 1 or 0 or 0 = 1 or 0 =1 第七章 语义分析和中间代码产生
A=? 结果=0 结果=1 B=1 B=0 A=? B=1 B=0 2、优化计算 • 根据逻辑关系自身的特点来实现布尔表达式的翻译: A=1 结果=1 A or B B=? A=0 A=0 结果=0 A and B B=? A=1 第七章 语义分析和中间代码产生
布尔表达式的翻译 A or B 翻译为 if A then true else B A and B 翻译为 if A then B else false not A 翻译为 if A then false else true 第七章 语义分析和中间代码产生
数值表示法计算布尔表达式 • 1——表示真0——表示假 • 布尔表达式 a or b and not c 翻译成如下三地址语句序列: T1 := not c T2 := b and T1 T3 := a or T2 四元式 ① ( not ,c, __ ,T1 ) ②( and , b , T1 ,T2 ) ③( or , a , T2 ,T3 ) • 关系表达式a<b可等价的写成: if a<b then 1 else 0 • 将它翻译成如下三地址语句序列: 100 if a<b goto 103 101 T:=0 102 goto 104 103 T:= 1 104 第七章 语义分析和中间代码产生
例7.2: p187 • a < b or c < d and e < f if① if ② if ③ • if①翻译成的三地址语句序列: 100 if a<b goto 103 101 T1:=0 102 goto 104 103 T1:= 1 104 • if ③翻译成的三地址语句序列: 108 if e<f goto 111 109 T3:=0 110 goto 112 111 T3:= 1 • if ②翻译成的三地址语句序列: 104 if c<d goto 107 105 T2:=0 106 goto 108 107 T2:= 1 • 112 T4:= T2 and T3 • 113 T5:= T1 or T4 第七章 语义分析和中间代码产生
7.4.2 作为条件控制的布尔式翻译 条件语句: if E then S1 else S2(7.10) 中的布尔表达式E,它的作用仅在于控制对S1和S2的选择。只要能完成这一使命,E 的值就无需最终保留在某个临时单元中。因此,作为转移条件的布尔式 E,我们可以赋予它两种“出口”。一个是“真”出口,出向S1;一个是“假”出口,出向S2。于是语句(7.10)可翻译成如图7.15所示的形式。 第七章 语义分析和中间代码产生
在这种翻译中,对于作为转移条件的布尔式,我们可以把它翻译成为一串跳转指令。在这种翻译中,对于作为转移条件的布尔式,我们可以把它翻译成为一串跳转指令。 在翻译过程中,我们假定可以用符号标号来标识一条三地址语句,并且假定每次调用函数newlabel后都返回一个新的符号标号。 对于一个布尔表达式E,我们引用两个标号:E.true是E为‘真’时的控制流转项的标号; E.false是E为‘假’时控制流转向的标号。 表7。7是按此方式将布尔表达式翻译成三地址代码的语义规则,应该掌握。 我们假设实现三地址代码时采用四元式形式实现,并且假定: (jnz , a ,-- , p ) 表示 if a goto p (jrop, x , y, p ) 表示 if x rop y goto p (j , --, --- , p ) 表示 goto p 课本P190讲的四元式链表翻译模式应该掌握。 第七章 语义分析和中间代码产生
M.q =104 M.q =102 a < b c < d e < f 100(j< , a , b , 0 ) 101 (j, _ , _ , 0 ) 102 102(j< , c , d , 0 ) 103 (j, _ , _ , 0 ) 104 104(j< , e , f , 0 ) 105 (j, _ , _ , 0 ) E.t={ 100,104 } E.f={ 103,105 } E.t={ 100 } E.f={ 101 } or E.t={ 104 } E.f={103,105 } E.t={ 102 } E.f={ 103 } and E.t={ 104 } E.f={ 105 } 关于a < b or c < d and e < f的翻译 第七章 语义分析和中间代码产生
7.5 控制语句的翻译 我们考虑文法: S→ if E then S1 | if E then S1 else S2 | while E do S1 其中E 布尔表达式。 与上一节一样,我们先讨论对这些语句进行翻译的一般语义规则。然后讨论如何通过一遍扫描产生上述语句的代码,给出相应的翻译模式。 第七章 语义分析和中间代码产生
条件语句S的语义规则允许控制从S 的代码S.code之内转移到紧接S.code之后的那条三地址指令。但是,有时候此条紧接S.code之后的指令是一条无条件转移指令,它转移到标号为L的指令。 属性S.next可以避免上述连续转移的发生,而从S.code之内直接转移到标号为L的指令。 S.next:的值是一个标号,指出继S 的代码之后将被执行的第一条三地址指令。 第七章 语义分析和中间代码产生
S→if E then S1的翻译 新标号E.true——标识S1的代码的第一条指令,如图7.17(a)所示。 • 表7.8给出了一个属性文法。E的代码中有这样的转移指令: 若E为真则转移到E.true, 若E为假则转移到S.next. 并置E.false为S.next. 第七章 语义分析和中间代码产生
if-then-else 语句的翻译 S→ if E then S1 else S2 布尔表达式E的代码中有这样的转移指令:若E为真则转移到S1的第一条指令, 若E为假则转移到S2的得一条指令。如图7.17(b)所示。 第七章 语义分析和中间代码产生
S→while E do S1的翻译 语句S→while E do S1 的结构图如7.17(c) 与上边两个语句相似, 不再重述。 第七章 语义分析和中间代码产生
100)第二次回填 a<b 102( j< , c , d , 0 ) 103 ( j , _ , _ , 0 ) c<d 100)第二次回填 104( + , y, z , T ) 105 ( := , T, _ , x ) x:= y + z while (a<b) do If (c<d) then x:= y + z ; ________________________ ⑤ 使用P195-196的翻译模式和回填技术通过一遍扫描翻译控制流语句的过程。(参看课本P194-196例7.6。) ① ________________________ ④ ② ③ 调用P190(5) E -> id1 relop id2 100( j< , a , b , 0 ) 101 ( j , _ , _ , 0 ) (5)M1.quad=100 104)第一次回填 (5)M2.quad=102 调用P171赋值 语句的语义规则 (4)M.quad=104 第七章 语义分析和中间代码产生
a<b 102( j< , c , d , 0 ) 103 ( j , _ , _ , 0 ) c<d 104( + , y, z , T ) 105 ( := , T, _ , x ) x:= y + z while (a<b) do If (c<d) then x:= y + z ; ________________________ ⑤ ① 使用P195-196的翻译模式和回填技术通过一遍扫描翻译控制流语句的过程。(参看课本P194-196例7.6。) ________________________ ④ ② ③ (5)M1.quad=100 调用P190(5) E -> id1 relop id2 102)第三次回填 100( j< , a , b , 100) 101 ( j , _ , _ , 0 ) 107)第四次回填 104)第一次回填 100)第二次回填 调用P171赋值 语句的语义规则 106( j , _, _ ,100 ) 接着:调用(9) L ->S 的语义规则 第七章 语义分析和中间代码产生 最后:调用(8) L -> L1;M S (8)的语义规则,注意这时M.quad=107
[例7.3] 写出条件语句 IF a > 0 THEN x:= x+1 ELSE x:=4*( x- 1) 四元式序列 解: 100 ( j > , a , 0 , 102) 101 ( j , , , 105) 102 (+, x , 1 , T1 ) 103 ( := , T1, , T2) 104 ( j , , , 108) 105 ( - , x , 1 , T3 ) 106 (* , 4 , T3 , T4 ) 107 ( := , T4 , , x ) 108 第七章 语义分析和中间代码产生
练习:将下列语句翻译成四元式序列。 : While (a > b) do if(c>d)then x:=y * z else x:=y+z • 100 ( j>,a,b,0 ) • 101 ( j,-,-,0 ) • ( j<,c,d,0 • ( j,-,-,0 ) • ( *,y,z,T1) • ( :=,T1,-,×) • ( j,-,-,0 ) • ( +,y,z,T2) • ( :=,T2,-,x) • ( j,-,-,0 ) • ( ) 102) 110) 104) 107) 109) 100) 第七章 语义分析和中间代码产生