编译原理 第6章 中间代码生成

合集下载

编译原理第三版课后习题答案

编译原理第三版课后习题答案

编译原理第三版课后习题答案编译原理是计算机科学中的一门重要课程,它研究的是如何将高级程序语言转换为机器语言的过程。

而《编译原理》第三版是目前被广泛采用的教材之一。

在学习过程中,课后习题是巩固知识、提高能力的重要环节。

本文将为读者提供《编译原理》第三版课后习题的答案,希望能够帮助读者更好地理解和掌握这门课程。

第一章:引论习题1.1:编译器和解释器有什么区别?答案:编译器将整个源程序转换为目标代码,然后一次性执行目标代码;而解释器则逐行解释源程序,并即时执行。

习题1.2:编译器的主要任务是什么?答案:编译器的主要任务是将高级程序语言转换为目标代码,包括词法分析、语法分析、语义分析、中间代码生成、代码优化和目标代码生成等过程。

第二章:词法分析习题2.1:什么是词法分析?答案:词法分析是将源程序中的字符序列划分为有意义的词素(token)序列的过程。

习题2.2:请给出识别下列词素的正则表达式:(1)整数:[0-9]+(2)浮点数:[0-9]+\.[0-9]+(3)标识符:[a-zA-Z_][a-zA-Z_0-9]*第三章:语法分析习题3.1:什么是语法分析?答案:语法分析是将词法分析得到的词素序列转换为语法树的过程。

习题3.2:请给出下列文法的FIRST集和FOLLOW集:S -> aAbA -> cA | ε答案:FIRST(S) = {a}FIRST(A) = {c, ε}FOLLOW(S) = {$}FOLLOW(A) = {b}第四章:语义分析习题4.1:什么是语义分析?答案:语义分析是对源程序进行静态和动态语义检查的过程。

习题4.2:请给出下列文法的语义动作:S -> if E then S1 else S2答案:1. 计算E的值2. 如果E的值为真,则执行S1;否则执行S2。

第五章:中间代码生成习题5.1:什么是中间代码?答案:中间代码是一种介于源代码和目标代码之间的表示形式,它将源代码转换为一种更容易进行优化和转换的形式。

编译原理6 语义分析和中间代码生成

编译原理6 语义分析和中间代码生成
引入中间代码的目的 1. 2. 3. 方便生成目标代码; 便于优化; 便于移植。
波兰逻辑学家卢卡西维奇(Lukasiewicz)发明的 一种表示法。 概念 一般,若e1,e2为任意的后缀表达式,Θ 为任意 双目运算符,则用Θ作用于e1和e2所代表的结果 用后缀式e1e2 Θ表示。 推而广之, Θ 为k目运算符,则Θ作用于e1e2„ek 的结果用e1e2„ek Θ来表示。
If e then x else y

e p1 jez x p2 jump p1:y p2:
在数组POST中出现的后缀式
e x y
p1 下标 数组 e p1 jez x p2 jump y
p2
符号表
后跟冒号的p1,p2实际上并不存储
产生式所带的语义动作,由以下模式描述。
E E(1)op E(2)
引入标号,在后缀式中加入条件转移,无条件转 移算符。
存储方式 后缀式存放在一维数组POST[1..N]中,每个元素 是运算符或者分量(指向符号表)。
转移算符
p jump 转到POST[p] e1e2pjlt e1<e2时,转到POST[p]
e p jez 若e=0,转到POST[p]
T.val=4 F.val=4 F.val=5 digit.lexval=4 digit.lexval=5
T.val=15 T.val=3 F.val=3 digit.lexval=3
*
3*5+4的带注释的分析树
例2 继承属性的例子
产 生式 D TL T int T real L L1,id L id 语 义 规 则 L.in:=T.type T.type=integer T.type:=real L1.in:=L.in addtype(id.entry,L.in) addtype(id.entry,L.in)

编译原理中间代码生成

编译原理中间代码生成

