编译原理 课件chapter8

合集下载

《编译原理》课件

《编译原理》课件
代码生成
编译器可以将高级语言编写的源代码转换成机器语言或低级语言,以便在特定的硬件平台上运行。编 译器还可以生成可执行文件或动态链接库等二进制文件。
编译器在人工智能领域的应用
机器学习编译器
机器学习编译器可以将机器学习模型转换成可执行代码,以便在嵌入式设备或边缘计算 设备上运行。这种编译器可以优化模型的计算性能和内存占用,提高模型的运行效率。
3
缺点
对于某些复杂文法,可能导致大量的无用推导和 状态爆炸。
自底向上的语法分析
分析步骤
从输入符号序列的最后一个符号开始,逐步向上构建语法树,直 到找到与文法中的某个产生式右部匹配的符号串。
优点
可以充分利用已知信息,避免不必要的推导和状态爆炸。
缺点
对于某些复杂文法,可能导致大量的无用归约和状态爆炸。
04
中间代码生成
中间代码生成的定义和任务
定义
中间代码生成是编译器的一个阶段,将源代码转换成中间代码的过程。
任务
将源代码转换成一种中间表示形式,以便进行后续的优化和目标代码生成。
三地址代码的生成
01
三地址代码是一种中间代码形 式,由一系列的三元式组成。
02
三元式的形式为(op, arg1, arg2),表示执行一个操作(op) 并产生一个结果,操作数arg1 和arg2来自寄存器、常数或之 前的计算结果。
语义分析
检查AST是否有语义错误,如类型错 误、未定义的变量等。
中间代码生成
将AST转换为中间代码,通常是三地 址代码。
代码优化
对中间代码进行优化,提高执行效 率。
代码生成
将中间代码转换为机器语言代码, 能够在特定硬件上执行。
编译器的分类

编译原理第8章

编译原理第8章
第八章 符号表
6、翻译模式
P:说明语句,D:类型说明语句,id:标识符(变量名),T:类型 T T T T integer {T.type:=integer;T.width:=4} 变量名及 real {T.type:=real;T.width:=8} 其性质填 T1 {T.type:=pointer(T1.type);T.width:=4} 入符号表 array[num] of T1 {T.type:=array(num.val,T1.type); offset T.width:=num.val*T1.width} D id:T {Enter(,T.type,offset); offset:=offset+T.width} offset D D;D P D {offset:=0} 内存用户区 语义子程序(语义动作) 产生式
* a * b * @b * @ b * @
c c c c b d a+a*(b-c)+(b-c)*d的DAG a:=b*-c+b*-c的语法树 a:=b*-c+b*-c的DAG
第八章 符号表
3、与后缀式的关系:表达式的抽象语法树形式的中间代码与后 缀式等价,后缀式是抽象语法树的线性表现形式,是树的结点 序列(每个结点都在其所有子结点之后立即出现 )。
第八章 符号表
符号表的作用和地位 符号的主要属性及作用 符号表的组织
第八章 符号表
一、符号表的作用和地位
一、本章主要内容: 静态语义检查和翻译中间代码; 二、静态语义检查的内容: 类型检查、控制流检查、一致性检查、相关名字检查、 名字的作用域分析等; 三、翻译产生中间代码的优点: 便于进行与机器无关的代码优化工作、使编译程序改变目标 机更容易、使编译程序的结构在逻辑上更为简单明确; 四、静态语义检查和中间代码产生在编译程序中的地位:

编译原理编译第八章

编译原理编译第八章

