【编译原理笔记】2.1 Programming Language Basics

对应龙书中1.6节

一、静态与动态特性(Static vs Dynamic)

1.1 基本定义

  • 静态问题(Static Issues) :在编译时就能确定和处理的问题

  • 动态问题(Dynamic Issues) :需要在运行时才能解决的问题

1.2 静态特性示例

cpp 复制代码
 // C/Java中的声明作用域
 int x;  // 编译时确定作用域
 static class MyClass {  // 静态类对象的位置在编译时确定
     // ...
 }

1.3 动态特性示例

cpp 复制代码
 void function() {
     int local_var;  // 局部变量的位置在运行时确定(栈分配)
 }

1.4 关键区别

特性类型 处理时机 示例 影响
静态 编译时 作用域、静态类型检查 编译效率、错误检测
动态 运行时 局部变量分配、多态 运行灵活性、性能开销

二、环境与状态(Environments and States)

2.1 两层映射模型

上图展示了名字到值的两阶段映射

2.2 环境(Environment)

  • 功能 :将名字(Names) 映射到存储位置(Locations)

  • 性质:相对静态,在编译时部分确定

  • 示例:变量名到内存地址的映射

2.3 状态(State)

  • 功能 :将存储位置(Locations) 映射到值(Values)

  • 性质:高度动态,在运行时不断变化

  • 示例:内存地址存储的实际数据值

2.4 实际意义

cpp 复制代码
 int x = 10;  // 环境:x → 内存地址0x1000
              // 状态:0x1000 → 值10
 x = 20;      // 状态变化:0x1000 → 值20(环境不变)

三、静态作用域与块结构(Static Scopes/Block Structures)

3.1 静态作用域规则

3.2 最近嵌套规则(Most Closely Nested Rule)

  1. 名字查找顺序:从最内层块开始,逐层向外

  2. 遮蔽(Shadowing):内层声明遮蔽外层同名声明

  3. 作用域确定:在编译时通过程序结构确定

3.3 块结构特性

  • 嵌套性:块可以嵌套在其他块中

  • 局部性:块内声明只在块内有效

  • 确定性:作用域在编译时完全确定


四、显式访问控制(Explicit Access Control)

4.1 访问修饰符

  • Public:公开访问,任何代码都可访问

  • Private:私有访问,只在类内部可访问

  • Protected:保护访问,类及其子类可访问

4.2 封装性设计

cpp 复制代码
 class MyClass {
     public int publicVar;     // 任何地方可访问
     private int privateVar;   // 仅本类内可访问  
     protected int protVar;   // 本类及子类可访问
 }

4.3 设计目标

  1. 信息隐藏:隐藏实现细节

  2. 接口隔离:明确公开的API

  3. 维护性:减少外部依赖带来的影响


五、动态作用域(Dynamic Scope)

5.1 定义规则

"A use of a name x refers to the declaration of x in the most recently called procedure with such a declaration."

最近调用原则 :名字x引用的是最近调用的包含x声明的过程中的声明。

5.2 与静态作用域对比

cpp 复制代码
 // 静态作用域示例
 int x = 1;
 void foo() { printf("%d", x); }  // 总是输出1
 ​
 // 动态作用域伪代码  
 int x = 1;
 void bar() { int x = 2; foo(); }  // 如果动态作用域,foo()输出2

5.3 实际应用场景

  1. 宏扩展(Macro Expansion)

  2. 面向对象编程中的方法解析

  3. 某些脚本语言(如早期LISP)

5.4 动态作用域的问题

  • 不可预测性:行为依赖于运行时调用序列

  • 调试困难:相同代码在不同上下文行为不同

  • 维护复杂:难以理解程序逻辑


六、参数传递机制(Parameter Passing Mechanisms)

6.1 传值调用(Call by Value)

cpp 复制代码
 void f(int x) {
     x = x + 1;    // 修改形参x
     print(x);     // 输出增加后的值
 }
 ​
 int main() {
     int y = 1;
     f(y + 1);     // 传递表达式y+1的值
     // y的值不变,仍为1
 }