编译原理中间代码生成在编译原理中,中间代码生成是编译器的重要阶段之一、在这个阶段,编译器将源代码转换成一种中间表示形式,这种中间表示形式通常比源代码抽象得多,同时又比目标代码具体得多。

中间代码既能够方便地进行优化,又能够方便地转换成目标代码。

为什么需要中间代码呢?其一,中间代码可以方便地进行编译器优化。

编译器优化是编译器的一个核心功能,它能够对中间代码进行优化,以产生更高效的目标代码。

在中间代码生成阶段,编译器可以根据源代码特性进行一些优化,例如常量折叠、公共子表达式消除、循环不变式移动等。

其二,中间代码可以方便地进行目标代码生成。

中间代码通常比较高级,比目标代码更具有表达力。

通过中间代码,编译器可以将源代码转换成与目标机器无关的形式,然后再根据目标机器的特性进行进一步的优化和转换,最终生成目标代码。

中间代码生成的过程通常可以分为以下几步:1.词法分析和语法分析:首先需要将源代码转换成抽象语法树。

这个过程涉及到词法分析和语法分析两个步骤。

词法分析将源代码划分成一个个的词法单元,例如标识符、关键字、运算符等等。

语法分析将词法单元组成树状结构,形成抽象语法树。

2.语义分析:在语义分析阶段,编译器会对抽象语法树进行静态语义检查,以确保源代码符合语言的语义规定。

同时,还会进行类型检查和类型推导等操作。

3.中间代码生成:在中间代码生成阶段,编译器会将抽象语法树转换成一种中间表示形式,例如三地址码、四元式、特定的中间代码形式等。

这种中间表示形式通常比较高级,能够方便进行编译器的优化和转换。

4.中间代码优化:中间代码生成的结果通常不是最优的,因为生成中间代码时考虑的主要是功能的正确性,并没有考虑性能的问题。

在中间代码生成之后,编译器会对中间代码进行各种优化,以产生更高效的代码。

例如常量折叠、循环优化、死代码删除等等。

5.中间代码转换:在完成了中间代码的优化之后,编译器还可以对中间代码进行进一步的转换。

这个转换的目的是将中间代码转换成更具体、更低级的形式,例如目标机器的汇编代码。

编译原理中的中间代码生成

编译原理中的中间代码生成

编译原理中的中间代码生成编译原理是计算机科学的一门重要课程。

在编译器的构造过程中,中间代码生成是其核心部分之一。

它是将源代码翻译为目标代码的重要中间阶段。

中间代码生成的过程涉及到链表、树,生成三元式、四元式等多种中间形式。

本文将介绍中间代码生成的过程和其在编译中的作用。

一、中间代码的概念中间代码是指在源程序和目标程序之间所生成的一系列指令的集合。

目标代码是指机器可执行的二进制代码,而中间代码则是一种可传递、可处理和可修改的编译代码形式。

中间代码属于一种中间状态,它不是源代码也不是目标代码,但可以被转换成目标代码。

中间代码可以基于语法树、语法分析栈、语法分析表进行生成,生成的中间代码需要满足语言语法结构和语义规则。

二、中间代码生成的流程在编译过程中,中间代码生成是指将源代码转换成中间代码的过程。

它是在词法分析、语法分析和语义分析阶段之后完成的。

下面介绍一下中间代码生成的流程。

1.源代码转换为语法树编译器通过词法分析和语法分析将源代码转换成语法树。

语法树是一种树形结构,它记录了源代码中各个语句的组成情况。

2.语法树进行语义分析在语法分析之后,编译器进行语义分析,检查语法树的合法性,然后根据语言的语义规则对语法树进行标注。

标注的内容包括符号表信息、数据类型等。

3.中间代码的生成在语义分析后,编译器进入中间代码的生成阶段,生成语句的中间代码。

中间代码通常采用三元式或四元式等形式。

三元式包含操作符、操作数以及结果的地址,四元式中还包括了类型信息。

