对应实践:Lab03 - step_3 语法分析与 AST 主要修改文件:
miniCompiler_lab/labs/lab03-step3/framework/student.c
到了这一章,编译器终于要开始处理“结构”了。token 流虽然已经比字符流干净很多,但它本质上仍然是一条线。而程序不是一条线。表达式有优先级,if 有条件和分支,函数定义有函数名和函数体,代码块里还会再套语句。
词法分析器负责把原材料切好;语法分析器负责把这些片段重新组装成有层次的树。这棵树,就是 AST。
3.1 为什么 token 流还不够
看下面这段代码:
int sum = x + y * z;
如果你只停在 token 流层面,它只是:
INT IDENT ASSIGN IDENT PLUS IDENT STAR IDENT SEMICOLON
但这串 token 里没有直接告诉你一个关键事实:这里应该先算 y * z,再和 x 做加法。
这说明 token 流只保存了“顺序”,还没有保存“结构关系”。而 parser 的工作,就是把这种结构关系补出来。
3.2 AST 为什么叫“抽象”语法树
很多人第一次看到 AST,会疑惑:为什么不是把源码原样存下来,而要“抽象”?
原因是编译器后面的阶段不需要保留所有书写细节。它真正关心的是:
- 这是一个变量声明,还是一个返回语句
- 这是一个二元运算,操作符是什么
- 这是一个
if,条件、then 分支、else 分支分别是什么
像多余空格、注释、甚至某些书写层面的细枝末节,都已经不重要了。AST 保留的是对后续语义检查和代码生成有意义的结构,而不是源码的排版外观。
3.3 递归下降为什么适合这门课
这门课选择的 parser 风格是递归下降。理由不是它“理论上最强”,而是它特别适合让你把语法结构和代码结构一一对应起来。
递归下降解析器里常见的一组函数:
parse_primaryparse_factorparse_termparse_comparisonparse_statementparse_function
它们并不是随手分出来的。它们正对应着“从最小表达式单元一路往上包”的过程。
也就是说,递归下降的一个巨大优点是:你几乎能直接从函数名看出 parser 正在哪一层结构上工作。
3.4 优先级不是额外补丁,而是函数层次本身
这一章特别值得建立一个直觉:表达式优先级并不是最后临时修一修,而是 parser 分层时就应该体现出来。
例如:
parse_factor处理乘除parse_term在它上面处理加减parse_comparison再往上处理<、>、<=、>=
这种分层一旦搭好,优先级几乎是自然长出来的,而不是靠后期打补丁硬拼出来的。
所以当你在 lab 里补 parse_primary 或观察 parse_if 的结构时,不要只把它当成几个函数分支。你真正该看到的是:语法层次正在通过函数调用层次显影。
3.5 parser 和 AST 为什么要分成两件事
这一章要同时抓住两类逻辑:
parser:怎样识别结构
AST:怎样保存结构
parser 负责“怎样认结构”,AST 负责“怎样把结构装进节点里”。
阅读时先问自己两个问题:
- 当 parser 识别出一个结构时,它会创建哪种 AST 节点
- 这类节点在后续语义分析和代码生成里为什么有用
只要你始终盯着“识别 -> 建树”这条线,parser 和 AST 就不会裂成两份互不相干的知识。
3.6 本章 practice 边界
这一章的 practice 路径是:
miniCompiler_lab/labs/lab03-step3/
主要修改文件:
framework/student.c
验证命令:
cd labs/lab03-step3
make clean && make test
本章 lab 故意没有把整份 parser 都掏给你,而是把最有代表性的三个结构节点留成了 TODO:
student_parse_primarystudent_parse_ifstudent_parse_function
为什么是这三个?
parse_primary是表达式树真正开始生长的地方parse_if是控制流结构第一次出现的地方parse_function把整个程序的最外层骨架搭起来
只要你把这三个点理解透,递归下降解析器的整体轮廓就已经建立起来了。
3.7 本章最值得观察的现象
你在这一章验证时,最该看的是 AST 的形状,而不是单个 token。
尤其要确认:
- 程序根节点是不是
Program main函数是不是被挂在函数定义节点下面if的条件和分支是不是分开保存x + y * z这种表达式的树形是不是体现了优先级
只要树形关系对了,后面的语义分析和代码生成才有可靠的输入。
3.8 本章小结
这一章让编译器第一次拥有“结构感”。从这里开始,输入不再只是 token 列表,而是已经能表达程序层次关系的 AST。后面无论做类型检查还是生成汇编,本质上都建立在这棵树上。
3.9 下一步
现在去完成:
- Lab03 - step_3 语法分析与 AST
- 对照验证输出,确认 AST 形状正确
- 然后继续进入 Chapter 4 — 符号表与语义分析