编译原理_chapter9
合集下载
编译原理chapter9 运行时存储空间组织
编译原理
chapter9
运行时存储空间组织
Chapter9 运行时存储空间组织
编译原理
chapter9
运行时存储空间组织
9.1 目标程序运行时的活动 9.2 运行时存储器的划分 9.3 简单的栈式存储分配 9.4 嵌套过程语言的栈式实现 9.5 堆式动态存储分配
编译原理
chapter9
运行时存储空间组织
编译原理
chapter9
运行时存储空间组织
1. 带有静态链的活动记录 带有静态链 静态链的活动记录 静态链:它指向直接外层过程的活动记录的起始位置, 静态链:它指向直接外层过程的活动记录的起始位置, 直接外层过程的活动记录的起始位置 用于访问各外层的变量(非局部变量)。 用于访问各外层的变量(非局部变量)。
动态链:指向调用本过程的最新活动 ④. 动态链:指向调用本过程的最新活动 返回地址 记录的起始地址; 记录的起始地址; 动态链 每个活动记录的大小在编译时可以确定 SP ( 除动态数据 ),因此以 为变址器可方便的访问各个数据 ,因此以SP为变址器可方便的访问各个数据
编译原理
chapter9
运行时存储空间组织
top
u=15 v=10 形式单元 参数个数 gcd(15,10)
sp top sp
2 返回地址 老sp
x=15 y=10
main() 全局 /静态区 静态区
编译原理
chapter9
运行时存储空间组织
program p; 9.4 嵌套过程语言的栈式实现 var a,x:integer; 语言为例, 以Pascal语言为例Q(b:integer); 语言为例 由于允许嵌套定义过程, procedure ,由于允许嵌套定义过程,则会 var i:integer; 出现“非局部名字的访问”问题。 出现“非局部名字的访问”问题。因此简单的栈式存储分 procedure R(u:integer;var v:integer); 配不适用。 配不适用。 var c,d:integer; begin if u=1 then R(u+1,v) 活动记录中可配有静态链和嵌套层次表两种方式来实现。 静态链和嵌套层次表43;c)*(b-d); 两种方式来实现。 end {R} begin …. R(1,x); ……. end {Q} procedure S; var c,i:integer; begin a=1;Q(c); …….end {S} begin a=0;S;…… end
chapter9
运行时存储空间组织
Chapter9 运行时存储空间组织
编译原理
chapter9
运行时存储空间组织
9.1 目标程序运行时的活动 9.2 运行时存储器的划分 9.3 简单的栈式存储分配 9.4 嵌套过程语言的栈式实现 9.5 堆式动态存储分配
编译原理
chapter9
运行时存储空间组织
编译原理
chapter9
运行时存储空间组织
1. 带有静态链的活动记录 带有静态链 静态链的活动记录 静态链:它指向直接外层过程的活动记录的起始位置, 静态链:它指向直接外层过程的活动记录的起始位置, 直接外层过程的活动记录的起始位置 用于访问各外层的变量(非局部变量)。 用于访问各外层的变量(非局部变量)。
动态链:指向调用本过程的最新活动 ④. 动态链:指向调用本过程的最新活动 返回地址 记录的起始地址; 记录的起始地址; 动态链 每个活动记录的大小在编译时可以确定 SP ( 除动态数据 ),因此以 为变址器可方便的访问各个数据 ,因此以SP为变址器可方便的访问各个数据
编译原理
chapter9
运行时存储空间组织
top
u=15 v=10 形式单元 参数个数 gcd(15,10)
sp top sp
2 返回地址 老sp
x=15 y=10
main() 全局 /静态区 静态区
编译原理
chapter9
运行时存储空间组织
program p; 9.4 嵌套过程语言的栈式实现 var a,x:integer; 语言为例, 以Pascal语言为例Q(b:integer); 语言为例 由于允许嵌套定义过程, procedure ,由于允许嵌套定义过程,则会 var i:integer; 出现“非局部名字的访问”问题。 出现“非局部名字的访问”问题。因此简单的栈式存储分 procedure R(u:integer;var v:integer); 配不适用。 配不适用。 var c,d:integer; begin if u=1 then R(u+1,v) 活动记录中可配有静态链和嵌套层次表两种方式来实现。 静态链和嵌套层次表43;c)*(b-d); 两种方式来实现。 end {R} begin …. R(1,x); ……. end {Q} procedure S; var c,i:integer; begin a=1;Q(c); …….end {S} begin a=0;S;…… end
编译原理 课件第九章
上下文语义的合法性检查的依据
在语义分析中,符号表所登记的内容将用于语义检查(如检查 一个名字的使用和原先的说明是否一致)和产生中间代码。通 过符号表中属性记录可进行相应上下文的语义检查。 例如,在一个C语言程序中出现 … int i [3][5]; //定义整型数组i … float i[4][2]; //定义实型数组i,重定义冲突 … int i [3][5]; //定义整型数组i,重定义冲突 … 编译过程首先在符号表中记录了标识符i的属性是3×5个整型元 素的数组,而后在分析第二、第三这两个定义说明时编译系统 可通过符号表检查出标识符i的二次重定义冲突错误。本例还可 以看到不论在后二句中i的其它属性与前一句是否完全相同,只 要标识符名重定义,就将产生重定义冲突的语义错误。
9.1符号表的作用和地位 符号表的作用和地位 9.2符号的主要属性及作用 符号的主要属性及作用 9.3符号表的组织 符号表的组织
9.1 符号表的作用和地位
收集符号属性 上下文语义的合法性检查的依据 作为目标代码生成阶段地址分配的依据
收集符号属性
编译程序扫描说明部分,收集有关标识符的属性,并在符号表 中建立符号的相应属性信息。 例如,编译程序分析到下述两个说明语句 int A; float B[5]; 则在符号表中收集到关于符号A的属性是一个整型变量,关于 符号B的属性是具有5个浮点型元素的一维数组。
9.2 符号的主要属性及作用
符号属性
1 符号名 2 符号的类型 3 符号的存储类别 4 符号的作用域及可视性 5 符号变量的存储分配信息 6 符型的成员信息 (3) 函数及过程的形参
① 符号名 符号表中设置一个符号名域,存放该标识符,该域通 常就是符号表的关键字域。
作为目标代码生成阶段地址分配的依据
编译原理chapter9优化
goto B2
t11 := 4 * i x := a[t11] t12 := 4 * i t13 := 4 * n t14 := a[t13] a[t12] := t14 t15 := 4 * n a[t15] := x
10.2.2 公共子表达式删除
如果表达式E先前已计算,并且从先前的计算到E的再次出现,E中变量的 值没有改变,那么E的这个再次出现称为公共子表达式
(2) j := n
do i = i +1; while(a[i]<v); (3) t1 := 4 * n
do j =j 1;while (a[j]>v); (4) v := a[t1]
if (i >= j) break;
(5) i := i + 1
x=a[i]; a[i]=a[j]; a[j]=x; (6) t2 := 4 * i
}
(7) t3 := a[t2]
10.2 优化的主要种类
本节所用的例子
i = m 1; j = n; v = a[n]; (9) j := j 1
while (1) {
(10) t4 := 4 * j
do i = i +1; while(a[i]<v); (11) t5 := a[t4]
do j =j 1;while (a[j]>v); (12) if t5>v goto (9)
10.2.2 公共子表达式删除
B5 x=a[i]; a[i]=a[j]; a[j]=x;
t6 := 4 * i x := a[t6] t7 := 4 * i t8 := 4 * j t9 := a[t8] a[t7] := t9 t10 := 4 * j a[t10] := x
t11 := 4 * i x := a[t11] t12 := 4 * i t13 := 4 * n t14 := a[t13] a[t12] := t14 t15 := 4 * n a[t15] := x
10.2.2 公共子表达式删除
如果表达式E先前已计算,并且从先前的计算到E的再次出现,E中变量的 值没有改变,那么E的这个再次出现称为公共子表达式
(2) j := n
do i = i +1; while(a[i]<v); (3) t1 := 4 * n
do j =j 1;while (a[j]>v); (4) v := a[t1]
if (i >= j) break;
(5) i := i + 1
x=a[i]; a[i]=a[j]; a[j]=x; (6) t2 := 4 * i
}
(7) t3 := a[t2]
10.2 优化的主要种类
本节所用的例子
i = m 1; j = n; v = a[n]; (9) j := j 1
while (1) {
(10) t4 := 4 * j
do i = i +1; while(a[i]<v); (11) t5 := a[t4]
do j =j 1;while (a[j]>v); (12) if t5>v goto (9)
10.2.2 公共子表达式删除
B5 x=a[i]; a[i]=a[j]; a[j]=x;
t6 := 4 * i x := a[t6] t7 := 4 * i t8 := 4 * j t9 := a[t8] a[t7] := t9 t10 := 4 * j a[t10] := x
编译原理第九章
间的分配中也必须对这些临时变量分配存储空间。
分配策略:如果两个临时变量名作用域不相交,则它们可以分配在
同一单元中。一个临时变量名自它第一次被定值(赋值)的地方起
直至它最后一次被引用的地方止,这区间的程序所能到达的全体四
元式构成了它的作用域。 令临时变量名都分配在局部数据区中,若某一单元已分配给某些
临时变量名,则把这些名字的作用域(它们必须互不相交信息记录 )作为此单元的分配信息记录下来。每当要对一个新临时变量名进 行分配时,首先求出此名的作用域,然后按序检查每个已分配单 元,一旦发现新求出的作用域与某个单元所记录的全部作用域均不 相交时就把这个单元分配给这个新名,同时把它的作用域也添加到 该单元的分配信息之中。如果新临时变量的作用域和所有已分配单 元的作用域均有冲突,则就分配给它一个新的单元,同时把新名的 作用域作为此单元的分配信息。
适于静态管理的语言必须满足的条件:
1. 数组的上下界必须是常数
2. 过程调用不允许递归
3. 不允许用户动态地建立数据实体
编译程序可以确定出现在程序中的数据实体的地址(一般相 对于各数据区基地址的偏移量)。由于过程调用不允许递归,数 据实体的存储地址就和过程相联系,过程调用的活动记录就可 以直接安排在目标代码之后,并把各数据项的存储地址填入到 相关的目标代码中,以便在运行时访问这些数据存储空间。这 里,不存在对存储区域的再利用。目标代码运行时不必进行运 行时的存储管理。
上一页
下一页
18
3.2 FORTRAN的局部数据区
FORTRAN的编译程序将每个程序段都定义对应的局部数据区,每个数据区都 有一个编号,在地址分配时,在符号表中,对每个数据名将登记上它是属于哪个 数据区的,以及在该区中的相对位置(DA、ADDR)。
分配策略:如果两个临时变量名作用域不相交,则它们可以分配在
同一单元中。一个临时变量名自它第一次被定值(赋值)的地方起
直至它最后一次被引用的地方止,这区间的程序所能到达的全体四
元式构成了它的作用域。 令临时变量名都分配在局部数据区中,若某一单元已分配给某些
临时变量名,则把这些名字的作用域(它们必须互不相交信息记录 )作为此单元的分配信息记录下来。每当要对一个新临时变量名进 行分配时,首先求出此名的作用域,然后按序检查每个已分配单 元,一旦发现新求出的作用域与某个单元所记录的全部作用域均不 相交时就把这个单元分配给这个新名,同时把它的作用域也添加到 该单元的分配信息之中。如果新临时变量的作用域和所有已分配单 元的作用域均有冲突,则就分配给它一个新的单元,同时把新名的 作用域作为此单元的分配信息。
适于静态管理的语言必须满足的条件:
1. 数组的上下界必须是常数
2. 过程调用不允许递归
3. 不允许用户动态地建立数据实体
编译程序可以确定出现在程序中的数据实体的地址(一般相 对于各数据区基地址的偏移量)。由于过程调用不允许递归,数 据实体的存储地址就和过程相联系,过程调用的活动记录就可 以直接安排在目标代码之后,并把各数据项的存储地址填入到 相关的目标代码中,以便在运行时访问这些数据存储空间。这 里,不存在对存储区域的再利用。目标代码运行时不必进行运 行时的存储管理。
上一页
下一页
18
3.2 FORTRAN的局部数据区
FORTRAN的编译程序将每个程序段都定义对应的局部数据区,每个数据区都 有一个编号,在地址分配时,在符号表中,对每个数据名将登记上它是属于哪个 数据区的,以及在该区中的相对位置(DA、ADDR)。
编译原理课件Chapter9
的偏移量,放在table表中的adr域,生成目标代 码时再放在code中的a域
procedure enter(k:object ); begin (* enter object into table *) tx:=tx+1; with table[tx] do (* 开域语句 *) begin kind:=k; (*表示table[tx].kind:=k;*) name:=id;(*表示table[tx].name:=id;*)
9.4.1 分表结构的组织管理
基本思想:每当编译程序扫描到一个分 程序结构开始时,为该分程序建立一张符 号表,在该分程序中定义的标识符,都被 登录在该符号表中。 而当编译程序扫描到一个分程序的结束 时,编译程序释放为该分程序所建立的符 号表。 这种符号表的分表结构与源程序的分程 序层次结构一一对应
9.3.3 关键字域的组织
符号表的关键字域(段)就是符号名称 第一种:等长关键字域(段)符号表 第二种:不等长关键字段符号表—采用关 键字池的索引结构。(P216)
其它域的组织
对于数组:维数、上下界值、计算下标量地址 所用的信息以及数组元素类型等 对于记录(结构、联合):域的个数、每个域名、 地址位移、类型等 对于过程或函数:形参个数、所在层次、函数返 回值类型、局部变量所占空间大小等
四元式表QT
9.3.2 符号表项的排列
符号表作为一个多元组,表中元组的排列组 织是构造符号表的重要成分。在编译程序的整 个工作过程中,符号表被频繁地用来建立表项, 找查表项,填充和引用表项的属性。因此表项 的排列组织对该系统运行的效率起着十分重要 的作用。在编译程序中,符号表项的组织传统 上采用三种构造方法。即线性法,排序组织法 及散列法。
编译原理 9章
address(A[i , j])=address(A[1,1])+(i-1)*n+(j-1)
address(A[i , j])=address(A[1,1])-n-1+(i*n+j)
注:上式中的第一部分是一常数,仅需计算一次。
2008年3月
设A是下面的说明语句定义的一个n维数组: array A[l1..u1 , l2..u2 , .. , ln..un] of integer
2008年3月
•多块存储方式 多块存储方式是对每一行都分配一个单 块数据区,每行的元素按递增次序存放在这块 数据区中。此外,还设一个指示器表,用以指 示这些单块数据区的开始位置。
2008年3月
9.3.3 多块存储方式
B0 指向第 1 行的指示器 指向第 2 行的指示器 … 指向第 m 行的指示器 A[2, 2] Rm : A[m, 1] A[m, 2] … A[m, n] … A[2, n] … A[1, n] R2 : R1 : A[2, 1] A[1, 1] A[1, 2]
•数据区
数据区是指一片相连的存储单元。 例:PASCAL主程序中所说明的变量运行时所需要 的存储单元以及主程序运行时所需要的临时工作 单元一起构成了一个数据区。
2008年3月
在编译时,任何变量运行时存储单元都可由一 对偶(数据区编号,位移)表示。其中,数据区编号 是分配给数据区的唯一编号;位移是指该存储单元相 对于该数据区起址的距离(或单元数)。 例如:对于编号为10的数据区 它的第1个存储单元可表示为(10,0) 第2个存储单元可表示为(10,1)
2008年3月
数组分配程序: begin i:=1 ; Size:=1 ; Conspart:=0; while i ≤n do
08979编译原理第九章
– –
–
–
中间表示:四元式 DAG图 控制流图 数据流方程
问题复杂度:往往是NP 完全或NP难
–
简化,小规模问题
…
优化算法
–
代码优化的基本过程
代码的描述 数据流分析(data-flow analysis) 控制流分析(control-flow analysis) 变换 (transformations)
(3)T1:=4*I (5)T3:=T2[T1] (6)T4:=T1 (8)T6:=T5[T4] (9)T7:=T3*T6 (10)P:=P+T7 (11)I:=I+1 (12)if I<=20 goto(3)
(3‘)T1:=T1+4
(12)if I<=20 goto(5)
(1)P:=0 (2)I:=1 (4)T2:=addr(A)-4 (7)T5:=addr(B)-4 (3)T1:=4*I
性能指标
–
–
–
目标
代码优化
优化策略:
– – –
权衡(trade off):意图、结果 简洁:KISS(Keep It Simple,Stupid) 分工:编译阶段、软件处理、硬件机制
优化的阶段:
front end (I.R)
中间代码优化
(source code)
用户
code generator
基本优化技术
常数合并(合并已知量) 常数传播 代数化简 强度削弱(削弱运算强度) 复写传播 删除多余运算 循环不变代பைடு நூலகம்外提 变换循环控制条件 删除无用赋值
–
–
中间表示:四元式 DAG图 控制流图 数据流方程
问题复杂度:往往是NP 完全或NP难
–
简化,小规模问题
…
优化算法
–
代码优化的基本过程
代码的描述 数据流分析(data-flow analysis) 控制流分析(control-flow analysis) 变换 (transformations)
(3)T1:=4*I (5)T3:=T2[T1] (6)T4:=T1 (8)T6:=T5[T4] (9)T7:=T3*T6 (10)P:=P+T7 (11)I:=I+1 (12)if I<=20 goto(3)
(3‘)T1:=T1+4
(12)if I<=20 goto(5)
(1)P:=0 (2)I:=1 (4)T2:=addr(A)-4 (7)T5:=addr(B)-4 (3)T1:=4*I
性能指标
–
–
–
目标
代码优化
优化策略:
– – –
权衡(trade off):意图、结果 简洁:KISS(Keep It Simple,Stupid) 分工:编译阶段、软件处理、硬件机制
优化的阶段:
front end (I.R)
中间代码优化
(source code)
用户
code generator
基本优化技术
常数合并(合并已知量) 常数传播 代数化简 强度削弱(削弱运算强度) 复写传播 删除多余运算 循环不变代பைடு நூலகம்外提 变换循环控制条件 删除无用赋值
编译原理课件chap9
第九章运行时存储空间组织
编译程序在完成词法、语法和语义分析后, 编译程序在完成词法、语法和语义分析后,在生成目标代 码之前, 码之前,需要把程序的静态正文和实现这个程序的运行时的 活动联系起来弄清楚将来在代码运行时刻, 活动联系起来弄清楚将来在代码运行时刻,源代码中的各种 变量、常量等用户定义的量是如何存放的,如何去访问它们。 变量、常量等用户定义的量是如何存放的,如何去访问它们。 在程序的执行过程中, 在程序的执行过程中,程序中数据的存取是通过与之对 应的存储单元来进行的。在程序语言中, 应的存储单元来进行的。在程序语言中,程序使用的存储单 元都是由标识符来表示的。它们对应的内存地址都是由编译 元都是由标识符来表示的。 程序在编译时或由其生成的目标程序运行时进行分配。 程序在编译时或由其生成的目标程序运行时进行分配。所以 对于编译程序来说存储组织与管理是一个复杂而又十分重要 的问题。 的问题。这一章就是对目标程序运行时的活动和运行环境进 行讨论,主要讨论存储组织与管理, 行讨论,主要讨论存储组织与管理 包括活动纪录的建立与管 理、存储器的组织与存储分配的策略、非局部名称的访问等 存储器的组织与存储分配的策略、 问题。 问题。
第九章 运行时存储空间组织
9。2。3存储分配策略 。 。 存储分配策略 不同的编译程序关于数据空间的存储分配策略可能 不同。静态分配策略在编译是对所有对象分配固定的 不同。静态分配策略在编译是对所有对象分配固定的 存储单元。且在运行是保持不变。 存储单元。且在运行是保持不变。栈式动态分配策略 在运行时把存储器作为一个栈进行管理,运行时, 在运行时把存储器作为一个栈进行管理,运行时,每 当调用一个过程, 当调用一个过程,它所需要的存储空间就动态的分配 于栈顶,一旦退出,它所占空间就予以释放。堆式动 于栈顶,一旦退出,它所占空间就予以释放。 态存储策略在运行时把存储器组织成堆结构, 态存储策略在运行时把存储器组织成堆结构,以便用 在运行时把存储器组织成堆结构 户关于存储空间的申请与归还(回收),凡申请者分 户关于存储空间的申请与归还(回收),凡申请者分 ), 给一块,凡释放者退回给堆。 给一块,凡释放者退回给堆。
编译程序在完成词法、语法和语义分析后, 编译程序在完成词法、语法和语义分析后,在生成目标代 码之前, 码之前,需要把程序的静态正文和实现这个程序的运行时的 活动联系起来弄清楚将来在代码运行时刻, 活动联系起来弄清楚将来在代码运行时刻,源代码中的各种 变量、常量等用户定义的量是如何存放的,如何去访问它们。 变量、常量等用户定义的量是如何存放的,如何去访问它们。 在程序的执行过程中, 在程序的执行过程中,程序中数据的存取是通过与之对 应的存储单元来进行的。在程序语言中, 应的存储单元来进行的。在程序语言中,程序使用的存储单 元都是由标识符来表示的。它们对应的内存地址都是由编译 元都是由标识符来表示的。 程序在编译时或由其生成的目标程序运行时进行分配。 程序在编译时或由其生成的目标程序运行时进行分配。所以 对于编译程序来说存储组织与管理是一个复杂而又十分重要 的问题。 的问题。这一章就是对目标程序运行时的活动和运行环境进 行讨论,主要讨论存储组织与管理, 行讨论,主要讨论存储组织与管理 包括活动纪录的建立与管 理、存储器的组织与存储分配的策略、非局部名称的访问等 存储器的组织与存储分配的策略、 问题。 问题。
第九章 运行时存储空间组织
9。2。3存储分配策略 。 。 存储分配策略 不同的编译程序关于数据空间的存储分配策略可能 不同。静态分配策略在编译是对所有对象分配固定的 不同。静态分配策略在编译是对所有对象分配固定的 存储单元。且在运行是保持不变。 存储单元。且在运行是保持不变。栈式动态分配策略 在运行时把存储器作为一个栈进行管理,运行时, 在运行时把存储器作为一个栈进行管理,运行时,每 当调用一个过程, 当调用一个过程,它所需要的存储空间就动态的分配 于栈顶,一旦退出,它所占空间就予以释放。堆式动 于栈顶,一旦退出,它所占空间就予以释放。 态存储策略在运行时把存储器组织成堆结构, 态存储策略在运行时把存储器组织成堆结构,以便用 在运行时把存储器组织成堆结构 户关于存储空间的申请与归还(回收),凡申请者分 户关于存储空间的申请与归还(回收),凡申请者分 ), 给一块,凡释放者退回给堆。 给一块,凡释放者退回给堆。
编译原理 第九章
E→TE’ E’→+TE’│ε
T→FT’ T’→*FT’│ε
F→(E)│i
电子科技大学计算机科学与工程学院
程序设计语言与编译
i+i*i#的递归下降分析过程
i
E
i
F M(i)
+
+ M(+) E’ T # + i # # + T’ E’ T M() M() # i * * F M(*)T’ M() # M(i) i # # T’ F M() M(i)
④
i=1没有操作 i=2,j=1, Ai=Q,Aj=R,有Q→Rb|b 把R→Sa|a代入上式得: Q→Sab|ab|b 该式无直接左递归 i=3,j=1, Ai=S,Aj=R,无相应产 生式,没有操作
电子科技大学计算机科学与工程学院
程序设计语言与编译
1.按R、Q、S排列, 代入后 R→Sa│a Q→Sab│ab│b S→Sabc│abc │bc│c 2.消除S中的直接左递归
P→P ’ P’→αP’│ε P γP’ P’αP’|βP’| P βP’|γP’ P’αP’|
改写为
改写为
电子科技大学计算机科学与工程学院
程序设计语言与编译
一般地:
A→A1|A2|…|Am|1|2|…|n (iε,j不以A开头)
改写为:
A→1P’│ 2P’│. . .│ nP’
程序设计语言与编译
二. 存在的问题
(1)回溯——公共左因子的存在 A→1| 2 (2)左递归 + A→Aα 或 AAα
直接左递归 间接左递归
(3)ε产生式
程序设计语言与编译
例子:
文法G(s): S → Sa
S → b 符合串baa的推导过程。 S S S b a
程序设计语言 编译原理(第三版)第9章
3.Par T T——为标号
30
9.5 嵌套过程语言的栈式实现
2.Par T T——为过程
⇒在进入T之后,为了建立T自己的display,T必须知道 它直接外层的display。 又P的display 或者正好就是这个外层的display, 或者包含了这个外层display
而由于T的层数是已知的
⇒只要知道P的display,T就可以用它来建立自己的display。 即假定T的层数为1,则T的display乃是由P的display的前1 个单元的内容和SP的现行值所组成。
i b(形参) 1(形参个数) 0
v
u 2 11 返回地址 17 d c v(形参) u(形参) 2(形参个数)
12
11 10 9
返回地址
5 i c 0 0 返回地址 0 x a 0
25
24 23 22
8
7 6 5 4 3 2
21
20 19 18 17
11
返回地址 11
1
0
返回地址
0
25
9.5 嵌套过程语言的栈式实现
31
9.5 嵌套过程语言的栈式实现
2.Par T T——为过程
⇒为了使得过程T工作时能够知道过程P的display,必须在P把 T作为实参传递给Q的时候把P自身的display地址也传过去。 即:过程P中的par T的作用可刻画为建立如下所示的两个相继 临时单元: 第一个临时单元B1:过程T的入口地址; 第二个临时单元B2:现行的display地址。; 然后执行(i+1)[TOP]:=addr(B1) 把第一临时单元B1的地址传给Q
8
9.2 运行时存储器的划分
三、存储分配策略 1.静态存储分配策略
30
9.5 嵌套过程语言的栈式实现
2.Par T T——为过程
⇒在进入T之后,为了建立T自己的display,T必须知道 它直接外层的display。 又P的display 或者正好就是这个外层的display, 或者包含了这个外层display
而由于T的层数是已知的
⇒只要知道P的display,T就可以用它来建立自己的display。 即假定T的层数为1,则T的display乃是由P的display的前1 个单元的内容和SP的现行值所组成。
i b(形参) 1(形参个数) 0
v
u 2 11 返回地址 17 d c v(形参) u(形参) 2(形参个数)
12
11 10 9
返回地址
5 i c 0 0 返回地址 0 x a 0
25
24 23 22
8
7 6 5 4 3 2
21
20 19 18 17
11
返回地址 11
1
0
返回地址
0
25
9.5 嵌套过程语言的栈式实现
31
9.5 嵌套过程语言的栈式实现
2.Par T T——为过程
⇒为了使得过程T工作时能够知道过程P的display,必须在P把 T作为实参传递给Q的时候把P自身的display地址也传过去。 即:过程P中的par T的作用可刻画为建立如下所示的两个相继 临时单元: 第一个临时单元B1:过程T的入口地址; 第二个临时单元B2:现行的display地址。; 然后执行(i+1)[TOP]:=addr(B1) 把第一临时单元B1的地址传给Q
8
9.2 运行时存储器的划分
三、存储分配策略 1.静态存储分配策略
廖力编译原理课件第9章
第九章 代码优化 3
第九章 代码优化
• 五、优化程度和优化代价的关系:
手工水平 优 化 程 度
优化代价
第九章 代码优化 4
9.1 优化概述
一、中间代码优化分类 • 1、局部优化 • 1)含义:局部优化是针对一段顺序执行语句序列的优 化。 • 2)主要方法 – 合并已知量 – 删除公共子表达式 – 变量传播与无用赋值删除
(1)Pi:=3.14 (2) T1 :=6.28 (3)T2:=R+r (4)A:= T1 *T2 (5)B:=A (6)T3:= T1 (7)T4:=T2 (8)T5:=T3*T4 (9)T6:=R-r (10)B:=T5*T6
第九章 代码优化 8
9.1 优化概述
• 1、局部优化 • 3)变量传播与无用赋值删除 (1)Pi:=3.14 (2)T1:=6.28 (3)T2:=R+r (4)A:=T1*T2 (5)B:=A (6)T3:=T1 (7)T4:=T2 (8)T5:=T3*T4 (9)T6:=R-r (10)B:=T5*T6 (1)Pi:=3.14 (2) T1 :=6.28 (3)T2:=R+r (4)A:= T1 *T2 (5)B:=A (6)T3:= T1 (7)T4:=T2 (8)T5:= T1 *T2 (9)T6:=R-r (10)B:=T5*T6 (1)Pi:=3.14 (2) T1 :=6.28 (3)T2:=R+r (4)A:= T1 *T2 (8)T5:= T1 *T2 (9)T6:=R-r (10)B:=T5*T6
第九章 代码优化 6
9.1 优化概述
• 1、局部优化 • 1)合并已知量 – 对于编译时 已知的常量, 不必生成目 标代码到运 行时才计算, 而是可以直 接对它计值, 并用计算结 果代替表达 式的计算代 码。 (1)Pi:=3.14 (2)T1:=2*Pi (3)T2:=R+r (4)A:=T1*T2 (5)B:=A (6)T3:=2*Pi (7)T4:=R+r (8)T5:=T3*T4 (9)T6:=R-r (10)B:=T5*T6 (1)Pi:=3.14 (2) T1 :=6.28 (3)T2:=R+r (4)A:= T1 *T2 (5)B:=A (6)T3:=6.28 (7)T4:=R+r (8)T5:=T3*T4 (9)T6:=R-r (10)B:=T5*T6
第九章 代码优化
• 五、优化程度和优化代价的关系:
手工水平 优 化 程 度
优化代价
第九章 代码优化 4
9.1 优化概述
一、中间代码优化分类 • 1、局部优化 • 1)含义:局部优化是针对一段顺序执行语句序列的优 化。 • 2)主要方法 – 合并已知量 – 删除公共子表达式 – 变量传播与无用赋值删除
(1)Pi:=3.14 (2) T1 :=6.28 (3)T2:=R+r (4)A:= T1 *T2 (5)B:=A (6)T3:= T1 (7)T4:=T2 (8)T5:=T3*T4 (9)T6:=R-r (10)B:=T5*T6
第九章 代码优化 8
9.1 优化概述
• 1、局部优化 • 3)变量传播与无用赋值删除 (1)Pi:=3.14 (2)T1:=6.28 (3)T2:=R+r (4)A:=T1*T2 (5)B:=A (6)T3:=T1 (7)T4:=T2 (8)T5:=T3*T4 (9)T6:=R-r (10)B:=T5*T6 (1)Pi:=3.14 (2) T1 :=6.28 (3)T2:=R+r (4)A:= T1 *T2 (5)B:=A (6)T3:= T1 (7)T4:=T2 (8)T5:= T1 *T2 (9)T6:=R-r (10)B:=T5*T6 (1)Pi:=3.14 (2) T1 :=6.28 (3)T2:=R+r (4)A:= T1 *T2 (8)T5:= T1 *T2 (9)T6:=R-r (10)B:=T5*T6
第九章 代码优化 6
9.1 优化概述
• 1、局部优化 • 1)合并已知量 – 对于编译时 已知的常量, 不必生成目 标代码到运 行时才计算, 而是可以直 接对它计值, 并用计算结 果代替表达 式的计算代 码。 (1)Pi:=3.14 (2)T1:=2*Pi (3)T2:=R+r (4)A:=T1*T2 (5)B:=A (6)T3:=2*Pi (7)T4:=R+r (8)T5:=T3*T4 (9)T6:=R-r (10)B:=T5*T6 (1)Pi:=3.14 (2) T1 :=6.28 (3)T2:=R+r (4)A:= T1 *T2 (5)B:=A (6)T3:=6.28 (7)T4:=R+r (8)T5:=T3*T4 (9)T6:=R-r (10)B:=T5*T6
精品课程《编译原理》PPT课件第9章 符号表
RINFL[rp]:
域名部分 区距部分
FTP是域类型部分
一个记录类型要占几个RINFL表项, 不同记录类型所占表项个数不一,而 在表项中没有链接部分,因此在不同 记录的RINFL表之间可放置一条空项, 以表示记录类型的RINFL表中的结束。
综上所述,我们有: TYPEL表 integer: i
real: r b a
临时变量 局部变量 DISPLAY表 形式参数2 形式参数1 过函名 管理信息
l+ 1 5 4 3 0-2
抽象地址的变化规律可图示如下:
实在声明:
(l,off) <标号声明部分> (l,off) (l,off) <常量声明部分> (l,off) (l,off) <类型声明部分> (l,off)
在整个编译阶段都离不开符号表。 二、符号表的内容 0 Pascal 有以下几种类型: 整 型:integer 实 型:real 布尔型:boolean 数组型:ARRAY[N1…N2]OF T 记录型:RECORD id1:T1;…; idn;Tn END
类型表TYPEL结构形如: TCLASS
三、标识符的作用域与处理 程序段:PROGRAM…………………END 过程段:PROCEDURE………………END 函数段: FUNCTION………………END 记录类型: RECORD………………END
具体实现方法可分为两种: 真删除法
加标记法
9.4 抽象地址的处理
存储分配分为静态分配与动态分配。 在编译时分配的称静态分配。 在目标程序运行时分配的称动态分配。
2.若ICLASS.t=1,则IADDR是类型长度 3.若ICLASS.v=1.则IADDR是形如: LEVEL OFF 的抽象地址,其中LEVEL 是层数,OFF是区距部分。
comp_Chapter9
重复信息的例子
如果用户忘了申明变量i(或者声明的时 候变量的拼写错误),而在程序中多出 使用i。 编译程序在每次碰到对i的使用的时候都 可能发现错误:变量i没有被定义。 这个错误信息将多次出现。而实际上这 个错误是唯一的。
语法错误提示信息(自顶向下)
在自顶向下的扫描过程中,如果扫描程 序碰到了非预期的符号输入,最简单的 提示方法就是:unexpected symbol: ‘?’ 自顶向下的分析过程中,扫描程序能够 十分清楚地知道当前正在按照什么规则 进行扫描,所以提示信息也可以给得更 加详细:在扫描???的时候碰到非预期的 符号??。
违反环境限制的错误:由于实现方面的问题,有些 编译器不接受语言的全集。同时语言本身也有限制。 比如:函数说明嵌套的深度,数组的最大层数。
错误复原
编写程序的过程中,出现错误是不可避免的。 编译程序在进行编译的时候,需要检查出程序 的错误。并且给出提示。 当编译程序碰到源程序中的错误的时候,应该 设法从错误中复原,并继续扫描程序以给出更 多的提示信息。更多的信息使得程序员能够更 加方便地修改程序。 可能复原是错误的。所以一般来讲,编译程序 给出的第一个错误是可靠的,而其他的错误信 息可能是不准确的。
错误复原的要点
株连信息的遏制
– 株连信息是指由于源程序中的一个错误而导 致编译程序向用户报告很多相关的出错信息。 而这些信息是不真实的。
重复信息的遏制
– 是指源程序中的一个错误而反映在源程序的 多处。
株连信息的例子
已经说明过程p(int a, int b);在使用的时 候写成了p(a.b)。 编译程序扫描的时候,首先发现“.”是 错误的,应为a不是结构类型的变量。然 后,发现b是错误的。最后发现p的参数 个数不同。 这些信息都是由于将‘,’误写做‘.’而 引起的。
编译原理编译第九章
整理课件
第二节 回溯分析法
一.一个实例
S→xAy A→ab│a 输入串为xay,说明分析过程
整理课件
S
S
S
x A yx A y x A y
ab
a
整理课件
二. 存在的问题
(1)回溯——公共左因子的存在
A→1| 2 (2)左递归
A→Aα 或 AAα
(3)ε产生式也会引起回溯
S→aAS
+
S→b
A→bAS
整理课件
S→Qc│c
Q→Rb│b
按S、Q、R排列, 代入后
R→Sa│a
S→Qc│c
Q→Rb│b
R→ Rbca│bca│ca│a 消除R中的直接左递归
R→ bcaR’│caR’│aR’
R’→ bcaR’│ 文法产生的语言:(bca|ca|a)(bca)*bc|bc|c
整理课件
按R、Q、S排列, 代入后
FIRST
E
(
i
E’
+
T
(
i
T’
*
F
(
i
整理课件
FOLLOW )# )# +)# +)# *+ ) #
G(E) E→TE’
E’→+TE’│ε
T→FT’
T’→*FT’ │ε
预测分析表
F→(E)│i
i
+
*
(
E E→TE’
E’
E’→+TE’
E→TE’
T T→FT’
T→FT’
T’
T’→ε
T’→*FT’
F F→i
若S * ...A, 则#FOLLOW(A),其中S为开始符号
第二节 回溯分析法
一.一个实例
S→xAy A→ab│a 输入串为xay,说明分析过程
整理课件
S
S
S
x A yx A y x A y
ab
a
整理课件
二. 存在的问题
(1)回溯——公共左因子的存在
A→1| 2 (2)左递归
A→Aα 或 AAα
(3)ε产生式也会引起回溯
S→aAS
+
S→b
A→bAS
整理课件
S→Qc│c
Q→Rb│b
按S、Q、R排列, 代入后
R→Sa│a
S→Qc│c
Q→Rb│b
R→ Rbca│bca│ca│a 消除R中的直接左递归
R→ bcaR’│caR’│aR’
R’→ bcaR’│ 文法产生的语言:(bca|ca|a)(bca)*bc|bc|c
整理课件
按R、Q、S排列, 代入后
FIRST
E
(
i
E’
+
T
(
i
T’
*
F
(
i
整理课件
FOLLOW )# )# +)# +)# *+ ) #
G(E) E→TE’
E’→+TE’│ε
T→FT’
T’→*FT’ │ε
预测分析表
F→(E)│i
i
+
*
(
E E→TE’
E’
E’→+TE’
E→TE’
T T→FT’
T→FT’
T’
T’→ε
T’→*FT’
F F→i
若S * ...A, 则#FOLLOW(A),其中S为开始符号
吉林大学编译原理课件第九章
过程中被声明的形参、 过程中被声明的形参、局部变量 临时变量
分配方法: 分配方法:
对每个被调用过程分配一段存储空间,sp存放当前 对每个被调用过程分配一段存储空间,sp存放当前 过程空间的开始地址;对变量X:(Level Level, 过程空间的开始地址;对变量X:(Level,off), 则其存放地址为off[sp]。 则其存放地址为off[sp]。 off[sp] 过程结束时自动释放空间; 过程结束时自动释放空间;
绑定:如果环境将名字x映射到存储单元 ,我们就说 绑定:如果环境将名字 映射到存储单元s, 映射到存储单元
x被绑定(binding)到s 。 被绑定( 被绑定 )
过程活动记录
过程活动记录(AR):过程的一个现场记录 过程的一个现场记录 过程活动记录 记录内容: 记录内容:
过程控制信息:先行活动记录的动态链指针、返回 过程控制信息:先行活动记录的动态链指针、 地址、层数和长度等 地址、 机器状态信息: 机器状态信息:寄存器状态等 全局变量信息:非局部变量的信息 全局变量信息 非局部变量的信息 局部变量值:形参变量、 局部变量值:形参变量、局部变量和临时变量
动态链: 动态链:
如果有调用链CallChain(S)=(M, ,R, S), 如果有调用链CallChain(S)=(M,…,R, S), CallChain(S)=(M, 则它对应的动态链为: 则它对应的动态链为: DynamicChain=[AR(M),…,AR(R),AR(S)] DynamicChain=[AR(M), ,AR(R),AR(S)]
换名调用
1)把过程当作宏来对待,也就是在调用点,用被调用过程的体 把过程当作宏来对待,也就是在调用点, 来替换调用者的调用,但是形参用对应的实参文字来代替。 来替换调用者的调用,但是形参用对应的实参文字来代替。这 种文字替换方式称为宏展开或内联展开。 种文字替换方式称为宏展开或内联展开。 被调用过程的局部名与调用过程的名字保持区别。 2)被调用过程的局部名与调用过程的名字保持区别。可以认为 在宏展开前, 在宏展开前,被调用过程的每个局部名字系统地被重新命名成 可区别的名字。 可区别的名字。 为保持实参的完整性, 3)为保持实参的完整性,实参可以由括号包围
分配方法: 分配方法:
对每个被调用过程分配一段存储空间,sp存放当前 对每个被调用过程分配一段存储空间,sp存放当前 过程空间的开始地址;对变量X:(Level Level, 过程空间的开始地址;对变量X:(Level,off), 则其存放地址为off[sp]。 则其存放地址为off[sp]。 off[sp] 过程结束时自动释放空间; 过程结束时自动释放空间;
绑定:如果环境将名字x映射到存储单元 ,我们就说 绑定:如果环境将名字 映射到存储单元s, 映射到存储单元
x被绑定(binding)到s 。 被绑定( 被绑定 )
过程活动记录
过程活动记录(AR):过程的一个现场记录 过程的一个现场记录 过程活动记录 记录内容: 记录内容:
过程控制信息:先行活动记录的动态链指针、返回 过程控制信息:先行活动记录的动态链指针、 地址、层数和长度等 地址、 机器状态信息: 机器状态信息:寄存器状态等 全局变量信息:非局部变量的信息 全局变量信息 非局部变量的信息 局部变量值:形参变量、 局部变量值:形参变量、局部变量和临时变量
动态链: 动态链:
如果有调用链CallChain(S)=(M, ,R, S), 如果有调用链CallChain(S)=(M,…,R, S), CallChain(S)=(M, 则它对应的动态链为: 则它对应的动态链为: DynamicChain=[AR(M),…,AR(R),AR(S)] DynamicChain=[AR(M), ,AR(R),AR(S)]
换名调用
1)把过程当作宏来对待,也就是在调用点,用被调用过程的体 把过程当作宏来对待,也就是在调用点, 来替换调用者的调用,但是形参用对应的实参文字来代替。 来替换调用者的调用,但是形参用对应的实参文字来代替。这 种文字替换方式称为宏展开或内联展开。 种文字替换方式称为宏展开或内联展开。 被调用过程的局部名与调用过程的名字保持区别。 2)被调用过程的局部名与调用过程的名字保持区别。可以认为 在宏展开前, 在宏展开前,被调用过程的每个局部名字系统地被重新命名成 可区别的名字。 可区别的名字。 为保持实参的完整性, 3)为保持实参的完整性,实参可以由括号包围
编译原理蒋宗礼课件第9章
2019/3/26
10
9.1.3 过程及其活动
• 出现在过程定义中的某些标识符具有特殊的 意义,称为该过程的形式参数,简称为形参。 调用过程时,表达式作为实在参数(或实参)传 递给被调用的过程,以替换出现在过程体中 的对应形式参数。9.1.4节将讨论实参和形参 的结合方法。 • 过程体的每次执行叫做该过程的一个活动。 过程p的一个活动的生存期是从过程体执行的 第一步到最后一步,包括执行被p调用的过程 的时间,以及再由这样的过程调用其它过程 所花的时间,等等。
• 计算实参并将其右值传递给被调用过程 • 传值方式可以如下实现:
– 被调用过程为每个形参开辟一个称为形式单元的 存储单元,用于存放相应实参的值。 – 调用过程计算实参,并把右值放入相应的形式单 元中。
实际参数A
A 单向传值
形式参数X
A的值 被调用者 直接使用
14
调用者
2019/3/26
2. 传地址
24
每个过程的活动记录内容
TOP 临时变量 数组内情向量 局部变量 形式单元
2 1
SP 0
静态链 动态链 返回地址
形式单元:存放相 应的实在参数的地 址或值。 局部数据区:局部 变量、内情向量、 临时工作单元 ( 如存 放对表达式求值的 结果)。
25
2019/3/26
9.2.3 局部数据的组织
2019/3/26
9
9.1.3 过程及其活动
• 将“过程、函数和方法”统称为“过程” • 过程定义是一个声明,它的最简单形式是把 一个标识符和一个语句联系起来。该标识符 是过程名,而这个语句是过程体。 • 当过程名出现在可执行语句中时,称相应的 过程在该点被调用。过程调用就是执行被调 用过程的过程体。注意,过程调用也可以出 现在表达式中。
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
24
2015-4-21
某分段式程序运行时的内存划分
指令代码 常数 程序段1 程序段2 …… 程序段i …… 程序段n 公用数据 临时变量 数组 简单变量 形式单元 寄存器保护区 返回地址 程序段i的活动记录
25
局 部 数 据 区
2015-4-21
静态存储分配策略
顺序分配算法(基于调用图)
按照程序段出现的先后顺序逐段分配 1/22 2/15 3/18
2015-4-21 21
9.2.3 局部数据的组织
在 X86/Linux 机器的结果和 SPARC/Solaris 工作 站不一样,是20和16。 typedef struct _a{ typedef struct _b{ char c1; 0 char c1; 0 long i; 4 char c2; 1 char c2; 8 long i; 4 double f; 12 double f;8 }a; }b;
9.3 静态存储分配策略
(1)PROGRAM CNSUME (2) CHARACTER *50 BUF (3) INTEGER NEXT (4〕 CHARACTER C,PRDUCE (5) DATA NEXT/1/,BUF/ ' '/ (6) C=PRDUCE()。 (7) BUF(NEXT:NEXT)=C (8〕 NEXT=NEXT+1 (9) IF(C.NE.' ' )GOTO 6 (10) WRITE(*,'(A)')BUF (11) END
10
2015-4-21
9.1.4 参数传递方式
信息交换方式 传统程序设计语言过程间交换信息的方法通 常是通过非局部名字和被调用过程的参数来 实现的。
传值 传地址 传值结果 传名
其主要区别在于实参所代表的究竟是左值、右 值还是实参的正文本身 2015-4-21 11
编译程序组织存储空间时必须考虑的问 题
2015-4-21 22
9.2.4 全局存储分配策略
静态存储分配策略(FORTRAN)
如果在编译时能确定数据空间的大小,则可采用 静态分配方法:在编译时刻为每个数据项目确定 出在运行时刻的存储空间中的位置。
动态存储分配策略(PASCAL,C)
如果在编译时不能确定运行时数据空间的大小, 则必须采用动态分配方法。允许递归过程及动态 申请、释放内存。 栈式动态存储分配 堆式动态存储分配
程序段
6 7/80 5
区域
0~9 0~22
4
3
0~16
23~40 17~31 41~62
27
4/17
6/10
5/23
2 1
思考:如何设计分配算法?
2015-4-21
共需要63个存储单元
9.3 静态存储分配策略
静态分配给语言带来的限制 不允许递归过程 数据对象的长度和它在内存中位置的限制, 必须是在编译时可以知道的 数据结构不能动态建立 例:一个Fortran 77程序
环境把名字映射到左值,而状态把左值映射到右值 赋值改变状态,但不改变环境。
如果环境将名字x映射到存储单元s,我们就说x 被绑定到s
环境 状态
名字
2015-4-21
内存位置 (变量)
值
5
9.1.2 声明的作用域
声明的作用域 是指程序中的这样一段区域,在该区域中,x 的引用均指向x的这一声明。 静态作用域和动态作用域 对于某种程序设计语言,如果只通过考察其程 序就可以确定某个声明的作用域,则称该语 言使用静态作用域; 否则称该语言使用动态作用域
过程能否递归? 当控制从过程的活动返回时,局部变量的值是否要 保留? 过程能否访问非局部变量? 过程调用的参数传递方式? 过程能否作为参数被传递? 过程能否作为结果值传递? 存储块能否在程序控制下动态地分配? 存储块是否必须显式地释放? 这些问题都对存贮分配策略有着直接的影响!
第9章 运行时的存储组织
9.1 与存储组织有关的源语言概念与特征 9.2 存储组织 9.3 静态存储分配 9.4 栈式存储分配 9.5 栈中非局部数据的访问 9.6 堆管理 9.7 本章小结
2015-4-21 2
9.1 与存储组织有关的源语言概念与特征
编译程序必须准确地实现包含在源程序中的 各种抽象概念 各种抽象概念,如名字、作用域、数据类型、 操作符、过程、参数和控制流结构等,
采用栈式存储分配机制 活动记录:运行时,每当进入一个过程就有一个 相应的活动记录压入栈顶。 活动记录一般含有连接数据、形式单元、局部变 量、局部数组的内情向量和临时工作单元等。
15
2015-4-21
每个过程的活动记录内容
——非嵌套语言(如C)
TOP 临时变量 数组内情向量 简单变量 形式单元
2015-4-21 20
9.2.3 局部数据的组织
在 SPARC/Solaris工作站上下面两个结构的 size 分别是24和16,为什么不一样? typedef struct _a{ typedef struct _b{ char c1; 0 char c1; 0 long i; 4 char c2; 1 char c2; 8 long i; 4 double f; 16 double f;8 }a; }b;
9.3 静态存储分配策略
(12)CHARACTER FUNCTION PRDUCE() (13) CHARACTER * 80 BUFFER (14) INTEGER NEXT (15) SAVE BUFFER,NEXT (16) DATA NEXT/81/ (17) IF(NEXT.GT.80)THEN (18) READ(*,'(A)')BUFFER (19) NEXT=1 (20) END IF (21) PRDUCE=BUFFER(NEXT:NEXT) (22 ) NEXT=NEXT+1 (23 ) END
6
2015-4-21
9.1.2 声明的作用域
作用域的显式控制 C++、Java和C#等使用public、private和 protected这样的关键字,对作用域进行显式控 制。 声明的作用域是通过符号表进行管理的
2015-4-21
7
9.1.3 过程及其活动
将“过程、函数和方法”统称为“过程” 过程定义是一个声明,它的最简单形式是把 一个标识符和一个语句联系起来。 该标识符是过程名,而这个语句是过程体。
2015-4-21
23
9.3 静态存储分配策略
如果在编译时就能确定一个程序在运行时所需 要的存储空间的大小,则在编译时就能安排好 目标程序运行时的全部数据空间,并能确定每 个数据项的地址,存储空间的这种分配方法称 为静态存储分配。必须满足如下条件:
数据对象的长度和它在内存中的位置在编译时必须 是已知的; 不允许过程的递归调用,因为一个过程的所有活动 都是用同样的局部名字绑定的; 数据结构不能动态建立,因为没有运行时的存储分 配机制。
2 1
SP 0
2015-4-21
参数个数 返回地址 旧SP
对任何局部变量X的引 用可表示为变址访问: dx[SP] dx:变量X相对于活动记 录起点的地址,在编译 时可确定。
16
每个过程的活动记录内容
——嵌套语言(如Pascal)
TOP 临时变量 数组内情向量
连接数据
局部变量
形式单元 2 1 SP0
9.3 静态存储分配策略
C 语言程序的全局变量和程序中出现的常量都 可以静态分配。 声明在函数外面
12
2015-4-21
9.2 存储组织
9.2.1 运行时内存的划分 9.2.2 活动记录 9.2.3 局部数据的组织 9.2.4 全局存储分配策略
2015-4-21
13
7.2.1 运行时内存的划分
目标代码 静态数据 栈 空闲 空间 堆
2015-4-21 14
9.2.2 活动记录
过程的每个活动所需要的信息用一块连续的存储 区来管理,这块存储区叫做活动记录 假定语言的特点为:允许过程递归调用、允许过程 含有可变数组,过程定义允许/不允许嵌套。
2015-4-21
静态链
动态链 返回地址
返回地址 动态链:指向调用该 过程前的最新活动记 录地址的指针。 静态链:指向静态直接 外层最新活动记录地址的 指针,用来访问非局部数 据。
17
每个过程的活动记录内容
TOP 临时变量 数组内情向量 局部变量 形式单元
2 1
SP 0
静态链 动态链 返回地址
9.3 静态存储分配策略
Fortran语言被设计成允许静态存储分配
cnsume的代码 代码
prduce的代码
character 50 buf integer next character c character 80 buffer integer next cnsume的活动记录 静态数据 prduce的活动记录
School of Computer Science & Technology Harbin Institute of Technology
第9章 运行时的存储组织
解决问题:符号空间到地址空间的映射问题 重点:符号表的内容、组织,过程调用实现,
静态存储分配、动态存储分配的基本
方法。
难点:活动记录、非局部数据的栈实现 问题
当过程名出现在可执行语句中时,称相应的 过程在该点被调用。 过程调用就是执行被调用过程的过程体。
2015-4-21
某分段式程序运行时的内存划分
指令代码 常数 程序段1 程序段2 …… 程序段i …… 程序段n 公用数据 临时变量 数组 简单变量 形式单元 寄存器保护区 返回地址 程序段i的活动记录
25
局 部 数 据 区
2015-4-21
静态存储分配策略
顺序分配算法(基于调用图)
按照程序段出现的先后顺序逐段分配 1/22 2/15 3/18
2015-4-21 21
9.2.3 局部数据的组织
在 X86/Linux 机器的结果和 SPARC/Solaris 工作 站不一样,是20和16。 typedef struct _a{ typedef struct _b{ char c1; 0 char c1; 0 long i; 4 char c2; 1 char c2; 8 long i; 4 double f; 12 double f;8 }a; }b;
9.3 静态存储分配策略
(1)PROGRAM CNSUME (2) CHARACTER *50 BUF (3) INTEGER NEXT (4〕 CHARACTER C,PRDUCE (5) DATA NEXT/1/,BUF/ ' '/ (6) C=PRDUCE()。 (7) BUF(NEXT:NEXT)=C (8〕 NEXT=NEXT+1 (9) IF(C.NE.' ' )GOTO 6 (10) WRITE(*,'(A)')BUF (11) END
10
2015-4-21
9.1.4 参数传递方式
信息交换方式 传统程序设计语言过程间交换信息的方法通 常是通过非局部名字和被调用过程的参数来 实现的。
传值 传地址 传值结果 传名
其主要区别在于实参所代表的究竟是左值、右 值还是实参的正文本身 2015-4-21 11
编译程序组织存储空间时必须考虑的问 题
2015-4-21 22
9.2.4 全局存储分配策略
静态存储分配策略(FORTRAN)
如果在编译时能确定数据空间的大小,则可采用 静态分配方法:在编译时刻为每个数据项目确定 出在运行时刻的存储空间中的位置。
动态存储分配策略(PASCAL,C)
如果在编译时不能确定运行时数据空间的大小, 则必须采用动态分配方法。允许递归过程及动态 申请、释放内存。 栈式动态存储分配 堆式动态存储分配
程序段
6 7/80 5
区域
0~9 0~22
4
3
0~16
23~40 17~31 41~62
27
4/17
6/10
5/23
2 1
思考:如何设计分配算法?
2015-4-21
共需要63个存储单元
9.3 静态存储分配策略
静态分配给语言带来的限制 不允许递归过程 数据对象的长度和它在内存中位置的限制, 必须是在编译时可以知道的 数据结构不能动态建立 例:一个Fortran 77程序
环境把名字映射到左值,而状态把左值映射到右值 赋值改变状态,但不改变环境。
如果环境将名字x映射到存储单元s,我们就说x 被绑定到s
环境 状态
名字
2015-4-21
内存位置 (变量)
值
5
9.1.2 声明的作用域
声明的作用域 是指程序中的这样一段区域,在该区域中,x 的引用均指向x的这一声明。 静态作用域和动态作用域 对于某种程序设计语言,如果只通过考察其程 序就可以确定某个声明的作用域,则称该语 言使用静态作用域; 否则称该语言使用动态作用域
过程能否递归? 当控制从过程的活动返回时,局部变量的值是否要 保留? 过程能否访问非局部变量? 过程调用的参数传递方式? 过程能否作为参数被传递? 过程能否作为结果值传递? 存储块能否在程序控制下动态地分配? 存储块是否必须显式地释放? 这些问题都对存贮分配策略有着直接的影响!
第9章 运行时的存储组织
9.1 与存储组织有关的源语言概念与特征 9.2 存储组织 9.3 静态存储分配 9.4 栈式存储分配 9.5 栈中非局部数据的访问 9.6 堆管理 9.7 本章小结
2015-4-21 2
9.1 与存储组织有关的源语言概念与特征
编译程序必须准确地实现包含在源程序中的 各种抽象概念 各种抽象概念,如名字、作用域、数据类型、 操作符、过程、参数和控制流结构等,
采用栈式存储分配机制 活动记录:运行时,每当进入一个过程就有一个 相应的活动记录压入栈顶。 活动记录一般含有连接数据、形式单元、局部变 量、局部数组的内情向量和临时工作单元等。
15
2015-4-21
每个过程的活动记录内容
——非嵌套语言(如C)
TOP 临时变量 数组内情向量 简单变量 形式单元
2015-4-21 20
9.2.3 局部数据的组织
在 SPARC/Solaris工作站上下面两个结构的 size 分别是24和16,为什么不一样? typedef struct _a{ typedef struct _b{ char c1; 0 char c1; 0 long i; 4 char c2; 1 char c2; 8 long i; 4 double f; 16 double f;8 }a; }b;
9.3 静态存储分配策略
(12)CHARACTER FUNCTION PRDUCE() (13) CHARACTER * 80 BUFFER (14) INTEGER NEXT (15) SAVE BUFFER,NEXT (16) DATA NEXT/81/ (17) IF(NEXT.GT.80)THEN (18) READ(*,'(A)')BUFFER (19) NEXT=1 (20) END IF (21) PRDUCE=BUFFER(NEXT:NEXT) (22 ) NEXT=NEXT+1 (23 ) END
6
2015-4-21
9.1.2 声明的作用域
作用域的显式控制 C++、Java和C#等使用public、private和 protected这样的关键字,对作用域进行显式控 制。 声明的作用域是通过符号表进行管理的
2015-4-21
7
9.1.3 过程及其活动
将“过程、函数和方法”统称为“过程” 过程定义是一个声明,它的最简单形式是把 一个标识符和一个语句联系起来。 该标识符是过程名,而这个语句是过程体。
2015-4-21
23
9.3 静态存储分配策略
如果在编译时就能确定一个程序在运行时所需 要的存储空间的大小,则在编译时就能安排好 目标程序运行时的全部数据空间,并能确定每 个数据项的地址,存储空间的这种分配方法称 为静态存储分配。必须满足如下条件:
数据对象的长度和它在内存中的位置在编译时必须 是已知的; 不允许过程的递归调用,因为一个过程的所有活动 都是用同样的局部名字绑定的; 数据结构不能动态建立,因为没有运行时的存储分 配机制。
2 1
SP 0
2015-4-21
参数个数 返回地址 旧SP
对任何局部变量X的引 用可表示为变址访问: dx[SP] dx:变量X相对于活动记 录起点的地址,在编译 时可确定。
16
每个过程的活动记录内容
——嵌套语言(如Pascal)
TOP 临时变量 数组内情向量
连接数据
局部变量
形式单元 2 1 SP0
9.3 静态存储分配策略
C 语言程序的全局变量和程序中出现的常量都 可以静态分配。 声明在函数外面
12
2015-4-21
9.2 存储组织
9.2.1 运行时内存的划分 9.2.2 活动记录 9.2.3 局部数据的组织 9.2.4 全局存储分配策略
2015-4-21
13
7.2.1 运行时内存的划分
目标代码 静态数据 栈 空闲 空间 堆
2015-4-21 14
9.2.2 活动记录
过程的每个活动所需要的信息用一块连续的存储 区来管理,这块存储区叫做活动记录 假定语言的特点为:允许过程递归调用、允许过程 含有可变数组,过程定义允许/不允许嵌套。
2015-4-21
静态链
动态链 返回地址
返回地址 动态链:指向调用该 过程前的最新活动记 录地址的指针。 静态链:指向静态直接 外层最新活动记录地址的 指针,用来访问非局部数 据。
17
每个过程的活动记录内容
TOP 临时变量 数组内情向量 局部变量 形式单元
2 1
SP 0
静态链 动态链 返回地址
9.3 静态存储分配策略
Fortran语言被设计成允许静态存储分配
cnsume的代码 代码
prduce的代码
character 50 buf integer next character c character 80 buffer integer next cnsume的活动记录 静态数据 prduce的活动记录
School of Computer Science & Technology Harbin Institute of Technology
第9章 运行时的存储组织
解决问题:符号空间到地址空间的映射问题 重点:符号表的内容、组织,过程调用实现,
静态存储分配、动态存储分配的基本
方法。
难点:活动记录、非局部数据的栈实现 问题
当过程名出现在可执行语句中时,称相应的 过程在该点被调用。 过程调用就是执行被调用过程的过程体。