一. 状态转换图的定义
有限的有向图 有向边上标记字符
x
2
唯一初态
1
若干终态(至少一个)
y
3
精选ppt
二. 状态转换图识别的串
从初态出发到某一终态路径上字符的连 接。下图是识别标识符的状态转换图:
字母或数字
字母
0
1 其它字符
* 2
精选ppt
第四节 词法分析器的设计
一. 单词符号
第四章设计的语言允许下述单词: 标识符、数字串、begin、end、integer、if、 then、else、function、read、write、
精选ppt
(9)buildlist:将token中的标识符存入符号表,并 将其在符号表中的位置填入val (10)dtb:将token中的数字串转换成二进制,并 存入常数表,位置填入val (11)val:存放标识符在符号表中的位置,或常数 在常数表中的位置 (12)return(c,val):返回二元式 (13)error:出错处理
<=
<>
类别编码
9 10 11 12 13 14
15
16
精选ppt
助记符
$FUNCTION $READ $WRITE $SUB $MUL $LT
$LE
$NE
单词符号
= > >= := ; (

类别编码
17 18 19 20 21 22 23
精选ppt
助记符
$EQ $GT $GE $ASSIGN $SEM $LPAR $RPAR
‘ : ‘: begin getchar; if character = ‘ = ‘ then return($ASSIGN,—) else error

第8章演示文稿

第8章演示文稿

• Triples are used in order to avoid the entering temporary names into symbol tables. • We can refer to a temporary value by this position in the statement
• Intermediate representation in the literature include:
– – – – syntax tree (section 5.2) postfix (section 2.3) three address code (chap. 8) others (AST, DAG, Control Flow Graphs (CFG), Program dependence Graph (PDG), Static Single Assignment Form, stack code)
– E.place is the name that will hold the value of E – E.code is a sequence of three-address statements evaluating E
• The function newtemp returns a sequence of distinct names • The function newlabel returns a sequence of distinct labels
14
• E.g.
• Ternary operation x[i] := y requires two entries in the triple structure and x := y[i] requires two operations.

编译原理 第八章

编译原理 第八章

② for(i=6,j=0; j<i; ++j) fun(i); 在六次循环中,i的值保持为6,则可优化为: for(i=6,j=0;j<6; ++j) fun(6);
3. 综合使用常数传播和常数合并进行优化处理 为了对保持定值的所有变量之值进行跟踪,建立一个局部符号表,使 每一个活动的变量在该表中有一个登记项,每当对这些变量进行再定 值时,就相应的修改其登记项中的内容。 例: t1=1; t1+=5; 优化为: t1=6; t2=t1; t2=6;
一. 强度削弱
用一种(或一串)执行时间较短的操作去等价的代替一个操作。 1. x*2n 替换为 x<<n (乘法用左移运算替换) x/2n 替换为 x>>n x%2n 替换为 x&(2n-1) 2. 乘以一个较小的整数可以用多个加法代替 x*=3 替换为 x1=x; x+= x1; x+= x1; 3. 较大整数的乘法可以联合使用位移和加法进行强度削弱优化 x*=9 替换为 x1=x; x*=27 替换为 x1=x; x1<<=3; x1<<=1; x+= x1; x+= x1; x1<<=2; x+= x1; x1<<=1; 4. 对于非算术运算进行强度削弱的情形 x+= x1; 例如:许多机器有多种形式的转移指令, 优化程序可以从其中选择效率更高的指令。
三. 无用变量与无用代码的删除
1. 无用变量:变量的最后一次引用到对该变量再置初值期间,可视为无用 变量。在变量的无用期间,对该变量的所有定值(如赋值)指令均可删去。 例: t=a; t+=5; x=t; …… /*此后的一个时间间隔内,t成为无用变量*/ t=c; /*在t的无用期内,对t的定值可以删除*/ …… t=b; /*t被再次置初值,无用期结束*/ y=t+a;

精品课程编译原理-PPT课件第8章 语法制导与中间代码生成

精品课程编译原理-PPT课件第8章  语法制导与中间代码生成

(3)一致性检查。在很多场合要求对象只能被 定义一次。例如Pascal语言规定同一标识符在一 个分程序中只能被说明一次,同一case语句的标 号不能相同,枚举类型的元素不能重复出现等等。
(4)上下文相关性检查。比如,变量名字必 须先声明后引用;
(5)名字的作用域分析。各变量的作用域可 能是不一样的,要通过分析明确各变量的作用域。
例子: a:=b*c+b*d的相应三元组
①(*, b, c) b*c ②(*, b, d) b*d ③(+, (1),(2)) b*c+b*d ④(:=,(3), a) a:=b*c+b*d
例子:tri(A*B+C) =tri(A*B)||tri(c)||2:(+,①≥,C) =1:(*, A,B) A*B 2:(+,①,C) A*B+C
8.2.2 S-属性文法和自下而上翻译 一般的属性文法的翻译器很难建立,然 而L-属性文法的翻译器很容易建立。
L-属性文法的一个特例叫S-属性文法。 S-属性文法是只含有综合属性的属性文法。
8.2.3 L-属性文法在自下而上分析中实现 L-属性文法允许一次遍历就计算出所以的 属性值。
8.3 中间代码的形式
3*5+6的带注释的分析树
只使用综合属性.
T.val=3 F.val=3
E.val=15 T.val=15
*
L
E.val=21
+
F.val=5
T.val=6 F.val=6 digit.lexval=6
digit.lexval=5
digit.lexval=3
3*5+6的带注释的分析树
继承属性
一个结点的继承属性值是由此结点的父结点和/或兄弟结 点的某些属性来决定的。

编译原理课件-目标程序运行时的组织

编译原理课件-目标程序运行时的组织
處理分程式結構存儲分配方案的一種 簡單辦法是,把分程式看成 “無名無參過 程”,它在哪里定義就在哪里被調用。因 此,可以把處理過程的存儲辦法應用到處 理分程式中。但這種做法是極為低效的。
一則,每逢進入 一個分程式,就照樣建立 連接數據和DISPLAY表,這是不必要的。 二則 ,當從內層分程式向外層轉移時,可 能同時要結束若干個分程式。
簡單的棧式分配方案
• 程式結構特點:過程定義不嵌套,過程可 遞歸調用,含可變數組;
• 例: main • 全局變數的說明
• proc R • …… • end R; • proc Q • …… • end Q; • 主程序執行語句
• end main
Main---->Q---->R
Main--->Q---->Q
棧式存儲組織review
數據空間的存儲管理:棧式存儲分配
– 過程(函數)的活動記錄:是一段連續的存儲區,存放過 程(函數)的一次執行所需要的資訊。
– 過程(函數)活動記錄的內容:聯繫單元(靜態鏈,動態鏈 和返回地址)、局部變數和臨時變數
棧式存儲分配的實現:
• 設置兩個指針:棧頂指針Top和當前活動記錄指針SP; • 調用一個過程(函數)前,先把過程(函數)的參數壓入數據棧; • 在數據棧中為過程(函數)的活動記錄分配空間; • 填寫聯繫單元內容; • 執行過程(函數)代碼; • 過程(函數)返回前,根據當前SP恢復Top指針,根據動態鏈恢
按照過程處理辦法,意味著必須一層 一層地通過“返回” 來恢復所要到達的 那個分程式的數據區,但不能直接到達。
例如:如果有一個從第5層分程式轉出到達 第1層分程式的標號L,雖然在第5層分程 式工作時知道L所屬的層數,我們極易從 DISPLAY中獲得第1層分程式的活動記 錄基址(SP),但是怎麼知道第1層分程 式進入時的TOP呢?唯一的辦法是從 5,4,3和2各層順序退出。但這種辦法是很 浪費時間的。

编译原理课件chap08(陈火旺)

编译原理课件chap08(陈火旺)

• •
8.2.1 栈式存储分配与活动记录 使用栈式存储分配法意味着程序运 行时,每当进入一个过程(或函数)就有一 个相应的活动记录累筑于栈顶,此记录 含有连接数据、形式单元、局部变量、 局部数组的内情向量和临时工作单元等; 在进入过程和执行过程的可执行语句之 前,再把局部数组所需空间累筑于栈顶, 从而形成过程工作时的完整数据区。
TOP
临时工作单元 内情向量 简单变量 形式单元 2 1 参数个数 返回地址 老SP
SP
0
第八章 运行时存储空间组织
4 3 TOP+3 2 1 TOP SP 0
参数个数n

T2 T1 P的活动记录 现行SP值
第八章 运行时存储空间组织
8.2 简单的栈式存储分配
• 我们首先考虑一种简单程序语言的 实现,这种语言没有分程序结构,过程 定义不允许嵌套,但允许过程的递归调 用,允许过程含有可变数组。例如,C语 言除不允许含有可变数组外,就是这样 一种语言。C语言的程序结构如下:
第八章 运行时存储空间组织
• • • • • • • • •
第八章 运行时存储空间组织

满足这些条件的语言有FORTRAN,还有 BASIC等语言。在这些语言中,编译程序可以完 全确定程序中数据项所在的地址(通常为相对于 各数据区起始地址的位移量)。由于过程调用不 允许递归,因此数据项的存储地址就与过程相联 系。过程调用所使用的局部数据区可以直接安排 在过程的目标代码之后,并把各数据项的存储地 址填入相关的目标代码中,以便在过程运行时访 问这个局部数据区。在此,不存在对存储区的再 利用问题;目标程序执行时不必进行运行时的存 储空间管理,过程的进入和退出变得极为简单。
第八章 运行时存储空间组织

编译原理compiler8

编译原理compiler8
图8.1 求基本块内变量的待用信息(例8.1) 初始
9
1. 二、寄存器描述和地址描述 2. 为了在代码生成中充分利用寄存器,生成尽
可能简短的代码,将使用寄存器描述数组 RVALUE[Ri]记录寄存器Ri是空闲着,还是已 分配给某些变量;将使用变量地址描述数组 AVALUE[A]来记录变量A的现行值是存放在 某个寄存器中,还是在某个主存单元中,或 者既在寄存器中又在主存中。
12
(3) 如果已无可用寄存器,即寄存器均被占用,则
只能从被占用的寄存器中选择一个Ri,先将占用 Ri的变量的现行值逐一保存到主存单元中,然后
才可分配给x使用。选择标准是使这种复制副本的
代价尽可能小,很明显,最好选在主存单元中已
副本的占用Ri的变量,或者该变量在P以后不再被 引用或在最远的将来才会被引用。在这种情况下,
op Ri, c(Rj) (Ri)op((Ri)+c) Ri (4) 间接型:
op Ri, *Rj (Ri)op((Rj)) Ri
op Ri, *M (Ri)op((M)) Ri
op Ri, *c(Rj) (Ri)op(((Ri)+c)) Ri 5
其他操作指令的指令意义为:
(1) MOV Ri, M (2) MOV M, Ri
3
二、目标机器 目标机多种多样,要生成好的目标代码,必须熟悉目标机, 特别是指令系统的细节。作为一般讨论,我们不打算讨论 十分依赖于目标机器细节的内容,当然也不可能生成完整 的满意的代码。我们只讨论一般技术,只针对一种抽象的 目标机,它是简单的,作为各种目标机的子集,它是公共 的。 目标机具有几个通用寄存器,它们同时可作为变址器。
2
第八章 代码生成
§8.1 目标代码

编译原理第八章

编译原理第八章

逆波兰表示很容易扩充到表达式以外的范围。
只要遵守运算对象后直接紧跟它们的运算符的规 则即可。 比如把转语句GOTO L写为“L jump ", 运算对象L为语句标号,运算符jump表示转到某个标 号L 。 再比如条件语句if E then S1 else S2 可表示为:ES1S2¥,把if then else看成三目运 算符,用¥来表示。
生成后缀式的属性文法 产生式 语义规则 S→id:=E Print( || E.code || ―:=‖)
E→E1+E2 E.code := E1.code || E2.code || ‖+‖ E→E1*E2 E.code := E1.code || E2.code || ‖*‖ E.code := E1.code || ―-― E→ -E1 E→ (E1) E.code := E1.code E.code := E→ id E→ num E.code := num.val; 属性 code 表示生成的代码
句子 int id1,id2 的语法树,使用 情况。
表示属性的传递
S-属性定义(S-属性文法)
仅包含综合属性的语法制导定义
如:算术表达式求值的属性文法
L-属性定义(L-属性文法)

既包括综合属性,又包括继承属性,即对 于所有A→X1 X2 … Xn,每一个属性 都是一个综合属性,或者Xi 属性计算仅 使用A X1 X2 … Xi-1 的属性
假如语法分析方法是自下而上的。在用某 一产生式进行归约的同时就执行相应的语 义动作,在分析出一个句子时,这个句子 的"值"也就同时产生了
3、属性文法的定义:
一个属性文法是一个三元组: A=(G,V,F),

安徽大学《编译原理》第8章课件

安徽大学《编译原理》第8章课件

(1) ( - C D T1 )
T1 := C - D
(2) ( * B T1 T2)
T2 := B * T1
(3) ( + A T2 T3)
T3 := A + T2
(4) ( - C D T4)
或 T4 := C - D
(5) ( ^ T4 N T5)
T5 := T4 ^ N
(6) ( / E T5 T6)
S id := E { S.type := if lookup_type (id.entry) = E.type then ok else type_error }
S if E then S1 { S.type := if E.type=bool then S1.type else type_error }
• int i[3,5];
• extern float i; • float i[3,4];
3
实现符号表的数据结构
• 线性表 • 有序表 • 二叉搜索树 • Hash表
4
创建符号表的时机
• 在语义分析前,最常见的是在语法分析的
同时创建。
5
作用域的问题
• 体现符号的作用域和可见性是符号表组织
与设计的一个重要方面
并返回该名字的存储位置 || 是TAC 语句序列之间的链接运算
S id := E { S.code := E.code || gen(id .place ‘:=’ E.place) } E id { E.place := id .place;E.code:=“” }
E int { E.place := newtemp; E.code := gen (E.place ‘:=’ int .val) }

编译原理chapter8

编译原理chapter8

对于任意一棵树,将它重写为等价的没有上 对于任意一棵树, 述任何一种情况的树: 述任何一种情况的树:
重写成一列不含SEQ和ESEQ结点的 重写成一列不含SEQ和ESEQ结点的规范树 结点的规范树 (canonical tree); tree); 将这一列树分组组合成其内不含转移和标号的基 将这一列树分组组合成其内不含转移和标号的基 本块(basic block)集合 集合; 本块(basic block)集合; 对基本块排序并形成一组轨迹 对基本块排序并形成一组轨迹(trace),轨迹中每 轨迹(trace), 一个CJUMP之后都直接跟随它的 之后都直接跟随它的false标号 标号。 一个CJUMP之后都直接跟随它的false标号。
Moving CALLS to Top Level
Tree语言允许将 Tree语言允许将CALL结点作为子表达式。 语言允许将CALL结点作为子表达式 结点作为子表达式。 但是,在实际应用中CALL的实现是:将结果返回 的实现是: 但是,在实际应用中CALL的实现是 到同一个规定的返回值寄存器 返回值寄存器TEMP(RV)中 到同一个规定的返回值寄存器TEMP(RV)中。 举例: BINOP( PLUS, CALL(…), CALL(…)) 利用重写规则解决:将每一个返回值立即赋给一个 利用重写规则解决: 新的临时寄存器。 新的临时寄存器。
Algorithm: Algorithm:
“subexpression-extraction” method; subexpression“subexpression“subexpression-insertion” method. 给定一个已清除了所有子表达式中的ESEQ的表达 给定一个已清除了所有子表达式中的ESEQ的表达 式或语句, 式或语句,算法将生成该表达式或语句的一个新版 本。 函数do_exp和do_stm辅助函数 函数do_exp和do_stm辅助函数recorder,使得 辅助函数recorder, recorder能够根据给它的指针表从右至左地从一个 recorder能够根据给它的指针表从右至左地从一个 表达式e 中抽出语句s 表达式ei中抽出语句si 。

