05 - 拆词和搭架子:词法分析 & 语法分析
上一章我们看了翻译流水线的全貌。这一章钻进最前面、也最能体现「翻译智慧」的两个工位:拆词和搭架子。它们合起来干的事,就是把「一串没有结构的字符」变成「一个有结构的意思」。
先感受一下问题有多难
机器拿到你的代码时,它看到的其实只是一长串字符,中间连词都没帮你分好:
result=1+2
对机器来说,这就是一串 r、e、s、u、l、t、=、1、+、2。它既不知道哪几个字母是一个整体,也不知道谁和谁是一伙的。要把这堆字符变成能执行的东西,得分两步走。
第一步:词法分析——断句成「词」
词法分析(Lexing)干的事,就是把字符流切成一个个有意义的最小单位,这些单位叫「词」(Token)。
result=1+2 经过词法分析后,变成:
[result] [=] [1] [+] [2]
名字 赋值 数字 加 数字
每个词还会被贴上一个「身份标签」:result 是名字,= 是赋值符号,1 和 2 是数字,+ 是运算符。
类比:你读英文
Ilikecats时,大脑第一件事就是把它断成I / like / cats。词法分析干的就是这件断句的活,顺便标注每个词是什么词性。
这一步也能抓出一类错误:如果你写了个 @ 这种语言里根本不存在的符号,词法分析当场就能报错——「我不认识这个词」。
第二步:语法分析——把词搭成一棵「树」
光有一堆词还不够。[result] [=] [1] [+] [2] 只是一排零散的词,它们之间的关系还没确定。谁先算?谁赋值给谁?
语法分析(Parsing)干的事,就是按照语法规则,把这些词组织成一棵有层次的「结构树」。 这棵树有个专门的名字,叫抽象语法树(AST),但你只要记住「一棵表示结构的树」就够了。
result = 1 + 2 搭出来的树,大概长这样:
=(赋值)
/ \
result +(加法)
/ \
1 2
这棵树清清楚楚地表达了:
- 最上面是「赋值」这个动作;
- 它把左边的
result和右边的「一个加法」联系起来; - 而这个加法,又是由
1和2组成的。
类比:小学语文分析句子成分——「我 吃 苹果」,你会画出「主语 + 谓语 + 宾语」的结构。语法分析做的是一模一样的事:把一排词,按规则组织成有主次、有嵌套的结构。
语法分析也能抓错误:如果你写了 result = 1 +(加号后面啥都没有),它按规则搭树时会发现「加法缺了右半边」,于是报语法错误。这就是典型的语法错误。
为什么「树」这么重要?
因为树天然表达了「先算谁、后算谁」的顺序和层次。
想想 1 + 2 * 3。凭什么是 2 * 3 先算?因为搭出来的树里,乘法在更靠下的一层,会被先处理:
+
/ \
1 *
/ \
2 3
一旦结构变成了这样一棵树,「运算顺序」这种看起来很微妙的规则,就变成了「从树的底层往上算」这么简单直接的一件事。结构一旦清晰,后面的翻译就水到渠成了。
走到这一步,我们收获了什么
经过拆词和搭架子,你那行代码已经从「一串字符」变成了「一棵结构清晰的树」。机器现在不仅知道你写了哪些词,还知道它们之间是什么关系。
接下来只要顺着这棵树,就能:
- 检查它讲不讲得通(语义分析);
- 把它翻译成机器能执行的东西。
而「怎么把这棵树变成能跑的东西」,正好分成两种截然不同的思路——这就是下一章的主角。
小结
- 机器拿到的只是一串没分好的字符,得先加工成有结构的意思。
- 词法分析:把字符流断成一个个「词」,并标注词性(像英文断句)。
- 语法分析:把这些词按规则搭成一棵「结构树」(像分析句子成分)。
- 树的好处:天然表达了层次和运算顺序,「先算谁」变成「从底往上算」。
- 这两步还能提前抓出词法错误和语法错误。
- 有了这棵树之后,怎么让它真正跑起来?下一章讲两条路:编译和解释。
上一章 ← 04 - 机器怎么读懂你写的代码 | 下一章 → 06 - 两条路:编译 vs 解释 | 回到 README 目录