4.中间代码优化在中间代码生成的过程中,编译器会尽可能地优化中间代码。

可以对中间代码进行多种优化,如常量合并、变量替换、公共子表达式消除等。

5.中间代码转换为目标代码在中间代码生成后,编译器将中间代码转换为目标代码。

目标代码可以是汇编代码或机器代码等不同形式的二进制代码。

三、中间代码生成优化的意义编译器中间代码优化的目标是提高程序的执行效率和降低其资源消耗。

执行效率的提高可以通过以下方式实现:1.减少内存使用编译器可以通过删除冗余代码、去除死代码和不必要的变量等方式来减少中间代码的内存使用。

编译原理中的中间代码生成

编译原理中的中间代码生成

编译原理中的中间代码生成编译原理是计算机科学中非常重要的一门课程,它研究的是将高级语言程序转化为低级语言程序,实现计算机能够理解和运行的目的。

但是高级语言相较于机器语言更为抽象和复杂,所以需要经过多个步骤的处理,其中中间代码生成就是其中的一个重要环节。

中间代码是指一种介于高级语言和机器语言之间的表示方式,它的作用是将高级语言程序转化为更容易被计算机处理的形式,同时它也提供了一种通用的平台,可以将同一份高级语言程序转化为多种低级语言程序,如汇编语言、机器语言等。

如今,多数编译器都采用中间代码进行转化和优化,它不仅可以提高代码执行效率,还可以提高程序的可移植性和可维护性。

那么,中间代码的生成是如何进行的呢?和编译器的其它部分一样,中间代码生成也是经过多个步骤的处理,其中最主要的步骤包括词法分析、语法分析、语义分析和中间代码生成。

词法分析的作用是将源程序的字符序列转换为单词序列。

它依靠的是正则表达式的特性,对源程序进行识别和划分,得到一系列单词。

这些单词包括关键字、标识符、常数、字符等,在很大程度上决定了接下来的语法分析和语义分析。

语法分析是将单词序列转化为抽象语法树的过程,它将程序以树的形式进行表示,更为直观和容易理解。

通过对抽象语法树的遍历,可以得到程序的各种信息,如变量名、函数名、常量、运算符和控制语句等。

对于每个节点,编译器会根据其语义和上下文信息,进行类型检查、错误检测和决策生成等操作,最终得到一个可运行的程序。

语义分析是识别程序中不符合语言规范或逻辑错误的部分,它是整个编译过程中最为复杂的一个环节。

在这个过程中,编译器需要根据程序的上下文信息,判断其意义和合理性,并进行正确的处理。

例如,当编译器遇到一个未定义的变量或函数时,它将会报错并停止编译。

语义分析可以避免很多程序运行时的错误,同时也是编译器优化的重要基础。

当编译器通过词法分析、语法分析和语义分析,得到一个完整、正确的程序后,就可以进行中间代码生成了。

编译原理之中间代码生产、词法优化与代码生成

编译原理之中间代码生产、词法优化与代码生成

编译原理之中间代码⽣产、词法优化与代码⽣成
中间代码⽣成
在把⼀个源程序翻译成⽬标代码的过程中,⼀个编译器可能构造出⼀个或多个中间表⽰。

这些中间表⽰可以有多种形式。

语法树是⼀种中间表⽰形式,它们通常在语法分析和语义分析中使⽤。

在源程序的语法分析和语义分析完成之后,很多编译器⽣成⼀个明确的低级的或类机器语⾔的中间表⽰。

我们可以把这个表⽰看作是某个抽象机器的程序。

该中间表⽰应该具有两个重要的性质:它应该易于⽣成,且能够被轻松地翻译为⽬标机器上的语⾔。

代码优化
机器⽆关的代码优化步骤试图改进中间代码,以便⽣成更好的⽬标代码。