编译原理课件8

编译原理课件8

运行时存储组织
活动记录(activation record)
过程活动记录
• 函数/过程调用或返回时,在运行栈上创建或从运行栈 上消去的栈帧(frame) 包含局部变量,函数实参,临时值(用于表达式计算的 中间单元)等数据信息以及必要的控制信息 某个数据对象的地址= 活动记录起始地址 + 偏移地址(offset)
D[2]
D[1]
Q 的活动记录
P 的活动记录 S 的活动记录
D[0]
main 的活动记录
运行时存储组织
活动记录
嵌套过程语言的栈式分配
• Display 表的维护(过程被调用和返回时的保存和恢复) 方法一 极端的方法是把整个 Display 表存入活动记录 若过程为第 n 层,则需要保存 D[0] ~D[n] ) 一个过程(处于第 n 层)被调用时,从调用 过程的 Display 表中自下向上抄录 n 个 SP 值,再加上本层的 SP 值 方法二 只在活动记录保存一个的 Display 表项,在静 态存储区或专用寄存器中维护全局 Display 表
数据信息
活动记录起始地址 (通常存于某专用寄存器中)
控制信息
运行时存储组织
活动记录
过程活动记录的栈式分配举例
void p( ) { … q( ); } void q( ) { … q( ); } int main { p( ); }
函数 q 被第二次激活时运 行栈上活动记录分配情况
q 的活动记录
运行时存储组织
栈式存储分配
用于有效实现可动态嵌套的程序结构
• 如实现过程/函数,块层次结构
可以实现递归过程/函数
• 比较:静态分配不宜实现递归过程/函数

