什么是程序?

Hmm....


你需要《程序设计语言的形式语义

  • by 梁红瑾 🎩
  • $\lambda$-calculus, operational semantics, Hoare logic, separation logic
  • 入围 “你在南京大学上过最牛的课是什么?” 知乎高票答案
    • 当然,我也厚颜无耻地入围了

不,你不需要

你能写一个 C 语言代码的 “解释器” 吗?

  • 如果能,你就完全理解了高级语言
  • 和 “电路模拟器”、“RISC-V 模拟器” 类似
    • 实现 gdb 里的 “单步执行”
while (1) {
  stmt = fetch_statement();
  execute(stmt);
}

“解释器” 的例子:用基础结构模拟函数调用和递归

  • 试试汉诺塔吧

这个问题已经超出了 90% 程序员的能力范围

ChatGPT 竟然改写对了!而且给出了非常优雅 (但也有缺陷) 的实现

void hanoi_non_recursive(int n, char from, char to, char via) {
  struct Element { int n; char from; char to; char via; };
  std::stack<Element> elements;
  elements.push({n, from, to, via});
  while (!elements.empty()) {
    auto e = elements.top();
    elements.pop();
    if (e.n == 1) {
      printf("%c -> %c\n", e.from, e.to);
    } else {
      elements.push({e.n - 1, e.via, e.to, e.from});
      elements.push({1, e.from, e.to, e.via});
      elements.push({e.n - 1, e.from, e.via, e.to});
    }
  }
}

当然,ChatGPT 也没能完全理解

给了他一个更难的题,果然翻车了 (思路基本正确,但不再优雅)

int f(int n) {
  if (n <= 1) return 1;
  return f(n - 1) + g(n - 2);
}

int g(int n) {
  if (n <= 1) return 1;
  return f(n + 1) + g(n - 1);
}

(你们会写这个的非递归吗)

简单 C 程序的状态机模型 (语义)

对 C 程序做出简化


状态机定义

  • 状态 = 堆 + 栈
  • 初始状态 = main 的第一条语句
  • 状态迁移 = 执行一条语句中的一小步

(这还只是 “粗浅” 的理解)

  • Talk is cheap. Show me the code. (Linus Torvalds)
    • 任何真正的理解都应该落到可以执行的代码

简单 C 程序的状态机模型 (语义)

状态

  • Stack frame 的列表 + 全局变量

初始状态

  • 仅有一个 frame: main(argc, argv) ;全局变量为初始值

状态迁移

  • 执行 frames.top.PC 处的简单语句
  • 函数调用 = push frame (frame.PC = 入口)
  • 函数返回 = pop frame

然后看看我们的非递归汉诺塔 (更本质)