“更好”通常意味着更快,但是也可能会有其他⽬标,如更短的或能耗更低的⽬标代码
代码⽣成
代码⽣成器以源程序的中间表⽰形式作为输⼊,并把它映射到⽬标语⾔。

如果⽬标语⾔是机器代码,那么就必须为程序使⽤的每个变量选择寄存器或内存位置。

然后,中间指令被翻译成为能够完成相同任务的机器指令序列。

代码⽣成的⼀个⾄关重要的⽅⾯是合理分配寄存器以存放变量的值。

(这⾥我觉得还存疑因为书本上下下段还说了⼀句话,上⾯对代码⽣成的讨论忽略了对源程序中的标识⾏进⾏存储分配的重要问题。

) 不过总之,运⾏时刻的存储组织⽅法依赖于被编译的语⾔。

编译器在中间代码⽣成或代码⽣成阶段做出有关存储分配的决定。

编译原理课件-中间代码生成

编译原理课件-中间代码生成
(2)E→E1 and E2 { backpatch(E 1.true, E2.codebegin); E.Codebegin:= E 1.codebegin; E.true:= E 2.true; E.false:= merge(E 1.false, E2false);}
(3) E→not E1 { E.true:= E 1.false; E.Codebegin:= E 1.codebegin; E.false:= E 1.true
(翻譯不是最優)
語句 if a<b or c<d and e<f then S1 else S2 的四元式
(1) if a<b goto (7) //轉移至(E.true )
(2) goto (3)
(3) if c<d goto (5)
(4) goto (p+1)
//轉移至(E.false)
(5) if e<f goto (7) (6) goto (p+1) (7)( S1的四元式
不同層次的中間代碼
源語言
中間代碼
(高級語言) (高級)
中間代碼 (中級)
中間代碼 (低級)
float a[10][20]; a[i][j+2];
t1 = a[i, j+2]
t1 = j + 2 t2 = i * 20 t3 = t1 + t2 t4 = 4 * t3 t5 = addr a t6 = t5 + t4 t7 = *t6
語義描述使用的變數和過程:
E.true : “真”鏈, E.false : “假”鏈
E.codebegin : E 的第一個四元式
Nextstat: 下一四元式地址

编译原理中的语法分析与中间代码生成

编译原理中的语法分析与中间代码生成

编译原理中的语法分析与中间代码生成编译原理是计算机科学中一门非常重要的学科,主要研究将高级语言翻译成机器语言的方法和技术。

其中,语法分析和中间代码生成是编译器实现的两个重要步骤。

一、语法分析语法分析是编译器将源代码转换成抽象语法树的过程。

在这个阶段,编译器会检查源代码的语法是否符合语言规范,并将代码转化为一系列的语法结构。

一个好的语法分析器能够快速准确地识别代码中的语言结构,同时能够在出现语法错误的时候给出有意义的错误报告。

常见的语法分析方法包括LL(1)分析、LR分析等。

LL(1)分析器通过构造预测分析表来实现分析,而LR分析器则采用自底向上的分析方法,通过状态迁移来实现分析。

在语法分析的过程中,编译器还需要处理语法的优先级,如算术运算符的优先级,逻辑运算符的优先级等。

对于不同的语言规范,将有不同的算法来处理语法。

例如,C语言中的运算符优先级和结合性与其他语言不同,因此需要特殊的处理方式。

二、中间代码生成中间代码生成是语法分析后的下一步,它的作用是将抽象语法树转化为中间表示,通常是三地址码或四地址码。

中间代码可以看作是目标代码的前一步,它是一种更加抽象的代码形式,方便后续的优化和翻译。

中间代码的生成方法有很多种,最常用的是遍历抽象语法树并根据语法结构生成中间代码。

不同的语言规范会对中间代码的生成方式有不同的要求。

例如,Java语言规范对着重于类型检查和异常处理的中间代码生成,而C语言的中间代码生成则着重于指针和数组的处理等。

在生成中间代码的过程中,编译器还需要考虑优化问题。

编译器能够在生成中间代码的时候进行一些基本的优化,例如删除冗余代码、常量合并等等,这样可以减少目标代码的大小和程序的运行时间。

总之,语法分析和中间代码生成是编译器实现的两个关键步骤。

它们需要一个好的算法和优秀的实现方式,以便在编译过程中产生高效、可靠的目标代码。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
37
布尔表达式的回填翻译(1)


布尔表达式用于语句的控制流时,它总是在为 true时或为false分别跳转到某个位置 引入两个综合属性


辅助函数

truelist: 包含跳转指令的列表,为true时执行这些指 令 falselist:包含跳转指令的列表,为false时执行这些 指令
D →T id ; D | ε T → B C | record ‘{’ D ‘}’ B → int | float C → ε | [num] C D生成一系列声明; T生成不同的类型; B生成基本类型int/float; C表示分量,生成[num]序列; 注意record中包含了各个字段的声明。字段声明和变量 声明的文法一致。
4)声明序列的SDT(2)

我们可以把offset看作是D的继承属性

P{D.offset=0} D D T id; {D1.offset= D.offset+ T.width;} D1
19
例 int a;声明过程的语法翻译
语法制导定义的SDT P→MD M→ε{offset=0;} D→T id;N D N→ε{ top.put(id.lexname,T.t,offset); offset=offset+T.w} D→ε T→BKC{T.t=C.t;T.w=C.w} K→ε{t=B.t;w=B.w;} B→int {B.t=integer;B.w=4;} C→ε{C.t=t;C.w=w;}
1)三地址代码(1)