编译原理蒋宗礼课件第8章

编译原理蒋宗礼课件第8章

22
8.4.2 程序块结构符号表的其他实现
对图8.10 中的程序
...
a0 ... b0 ...
NULL NULL
(a) 处理到语句(5)时的符号表
... a0 ... b1 ... b0 NULL NULL
(b) 处理到语句(7)时的符号表
23
8.4.2 程序块结构符号表的其他实现
对图8.10中的程序
名字 符号种类 符号表表项1 符号表表项2 符号表表项3 abc i myarray ... 变量 变量 数组 int int int ... 基本属性 类型 地址 扩展属性指针 0 4 8 NULL NULL 维数 2 各维维长 3 4 扩展属性
图8.3 多种符号共用符号表的一种实现结构
11
8.1.2 符号表中的属性
19
8.4.2 程序块结构符号表的其他实现
• 将所有块的符号表放在一个大数组中,然后再引入 一个程序块表来描述各程序块的符号表在大数组中 的位置及其相互关系
名字 外层块 符号个数 起始指针 0 1 2 3 -1 0 1 1 2 1 1 1 程序块表 1 2 3 4 5 a b b b a 符号表 属性
– 如栈式存储分配时,i的地址是以栈指针sp为基址 加上i相对于活动记录起始地址的偏移量offseti
• 符号表中各符号的地址属性就是该符号相对于 第一个符号的偏移地址
13
8.3 符号表的组织结构 8.3.1 符号表的线性表实现
• 用线性表实现符号表较为直观
– 数组实现:插入n个符号、执行e次查找操作的时 间复杂度为T(n, e) = O(n(n+e)) – 有序数组实现:插入n个符号、执行e次查找操作 的时间复杂度为T(n, e) = elog n+ (log i) + i ≤ (n+e)log n+O(n2)

