第四章 语法制导翻译• 语义分析的任务 在词法分析和语法分析的基础上,分析所写源程序的含义,在理解含义的基础上为生成相应的目标代码作好准备或直接生成目标代码。 语义检查、语义处理 (1)语义检查 例:类型、运算、维数、越界 (2)语义处理 例:变量的存储分配 例:表达式的求值 例:语句的翻译(中间代码的生成)
第四章 语法制导翻译 • 本章内容
– 介绍一种形式化的语义描述方法: 语法制导翻译方法及其两种具体形式:( 1 )语法制导定义(语义的抽象说明)( 2 )翻译方案(语义规则的计算次序)– 介绍语法制导的翻译的实现方法。
属性 1 、定义:代表与文法符号 (Vt 或 Vn ) 相关的信息。属性可
以为任何特性。 例如:变量的类型、层次,存储地址;表达式类型,值;程序的目标代码等。 2 、属性值 : 与属性相关的信息,可以在语法分析过程中计算和传递。 3 、属性的表示: X. 属性值 产生式的左、右部有相同的符号时用下标或上标来区别。 例 E→E1+T { E.val:=E1.val+T.val}
属性 4 、属性加工的过程即语义的处理过程 5 、属性值分成不相交的两类: 综合属性 (synthesized attribute)
继承属性 (inherited attribute) 。 在语法树中, 一个结点的综合属性值由子结点的属性值来计算; 一个结点的继承属性值是由该结点兄弟结点和 / 或父结点的属性值来计算。
注意: 终结符只有综合属性,由词法分析程序提供; 非终结符既有综合属性和继承属性。
每个文法符号的继承属性和综合属性之交集为空集。
语义规则• 为文法的每一个规则配备的计算属性的计算规则,称为语义规则。
• 每个文法符号具有一组属性,文法的每一个产生式 A→β都有与其相关的语义规则的集合,每条语义规则的形式为:
b=f (c1, c2, …,ck)
• 通常,语义规则中的函数 f写成表达式的形式。有时,语法制导定义中的某些语义规则就是为了产生代码,这样的语义规则一般写成过程调用的形式。在这种情况下,可以把语义规则看成是定义相关非终结符的虚拟综合属性
属性文法• 对某上下文无关文法,当为每个文法符号引进一组属性,且让文法中的产生式规则附加对属性进行处理的语义规则时,称该文法为属性文法。
• 根据不同属性文法于法成分的语义,可以设计对不同语法成分进行翻译的属性文法。
• 属性文法形式为: 文法规则 (产生式 ) 语义规则 规则 1 相关的属性等式 ... ... 规则 n 相关的属性等式
4.1 语法制导的定义 例:简单算术表达式的语法制导定义 1.编制算术表达式的文法 2.引入属性表示语义信息 将值 val 作为表达式 E、项 T 和因子 F 的属性 3.用语义规则描述表达式的求值
4.1 语法制导的定义
• Val: 表示非终结符的整数值 , 综合属性• lexval 是单词 digit 的属性
产 生 式 语 义 规 则 L E print (E.val) E E1 + T E.val := E1 .val + T.val
E T E.val := T.val T T1 * F T.val := T1.val * F.val
T F T.val := F.val F (E) F.val := E.val F digit F.val := digit.lexval
4.1 语法制导的定义4.1.1 语法制导定义的形式• 基础文法• 每个文法符号有一组属性• 每个文法产生式 A 有一组形式为 b := f(c1,
c2, …, ck ) 的语义规则,其中 f 是函数, b 和c1, c2, …, ck 是该产生式文法符号的属性– 综合属性:如果 b 是 A 的属性, c1 , c2 , …, ck 是产
生式右部文法符号的属性或 A 的其它属性。– 继承属性:如果 b 是产生式右部某个文法符号 X
的属性。
4.1 语法制导的定义4.1.2 综合属性1 、 S 属性定义:仅仅使用综合属性的语法制导定义
产 生 式 语 义 规 则 L E print (E.val) E E1 + T E.val := E1 .val + T.val
E T E.val := T.val T T1 * F T.val := T1.val * F.val
T F T.val := F.val F (E) F.val := E.val F digit F.val := digit.lexval
4.1 语法制导的定义2 、注释分析树例: 8+5*2 的注释分析树
digit.lexval = 2
L
E.val = 18
T.val = 10E.val = 8
T.val = 8
F.val = 8
digit.lexval = 8
T.val = 5
+
*
F.val = 5
F.val = 2
digit.lexval = 5
4.1 语法制导的定义分析树各结点属性的计算可以自下而上地完成
digit.lexval = 2
L
E.val = 18 n
T.val = 10E.val = 8
T.val = 8
F.val = 8
digit.lexval = 8
T.val = 5
+
*
F.val = 5
F.val = 2
digit.lexval = 5
4.1 语法制导的定义分析树各结点属性的计算可以自下而上地完成
digit.lexval = 2
L
E.val = 18 n
T.val = 10E.val = 8
T.val = 8
F.val = 8
digit.lexval = 8
T.val = 5
+
*
F.val = 5
F.val = 2
digit.lexval = 5
4.1 语法制导的定义分析树各结点属性的计算可以自下而上地完成
digit.lexval = 2
L
E.val = 18 n
T.val = 10E.val = 8
T.val = 8
F.val = 8
digit.lexval = 8
T.val = 5
+
*
F.val = 5
F.val = 2
digit.lexval = 5
4.1 语法制导的定义分析树各结点属性的计算可以自下而上地完成
digit.lexval = 2
L
E.val = 18 n
T.val = 10E.val = 8
T.val = 8
F.val = 8
digit.lexval = 8
T.val = 5
+
*
F.val = 5
F.val = 2
digit.lexval = 5
4.1 语法制导的定义分析树各结点属性的计算可以自下而上地完成
digit.lexval = 2
L
E.val = 18 n
T.val = 10E.val = 8
T.val = 8
F.val = 8
digit.lexval = 8
T.val = 5
+
*
F.val = 5
F.val = 2
digit.lexval = 5
4.1 语法制导的定义分析树各结点属性的计算可以自下而上地完成
digit.lexval = 2
L
E.val = 18 n
T.val = 10E.val = 8
T.val = 8
F.val = 8
digit.lexval = 8
T.val = 5
+
*
F.val = 5
F.val = 2
digit.lexval = 5
4.1 语法制导的定义分析树各结点属性的计算可以自下而上地完成
digit.lexval = 2
L
E.val = 18 n
T.val = 10E.val = 8
T.val = 8
F.val = 8
digit.lexval = 8
T.val = 5
+
*
F.val = 5
F.val = 2
digit.lexval = 5
4.1 语法制导的定义分析树各结点属性的计算可以自下而上地完成
digit.lexval = 2
L
E.val = 18 n
T.val = 10E.val = 8
T.val = 8
F.val = 8
digit.lexval = 8
T.val = 5
+
*
F.val = 5
F.val = 2
digit.lexval = 5
4.1 语法制导的定义分析树各结点属性的计算可以自下而上地完成
digit.lexval = 2
L
E.val = 18 n
T.val = 10E.val = 8
T.val = 8
F.val = 8
digit.lexval = 8
T.val = 5
+
*
F.val = 5
F.val = 2
digit.lexval = 5
4.1 语法制导的定义分析树各结点属性的计算可以自下而上地完成
digit.lexval = 2
L
E.val = 18 n
T.val = 10E.val = 8
T.val = 8
F.val = 8
digit.lexval = 8
T.val = 5
+
*
F.val = 5
F.val = 2
digit.lexval = 5
4.1 语法制导的定义分析树各结点属性的计算可以自下而上地完成
digit.lexval = 2
L
E.val = 18 n
T.val = 10E.val = 8
T.val = 8
F.val = 8
digit.lexval = 8
T.val = 5
+
*
F.val = 5
F.val = 2
digit.lexval = 5
4.1 语法制导的定义注释分析树 : 结点的属性值都标注出来的分析
树
digit.lexval = 2
L
E.val = 18 n
T.val = 10E.val = 8
T.val = 8
F.val = 8
digit.lexval = 8
T.val = 5
+
*
F.val = 5
F.val = 2
digit.lexval = 5
4.1 语法制导的定义4.1.3 继承属性例 . 考虑下面类似 C语言中变量声明的简单文法:
D→T L T→ int |float L→L , id|id
产 生 式 语 义 规 则 D TL L.in := T.type
T int T. type := integer
T real T. type := real
L L1, id L1.in := L.in;
addtype (id.entry, L.in ) L id addtype (id.entry, L.in )
4.1 语法制导的定义int id1, id2, id3 的注释分析树
D
int
T.type = integer
, id3
L.in = integer
L.in = integer
L.in = integer id2
id1
,
4.1 语法制导的定义4.1.4 属性依赖图
int id1, id2, id3 的分析树的依赖图
D TL L.in := T.type
D
int
T
, id3
L
L
L id2
id1
,
1 entry
10 2 entry
3 entry
in 9
8in 7
6in 54 type
4.1 语法制导的定义4.1.4 属性依赖图
int id1, id2, id3 的分析树的依赖图L L1, id L1.in :=
L.in;
addtype (id.entry, L.in )
D
int
T
, id3
L
L
L id2
id1
,
1 entry
10 2 entry
3 entry
in 9
8in 7
6in 54 type
4.1 语法制导的定义4.1.5 属性计算次序拓扑排序:结点的一种排序,使得边只会从该次序中
先出现的结点到后出现的结点。例: 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10
D
int
T
, id3
L
L
L id2
id1
,
1 entry
10 2 entry
3 entry
in 9
8in 7
6in 54 type
4.1 语法制导的定义属性计算次序 构造输入的分析树
D
int
T
, id3
L
L
L id2
id1
,
1 entry
10 2 entry
3 entry
in 9
8in 7
6in 54 type
4.1 语法制导的定义属性计算次序 构造输入的分析树,构造属性依赖图
D
int
T
, id3
L
L
L id2
id1
,
1 entry
10 2 entry
3 entry
in 9
8in 7
6in 54 type
4.1 语法制导的定义属性计算次序 构造输入的分析树,构造属性依赖图,对结点进行拓
扑排序D
int
T
, id3
L
L
L id2
id1
,
1 entry
10 2 entry
3 entry
in 9
8in 7
6in 54 type
4.1 语法制导的定义属性计算次序 构造输入的分析树,构造属性依赖图,对结点进行拓
扑排序,按拓扑排序的次序计算属性。D
int
T
, id3
L
L
L id2
id1
,
1 entry
10 2 entry
3 entry
in 9
8in 7
6in 54 type
例 5 . 6 图 5 . 5的拓扑排序是:
1, 2, 3, 4, 5, 6, 7, 8, 9,10
a4:=real;
a5:=a4;
addtype(id3entry,a5);
a7:=a5;
addtype(id2entry,a7);
a9:=a7;
addtype(id1entry,a9);
◆语义规则的计算方法 1 .分析树法 : 输入串 分析树 依赖图 计算次序 2.基于规则的方法: 在构造编译器时,用 手工或专门的工具来分析语义规则 ,确定 属性值的计算顺序。 3. 忽略语义规则的方法:在分析过程中翻 译,那么计算顺序由分析方法来确定而 表面上与语义规则无关。实际上,限制 语法制导定义,使属性值的计算顺序能 和语法分析过程同步进行。
4.2 S 属性定义的自下而上计算 4.2.1 语法树• 语法树是分析树的浓缩表示:算符和关键字是作为
内部结点。 • 语法制导翻译可以基于分析树,也可以基于语法树• 单非产生式链消失• 语法树的例子:
if-then-else
B S1S2
+
*
25
8
4.2 S 属性定义的自下而上计算4.2.2 构造语法树的语法制导定义
产 生 式 语 义 规 则 E E1 + T E.nptr := mknode( ‘+’, E1.nptr, T.nptr)
E T E.nptr := T.nptr
T T1*F T.nptr := mknode( ‘*’, T1.nptr, F.nptr)
T F T.nptr := F.nptr
F (E) F.nptr := E.nptr
F id F.nptr := mkleaf (id, id.entry)
F num F.nptr := mkleaf (num, num.val)
4.2 S 属性定义的自下而上计算a+5*b 的语法树的构造
E.nptr
T.nptrE.nptr
T.nptr
F.nptr
id
T.nptr
+
*
F.nptr
F.nptr
id
num
id idnum 5
*
+
指向符号表中 a 的入口
指向符号表中 b 的入口
4.2 S 属性定义的自下而上计算a+5*b 的语法树的构造
E.nptr
T.nptrE.nptr
T.nptr
F.nptr
id
T.nptr
+
*
F.nptr
F.nptr
id
num
id idnum 5
*
+
指向符号表中 a 的入口
指向符号表中 b 的入口
4.2 S 属性定义的自下而上计算a+5*b 的语法树的构造
E.nptr
T.nptrE.nptr
T.nptr
F.nptr
id
T.nptr
+
*
F.nptr
F.nptr
id
num
id idnum 5
*
+
指向符号表中 a 的入口
指向符号表中 b 的入口
4.2 S 属性定义的自下而上计算a+5*b 的语法树的构造
E.nptr
T.nptrE.nptr
T.nptr
F.nptr
id
T.nptr
+
*
F.nptr
F.nptr
id
num
id idnum 5
*
+
指向符号表中 a 的入口
指向符号表中 b 的入口
4.2 S 属性定义的自下而上计算a+5*b 的语法树的构造
E.nptr
T.nptrE.nptr
T.nptr
F.nptr
id
T.nptr
+
*
F.nptr
F.nptr
id
num
id idnum 5
*
+
指向符号表中 a 的入口
指向符号表中 b 的入口
4.2 S 属性定义的自下而上计算a+5*b 的语法树的构造
E.nptr
T.nptrE.nptr
T.nptr
F.nptr
id
T.nptr
+
*
F.nptr
F.nptr
id
num
id idnum 5
*
+
指向符号表中 a 的入口
指向符号表中 b 的入口
4.2 S 属性定义的自下而上计算a+5*b 的语法树的构造
E.nptr
T.nptrE.nptr
T.nptr
F.nptr
id
T.nptr
+
*
F.nptr
F.nptr
id
num
id idnum 5
*
+
指向符号表中 a 的入口
指向符号表中 b 的入口
4.2 S 属性定义的自下而上计算a+5*b 的语法树的构造
E.nptr
T.nptrE.nptr
T.nptr
F.nptr
id
T.nptr
+
*
F.nptr
F.nptr
id
num
id idnum 5
*
+
指向符号表中 a 的入口
指向符号表中 b 的入口
4.2 S 属性定义的自下而上计算a+5*b 的语法树的构造
E.nptr
T.nptrE.nptr
T.nptr
F.nptr
id
T.nptr
+
*
F.nptr
F.nptr
id
num
id idnum 5
*
+
指向符号表中 a 的入口
指向符号表中 b 的入口
4.2 S 属性定义的自下而上计算4.2.3 S 属性的自下而上计算
将 LR 分析器增加一个域来保存综合属性值。
. . . . . .
Z Z. z
Y Y. y
X X.x
. . . . . .
栈 state val
top
4.2 S 属性定义的自下而上计算4.2.3 S 属性的自下而上计算
将 LR 分析器增加一个域来保存综合属性值。
. . . . . .
Z Z. z
Y Y. y
X X.x
. . . . . .
栈 state val
top若产生式 A →XYZ 的语义规则是A.a := f (X.x, Y.y, Z.z)
4.2 S 属性定义的自下而上计算4.2.3 S 属性的自下而上计算
将 LR 分析器增加一个域来保存综合属性值。
. . . . . .
Z Z. z
Y Y. y
X X.x
. . . . . .
栈 state val
top若产生式 A →XYZ 的语义规则是A.a := f (X.x, Y.y, Z.z) ,那么归约后:
. . . . . .
A A.a
. . . . . .
top
4.2 S 属性定义的自下而上计算台式计算器的语法制导定义改成栈操作代码
. . . . . .
Z Z. z
Y Y. y
X X.x
. . . . . .
栈 state val
top
产 生 式 语 义 规 则 L E n print (E.val) E E1 + T E.val :=E1 .val +T.val
E T E.val := T.val T T1 * F T.val := T1.val * F.val
T F T.val := F.val F (E) F.val := E.val F digit F.val := digit.lexval
4.2 S 属性定义的自下而上计算台式计算器的语法制导定义改成栈操作代码
. . . . . .
Z Z. z
Y Y. y
X X.x
. . . . . .
栈 state val
top
产 生 式 代 码 段 L E n print (E.val) E E1 + T E.val :=E1 .val +T.val
E T E.val := T.val T T1 * F T.val := T1.val * F.val
T F T.val := F.val F (E) F.val := E.val F digit F.val := digit.lexval
4.2 S 属性定义的自下而上计算台式计算器的语法制导定义改成栈操作代码
. . . . . .
Z Z. z
Y Y. y
X X.x
. . . . . .
栈 state val
top
产 生 式 代 码 段 L E n print (val [ top1] ) E E1 + T E.val :=E1 .val +T.val
E T E.val := T.val T T1 * F T.val := T1.val * F.val
T F T.val := F.val F (E) F.val := E.val F digit F.val := digit.lexval
4.2 S 属性定义的自下而上计算台式计算器的语法制导定义改成栈操作代码
. . . . . .
Z Z. z
Y Y. y
X X.x
. . . . . .
栈 state val
top
产 生 式 代 码 段 L E n print (val [ top1] ) E E1 + T val [top 2 ] :=
val [top 2]+val [top] E T E.val := T.val T T1 * F T.val := T1.val * F.val
T F T.val := F.val F (E) F.val := E.val F digit F.val := digit.lexval
4.2 S 属性定义的自下而上计算台式计算器的语法制导定义改成栈操作代码
. . . . . .
Z Z. z
Y Y. y
X X.x
. . . . . .
栈 state val
top
产 生 式 代 码 段 L E n print (val [ top1] ) E E1 + T val [top 2 ] :=
val [top 2]+val [top] E T T T1 * F T.val := T1.val * F.val
T F T.val := F.val F (E) F.val := E.val F digit F.val := digit.lexval
4.2 S 属性定义的自下而上计算台式计算器的语法制导定义改成栈操作代码
. . . . . .
Z Z. z
Y Y. y
X X.x
. . . . . .
栈 state val
top
产 生 式 代 码 段 L E n print (val [ top1] ) E E1 + T val [top 2 ] :=
val [top 2]+val [top] E T T T1 * F val [top 2 ] :=
val [top 2]val [top] T F T.val := F.val F (E) F.val := E.val F digit F.val := digit.lexval
4.2 S 属性定义的自下而上计算台式计算器的语法制导定义改成栈操作代码
. . . . . .
Z Z. z
Y Y. y
X X.x
. . . . . .
栈 state val
top
产 生 式 代 码 段 L E n print (val [ top1] ) E E1 + T val [top 2 ] :=
val [top 2]+val [top] E T T T1 * F val [top 2 ] :=
val [top 2]val [top] T F F (E) F.val := E.val F digit F.val := digit.lexval
4.2 S 属性定义的自下而上计算台式计算器的语法制导定义改成栈操作代码
. . . . . .
Z Z. z
Y Y. y
X X.x
. . . . . .
栈 state val
top
产 生 式 代 码 段 L E n print (val [ top1] ) E E1 + T val [top 2 ] :=
val [top 2]+val [top] E T T T1 * F val [top 2 ] :=
val [top 2]val [top] T F F (E) val [top 2 ] :=
val [top 1] F digit F.val := digit.lexval
4.2 S 属性定义的自下而上计算台式计算器的语法制导定义改成栈操作代码
. . . . . .
Z Z. z
Y Y. y
X X.x
. . . . . .
栈 state val
top
产 生 式 代 码 段 L E n print (val [ top1] ) E E1 + T val [top 2 ] :=
val [top 2]+val [top] E T T T1 * F val [top 2 ] :=
val [top 2]val [top] T F F (E) val [top 2 ] :=
val [top 1] F digit
翻译输入 3*5+4n所做的移动
输入 state val 使用的产生式3*5+4n - -
*5+4n 3 3
*5+4n F 3 Fdigit
*5+4n T 3 TF
5+4n T* 3-
+4n T* 5 3-5
+4n T* F 3-5 F digit
+4n T 15 T T*F
+4n E 15 E T
4n E+ 15-
n E+4 15-4
n E+F 15-4 F digit
n E+T 15-4 T F
n E 19 E E+T
En 19 -
L 19 L En
总结:
采用自底向上分析,例如 LR分析,首先给出 S-属性定义,然后,把 S-属性定义变成可执行的代码段,这就构成了翻译程序。象一座建筑,语法分析是构架,归约处有一个“挂钩”,语义分析和翻译的代码段(语义子程序)就挂在这个钩子上。这样,随着语法分析的进行,归约前调用相应的语义子程序 ,完成翻译的任务。
4.3 L 属性定义的自上而下计算
边分析边翻译的方式能否用于继承属性?
• 属性的计算次序一定受分析方法所限定的分析树结点建立次序的限制。
4.3 L 属性定义的自上而下计算
边分析边翻译的方式能否用于继承属性?
• 属性的计算次序一定受分析方法所限定的分析树结点建立次序的限制。
• 分析树的结点是自左向右生成。
4.3 L 属性定义的自上而下计算
边分析边翻译的方式能否用于继承属性?
• 当翻译在分析时发生,属性的计算次序一定受分析方法所限定的分析树结点建立次序的限制。
• 分析树的结点是自左向右生成。• 如果属性信息是自左向右流动,那么就有可能在分
析的同时完成属性计算。
4.3 L 属性定义的自上而下计算
语法制导定义的分类:• S_ 属性定义:所有的文法符号的属性都是综合属性。
– 实际上是说:对于所有A → X 1 X 2 … X n ,A的属性计算仅用X 1… X n 的属性
• L_ 属性定义:如果每个产生式规则 U→X1X2…Xn 对应的语义规则中的每个属性:– 或者是综合属性,– 或者是这样的继承属性:
• Xj.a 或者仅仅依赖于 U 。
• Xj.a 依赖于 Xj 左边的符号的属性。• S_ 属性定义也是 L_ 属性定义。
L-属性定义
在语法分析过程中进行语义分析和翻译,属 性的计算顺序受到语法分析建立分析树结点顺序的限制。
一种自然的计算属性的顺序是按深度优先
访问分析树结点的顺序,它适应多种自底向上
和自顶向下的翻译方法。
L-属性定义 可用于按深度优先顺序计算属性值。
◆深度优先顺序计算属性
PROCEDURE dfvisit(n:node); BEGIN FOR n 的每个子结点 m,从左至右 DO BEGIN 计算 m的继承属性; dfvisit(m) END; 计算 n的综合属性 END;
4.3 L 属性定义的自上而下计算
变量类型声明的语法制导定义是一个 L 属性定义
Int a1,a2,a3产 生 式 语 义 规 则 D TL L.in := T.type T int T. type := integer T real T. type := real L L1, id L1.in := L.in;
addtype (id.entry, L.in ) L id addtype (id.entry, L.in )
翻译方案• 语法制导定义基于属性文法,其计算次序被隐藏。• 如果在进行语义定义的时候,陈述了一些实现的细节,我们称为翻译方案,其特征:– 规定在语法分析中使用语义规则进行计算的次序。– 保证当动作使用某属性时,该属性必须是可用的。
其实现方法为:– 将语义动作放在 {}内插入到产生式中的某个位置。
L_属性定义是可以使用翻译方案计算的一类语义定义方式,因为我们可以在语法树中按照深度优先的方法遍历这个分析树,当动作使用某属性时,可以保证该属性是可用的。
翻译模式的设计条件:语法制导定义是 L-属性定义
保证语义动作不会引用还没有计算的属性值。1. 只需要综合属性的情况: 为每一个语义规则建立一个包含赋值的动作,并把这个动作放在相应的产生式右边的末尾。
例如: TT1+F { Tval:=T1 val+F val } TT1*F {Tval:=T1 val * F val}
2. 既有综合属性又有继承属性•产生式右边的符号的继承属性必须在先于这个符号的动作中计算出来。 •一个动作不能引用这个动作右边符号的综合属性。 •产生式左边非终结符号的综合属性只有在它所引用的所有属性都计算出来以后才能计算。计算这种属性的动作通常可放在产生式右端的未尾。
翻译模式的设计
例:一个简单的翻译模式 E→TR R→addop T {print(addop.lexeme)}R1|ε T→num{print(num.val)}
把语义动作看成终结符号,输入 9-5+2,其分析树如图,当按深度优先遍历它,执行遍历中访问的语义动作,将输出
9 5 - 2 +
它是输入表达式 9-5+2的后缀式。
E
T
9T
Pt(´9´)R
Pt(´-´)
Pt(´+´)
R-
5 Pt(´5´)
+
T
2 Pt(´2´)
R
9-5+2的带语义动作的分析树E→TR R→addop T {print(addop.lexeme)}R1|ε
T→num{print(num.val)}
例:以下是说明语句的语法制导定义请建立该文法的翻译方案。
文法规则 语义规则
D→T L L.type = T.type
T→ int T.type = integer
T→float T.type = real
L→L1 , id L1.type=L.type
Addtype(id.entry,L.type)
L→id Addtype(id.entry,L.type)
翻译方案的设计• 将语义动作中的计算向前移,使继承属性的计算出现在其文法符号之前
D → T { L.type = T.type } L
T → int { T.type = integer }
T → real { T.type = real }
L → { L1.type = L.type } L1 , id {Addtype(id.entry,L.type) }
L → id {Addtype(id.entry,L.type)}
4.3.3 自顶向下的翻译
用翻译模式构造自顶向下翻译。
一、 从翻译模式中消除左递归
对于一个翻译模式,若采用自顶向下分析,必须消除左递归和提取左公因子,在改写基本文法时考虑属性值的计算。
例 4.10 p118带左递归的文法的翻译模式被转换成 p125的带右递归的文法的翻译模式。
4.3 L 属性定义的自上而下计算
例 左递归的消除引起继承属性产 生 式 语 义 规 则 E E1 + T E.nptr := mknode( ‘+’, E1.nptr, T.nptr)
E T E.nptr := T.nptr
T T1*F T.nptr := mknode( ‘*’, T1.nptr, F.nptr)
T F T.nptr := F.nptr
F (E) F.nptr := E.nptr
F id F.nptr := mkleaf (id, id.entry)
F num F.nptr := mkleaf (num, num.val)
4.3 L 属性定义的自上而下计算
E T {R.i := T.nptr}R {E.nptr := R.s}
R +T {R1.i := mknode ( ‘+’, R.i, T.nptr)}
R1 {R.s := R1.s}
R {R.s := R.i }
T F {W.i := F.nptr}W {T.nptr := W.s}
W *F {W1.i := mknode ( ‘*’, W.i, F.nptr)}
W1 {W.s := W1.s}
W {W.s := W.i }
4.3 L 属性定义的自上而下计算
E T {R.i := T.nptr} T + T + T + …R {E.nptr := R.s}
R +T {R1.i := mknode ( ‘+’, R.i, T.nptr)}
R1 {R.s := R1.s}
R {R.s := R.i }
T F {W.i := F.nptr}W {T.nptr := W.s}
W *F {W1.i := mknode ( ‘*’, W.i, F.nptr)}
W1 {W.s := W1.s}
W {W.s := W.i }
4.3 L 属性定义的自上而下计算T
F.nptrF.nptr
id
i W
*
* F.nptr
id
num
id
id
num 5
*
*
指向符号表中 a 的入口
指向符号表中 b 的入口
i W s
i W
略去了 E TR T 部分
4.3 L 属性定义的自上而下计算
4.3.3 预测翻译器的设计把预测分析器的构造方法推广到翻译方案的实现
产生式 R +TR | 的分析过程procedure R;
beginif lookahead = ‘+’ then begin
match ( ‘+’ ); T; Rendelse begin /* 什么也不做 */end
end
4.3 L 属性定义的自上而下计算
function R (i :syntax_tree_node ) :syntax_tree_node;var nptr , i1, s1, s : syntax_tree_node;
addoplexeme : char;begin
if lookahead = ‘+’ then begin /* 产生式 R +T R */
addoplexeme := lexval;match( ‘+’ );nptr := T;
i1 := mknode(addoplexme, i , nptr) ; s1 := R (i1 ); s : = s1
endelse s := i; /* 产生式 R */return s
end;
R : i, sT : nptr+ : addoplexeme
4.3 L 属性定义的自上而下计算
4.3.4 用综合属性代替继承属性
Pascal 的声明,如 m, n : integerD L : TT integer | charL L, id | id
4.3 L 属性定义的自上而下计算
4.3.4 用综合属性代替继承属性
Pascal 的声明,如 m, n : integerD L : TT integer | charL L, id | id
改成从右向左归约D id LL , id L | : TT integer | char
4.3 L 属性定义的自上而下计算
4.3.4 用综合属性代替继承属性
Pascal 的声明,如 m, n : integerD L : TT integer | charL L, id | id
改成从右向左归约D id LL , id L | : TT integer | char
D
:
L
,
id
Lid
integer
T
4.3 L 属性定义的自上而下计算
D id L { addtype (id. entry, L. type)}L , id L1 {L. type := L1. Type;
addtype (id. entry, L1. type)}
L : T {L. type := T. type}T integer {T. type := integer}T real {T. type := real}
D
:
L
,
id
Lid
integer
T
• 采用递归下降分析法编写预翻译程序
4.3 L 属性定义的自上而下计算
4.4 L 属性的自下而上计算 在自下而上分析的框架中实现 L 属性定义的方
法
• 它能实现任何基于 LL(1) 文法的 L 属性定义。
• 也能实现许多(但不是所有的)基于 LR(1) 的 L 属性定义。
4.4 L 属性的自下而上计算 4.4.1 删除翻译方案中嵌入的动作E T RR + T {print (‘+’)}R1 | T {print (‘’)}R1 |
T num {print (num.val)}
4.4 L 属性的自下而上计算 4.4.1 删除翻译方案中嵌入的动作E T RR + T {print (‘+’)}R1 | T {print (‘’)}R1 |
T num {print (num.val)}在文法中加入产生的标记非终结符,让每个嵌入动作由不同标记非终结符 M 代表,并把该动作放在产生式 M 的右端。
4.4 L 属性的自下而上计算 4.4.1 删除翻译方案中嵌入的动作E T RR + T {print (‘+’)}R1 | T {print (‘’)}R1 |
T num {print (num.val)}在文法中加入产生的标记非终结符,让每个嵌入动作由不同标记非终结符 M 代表,并把该动作放在产生式 M 的右端。
E T RR + T M R1 | T N R1 | T num {print (num.val)}M {print (‘+’)}N {print (‘’)}
4.4 L 属性的自下而上计算 4.4.2 分析栈上的继承属性
例 int p, q, r D T {L.in := T.type}
LT 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 )}
4.4 L 属性的自下而上计算 4.4.2 分析栈上的继承属性属性位置能预测
例 int p, q, r D T {L.in := T.type}
LT 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 )}
D
T L
L, r
L , q
p
int
type
in
in
in
4.4 L 属性的自下而上计算 D
T L
L, r
L , q
p
int
type
in
in
in
产 生 式 代 码 段 D TL
T int val[top] := integer
T real val[top] := real
L L1, id addtype(val[top], val[top3])
L id addtype(val[top], val[top1])
4.4 L 属性的自下而上计算 属性的位置不能预测S aAC C.i := A.sS bABC C.i := A.sC c C.s := g(C.i)
4.4 L 属性的自下而上计算 属性的位置不能预测S aAC C.i := A.sS bABC C.i := A.sC c C.s := g(C.i)
增加标记非终结符S aAC C.i := A.sS bABMC M.i := A.s; C.i := M.sC c C.s := g(C.i)M M.s := M.i
4.4 L 属性的自下而上计算 4.4.3 模拟继承属性的计算继承属性是某个综合属性的一个函数
S aAC C.i := f (A.s)C c C.s := g(C.i)
4.4 L 属性的自下而上计算 4.4.3 模拟继承属性的计算继承属性是某个综合属性的一个函数
S aAC C.i := f (A.s)C c C.s := g(C.i)
增加标记非终结符,把 f(A.s) 的计算移到对标记
非终结符归约时进行。S aANC N.i := A.s; C.i := N.sN N.s := f (N.i)C c C.s := g(C.i)
4.4 L 属性的自下而上计算例 数学排版语言 EQN S {B.ps := 10 }
B {S.ht := B.ht } B {B1.ps := B.ps } B1 {B2.ps := B.ps } B2 {B.ht := max(B1.ht, B2.ht ) } B { B1.ps :=B.ps } B1
sub { B2.ps := shrink(B.ps) }B2 {B.ht := disp (B1.ht, B2.ht ) }
B text {B.ht := text.h B.ps }
4.4 L 属性的自下而上计算 产 生 式 语 义 规 则
S LB B.ps := L.s; S.ht := B.ht
L L.s := 10
B B1 MB2 B1.ps := B.ps; M.i := B.ps;
B2.ps := M.s;B.ht := max(B1.ht, B2.ht )
M M.s := M.i
B B1 sub
NB2
B1.ps :=B.ps; N.i := B.ps;
B2.ps := N.s; B.ht := disp (B1.ht, B2.ht )
N N.s := shrink(N.i)
B text B.ht := text.h B.ps
4.4 L 属性的自下而上计算 产 生 式 代 码 段
S LB B.ps := L.s; S.ht := B.ht
L L.s := 10
B B1 MB2 B1.ps := B.ps; M.i := B.ps;
B2.ps := M.s;B.ht := max(B1.ht, B2.ht )
M M.s := M.i
B B1 sub
NB2
B1.ps :=B.ps; N.i := B.ps;
B2.ps := N.s; B.ht := disp (B1.ht, B2.ht )
N N.s := shrink(N.i)
B text B.ht := text.h B.ps
4.4 L 属性的自下而上计算 产 生 式 代 码 段
S LB val[top1] := val[top]
L L.s := 10
B B1 MB2 B1.ps := B.ps; M.i := B.ps;
B2.ps := M.s;B.ht := max(B1.ht, B2.ht )
M M.s := M.i
B B1 sub
NB2
B1.ps :=B.ps; N.i := B.ps;
B2.ps := N.s; B.ht := disp (B1.ht, B2.ht )
N N.s := shrink(N.i)
B text B.ht := text.h B.ps
4.4 L 属性的自下而上计算 产 生 式 代 码 段
S LB val[top1] := val[top]
L val[top+1] := 10
B B1 MB2 B1.ps := B.ps; M.i := B.ps;
B2.ps := M.s;B.ht := max(B1.ht, B2.ht )
M M.s := M.i
B B1 sub
NB2
B1.ps :=B.ps; N.i := B.ps;
B2.ps := N.s; B.ht := disp (B1.ht, B2.ht )
N N.s := shrink(N.i)
B text B.ht := text.h B.ps
4.4 L 属性的自下而上计算 产 生 式 代 码 段
S LB val[top1] := val[top]
L val[top+1] := 10
B B1 MB2 val[top2] := max(val[top2], val[top])
M M.s := M.i
B B1 sub
NB2
B1.ps :=B.ps; N.i := B.ps;
B2.ps := N.s; B.ht := disp (B1.ht, B2.ht )
N N.s := shrink(N.i)
B text B.ht := text.h B.ps
4.4 L 属性的自下而上计算 产 生 式 代 码 段
S LB val[top1] := val[top]
L val[top+1] := 10
B B1 MB2 val[top2] := max(val[top2], val[top])
M val[top+1] := val[top1]
B B1 sub
NB2
B1.ps :=B.ps; N.i := B.ps;
B2.ps := N.s; B.ht := disp (B1.ht, B2.ht )
N N.s := shrink(N.i)
B text B.ht := text.h B.ps
4.4 L 属性的自下而上计算 产 生 式 代 码 段
S LB val[top1] := val[top]
L val[top+1] := 10
B B1 MB2 val[top2] := max(val[top2], val[top])
M val[top+1] := val[top1]
B B1 sub
NB2
val[top3]:= disp (val[top3], val[top] )
N N.s := shrink(N.i)
B text B.ht := text.h B.ps
4.4 L 属性的自下而上计算 产 生 式 代 码 段
S LB val[top1] := val[top]
L val[top+1] := 10
B B1 MB2 val[top2] := max(val[top2], val[top])
M val[top+1] := val[top1]
B B1 sub
NB2
val[top3]:= disp (val[top3], val[top] )
N val[top+1] := shrink(val[top2])
B text B.ht := text.h B.ps
4.4 L 属性的自下而上计算 产 生 式 代 码 段
S LB val[top1] := val[top]
L val[top+1] := 10
B B1 MB2 val[top2] := max(val[top2], val[top])
M val[top+1] := val[top1]
B B1 sub
NB2
val[top3]:= disp (val[top3], val[top] )
N val[top+1] := shrink(val[top2])
B text val[top] := val[top] val[top1]
4.5 递 归 计 算 回顾:语法制导定义的实现• 分析树方法。
4.5 递 归 计 算 回顾:语法制导定义的实现• 分析树方法。• 边分析边进行属性计算,只能完成 L 属性计
算(忽略规则的方法)。
4.5 递 归 计 算 回顾:语法制导定义的实现• 分析树方法。• 边分析边进行属性计算,只能完成 L 属性计
算(忽略规则的方法)。• 本节介绍先分析后计算的方法,不局限于 L
属性计算(基于规则的方法)。
4.5 递 归 计 算 回顾:语法制导定义的实现• 分析树方法。• 边分析边进行属性计算,只能完成 L 属性计
算(忽略规则的方法)。• 本节介绍先分析后计算的方法,不局限于 L
属性计算(基于规则的方法)。– 为每个非终结符构造一个属性计算函数,但是该
函数不含语法分析部分 。
4.5 递 归 计 算 回顾:语法制导定义的实现• 分析树方法。• 边分析边进行属性计算,只能完成 L 属性计
算(忽略规则的方法)。• 本节介绍先分析后计算的方法,不局限于 L
属性计算(基于规则的方法)。– 为每个非终结符构造一个属性计算函数,但是该
函数不含语法分析部分 。– 为非终结符的不同综合属性构造不同的函数。
4.5 递 归 计 算4.5.1 自左向右遍历
为 B 构造一个属性计算函数 S {B.ps := 10 }
B {S.ht := B.ht } B {B1.ps := B.ps }
B1 {B2.ps := B.ps }
B2 {B.ht := max(B1.ht, B2.ht ) }
B { B1.ps :=B.ps }
B1
sub { B2.ps := shrink(B.ps) }
B2 {B.ht := disp (B1.ht, B2.ht ) }
B text {B.ht := text.h B.ps }
4.5 递 归 计 算function B(n, ps);var ps1, ps2, ht1, ht2;begin
case 在结点 n 的产生式 of‘B B1 B2’:
ps1 := ps;ht1 := B(child(n,1), ps1);ps2 := ps;ht2 := B(child(n,2), ps2);return max(ht1, ht2);
B {B1.ps := B.ps } B1 {B2.ps := B.ps } B2 {B.ht := max(B1.ht, B2.ht ) }
4.5 递 归 计 算function B(n, ps);var ps1, ps2, ht1, ht2;begin
case 在结点 n 的产生式 of‘B B1 sub B2’:
ps1 := ps;ht1 := B(child(n,1), ps1);ps2 := shrink(ps);ht2 := B(child(n,3), ps2);return disp(ht1, ht2);
B {B1.ps := B.ps } B1 sub{B2.ps := shrink(B.ps)} B2{B.ht := disp (B1.ht, B2.ht ) }
4.5 递 归 计 算function B(n, ps);var ps1, ps2, ht1, ht2;begin
case 在结点 n 的产生式 of‘B text’:
return ps text.h;default:
errorend
B text {B.ht := text.h B.ps }
4.5 递 归 计 算4.5.2 其它遍历方法
按所需次序访问结点的子结点,可用于非 L属性定义。
A LM L.i := l(A.i); M.i := m(L.s); A.s := f (M.s) A QR R.i := r(A.i); Q.i := q(R.s); A.s := f (Q.s)
i A s
i M si L s
i A s
i R si Q s
4.5 递 归 计 算‘A LM’: /* 从左到右的次序 */
li := l(ai);ls := L(child(n,1), li);mi := m(ls);ms := M(child(n,2), mi);return f (ms);
i A s
i M si L s
i A s
i R si Q s
4.5 递 归 计 算‘A QR’: /* 从右到左的次序 */
ri := r(ai);rs := R(child(n,2), ri);qi := q(rs);qs := Q(child(n,1), qi);return f (qs);
i A s
i M si L s
i A s
i R si Q s
4.5 递 归 计 算4.5.3 多次遍历 S E E.i := g(E.s); S.r := E.tE E1E2 E.s := fs(E1.s, E2.s); E1.i := fi1(E.i);
E2.i := fi2(E.i); E.t := ft (E1.t, E2.t)
E id E.s := id.s; E.t := h(E.i)
S r
i E s t
i E1 s t
i E s t
i E2 s t
i E s t
id s
4.5 递 归 计 算综合属性 t 不可能和 s 在同一遍扫描中完成计算
i E s t
S r
i E s t
id s
i E s t
id s
4.5 递 归 计 算function Sr(n);begin
s := Es(child(n,1));i := g(s);t := Et(child(n,1), i);return t
end;
4.5 递 归 计 算function Es(n); | function Et(n, i);begin | begincase 在结点 n 的产生式 of | case 在结点 n 的产生式 of
‘E E1 E2’: | ‘E E1 E2’:s1 := Es(child(n,1)); | i1:= fi1(i);s2 := Es(child(n,2)); | t1 := Et(child(n,1), i1);return fs(s1, s2); | i2:= fi2(i);
‘E id’: | t2 := Et(child(n,2), i2);return id.s; | return ft(t1, t2);
default: | ‘E id’:error | return h(i);
end | default:end; | error
| end | end;
本 章 要 点• 语义规则的两种描述方法:语法制导的定义和
翻译方案。• 设计简单问题的语法制导定义和翻译方案,这
是本章的重点和难点。• 语义规则的三种计算方法:分析树方法、基于
规则的方法和忽略规则的方法。 • S 属性的自下而上计算(边分析边计算)。• L 属性的自上而下计算(边分析边计算)。• 递归计算(先分析后计算)。