编译原理笔记07:运行时环境

Posted by LiYixian on Tuesday, November 28, 2023 | 阅读 | ,阅读约 2 分钟

Summary:

  • 源语言相关问题
  • 存储组织
  • 内存分配策略
  • 访问非局部名字
  • 参数传递

源语言相关问题

过程(函数):procedure(静态)/activation(动态,一次执行)

  • 过程定义、过程名、过程体
  • 函数、调用、形参、实参
  • 生存期

过程的生命期或者不重叠、或者嵌套;
递归:过程 p 的某个活动尚未结束,可以开始它的一个新的活动

控制栈:DFS 活动树,活动开始时结点入栈、结束后弹出

声明:规定名字的含义
-> 作用域:声明起作用的范围,利用符号表
名字的绑定(声明的动态概念):环境把名字映射到存储位置,状态把存储位置映射到存储数据
-> 赋值语句改变状态,但不改变环境

存储组织

在控制栈里保存各种状态信息,调用返回时从控制栈恢复
活动记录

局部数据布局对不同类型有对齐/补丁/压缩的问题
名字的左值和右值:左值是地址,右值是值

内存分配策略

  • 静态分配:编译时确定所有数据的内存分布(不能递归、不能 new)
  • 栈分配:运行时需要局部变量时在栈区分配局部变量(new 出来的对象也在栈区,有生命周期)
    • 调用序列和返回序列:调用时 push,结束后 pop
    • 计算实参、返回值、设置控制链接和访问链接、保存寄存器值和其他状态信息

  • 堆分配:用户在运行时动态地在堆上分配和释放内存(所有变量都需要 new 和手动 delete)
    • 从空闲块链表为活动记录分配块表,释放时退回
    • 局部名字的值在活动结束后仍能保持;被调用函数的活动生存期可以比被调用者长

访问非局部名字

注意:非局部名字不是局部变量也不是全局变量
block 的最近嵌套规则:对 block 中引用的变量,使用离它最近的(外层)block 中的声明

包含过程嵌套的静态作用域:使用访问链接实现
e.g. PASCAL 语言允许过程嵌套,如果把一个 child 过程作为参数传递给其他函数,那么这个过程在哪里都可以访问 parent 过程中定义的变量,因此存在非局部名字,需要访问链判断是否能够访问指定变量
-> 访问链是静态链,指向代码中的直接父过程(固定);控制链是动态链,指向调用它的过程(可变)

参数传递

  • 传值:将右值传给形参,与局部名字同样处理,存在被调用函数的活动记录中,对形参操作不影响实参的值
  • 传地址:将左值传给形参
  • 复制-恢复:调用前传值,返回时将值复制回实参
  • 传名:相当于宏