活动与活动记录
概念:
- 过程的一次执行称为过程的一次活动
- 把过程的一个活动所需要的信息组成的一块连续的存储单元 ,称为活动记录
理解:
- 一个活动所需要的信息的每个数据项有相同的生存周期,因此,将它们组成一个活动记录是很自然的
- 把活动看作位于栈上的方法(
不严谨),或许更好理解? - 源语言不同,活动记录的域不同——活动记录因语言而异,下面的内容你更能体会到这一点(比如过程能否作为参数?)
运行时的内存分配
内存被划分为:
目标代码 | (编译后才知道大小) |
静态数据 | (生命周期是整个活动) |
栈 | (Stack) |
↓ | |
↑ | |
堆 | (Heap) |
内存分配策略:
- 静态的:编译时就能确定每个数据目标在运行时刻的存储空间需求,因而在编译时就可以给他们分配固定的内存空间(这样的话,代码就不能有可变数组,也不能出现递归结构——否则编译时算不出需要的空间大小)
- 栈式的:动态分配策略的一种。栈的Push和Pop操作完美契合了程序的运行过程(与函数调用简直
天作之合);缺点也有,在运行之前,即编译时,我们就要知道所需空间的大小。 - 堆式的:动态分配策略的一种。如果基于堆进行分配,就不用再去考虑空间大小、生命周期了;代价是更慢的速度。
Java中对Stack/Heap的使用就很值得推荐,new出的对象都在堆中,栈上存放有指向它们的引用。这就是题外话了,与编译原理无关 >_<
内存分配影响语言特征:
- 过程能否递归
- 过程能否访问非局部变量
- 过程能否作为参数
- 过程结束后,其对局部变量的影响能否保留
PL/0的活动记录(模板)
- 局部变量
- 参数
- 参数个数
- RA—— 返回地址,填“?”
- DL—— 动态链(访问链)谁调用了我?
- SL—— 静态链(控制链)直接外层的SP
PL/0的活动记录(例题)
procedure P;
var a, b;
procedure Q(b);
var i;
procedure R(u, v);
var c, d;
begin
if(u = 1) then R(u + 1, v);
end;
begin
R(1, x);
end;
procedure S;
var i, j;
begin
a = 1;
Q(a);
end;
begin
S;
end.
这里有三层过程。划分好层次,再
套用模板,题目迎刃而解。
E N D END END