特点

形式简单、语义明确、便于翻译 独立于目标语言 一般情况可以写成x=y op z 名字:用源程序中名字作为三地址代码的地址 常量:源程序中出现的、或者生成的常量 编译器生成的临时变量
4

每条指令右侧最多有一个运算符


运算分量:

三地址代码(2)

指令

27
1)控制流语句的翻译
S if (B) S1 | if (B) S1 else S2 | while (B) S1 | S1;S2 | assign
28
控制流语句的翻译
B.code B.true: S1.code ... (a) if begin: B.true: B.code S1.code goto begin ... (c) while 指向B.true 指向B.false 指向B.true 指向B.false

在处理一个过程/函数时,它声明的变量应该放 到单独的符号表中去; 这些变量的内存布局独立


SDT的处理方法

相对地址从0开始; 假设变量的放置和声明的顺序相同;

top.put(id.lexeme, T.type, offset)创建符号 表条目
18
变量offset记录当前可用的相对地址; 每“分配”一个变量,offset的值增加相应的位置

20
int a;
语法分析 语义信息 语法分析 语义信息
ε M offset=0 M int MB B.t=int, B.w=4 MBε MBK t=int w=4 MBKε MBKC C.t=int C.w=4 MT T.t=int T.w=4
MTid; MTid;ε MTid;N id的属性入表 offset=4 MTid;Nε MTid;ND MD P
30

继承属性


B.true,B为真时控制到达的位置; B.false,B为假时控制到达的位置。
if a<b goto B.true goto B.false
如果B1为真,则立即可知B为真,即B1.true与B.true相同; 如果B1为假,则必须计算B2的值,令B1.false为B2的开始 B2的true、false分别与E的true、false相同
第6章 中间代码生成
1
第6章 中间代码生成

中间代码表示

三地址码
四元式

类型和声明 赋值语句的翻译 控制语句的翻译

布尔表达式的翻译

控制语句的翻译
2
6.1 中间代码表示

作用

过渡:经过语义分析被译成中间代码序列
中间语言的语句 便于编译系统的实现、移植、代码优化

形式


优点

3
31

a<b


B→B1||B2

布尔表达式代码的例子


