什么是自上而下分析 - 编译原理剖析
引言
在编译原理中,语法分析是编译过程的关键环节,而自上而下分析(Top-Down Parsing)是一种重要的语法分析方法。它从文法的起始符号开始,逐步推导至输入的词法单元,构建语法树。本文将详细讲解自上而下分析的原理、实现方式,并分析其可能遇到的问题及解决方案。
什么是自上而下分析?
自上而下分析是一种从文法的**起始符号(Start Symbol)**出发,按照语法规则逐步推导出输入词法单元的解析方法。它试图从"整体"到"局部"构建语法树,与自底向上分析(Bottom-Up Parsing)相反,更接近人类理解代码的方式。
例如,对于文法:
css
S -> A + B
A -> a
B -> b
输入 a + b
,自上而下分析会从 S
开始,推导出 A + B
,再分别推导出 a
和 b
,最终匹配输入。
自上而下分析的工作原理
自上而下分析基于上下文无关文法(CFG),其步骤如下:
- 从起始符号开始:以文法的起始符号为根。
- 选择产生式:根据当前非终结符选择一个产生式展开。
- 匹配输入:将展开的符号与输入的词法单元对比。
- 递归推导:重复此过程,直到匹配整个输入或失败。
实现方式
-
递归下降分析 :
-
为每个非终结符编写递归函数。
-
示例伪代码:
scssfunction parse_S() { parse_A(); match('+'); parse_B(); } function parse_A() { match('a'); } function parse_B() { match('b'); }
-
-
LL(1) 分析 :
- 使用预测表根据当前输入符号选择产生式。
- "LL(1)"表示从左到右扫描、最左推导、预看一个符号。
自上而下分析的优点
- 直观性:从整体到局部,易于理解。
- 实现简单:递归下降分析适合小型语言。
- 错误检测:能较早发现语法错误。
自上而下分析的问题
自上而下分析在某些情况下会遇到挑战,以下是主要问题及解释:
1. 左递归问题
考虑文法:
r
E -> E + T
E -> T
解析 E
时会无限递归调用 E -> E + T
,导致死循环。这种情况称为左递归。为解决此问题,我们需要改造文法。例如,将其改写为:
r
E -> T E'
E' -> + T E' | ε
T
和 E'
是什么关系?
E
(表达式) :表示整个表达式,如3 + 5 + 7
。T
(项) :表示表达式中最基本的单元,如数字3
或5
,不包含加法运算。E'
(E撇,表达式尾部) :表示T
后面的可选部分,用于处理加法。它可以是+ T E'
(继续加下一个项,例如+ 5 + 7
)或ε
(空串,表示没有更多加法)。- 关系 :
E -> T E'
表示一个表达式由一个基本项T
开始,后面跟着E'
,而E'
负责递归地处理所有后续的加法部分。例如:- 输入
3 + 5
:E
推导为T E'
。T
匹配3
。E'
推导为+ T E'
,匹配+ 5
,最后的E'
推导为ε
,结束。
- 输入
这样,左递归被消除,解析器可以从左到右逐步处理输入。
2. 回溯问题
对于文法:
css
S -> A b
S -> A c
A -> a
输入 a b
,解析器可能先尝试 S -> A c
,失败后回溯到 S -> A b
。回溯增加复杂度,解决方法是确保文法满足 LL(1) 条件,即每个选择在预看一个符号时是唯一的。
3. 二义性文法
文法:
rust
E -> E + E | E * E | n
输入 n + n * n
可以解析为 (n + n) * n
或 n + (n * n)
,自上而下分析无法自动决定。需引入优先级规则(如 *
先于 +
)或改写文法。
4. 预看限制
对于:
rust
S -> if E then S
S -> if E then S else S
输入 if ...
时,预看一个符号无法决定选择哪个产生式,可能需要 LL(k) 分析。
解决方法
- 消除左递归 :如上文将
E -> E + T
改为E -> T E'
。 - 确保 LL(1):计算 FIRST 和 FOLLOW 集,构造预测表。
- 处理二义性:定义运算符优先级。
- 使用工具:如 ANTLR,自动生成解析器。
实际应用举例
输入:
3 + 5 + 7
文法:
rust
E -> T E'
E' -> + T E' | ε
T -> n
解析过程:
E -> T E'
。T -> n
,匹配3
。E' -> + T E'
,匹配+ 5
。E' -> + T E'
,匹配+ 7
。E' -> ε
,结束。
总结
自上而下分析是一种直观高效的语法分析方法,适合简单语言的解析器设计。通过消除左递归(如用 T
和 E'
分担表达式和加法的角色)、避免回溯和二义性,它可以很好地工作。希望本文澄清了 T
和 E'
的关系,若有兴趣,不妨尝试实现一个简单的递归下降解析器!