特点

  • 传递实际参数的副本

  • 函数内修改不影响原始变量

  • 适用于基本数据类型

6.2 传引用调用(Call by Reference)

cpp 复制代码
 void swap(int &x, int &y) {  // C++引用参数
     int temp = x;
     x = y;
     y = temp;
 }
 ​
 int main() {
     int a = 1, b = 2;
     swap(a, b);  // a和b的值被交换
 }

应用场景

  • 数组传递

  • 指针参数

  • 类对象传递(大多数面向对象语言)

特点

  • 传递实际参数的引用

  • 函数内修改影响原始变量

  • 适用于需要修改参数值的场景

6.3 传名调用(Call by Name)

cpp 复制代码
 #define MAX(a, b) ((a) > (b) ? (a) : (b))
 ​
 int main() {
     int x = 1, y = 2;
     int z = MAX(++x, y);  // 展开为: ((++x) > (y) ? (++x) : (y))
     // x可能被多次求值(这里x变为3)
 }

特点

  • 类似宏替换,参数表达式在调用点展开

  • 可能多次求值同一表达式

  • 现代语言较少使用(Algol 60特性)


七、别名问题(Aliasing)

7.1 别名定义

"An interesting consequence of call-by-reference parameter passing. It is possible that two formal parameters can refer to the same location."

别名:多个名字指向同一个内存位置。

典型示例

cpp 复制代码
void q(int x[], int y[]) {
    x[10] = 2;    // 修改x
    // 如果x和y是同一数组,y[10]也变为2
}

void p() {
    int a[100];
    q(a, a);      // 传递同一数组的两个别名
}

7.2 别名产生场景

  1. 传引用调用:多个参数指向同一对象

  2. 指针别名:不同指针指向同一内存

  3. 数组重叠:数组切片或子数组

7.3 别名的问题

  1. 优化障碍:编译器难以确定内存独立性

  2. 正确性风险:意外修改共享数据

  3. 调试困难:难以追踪数据流

解决方案

cpp 复制代码
// 使用const限制修改
void q(const int x[], int y[]) {
    // x[]只读,避免意外修改
    y[10] = 2;
}

// 使用restrict关键字(C99)
void q(int *restrict x, int *restrict y) {
    // 向编译器保证x和y不重叠
    x[10] = 2;
}

八、核心概念总结

静态vs动态的权衡

方面 静态优势 动态优势
性能 编译时优化 运行时灵活性
错误检测 早期发现 适应性强
确定性 行为可预测 支持多态

作用域规则演进

复制代码
动态作用域(早期语言) → 静态作用域(现代语言) → 显式访问控制(面向对象)

参数传递发展

复制代码
传名调用(Algol) → 传值调用(函数式) → 传引用调用(面向对象)

现代语言设计趋势

  1. 默认安全:传值为主,显式传引用

  2. 静态检查:尽可能在编译时发现问题

  3. 明确语义:减少隐式行为和别名

  4. 封装性:通过访问控制管理复杂性

这些基础概念为理解编程语言设计、编译器实现和程序正确性提供了理论基础,是计算机科学教育的核心组成部分。

相关推荐
人工智能培训3 小时前
大模型-去噪扩散概率模型(DDPM)采样算法详解
算法
Excuse_lighttime3 小时前
只出现一次的数字(位运算算法)
java·数据结构·算法·leetcode·eclipse
liu****3 小时前
笔试强训(二)
开发语言·数据结构·c++·算法·哈希算法
挺6的还4 小时前
高并发内存池
c++
无限进步_4 小时前
扫雷游戏的设计与实现:扫雷游戏3.0
c语言·开发语言·c++·后端·算法·游戏·游戏程序
jianqiang.xue4 小时前
单片机图形化编程:课程目录介绍 总纲
c++·人工智能·python·单片机·物联网·青少年编程·arduino
qq_433554544 小时前
C++ 完全背包
开发语言·c++·算法
lingran__4 小时前
算法沉淀第二天(Catching the Krug)
c++·算法
Yupureki4 小时前
从零开始的C++学习生活 8:list的入门使用
c语言·c++·学习·visual studio