编译原理7~9
一些概念
综合属性:从下到上 val
继承属性:从上到下 in
S-翻译模式(S-Attributed)和L-翻译模式(L-Attributed)是两种不同的语法指导翻译(Syntax-Directed Translation, SDT)
S:只能用综合属性
T:都OK
“翻译模式”(Translation Scheme)是编译原理中一个重要的概念,尤其是在语法指导翻译(Syntax-Directed Translation)的上下文中。它与你刚才提到的语义动作、属性文法、三地址代码密切相关,但又有其特定的定义和用途。
✅ 什么是翻译模式?
翻译模式是指将语法规则与语义动作结合起来的一种描述方式。它是一种在语法分析过程中嵌入语义动作的方法,用于指导如何将源程序翻译成中间代码或目标代码。
换句话说,翻译模式 = 文法 + 语义动作。
这些语义动作通常以花括号 { ... }
的形式插入到产生式的右侧,表示当解析器识别出该语法结构时应执行的操作,比如生成三地址码、设置属性值等。
🧩 翻译模式的形式示例
例如,考虑如下翻译模式中的产生式:
E → E1 + T { E.place := newtemp(); emit(E.place ':=' E1.place '+' T.place); }
这个产生式的含义是:
- 当识别出
E → E1 + T
这个语法结构时, - 执行
{ ... }
中的语义动作:- 为结果分配一个新的临时变量
newtemp()
; - 生成一条三地址码指令:
t := E1 + T
; - 并将这个临时变量的位置赋给
E.place
,供后续使用。
- 为结果分配一个新的临时变量
🔍 翻译模式 vs 其他概念的区别
概念 | 定义与作用 | 举例/说明 |
---|---|---|
翻译模式 | 是一种将文法与语义动作结合的方式,在语法分析过程中逐步进行翻译操作。 | 如上例,包含文法+语义动作 |
语义动作 | 是翻译模式的一部分,表示在某个语法结构被识别后要执行的具体操作。 | { emit(...); } |
属性文法 | 更系统化地定义了语法符号上的属性及其计算规则,支持继承属性和综合属性。 | E.type = E1.type |
三地址代码 | 是翻译的结果之一,是一种中间表示形式,便于优化和目标代码生成。 | t1 := a + b |
📌 翻译模式的特点
- 依赖语法分析顺序:翻译模式的动作必须按照语法分析器的遍历顺序来安排(如自底向上或自顶向下),否则可能导致错误。
- 适合简单翻译任务:适用于像表达式求值、基本控制流翻译等任务。
- 不够灵活:如果需要复杂的属性传递或跨多个节点的信息处理,更适合使用属性文法。
🧱 翻译模式的应用场景
翻译模式广泛用于:
- 表达式的翻译(生成三地址码)
- 控制结构(if、while、for)的翻译
- 类型检查(配合属性)
- 基本块划分、控制流图构造等
✅ 总结一句话:
翻译模式是在文法规则中嵌入语义动作,用于指导编译器在语法分析的同时完成翻译任务的一种机制。
它是语法指导翻译的具体实现方式,常用于生成三地址代码,而其中的语义动作则是实际执行翻译操作的部分。
如果你看到一段文法中有类似这样的内容:
S → if (E) S1 { backpatch(E.truelist, S1.quad); ... }
这就是典型的翻译模式:既有文法结构,又有嵌入的语义动作,用来生成中间代码并管理跳转链表(如拉链技术)。
第八章
练习8 参考8.3.3.6节采用拉链与代码回填技术进行布尔表达式和控制语句(不含break)翻译的S翻译模式片段及所用到的语义函数,设在该翻译模式基础上增加下列两条产生式及相应的语义动作集合:
S→S’ {S.nextlist := S’.nextlist}
S’→id := E’ {S’.nextlist := " "; emit(id.place ‘:=’ E’.place)}
其中,E’是生成算术表达式的非终结符(对应8.3.3.1节中的A)。
若在基础文法中增加对应for循环语句的产生式
S→for (S’; E; S’) S
试给出相应该产生式的语义动作集合。
注:for 循环语句的语义与C语言中的for循环语句相同。
这条产生式 S' → id := E'
以及相应的语义动作 {S'.nextlist := " "; emit(id.place ':=' E'.place)}
是用于描述赋值语句的翻译过程。这里,id
表示一个标识符(即变量名),而 E'
是代表某个算术表达式的非终结符(根据题目描述,对应于8.3.3.1节中的A)。下面是对这个产生式及其语义动作的解释:
-
S' → id := E'
:这条规则表示一个赋值语句,其中左边是一个标识符id
,右边是一个表达式E'
。也就是说,这个产生式是用来生成将表达式的值赋给某个变量的语句。 -
{S'.nextlist := " "; ...}
:这里的nextlist
是一个链表,用来记录控制流语句(如条件语句或循环)中需要跳转的目标位置。对于赋值语句来说,它并不改变程序的控制流(即不会导致任何跳转),所以这里将S'.nextlist
设置为空字符串" "
,意味着该语句没有后续的跳转目标。在某些编译器实现中,这可能被设置为null
或者其他形式的空值。 -
emit(id.place ':=' E'.place)
:这是生成中间代码的一部分。emit
函数的作用是输出一条三地址码指令。在这个上下文中,id.place
和E'.place
分别指的是变量和表达式的存放位置(比如寄存器或者内存地址)。因此,emit(id.place ':=' E'.place)
这条语句的意思是生成一条赋值指令,将表达式E'
的计算结果存储到变量id
所指定的位置中。
综上所述,这个产生式和它的语义动作集主要用于处理简单的赋值语句,将右侧表达式的值赋给左侧的变量,并且由于赋值操作不会影响程序的控制流,所以对应的 nextlist
被置为空。这种机制是编译原理中语法指导翻译的一种应用,目的是为了生成中间代码或目标代码。
AI答案:
{L1 = newlabel(); // 条件判断入口L2 = newlabel(); // continue 跳转目标(步进语句处)// 1. 初始化语句 S₁'emit(label L1); // 初始化之后跳到条件判断backpatch(S₁'.nextlist, L1);// 2. 条件表达式 EE.code; // 生成布尔表达式的代码backpatch(E.truelist, L2); // 条件为真跳到循环体开始falselist = E.falselist;// 3. 设置 continue 跳转目标S₃.continue_list = makelist(L2);// 4. 循环体 S₃S₃.code;// 5. 循环体结束后跳到步进语句处emit(goto L2);// 6. 插入步进语句标签 L2emit(label L2);backpatch(S₂'.nextlist, L2); // 执行步进语句// 7. 步进语句后跳回条件判断点emit(goto L1);// 8. 回填 falselist,即跳出循环backpatch(falselist, nextinstr());// 9. 设置 S.nextlistS.nextlist = merge(S₃.nextlist, S₂'.nextlist);
}
``
另一个参考:
疑似卷子答案
另另一个参考:
另一个版本书的答案