if (x<100 || x > 200 && x!= y ) x = 0; 相应的代码
32
布尔表达式的代码的SDD(1)
33
布尔表达式的代码的SDD(2)
接上表
34
混合模式布尔表达式的翻译示例
例如:4+a>b-c && d t1=4+a t2=b-c if t1>t2 goto L1 goto Lfalse L1: if d goto Ltrue goto Lfalse
14
1)局部变量的存储布局

变量的类型可以确定变量需要的内存


称为类型的宽度 可变大小的数据结构先只需要考虑指针


一个函数的局部变量总是分配在连续的区间; 因此我们可以给每个变量分配一个相对于这 个区间开始处的相对地址 变量的类型信息保存在符号表中;
15
2)计算T的类型和宽度的SDT


综合属性:type,width t和w用于类型和宽度信息从B传递到C→ε


语义


B → B‖B false
| B && B | !B | (B) | E rel E | true |

短路代码

B1‖B2中B1为真时,不计算B2,整个表达式为真。因 此,当B1为真时应该跳过B2的代码。 B1&&B2中B1为假时,不计算B2,整个表达式为假
通过跳转指令实现控制流的处理 运算符本身不在代码中出现;

运算/赋值指令:x=y op z x=op y 复制指令:x=y 无条件转移指令:goto L 条件转移指令:if x goto L ifFalse x goto L 条件转移指令:if x relop y goto L
5
三地址代码(3)

指令


过程调用/返回:
param x1 param x2 … param xn call p, n
35
回填(1)


布尔表达式和控制流语句生成目标代码的关 键问题:某些跳转指令应该跳转到哪里 例如:if (B) S



按照短路代码的翻译方法,B的代码中有一些跳 转指令在B为假时执行, 这些代码的目标应该跳过S对应的代码。 我们把这个目标的标号作为语句的继承属性next 进行传递。但这个方法需要第二趟处理。
包括:控制结构、数据结构、单词
充分了解它们的实现方法 了解中间代码的语义 了解运行环境
23

目标语言的语义

6.3 赋值语句的翻译


将一个表达式翻 译成为三地址指 令序列 表达式的SDD



属性code表示 代码 addr表示存放 表达式结果的 地址 new Temp() 可以生成一个 临时变量 gen(…)生成 一个指令
21
5)记录中的域的处理


我们可以为每个记录创建单独的符号表 处理时



首先创建一个新的符号表,压到栈顶; 然后处理对应于字段声明的D,字段都被加入到新符 号表中; 最后根据栈顶的符号表构造record类型表达式;符号 表出栈
22
6.3 赋值语句的翻译
翻译的需求

Байду номын сангаас
充分了解各种语言现象的语义

B.code
S1.code goto S.next B.false: S2 .code ... (b) if-else B.true:
指向B.true 指向B.false
继承属性 B.true, B.false S.next
29
6.4.1布尔表达式的翻译

布尔表达式可以用于改变控制流/计算逻辑值。 文法
Makelist(i) Merge(p1,p2) Backpatch(p,i)
38
翻译模式用到如下三个函数: 1.makelist(i):创建一个仅包含i的新表,i 是三地址码/四元式的一个索引(下标), 或说i是代码序列的一个标号。 2.merge(p1,p2):连接由指针p1和p2指向 的两个表并且返回一个指向连接后的表的 指针。 3.backpatch(p,i):把i作为目标标号回 填到p所指向的表中的每一个转移指令中去。 此处的“表”都是为“回填”所拉的链

如何一趟处理完毕呢?
36
回填(2)

基本思想:
记录B中所有原来生成goto S.next, if … goto S.next的代码位置; 当S.next的值已知时,把记录中的所有指令的目标 都填上这个值。


回填技术:

生成跳转指令时暂时不指定目标标号, 使用列表分别记录这些不完整的指令; 等直到正确的目标时再填写目标标号; 每个列表中的指令都指向同一个目标
9
3)三地址代码与四元式的的关系
一般形式 x := y op z

其中 x, y, z 为变量名、常数或编译产生的临 时变量 四元式(op, y, z, x)
相关文档
最新文档