510 likes | 689 Views
第六章 语义分析和语法制导翻译. 语义分析的任务:检查语义错误 类型检查: 运算数类型 一致性检查: 名字声明与引用 控制流检查: 转移目标 名字检查: 作用域 翻译的任务:建立等价的目标程序 生成中间语言的指令序列 名字绑定: 变量名、过程名 建立运行环境. 6.1 属性文法. 语义分析与语法制导翻译的描述方法 属性文法的定义: A=(G,V,F) G 是上下文无关文法 V 属性的有穷集 F 关于属性的断言和谓词. 用法. 针对语义,为文法符号设置属性 终结符使用单词的属性 为每个产生式设置语义规则 通过描述各属性的关系
E N D
第六章 语义分析和语法制导翻译 • 语义分析的任务:检查语义错误 • 类型检查: 运算数类型 • 一致性检查: 名字声明与引用 • 控制流检查: 转移目标 • 名字检查: 作用域 • 翻译的任务:建立等价的目标程序 • 生成中间语言的指令序列 • 名字绑定: 变量名、过程名 • 建立运行环境
6.1 属性文法 语义分析与语法制导翻译的描述方法 • 属性文法的定义: • A=(G,V,F) • G 是上下文无关文法 • V 属性的有穷集 • F 关于属性的断言和谓词
用法 • 针对语义,为文法符号设置属性 • 终结符使用单词的属性 • 为每个产生式设置语义规则 • 通过描述各属性的关系 • 将语义分析和翻译步骤定义为产生式的断言和谓词
例6-1: 计算器的算法设计 • 需求:算术表达式的求值 • 设计: • 编制算术表达式的文法 • 引入属性表示语义信息 • 将值 val 作为表达式 E、项 T 和因子 F 的属性 • 用语义规则描述表达式的求值
属性文法(语法制导定义) • attr 是单词 digit 的属性 • print( val ) 是输出函数
例6-2:说明语句的类型信息统计 • 说明语句的作用 • 支持语义分析,提供语义检查的依据 • 设计 • 编写说明语句的文法 • 将类型信息作为类型描述 T 的属性 type 和变量表 L 的属性 in。 • 目的 • 分析说明语句 D,获取变量的类型信息
描述类型信息提取的属性文法 • entry 单词 id 的属性(符号表入口) • addtype 在符号表中为变量填加类型信息
属性文法的作用 • 抽象描述语义处理的要求 • 语义信息及其计算关系 • 适用于各种语义处理(分析、翻译、计算) • 语义处理的步骤 • 属性求值计算、断言检查 • 语义处理算法的描述方法 • 一种通用的语义处理算法设计方法
属性分类: • 综合属性 • 从其子结点的属性值计算出来的; • 如:E.val、T.type • 继承属性 • 从其兄弟结点和父结点的属性值计算出来的 • 如:L.in • 固有属性(单词属性)
属性的计算 • 构造语法分析树,填加响应的语义规则 • 综合属性 • 自底向上按照语义规则来计算各结点的综合属性值 • 继承属性 • 需要探讨计算次序
例6-4:real id1,id2,id3 的分析树和属性计算 addtype addtype addtype
S-属性定义: • 仅包括综合属性 • 对于所有A → X1X2…Xn, • A的属性计算仅用X1…Xn的属性 • 如:算术表达式求值的属性文法
L-属性定义: • 其属性可用深度优先的顺序从左至右计算 • 对于所有 A→X1X2…Xn • Xi属性计算仅使用A X1X2…Xi-1的属性 • 如:说明语句的属性文法
翻译模式(Translation Schemes) • 特征 • 规定在语法分析中使用语义规则进行计算的次序 • 保证当动作使用某属性时,该属性必须是可用的 • 实现方法 • 将语义动作插入到产生式中的某个位置
例6-5:建立说明语句的翻译方案 • 将语义动作中的计算向前移,使继承属性的计算出现在其文法符号之前
翻译模式的设计 D → T { L.in := T.type } L T → int { T.type := integer } T → real { T.type := real } L → { L1.in := L.in } L1 , id { addtype(id.entry, L.in) } L → id { addtype(id.entry, L.in) }
习题 1. 下列文法是一个二进制数的文法。试根据该文法,编写一个语法制导定义,描述由 S 生成的二进制数的数值计算。 S -> L . L L -> L B | B B -> 0 | 1 2. 参照下列表达式文法编写语法制导定义,描述表达式的类型计算。要求在不同精度的数的计算中,结果取精度高的类型。 E -> E + T | T T -> n.n | n
6.2 中间语言 • 用于编译程序 • 源程序经过语义分析被译成中间代码序列 • (中间语言的语句) • 用中间语言过渡的好处: • 便于编译系统的实现、移植、代码优化
常用的中间语言 • 三地址代码(四元式) • 语法结构树(三元式) • 后缀式 特点 • 形式简单、语义明确、便于翻译 • 独立于目标语言
语法制导编译 描述方法 • 利用属性文法描述如何将各种语句和表达式翻译成中间代码 工作方式 • 分析与综合并行进行 • 每识别出一个语言结构时, • 完成相应的语义检查与中间代码生成
语法结构树 • 例 6-5:表达式 (A - 12) * B + 6 的语法结构树
将赋值语句变换为语法结构树 • 设置属性: • E.p 是语法结构树指针 • id.entry 是名字的表项入口 • num.val 是数值 • 树构造函数 • mknode 建中间结点 • mkleaf 建叶结点
例6-6:a := b * (- c) + b * (- 34) 的语法结构树 root := * - 0 id a id b id c + * - 0 id b num 34
地址 算符 操作数 操作数 0 1 2 3 4 5 6 7 8 9 10 语法结构树的三元式表示
三地址代码 一般形式 x := y op z • 其中 x, y, z 为变量名、常数或编译产生的临时变量 • 四元式(op, x, y, z) 种类:x := y op z 双目运算 x := op y 单目运算 x := y 赋值 if x relop y goto l 条件转移
其他三地址代码 goto l 无条件转移 param x 实在参数 call p, n (n是参数个数) 过程调用 return x 过程返回 x := y[i] 数组运算 x[i] := y x := &y 指针运算 x := *y *x = y
6.3赋值语句的翻译 翻译的需求 • 充分了解各种语言现象的语义 • 包括:控制结构、数据结构、单词 • 充分了解它们的实现方法 • 目标语言的语义 • 了解中间代码的语义 • 了解运行环境
实现赋值语句的翻译 语义过程 • 产生一条中间代码 gen(code) • 产生新的临时变量 newtemp 属性设置 • 中间代码序列 code • 存储位置 place
赋值语句的四元式翻译 S → id := E S.code := E.code || gen( id.place':='E.place ) E → E1 + E2 E.place := newtemp; E.code := E1.code || E2.code || gen(E.place':='E1.place'+'E2.place) E → E1 * E2 E.place := newtemp; E.code := E1.code || E2.code || gen(E.place':='E1.place'*'E2.place)
E → - E1 E.place := newtemp; E.code := E1.code || gen(E.place':=0-'E1.place) E → ( E1 ) E.place:= E1.place; E.code:= E1.code E → id E.place:= id.place; E.code:= ' ' E → num E.place:= num.val;E.code:= ' ' • 注释: || 表示代码序列的连接
结果:开始符号的属性 S.code • 1) 找出分析树中使用的产生式规则 • 2) 根据产生式的语义规则,代换公式中的各属性 • 3) 反复使用 1) 和 2) 改写公式,最后得到代码生成语句组成的公式 • 组成语句的翻译结果(中间代码序列)
中间代码的生成过程 S.code => E.code || gen( ‘a:=‘E.place ) /* ‘a’ => id.place */ => E1.code || E2.code || gen( ‘t1:=‘E1.place’+’E2.place ) || gen( ‘a:=t1’ ) /* newtemp => t1 => E.place */ => E11.code || gen( ‘t2:= 0 -’ E11.place ) /* newtemp => t2 => E1.place */
|| E21.code || E22.code || gen( ‘t3:=’ E21.place’*’E22.place ) /* newtemp => t3 => E2.place */ || gen( ‘t1:=t2+t3’ ) || gen( ‘a:=t1’ ) => gen( ‘t2:= 0 - c’ ) || gen( ‘t3:=b*34’ ) /* ‘c’ => E11.place */ /* ‘b’ => E21.place */ /* ‘34’ => E22.place */ || gen( ‘t1:=t2+t3’ ) || gen( ‘a:=t1’ ) /* ‘ ’ => E21.code => E22.code */
表达式翻译中的其他问题 • 运算类型检查 • 利用符号表保存的名字类型 • 类型自动转换 • 填加专用指令 • 临时变量空间的统计 • 了解需求、及时释放
6.4 控制结构的翻译 • 高级语言的控制结构 • 顺序 begin 语句; 语句 … end • 条件 if_then_else if_then switch case • 循环 while_do do_while for repeat_util • 三地址代码的控制结构 • goto l • if x relop y goto l
S1.code C.code C.true to C.true to C.false = S.next to S1.next = S.begin … S.next S.begin S → while C do S1 的翻译 • 属性设置 布尔式 C • 真出口 true • 假出口 false 语句 S • 入口 begin • 后续段入口 next S.code goto S.begin
S → while C do S1 代码生成的语义规则 C.false := S.next; C.true := newlabel; S.begin := S1.next := newlabel; S.code := gen( S.begin':' ) || C.code || gen( C.true':' ) || S1.code || gen( 'goto'S.begin ) 语义过程 • 新标号的产生 newlabel • 继承属性:C.true C.false S.next • 综合属性:S.code S.begin
C.code to C.true • to C.false S1.code S2.code C.true C.false to S1.next = S.next to S2.next = S.next … S.next S.begin S → if C then S1 else S2的翻译 goto S.next
S → if C then S1 else S2 代码生成的语义规则 C.true := newlabel; C.false := newlabel; S1.next := S2.next := S.next; S.code := C.code || gen( C.true':' ) || S1.code || gen( 'goto' S.next ) || gen( C.false':' ) || S2.code
简单布尔表达式的翻译 C → E1 relop E2 语义规则 C.code := E1.code || E2.code || gen( 'if' E1.place relop.op E2.place 'goto‘C.true ) || gen( 'goto‘C.false )
例 6-8:翻译下列语句 while a < b do if c < 5 then x := y else while x > y do z := x + 1;
C.code 生成的三地址代码序列 C1.code L1: if a < b goto L2 goto Lnext L2: if c < 5 goto L3 goto L4 L3: x := y goto L1 L4: L5: if x > y goto L6 goto L1 L6: t1 := x + 1 z := t1 goto L5 goto L1 Lnext: S11.code S1.code S12.code
控制结构翻译中的其他问题 • 分层结构的记录 • 涉及变量的作用域 • 转移目标的先引用后定义 • 使用回填技术 • 涉及循环语句、条件语句、转移标号
6.5 属性文法的实现 • 分析 • 属性属于文法符号 • 局限于产生式 • 递归子程序的改进 • 为每个文法符号设置结构或对象类 • 以每个属性为分量 • 每个函数设置一个结构(或对象类)指针
例 6-9:条件语句的翻译实现 • S 的结构 struct S_Attr { char pCode[MAX]; int iNext; }; • C 的结构 struct C_Attr { char pCode[MAX]; int iFalse; int iTrue; };
语句 S 的递归函数 void S( struct S_Attr *pS ) { if( lookhead == IF ) { struct C_Attr aC; struct S_Attr aS1; /* if C then S1 */ aC.iTrue = newLabel(); aS1.iNext = aC.iFalse = pS->iNext; match(IF); C( &aC ); match(THEN); S( &aS1 ); sprintf(pS->code, “%sL%d:\n%s\n”, aC.code, aC.iTrue, aS1.code); } … }
习题 1.把下列语句翻译成三地址代码 while a > 10 if b = 100 then while a < 20 do a := a + b - 1