当前位置:文档之家› 第11章 语义分析和中间代码生成

第11章 语义分析和中间代码生成


13. E5 → E3 + E4 E5.PLACE = newtemp() = T2 emit (T2, =, c , +, d) 15. E6 → (E5) E6.PLACE = E5.PLACE = T2 16. E7 → E2 * E6 E7.PLACE = newtemp() = T3 emit (T3, =, T1 , * , T2 ,) 17. A → i := E7 emit (a, = , T3)
(5) T → integer { } {
T.TYPE=integer; T.WIDTH=4; T.TYPE=real; T.WIDTH=8;
(6) T → real
}
五、赋值语句的翻译
赋值语句实例: abc:=1; a:=1+2; b:=a+b*c; 赋值语句的文法表示: A → i := E E→i E → - E1 E →(E1) E→E1 op E2 …
例子:a:=-b*(c+d)的语法分析
步骤 0 1 2 3 4 5 6 7 8 符号栈 i i := i := i := - i i := - E1 i := E2 i := E2 * i := E2 * ( 归约步骤 源程序 a := - b * ( c + d ) := - b * ( c + d ) -b*(c+d) b*(c+d) *(c+d) *(c+d) *(c+d) (c+d) c+d)
(4) newtemp() 生成一个新的临时变量,返回其整数编码。 (5) entry(i) 在符号表中查找符号 i ,如果存在,则返回它 在符号表中的位置。 (6) emit (x = y op z) 生成一个新的三地址语句,添加到中间代码 表的结尾。(注:指针ip指向中间代码表的结 尾,emit将新的三地址语句添加到ip指向的位 置,然后ip自动加1,指向新的结尾。)
语义子程序实例
(1) E → E1 + E2 { E.VAL := E1.VAL + E2.VAL } (2) E → i { E.VAL := i.VAL }
分析输入串“i+i‖时,语义分析与语法分 析同步进行。由语法分析判断输入串 “i+i‖是否合法,由语义分析计算“i+i‖ 的值。
yacc中的语义子程序
语义子程序
A → i := E { P=entry(); if(P!=0) emit (P = E.PLACE); else error(); } E → i { P=entry(); if(P!=0) E.PLACE=P; else error(); }
E → - E1 { E.PLACE=newtemp(); emit (E.PLACE = - E1.PLACE); } E →(E1) { E.PLACE = E1. PLACE } E→E1 op E2 { E.PLACE=newtemp(); emit(E.PLACE = E1.PLACE op E2.PLACE); }
归约时(ZXY),语义值保存到新符号(Z)中:

状态栈 Z.XXX 语义栈
Z
符号栈
可见:在每一次归约时,都必须保存符号的语义值。
4. 语义动作和语义子程序
每当用一个产生式进行匹配或归约时,需要 执行相应的动作对语义值进行操作,这些动 作称为语义动作。 每个产生式对应一个语义子程序,负责完成 相应的语义动作。 每当用一个产生式进行匹配或归约时,相应 的语义子编号 名字 … … … a b … … … … 地址 … … 1000 1004
13
14 …
c
d …

