在大屏或电脑上体验更佳——动画和操作区域更宽敞。
输入

词法分析与语法分析

词法分析器把源文本分成记号,语法分析器把记号组织成后续编译阶段使用的结构。12 + 3 * 4 先生成五个保持原顺序的记号,再被解析为 12 + (3 * 4),结果是 24;若只从左到右计算,则得到 60。

词法分析负责切分和分类,语法分析负责层级。乘法优先不是把 * 记号提前,而是由解析调用的组织方式决定。

词法和语法分析如何工作

词法分析从左到右扫描。数字开始一个数值词素,相邻数字继续加入它,因此 12 是一个 NUMBER(12),不是两个数字记号。+、*、(、) 各自形成记号。空白只推进扫描位置,不产生记号。@ 等未知字符没有可接受的类别,会使词法分析停止。

语法分析读取记号种类,不处理空格或原字符偏移。本课有三条递归下降规则:primary() 接受 NUMBER 或括号表达式;term() 处理 STAR 循环;expr() 处理 PLUS 循环。term 必须先完成自己负责的乘法,才能返回正在等待的 expr,优先级由此产生。

数字生成 AST 叶子。消耗运算符时不立即创建父节点,而是保留左子树和运算符,等待子调用解析右侧,再将两边归约为 Mul 或 Add。括号控制解析调用,结果树已记录其作用,因此不成为本课的 AST 节点。

词法与语法分析逐步演示

默认源文本为 12 + 3 * 4。

  1. 扫描 1,再把相邻的 2 加入同一范围,生成 NUMBER(12)。
  2. 跳过第一个空格,不在记号带上留占位。
  3. 生成 PLUS(+),跳过第二个空格,生成 NUMBER(3)。
  4. 第三个空格后生成 STAR(*),第四个空格后生成 NUMBER(4)。共有五个记号,另有 EOF 标记。
  5. 此时 PLUS 仍在 STAR 前,记号顺序尚未决定分组,因为还没有层级。
  6. expr() 调用 term(),后者调用 primary(),消耗 NUMBER(12) 并创建叶子 12。
  7. term 看到 PLUS 而非 STAR,返回 12。外层 expr 消耗 PLUS,保留 left = 12,再调用 term 解析右操作数。
  8. 右侧 term 消耗 NUMBER(3),看到 STAR,保留 left = 3,再调用 primary 取得 NUMBER(4)。
  9. term 将 3 * 4 归约为 Mul;该子树返回后,等待中的 expr 才把 12 + Mul 归约为 Add 根。
  10. 全部记号已消耗,求值为 12 + (3 * 4) = 24。

记号带始终不重排。调用面板显示 expr 等待 term 完成 STAR,AST 父节点依归约顺序出现:先 Mul,后 Add。

控制流怎样变成树层级

语法规定 PLUS 的每个操作数都由 term 处理,而 term 先完成乘法,最终树为 Add(12, Mul(3, 4))。若把 PLUS、STAR 放进同一个从左到右循环,同一记号带会得到 Mul(Add(12, 3), 4),结果为 60。改变的是解析控制流,不是运算符。

AST 保存分组决定,后续生成、优化和求值无需重新查询记号优先级。(12 + 3) * 4 也用同一套规则:primary 在括号中再次调用 expr,内层 Add 先完成,外层 term 再生成 Mul,此时 60 才是正确结果。

时间与空间复杂度

设源字符数 c、记号数 t、最大括号嵌套深度 d。

阶段时间辅助空间原因
词法分析O(c)O(t)每字符扫描一次,保存记号
语法分析O(t)O(t)每记号消耗一次,AST 节点数 O(t)
解析调用栈包含在上项O(d + 1)嵌套括号增加递归层,基础规则占常数帧

这是当前确定性小语法的上界,不保证任意语法或解析策略都是线性。

边界情况

  • 空输入或只有空白:词法分析得到空记号带,语法分析在需要 primary 时遇到 EOF,拒绝。
  • 12+3*4 与带空格版本有相同记号与树,空白由词法阶段处理。
  • 12 + @ 4 在词法阶段停止,不创造 @ 记号,也不开始解析。
  • 12 + * 4 词法合法、语法非法,primary 需要数字或左括号,却遇到 STAR。
  • (12 + 3 * 4 已形成内部子树,但 take("RPAREN") 在 EOF 处失败。

常见错误

  • 每个数字字符发一个 NUMBER,把 12 拆开后留下没有运算符连接的第二个操作数。
  • 认为能分词就语法正确。12 + * 4 的记号完整,但不满足语法。
  • 读到运算符立即创建父节点。右子树还没有解析完,必须等待。
  • 将加法、乘法写进同一解析循环,默认结果就从 24 变成 60。
  • 说 AST 创造优先级。解析控制流选择分组,AST 记录结果。
  • 在本课 AST 中保留括号节点。括号效果已由树层级表达。

模型范围与扩展

本课接受非负整数、加法、乘法和一层括号。省略标识符、一元运算、减除法、字符串、注释、源码位置、类型检查、错误恢复;实际解析器常会报告多个诊断,而非首次错误就停止。

同样结构可用于查询语言、配置表达式、模板和 DSL,以及编译器、检查工具。新增同优先级运算符通常扩展现有循环,新增优先级通常增加规则和调用边界,因此各规则应有明确职责。