编译原理 8章

编译原理 8章

8.1 一般原理和树变换
• 语法制导翻译法(SDTS) 一个源语言 一个目标语言 一组翻译规则 • SDTS是一个CFG(Context Free源自Grammar) 上下文无关文法。
SDTS是一个上下文无关文法
• T=(VT, VN, Δ , R , S) VT: 有穷输入字母表 VN: 有穷非终结符号集合 Δ: 有穷输出字母表 R : 一组A→w,y 规则的有穷集合 A∈VN, w∈(VT∪VN)*, y∈(Δ∪VN)* S : 开始符号
T1的基础源文法是: E→E+T|E-T|-T|T T→[E]|A A→a|b|c T1的基础目标文法则是: E→T E ADD | E T SUB | T NEG | T T→E | A A→x|y|z
8.1一般原理和树变换 8.1一般原理和树变换
一般原理(5) 8.1.1 一般原理(5)
• 一个翻译模式是一个形如(u,v)的串对,其中: u是SDTS基础源文法的一个句型,它是由VN和VT中元 素组成的串。 而v称为与其对应的翻译,它是由VN和Δ中元素组成 的串。 • 翻译模式的定义如下: ①(S,S)是一个翻译模式,且这两个S是相关的(S是 SDTS的开始符号). ②(aAb,a’Ab’)是一个翻译模式,且两个A是相关的: 此外,若A→g,g’是R中的一条规则,那么(agb, a’g’b’)也是一个翻译模式。规则中g和g’的非终结 符之间的相关性也必须带进这种翻译模式之中。
• 翻译模式是一个形如(u,v)串对 • 例如对输入串 -[a+c]-b的翻译过程 (E,E)=>(E-T2, E T2 SUB) =>(-T1-T2, T1 NEG T2 SUB) =>(-[E]-T2, E NEG T2 SUB) =>(-[E+T1]-T2, T1 E ADD NEG T2 SUB) =>(-[T3+T1]-T2, T1 T3 ADD NEG T2 SUB) =>(-[A+T1]-T2, T1A ADD NEG T2 SUB) =>(-[a+T1]-T2, T1 x ADD NEG T2 SUB) =>(-[a+A]-T2, A x ADD NEG T2 SUB) =>(-[a+c]-T2, z x ADD NEG T2 SUB) =>(-[a+c]-A, z x ADD NEG A SUB) =>(-[a+c]-b, z x ADD NEG y SUB)