… …
1008
1012 …
代码
数据
语法制导翻译
随着语法分析的进行,语义子程序依次被调 用,逐步生成中间代码(和相关数据)。语 法分析完成时,也就获得了完整的与源代码 等价的中间代码。 在语法分析的过程中,由各个产生式对应的 语义子程序对源代码进行翻译(生成中间代 码)的方法称为语法制导翻译。
中间代码有不同的表现形式(如三地址代码、 四元式、后缀式、语法树等),本课程采用 三地址代码的形式。 三地址代码常用的语句形式有以下几类:
(其中,op为一元或二元运算符,rop为关系
运算符,x、y、z为操作数。)
常用的三地址语句形式
(1) x = y op z (二元运算) (2) x = op y(一元运算) (3) x = y(赋值) (4) goto x(无条件转移) (5) if x goto y(条件转移) (6) if x rop y goto z(条件转移)
2. 语义分析和语法分析的关系
语法分析只能判断一个句子是否合法,不能给出句 子的含义。句子的含义是通过语义分析体现出来的。 例:一个计算程序对表达式“i+i‖的分析过程。 表达式文法G(E) : E→E+E|E–E|E*E|E/E E→i
仅执行语法分析
#
i # E #
+ E #
i + E #
E + E #
1. goto语句的翻译
goto语句实例: goto L; goto L1; goto L2; goto语句的文法表示: S → goto lable 根据标号lable是否已定义,分为两种情况:
(1) lable已定义
… L: // 将L加入符号表,定义否为“已”,地 址为其后第一个三地址语句的地址。 … goto L; // 查符号表,取出L的地址xxx,生成三 地址语句 goto xxx。 … goto L; // 同上 …
三、语义变量和语义函数
语义子程序中常用到的变量和函数: (1) 表示符号 i 对应的变量的名称。 (2) E.PLACE 表示符号E对应的变量在符号表中的位置(普 通变量)或整数编码(临时变量)。 (3) enter(NAME, TYPE, OFFSET) 将一个新的符号加入符号表。
E1 → i E2 → - E1
9 10 11 12 13 14 15 16 17 18
i := E2 * ( i i := E2 * ( E3 i := E2 * ( E3 + i := E2 * ( E3 + i i := E2 * ( E3 + E4 i := E2 * ( E5 i := E2 * ( E5 ) i := E2 * E6 i := E7 A
中间代码实例
源语句 a: = - b * c + d 对应的中间代码为 (1) t1 = - b (2) t2 = t1 * c (3) t3 = t2 + d (4) a = t3 注意:语义分析不仅要生成中间代码,还需 要生成相关的数据(存放在相应的表格中)。
语义分析的结果
中间代码表
编号 三地址语句 … … 100 101 102 103 … … … t1 = - b t2 = t1 * c t3 = t2 + d a = t3 … … … 11 12
语义栈
移进时(C、D),语义值同步入栈:
状态栈 D C X 符号栈 D.XXX C.XXX X.XXX 语义栈
归约时(YCD),语义值保存到新符号(Y)中:
状态栈 Y X 符号栈 Y.XXX X.XXX 语义栈
中间代码表
编号 三地址语句 … 100 ip → 101 … T1 = - b T2 = c + d T3 = T1 * T2 a = T3
102 103 104
六、控制语句的翻译
语句级控制结构是语言用来构造各种语句执 行顺序的机制。 传统语言有3种语句级控制结构: 1. 顺序 2. 选择 3. 重复
符号表
名字 类型

定义否 地址
… L
… … …
标号 已
… 108
三地址语句 … (n) goto 108 …
(2) lable未定义
… goto L; // 生成三地址语句 goto 0,将L加入符号表, 类型为“标号”,定义否为“未”,地址为本三地址语句的 地址。 … goto L; // 生成三地址语句 goto ?,与符号表中L的地 址组成一个链表(“拉链”),更新L的地址为本三地址语 句(链首)的地址。 … goto L; // 同上 … … L: // ―回填”三地址语句链表,更新符号表中L的 地址,定义否改为“已” 。 …
E3 → i
E4 → i E5 → E3 + E4 E6 → (E5) E7 → E2 * E6 A → i := E7
+d) +d) d) ) ) )
例子:a:=-b*(c+d)的翻译
4. E1 → i 中间代码表 E1.PLACE = entry() = b 编号 三地址语句 5. E2 → - E1 … … E2.PLACE = newtemp() = T1 ip → 100 T1 = - b emit ( T1, =, -,b) 101 9. E3 → i E3.PLACE = entry() = c 12. E4 → i E4.PLACE = entry() = d
实例分析:
main1.c + lex3.l + yacc5.y
二、中间代码
编译程序的任务是将源程序翻译成目标程序。 因此,编译程序的语义分析不仅要操作各符 号的语义值,还需要完成源程序中各个语句 的翻译,将源代码翻译成目标代码。 通常情况下,由于通用性和优化的考虑,语 义分析生成的目标代码并不是最终的与硬件 相关的汇编代码或机器代码,而是某种特定 形式的中间代码。
E #
分析结果:“i+i‖是一个合法的表达式
结合了语义分析的语法分析
相关主题