第七章语义分析与中间代码生成

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
4
逆波兰表示法用不着使用括号, 逆波兰表示法用不着使用括号,根据运算量和算 符出现的先后位置, 符出现的先后位置,以及每个算符的目数就完全 决定一个表达式的分解。 决定一个表达式的分解。 例如: (a+b)*c将被表示成 例如: (a+b)*c将被表示成 ab+c* 所代表的表达式是a*(b+c) abc+* 所代表的表达式是a*(b+c) 所代表的表达式是(a+b)*(c+d) Ab+cd+* 所代表的表达式是(a+b)*(c+d) 把一般表达式翻译为后缀式是很容易的。 7.1给 把一般表达式翻译为后缀式是很容易的。表7.1给 出了把表达式翻译为后缀式的语义规则描述, 出了把表达式翻译为后缀式的语义规则描述,其 E.code表示 后缀形式,op表示任意二元操作符 表示E 中E.code表示E后缀形式,op表示任意二元操作符 ||”表示后缀形式的连接。 ,“||”表示后缀形式的连接。 产生式 E→E1 op E2 E →(E1) E → id 语义规则 E.code:=E1.code||E2.code||op E.code:=E1.code E.code:=id
语法分析器 静态检查器 中间代码产生器 代码 语法分析器
中间
图7.1静态检查和中间代码产生的地位
2
7.1中间语言 7.1中间语言
在6.2.4节中介绍了抽象语法树,它是源 6.2.4节中介绍了抽象语法树, 节中介绍了抽象语法树 程序的中间表示方法之一。 程序的中间表示方法之一。在此将介绍其 它几种常见的中间语言形式。 它几种常见的中间语言形式。 常见的中间语言有:后缀式( 常见的中间语言有:后缀式(逆波兰表示 ),树型表示 三元式和四元式等。 树型表示, 法),树型表示,三元式和四元式等。
E → E1 * E2
E.place := newtemp; E.code := E1.code || E2.code ||
gen(Байду номын сангаас.place':='E1.place'*'E2.plac
13
E → - E1
E.place := newtemp; E.code := E1.code || gen(E.place':=0-'E1
表中的@表示求负运算符。 表中的@表示求负运算符。 凡只需一个运算符的算符一律规定使用ARG1 凡只需一个运算符的算符一律规定使用ARG1
16
2.三元式
为了避免把临时变量填入到符号表, 为了避免把临时变量填入到符号表,三元 式是由算符OP,两个操作数域ARG1 ARG2组 OP,两个操作数域ARG1和 式是由算符OP,两个操作数域ARG1和ARG2组 成。两操作数域或者是指向符号表的指针 或者是指向三元式表的指针。 ,或者是指向三元式表的指针。
12
表7.3 对赋值语句产生三地址代码的属性文法 S → id := E E → E1 + E2
S.code := E.code || gen( id.place':='E.place E.place := newtemp; E.code := E1.code || E2.code || gen(E.place':='E1.place'+'E2
8
之所以称为三地址代码是因为每条语句通常包含 三个地址,两个用来表示操作数, 三个地址,两个用来表示操作数,一个用来存放 结果。对于后面给出的三地址代码中, 结果。对于后面给出的三地址代码中,用户定义 的名字在实际实现时将由指乡符号表中的相应名 字入口的指针所代替。 字入口的指针所代替。 常用的三地址语句种类 1)x := y op z 2)x := op y 3)x := y 4)if x relop y goto l 双目运算 单目运算 赋值 条件转移
第七章 语义分析和中间代码产生
紧接在词法分析和语法分析之后,编译程序 要做的工作就是进行静态语义检查和翻译。 静态语义检查通常包括: 1)类型检查 2)控制流检查 3)一致性检查 4)相关名字检查 其它如名字的作用域分析等也都是静态语义 分析的工作。
1
虽然源程序可以直接翻译为目标语言代码,但是许 多编译程序却采用了独立于机器的、复杂性介于源 语言和机器语言之间的中间语言。这样的好处是: 1)便于进行与机器无关的代码优化工作; 2)使编译程序改变目标机更容易; 3)使编译程序的结构在逻辑上更为简单明确。以 中间语言为界面,编译前端和后端的接口更清晰。 静态语义检查和中间代码产生在编译程序中的地位 如图7.1 如图7.1
5
逆波兰表示法中栈的使用
后缀式的计值用栈实现非常方便,一般 后缀式的计值用栈实现非常方便, 的计值过程是:自左至右扫描后缀式, 的计值过程是:自左至右扫描后缀式,每 碰到运算量就把它推进栈,每碰到K 碰到运算量就把它推进栈,每碰到K目算 符就把它作用于栈顶部的k个项, 符就把它作用于栈顶部的k个项,并用运 算的结果来代替这k个项( 算的结果来代替这k个项(运算的结果仅 有一项)。 有一项)。
11
表7.3是为赋值语句生成三地址代码的S-属性文法 7.3是为赋值语句生成三地址代码的 是为赋值语句生成三地址代码的S 定义。如给定输入a:=b*-c+b*- 非终结符号S 定义。如给定输入a:=b*-c+b*-c。非终结符号S 有综合属性S.code,它代表赋值语句S 有综合属性S.code,它代表赋值语句S的三地址 代码。非终结符号E有如下两个属性: 代码。非终结符号E有如下两个属性: 1)E.place表示存放E值的名字; E.place表示存放 值的名字; 表示存放E 2)E.code表示对E求值的三地址语句序列。 E.code表示对 求值的三地址语句序列。 表示对E 函数newtemp的功能是 每次调用它时, 的功能是, 函数newtemp的功能是,每次调用它时,将返回 一个不同临时变量名字, T1,T2, 一个不同临时变量名字,如T1,T2,…。 为方便,使用gen(x’:=‘y’+’z)表示生成三地址语 为方便,使用gen(x’:=‘y’+’z)表示生成三地址语 X:=y+z。代替x,y或 句X:=y+z。代替x,y或z出现的表达式在传递给 gen时求值,用单引号括起来的运算符或操作数 gen时求值 时求值, 将保留引号里字面的符号。在实际实现中, 将保留引号里字面的符号。在实际实现中,三地 址语句序列往往是被存放到一个输出文件中, 址语句序列往往是被存放到一个输出文件中,而 不是将三地址语句序列置入code属性之中 属性之中。 不是将三地址语句序列置入code属性之中。
表达式的三元式: 表达式的三元式:w*x+(y+z) (1) *, w, x (2) +, y, z (3) +, (1), (2) 第三个三元 式中的操作数(1) 式中的操作数 (2)表示第 和第 表示第(1)和第 表示第 (2)条三元式的计 条三元式的计 算结果。 算结果。
6
7.1.2图表示法 图表示法
图表示法包括DAG与抽象语法树 图表示法包括DAG与抽象语法树 无循环有向图DAG:与抽象语法树一样, 无循环有向图DAG:与抽象语法树一样, 对表达式中的每个子表达式,DAG中都有 对表达式中的每个子表达式,DAG中都有 一个结点。 一个结点。一个内部结点代表一个操作符 它的孩子代表操作数。 ,它的孩子代表操作数。 不同点: DAG中代表公共子表达式的结 不同点:在DAG中代表公共子表达式的结 点具有多个父结点, 点具有多个父结点,而在一棵抽象语法树 中公共子表达式被表示为重复的子树。 中公共子表达式被表示为重复的子树。 可见P167 可见P167
E → ( E1 ) E → id E → num
E.place:= E1.place; E.code:= E1.code E.place:= id.place; E.code:= ' ' E.place:= num.val;E.code:= ' ' ;
注释: || 表示代码序列的连接 注释:
14
三地址语句可看成中间代码的一种抽象形 通常有三种表示方法:四元式、 式。通常有三种表示方法:四元式、三元 间接三元式。 式、间接三元式。 1.四元式 1.四元式 四元式是一种比较普遍采用的中间代码形 四元式的四个组成部分是:算符OP, OP,第 式.四元式的四个组成部分是:算符OP,第 一运算量ARG1,第二运算量ARG2 ARG1,第二运算量ARG2以及运算结 一运算量ARG1,第二运算量ARG2以及运算结 RESULT.其中 其中, 果RESULT.其中,运算量和运算结果有时指 用户自定义的变量, 用户自定义的变量,有时指编译程序引进 的临时变量。 的临时变量。 如果OP是一个算术或逻辑算符, OP是一个算术或逻辑算符 如果OP是一个算术或逻辑算符,则RESULT 总是一个新引进的临时变量, 总是一个新引进的临时变量,它用来存放 运算结果。 运算结果。
15
例如:赋值语句A:=-B*(C+D)的四元式表示。 A:=例如:赋值语句A:= B*(C+D)的四元式表示。 的四元式表示
OP ARG1 ARG2 (1) @ (2) + (3) * (4) := B C T1 T3 — D T2 — RESULT T1 T2 T3 A 注解 T1为临时变量 T2为临时变量 T3为临时变量 赋值运算
7
7.1.3三地址代码 三地址代码
一般形式 x := y op z 其中 x, y, z 为变量名、常数或编译产生的 为变量名、 临时变量; 临时变量; Op代表运算符号如定点运算符、浮点运算符、 Op代表运算符号如定点运算符、浮点运算符、 代表运算符号如定点运算符 逻辑运算符等等。 逻辑运算符等等。 每个语句的右边只能有一个运算符。例如,源 每个语句的右边只能有一个运算符。例如, 语言表达式x+y*z可被翻译为如下语句序列: x+y*z可被翻译为如下语句序列 语言表达式x+y*z可被翻译为如下语句序列: T1:=y*z T2:=x+T1 其中T1 T2为编译时产生的临时变量。 其中T1,T2为编译时产生的临时变量。 T1, 为编译时产生的临时变量
9
其他三地址种类
goto l param x (n是参数个数 是参数个数) call p, n (n是参数个数) return x x := y[i] x[i] := y x := &y x := *y *x = y 无条件转移 实在参数 过程调用 过程返回 数组运算 指针运算
10
生成三地址代码时,临时变量的名字对应抽 生成三地址代码时, 象语法树的内部结点。对于产生式E 象语法树的内部结点。对于产生式E →E1+E2的左端的非终结符号 而言, →E1+E2的左端的非终结符号E而言,它的 的左端的非终结符号E 经过计算得出的值往往放到一个新的临时变 量T中。 赋值语句id:=E的三地址代码包括 的三地址代码包括: 赋值语句id:=E的三地址代码包括:对表达 求值并置于变量T 式E求值并置于变量T中,然后进行赋值 id.place:=T。 id.place:=T。如果一个表达式仅有一个单个 标示符,例如y,则由 自身保留表达式的值。 则由y 标示符,例如y,则由y自身保留表达式的值。
3
7.1.1逆波兰表示法 7.1.1逆波兰表示法
逆波兰表示法是把运算量(操作数)写在前面, 逆波兰表示法是把运算量(操作数)写在前面, 把算符写在后面(后缀),也称后缀表示法。 ),也称后缀表示法 把算符写在后面(后缀),也称后缀表示法。 例如:a+b写成 写成ab+, a*b写成 写成ab* .用这种办法表 例如:a+b写成ab+, a*b写成ab* .用这种办法表 示的表达式称为后缀式。 示的表达式称为后缀式。 一个表达式E的后缀形式定义: 一个表达式E的后缀形式定义: 1)如果E是一个变量或常量,则E的后缀式是E自 如果E是一个变量或常量, 的后缀式是E 身。 2)如果E是E1 op E2形式的表达式,这里op是任 如果E E2形式的表达式 这里op是任 形式的表达式, 何二元操作符, 的后缀式为E1’E2’op 何二元操作符,则E的后缀式为E1’E2’op ,这里 E’和E2’分别为E1和E2的后缀式。 E’和E2’分别为 和E2的后缀式 分别为E1 的后缀式。 3)如果E是(E1)形式的表达式,则E1的后缀式 如果E E1)形式的表达式, E1的后缀式 就是E的后缀式。 就是E的后缀式。
相关文档
最新文档