编译原理第八章

编译原理第八章

2013年8月21日2时45分
(3) 在符号表的信息栏中引入一个指针域(previous)用以 链接它在同一过程内的前一域名字在表中的下标(相对位 置)。每一层的最后一个域名字,其previous之值为0。这 样,每当需要查找一个新名字时,就能通过DISPLAY找出 当前正在处理的最内层的过程及所有外层的子符号表在栈 符号表中的位置。然后,通过previous可以找到同一过程 内的所有被说明的名字。
2013年8月21日2时45分
8.4 符号表的内容
符号表的信息栏中登记了每个名字的有关的性质,如类型、 种属、大小以及相对数。 对于变量名、数组名和过程名,信息栏中一般有下列信息: (1)变量 类型(整数、实、双实、布尔、字符、复、标号 或指针); 种属(简单变量、数组或记录结构); 长度(所需的存储单元数); 相对数(存储单元数); 若为数组,则记录其内情况向量。
2013年8月21日2时45分
杂凑技术
对于表格处理来说,根本问题在于如何保证查表与填表两 方面的工作都能高效地进行。对于线性表来说,填表快, 查表慢。而对于对折法而言,则填表慢,查表快。杂凑法 正是一种争取查表、填表两方面都能高速进行的统一技术。 这种办法是:假定有一个足够大的区域,这个区域以填写 一张含N项的符号表。构造一个地址函数H。对于地址函 数H有两点要求:第一,函数的计算要简单、高效;第二, 函数值能比较均匀地分布。对于杂凑技术还应设法解决 “地址冲突”的问题。
2013年8月21日2时45分
8.2 整理与查找
符号表作为一个多元组,表中元组的排列组织是构造符号 表的重要成分。在编译程序的整个工作过程中,符号表被 频繁地用来建立表项,找查表项,填充和引用表项的属性 。因此表项的排列组织对该系统运行的效率起着十分重要 的作用。在编译程序中,符号表项的组织传统上采用三种 构造方法。即线性法,二分法及散列法。
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
23
i:
x:=…… …………….
j:
… := …x…
j是i中x的下次引用信息(在基本块之内)。 二. 收集基本块中关于名字的下次引用信息
假定变量的符号表表项中含有记录下次引用 信息和活跃信息的域,所有的非临时变量在出口 处都是活跃的 。
24
1. 开始时,把基本块中各变量的符号表表项中 的下次引用信息域置为“无下次引用”,活跃 信息域置为“活跃”。 2.从基本块出口到基本块入口由后向前依次处
c
d u v
活 活
非 活 活 活 非
非 活 活
27
8.5 一个简单的代码生成器 充分利用寄存器,即,一方面尽可能地让变量 的值保留在寄存器中(即不编出把该变量的值存 到内存单元的指令),直到该寄存器必须用来存 放别的变量值或者已到达基本块出口为止;另一 方面,后续的目标代码尽可能地引用变量在寄存 器中的值,而不访问主存。 例如,a:=b+c (1) Ri中存放了b的值,而Rj中存放了c的值, 且b在此语句之后不再活跃。 ADD Rj,Ri 其开销为1,结果在Ri中。
3
contents(a)表示由a所代表的寄存器或存储单元的 内容。 有关地址方式及它们的汇编语言形式和有关开销 如表8.1所示。 表8.1 目标机器的地址方式
地址方式 汇编 地址 开销 M 1 直接地址方式 M R R 0 寄存器方式 *R Contents(R) 0 间接寄存器 c( R) c+ Contents(R) 1 索引方式 1 间接索引方式 *c(R) C(c+ contents(R))
30
8.5.2 代码生成算法 对每个形如 i:x:=y op z {下次引用信息} 依次执行下述步骤: 1. L:= getreg(i:x:=y op z) L常常是一个寄存器,也可能是一个存储单 元,用来存放计算y op z所得的结果。 2. 考虑y的地址描述器以确定y,y 为y的值当 前的存放位置。若y的值同时在主存中和一 个寄存器中,那么y 取寄存器更好。若y的 值尚不在L中,则生成指令: MOV y',L
例:
L1: if a<b goto L2 goto Lnext L2: if c<d goto L3 goto L4 L3: t1 :=y+z x :=t1 goto L1 t2 :=y-z x :=t2 goto L1
L4:
21
例:
L1: if a<b goto L2 goto Lnext L2: if c<d goto L3 goto L4 L3: t1 :=y+z x :=t1 goto L1 t2 :=y-z x :=t2 goto L1
13
这个序列可翻译成如下的机器指令: MOV #0, 12(R3) 注意在寄存器R3中的值不能在编译时确定。 8.3 基本块和流图 三地址语句序列的一种图表示法称为流图, 它对理解代码生成算法是很有用的。流图中的结 点表示计算,边表示控制流向。
14
8.3.1 基本块 定义 一个基本块是这样一个连续语句序列: 其中控制流从第一条语句(称为入口〕进入, 从最后一条语句(称为出口)离开,中途没有 停止或分枝。例如:
6
假定R1和R2中分别包含b和c的值,并且b的 值在这个赋值以后不再需要,则我们还有: 4.ADD R2 , R1 MOV R1 , a cost=3 有效地利用它的地址能力和寄存器。
7
8.2 运行存储管理 运行时刻管理活动记录应生成哪些代码,静态 分配和栈式分配。 运行时活动记录的分配和释放是作为过程调 用和返回序列的一部分,集中讨论如下三地址语 句生成哪些代码: 1. call (调用); 2. return (返回); 3. halt (暂停); 4. action (动作〕,为其它语句占有位置。
第八章 代码生成 序
8.1 目标机器
8.2 运行存储管理 8.3 基本块和流图 8.4 下次引用信息 8.5 一个简单的代码生成器
1

中间代码
代码生成器
目标代码
符号表
中间代码: 后缀式,三地址代码,语法树。 符号表中的项:名字,类型, 嵌套深度,偏移量 目标代码:绝对机器代码,可再定位代码,汇编
2
4
指令开销 开销是与一条指令的长度(按字计算)相对应 的。对绝大多数机器和绝大多数指令而言,用来 从存储器中获取一条指令的时间超过了执行该指 令的时间。 指令开销=源地址开销 +目的地址开销+1 1.MOV R0,R1 1 2.MOV R5,M 2 3.ADD #1,R3 2 4.SUB 4(R0),*12(R1) 3 contents(contents(12+contents(R1))) -contents(4+contents(R0))
5
生成高质量目标机器代码的一些困难。 如, a:=b+c用不同的指令序列来实现:
1.MOV b , R0 ADD c ,R0 cost=6 MOV R0 , a 2.MOV b , a ADD c , a cost=6 假定R0,R1和R2中分别存放了a,b和c的地址: 3.MOV *R1 , *R0 ADD *R2 , *R0 cost=2
8
三地址代码 S的活动记录 p的活动记录
/*s的代码 */
action1
call p
返回地址
返回地址
action2
halt
arr
buf
/*p的代码 */
action3 return
i
n
9
jห้องสมุดไป่ตู้
8.2.1静态分配管理
call调用语句 MOV #here+20,callee.static_area GOTO callee.code_area MOV指令存放返回地址。 GOTO指令将控制转移到被凋用过程的目标 代码。callee.static_area和callee.code_area分别指 示被调用过程活动记录的始址和第一条指令的 地址。 从过程callee的返回: GOTO *callee.static_area
/*转移到被调用过程的代码的第一条指令*/ 属性caller.recordsize代表一个活动记录的大小。
11
MOV top, sp ADD #caller.recordsize,top
返回序列包括两个部分: GOTO *0(SP)/*返回到调用过程*/ MOV sp, top SUB #caller.recordsize, SP
理各个三地址语句。对每一个三地址语句
i:x:=y op z,依次执行下述步骤:
(a)把当前符号表中变量x的下次引用信息和活
跃信息附加到语句i上; (b)把符号表中x的下次引用信息和活跃信息分 别置为“无下次引用”和“非活跃”;
25
(c)把当前符号表中变量y和z的下次引用信息 和活跃信息附加到语句i上; (d)把符号表中y和z的下次引用信息均置为i,活 跃信息均置为“活跃”。 注意: 以上次序不可颠倒,因为y和z也可能是x。 例: t :=a-b u:=a-c v:=t+u d:=v+u
t1 :=a * a t2 :=a * b t3 :=2 *t2 t4 :=t1+t2 t5 :=b * b t6 :=t4+t5
15
一条三地址语句x :=y+z称为对x定值并引 用y和z。在一个基本块中的一个名字,所谓在 程序中的某个给定点是活跃的,是指如果在程 序中(包括在本基本块或在其它基本块中〕它 的值在该点以后被引用。
28
(2)b存放在Ri中,而c在一个存储单元里,并 假定b不再活跃。 ADD c,Ri 其开销为2 (3)或者 MOV c,Rj ADD Rj,Ri 其开销为3 8.5.1 寄存器描述器和地址描述器
代码生成算法将使用寄存器描述器和地址描述 器来记录寄存器的内容和名字的地址。
29
1.寄存器描述器记录每个寄存器的当前内容, 每当需要一个新的寄存器时,首先查看此描 述器。假定在初始时寄存器描器指示所有的 寄存器均为空。当对基本块进行代码生成时 ,每个寄存器在任一 给 定时刻将保留零个或 多个名字的值。 2.地址描述器记录在运行时刻的一个名字 的当 前值存放的一个位置或多个位置。它可能是 一个寄存器地址、一个栈地址、一个存储单 元地址、或这些地址的一个集合。
L4:
22
8.4 下次引用信息 一. 下次引用信息的用途 充分利用寄存器,把基本块内还要被引用的变 量值尽可能保存在寄存器中,同时把基本块内不 再被引用的变量所占用的寄存器及早释放掉。 术语:下次引用信息,或说下一个引用点。 每当翻译一条三地址语句x:=y op z时,我们 需要知道,x,y,z是否还会在基本块内被引用 以及用于哪些三地址语句中。
26
(1)t:=a+b {t:3,活; 名字 下次引用 活跃 3 无 t 无 非 a:2,活;b:无,活} 活 非 活 1 2 a 无 (2)u:=a-c {u:3,活;a,c:无,活} (3)v:=t+u {u,v:4,活;t:无,非} (4)d:=v+u {d,u,v:无,活} b 1 无 2 无 无 4 无 3 无 无 4 无 活 活
8.2.3 名字的运行地址 x:=0 静态分配区域的开始地址是static, x的相对地 址12,则x的实际地址应为static+12。 static [12]:=0
12
如果静态区域是从地址100开始,则上述语句的 目标代码为: MOV #0,112 栈式分配,用一个display表存取非局部名字, 又假定该display表是存放在一些寄存器中,并且 x是局部于一个活动记录的变量,该活动记录的 display表指针在寄存器R3中,那么,X:=0翻译 成为如下三地址语句; t1:=12+R3 *t1:=0 其中t1中存放的是x的地址。
8.1 目标机器 按字节编址,以4个字节为一个字. 通用寄存器R0,R1,…,Rn-1。 两地址指令形式: op source,destination 其中op是一个操作码,source和destination称为 源和目的,是数据域。例如有如下的操作码: MOV (将源移到目的中) ADD (将源加到目的中) SUB (在目的中减去源)
相关文档
最新文档