对应实践:Lab02 - step_2 词法分析器 主要修改文件:
miniCompiler_lab/labs/lab02-step2/framework/student.c
到了这一章,编译器第一次开始真正“看懂一点源码”。但注意,这里的“看懂”还非常有限。词法分析器并不知道一条 if 语句是否合法,也不知道 x + y * z 的优先级是什么。它只负责做一件事:把一串连续字符切成一串更有结构的 token。
这一步之所以重要,是因为后面的语法分析器不适合直接面对原始字符流。对 parser 来说,if、return、123、+、{ 这些词法单元已经比单个字符更接近语言结构。
2.1 为什么上一章的能力已经不够了
在 Chapter 1 里,编译器已经能读文件、写输出,但它对输入内容本身几乎一无所知。无论你给它的是 return 0;,还是一段完全无意义的字符串,它都只会照样吐出固定汇编模板。
这说明第一章建立的是编译器壳子,而不是语言前端。
从这一章开始,项目第一次需要回答这样的问题:
- 这个单词是关键字还是普通标识符?
==和=为什么不能当成同一个东西?- 注释和空白为什么不应该进入后面的语法阶段?
这几个问题看起来零碎,但其实都指向同一件事:先把字符流整理成 token 流。
2.2 先建立一个正确直觉:token 不是“单词”,而是分类后的片段
很多初学者会把 token 粗糙地理解成“源码里的一个词”。这个说法不算完全错,但不够准确。
更好的理解是:
token 是源码中一个被识别、被分类、并且足以交给下一阶段继续处理的片段。
例如在下面这段代码里:
if (sum > 25) {
return 1;
}
词法分析器看到的不是一句完整控制流语句,而是一段段被分类的片段:
if-> 关键字(-> 左括号sum-> 标识符>-> 比较运算符25-> 数字字面量)-> 右括号{-> 左花括号return-> 关键字1-> 数字;-> 分号}-> 右花括号
一旦这一步完成,后面的 parser 就不用再去猜字符组合,而是可以直接在 token 层面谈结构。
2.3 这一章最该抓住的三类动作
词法分析器看起来分支很多,但先不要被所有 token 类型压住。它最核心的动作可以压成三类:
读取当前位置 -> 判断片段类型 -> 生成一个 token 并推进光标
做 lab 时也按这个顺序理解:
- 状态推进:
peek、peek_next、advance - 片段扫描:标识符、数字、字符串
- 主分发入口:
lexer_next
如果你一开始就陷进所有 case 分支里,很容易被细节淹没。更有效的观察方式是先看“它怎样移动光标,怎样跳过不重要的东西,怎样把重要东西打包成 token”。
2.4 空白和注释为什么要在这一层就处理掉
这一章最容易被低估的函数之一,是跳过空白与注释的逻辑。
这件事之所以应该发生在 lexer,而不是 parser,原因很简单:空格、换行、注释属于书写层面的噪声,不属于语言结构本身。对语法分析来说,return 0; 和
return 0; // comment
如果语义完全一样,那就不应该让 parser 去反复应付这些干扰。
也就是说,lexer 的一项重要职责,不只是“认出有用的 token”,还包括“提前丢掉后面阶段不该关心的东西”。
2.5 关键字和标识符为什么要区分
从字符形状上看,if 和 sum 很像。它们都满足“字母开头,后面跟字母、数字或下划线”。
如果你只靠字符规则扫描,它们都会先落在“像标识符”的这类片段里。真正让 if 变成关键字的,不是扫描方式变了,而是你在扫描完成后,又查了一次关键字表。
这一步非常值得你建立直觉,因为它会反复出现:编译器经常先按一个宽规则识别,再按更具体的语义做二次分类。
2.6 本章 practice 边界
这一章的 practice 路径是:
miniCompiler_lab/labs/lab02-step2/
主要修改文件:
framework/student.c
验证命令:
cd labs/lab02-step2
make clean && make test
本章 lab 留给你的不是整份 lexer,而是三段最有代表性的骨架:
student_skip_whitespacestudent_scan_identifierstudent_scan_number
这三个函数刚好覆盖了 lexer 最核心的三类动作:
- 跳过无用噪声
- 扫描名字类 token
- 扫描数字类 token
只要你把这三件事写稳,lexer_next 这类主分发逻辑就会突然变得清晰很多。
2.7 本章最该盯住的验证现象
这一章不要只盯着“测试通过没通过”。你更应该观察:
- token 类型是否对
- token 的值是否对
- 注释和空白是否真的被跳过去了
if、return这类词是否被识别成关键字,而不是普通标识符
只要这四类现象稳定,说明你的 lexer 已经具备把字符流交给 parser 的资格。
2.8 本章小结
词法分析器做的不是“理解程序含义”,而是先把连续字符整理成更适合继续推理的 token 流。它是语法分析的前门,没有这一步,后面的 AST 根本无从谈起。
2.9 下一步
现在去完成:
- Lab02 - step_2 词法分析器
- 观察 token 序列是否和讲义预期一致
- 然后继续进入 Chapter 3 — 语法分析器与 AST