在进行语法分析的过程中,我们需要根据文法构建语法分析树。如果分析树构建成功则说明语法正确,反之语法错误。因此,如何构建一棵语法分析树非常重要
构建语法分析树有两种方式,一种是自上而下的分析方法(由根部开始构建语法分析树),另一种是自下而上的分析方法。本文采用的是自上而下的分析方法
自上而下的分析方法存在一个问题:文法中存在左递归怎么办?
什么是左递归?假设存在一个文法 E → E+E
,可能会存在以下的推导过程
$$ E→E+E→E+E+E→E+E+E+E→... $$
没完没了,陷入左递归状态,因此我们需要消除左递归
左递归的类型有以下两种:
直接左递归
- 例如 $A→A\alpha|\beta$
间接左递归
- 例如 $A→^+A\alpha$
消除直接左递归
直接左递归较为直观,以上文提到的 $A→A\alpha|\beta$ 为例,我们对他进行推导
$$ A→A\alpha→A\alpha\alpha→A\alpha\alpha\alpha→...→\beta \alpha...\alpha $$
可以看出,此文法生成的串一定以 $\beta$ 开头,后面跟随若干个 $\alpha$,且 $\alpha$ 的个数可以为 0
因此我们可以定义一个新的非终结符 $A'$,且新的文法满足以下条件
- 令 $\alpha$ 可以重复,且不产生左递归(即使用右递归)
- 让 A 的产生式以 $\beta$ 开头(消除原有的左递归)
因此新的文法如下
$$ \begin{align*} A&→\beta A\\ A'&→\alpha A'|\epsilon \end{align*} $$
事实上,消除左递归的过程就是把左递归转换成了右递归
再举个例子,消除下面文法的左递归
$$ \begin{align*} E&→E+T|T\\ T&→T*F|F\\ F&→(E)|id \end{align*} $$
仔细观察上述文法,发现只有产生式 1 和产生式 2 有左递归。对于产生式 1,可以将 +T
看成一个整体 $\alpha$,T
看成是 $\beta$,于是产生式 1 就可以看成是
$$ E→E\alpha|\beta $$
根据第一个例子中消除左递归的方式,产生式 1 消除左递归后变为
$$ \begin{align*} E&→\beta E'\\ E'&→\alpha E'|\epsilon \end{align*} $$
再将 $\alpha,\beta$ 换回原来的符号
$$ \begin{align*} E&→TE'\\ E'&→+TE'|\epsilon \end{align*} $$
同理,对于产生式 2,将 *F
看成一个整体 $\alpha$,F
看成是 $\beta$,于是产生式 2 消除左递归后变为
$$ \begin{align*} T&→FT'\\ T'&→*FT'|\epsilon \end{align*} $$
消除直接左递归的一般形式
如果某条产生式具有直接左递归,例如
$$ A→A\alpha_1|A\alpha_2|...|A\alpha_n|\beta_1|\beta_2|...|\beta_m $$
其中,$\alpha_i\neq \epsilon$ 且 $\beta$ 不以 $A$ 开头
我们将其转换成不含左递归的产生式
$$ \begin{align*} A&→\beta_1A'|\beta_2A'|...|\beta_mA'\\ A'&→\alpha_1A'|\alpha_2A'|...|\alpha_nA'|\epsilon \end{align*} $$
消除左递归是要付出代价的,引进了一些非终结符和 $\epsilon$ 产生式
消除间接左递归
例如以下文法
$$ \begin{align*} S&→Aa|b\\ A&→Ac|Sd|\epsilon \end{align*} $$
随便推导一下
$$ S→Aa→Sda $$
可以发现推导了两步就出现了左递归。消除间接左递归的方法也很简单,对于上面的例子
- 首先将 S 的定义带入 A 的产生式,得
$$ A→Ac|Aad|bd|\epsilon $$
- 消除 A 产生式的直接左递归,得
$$ \begin{align*} A→bdA'|A'\\ A'→cA'|adA'|\epsilon \end{align*} $$
消除间接左递归的方法总结下来,分以下 3 步
- 将递归链上的非终结符逐级带入产生直接左递归
- 消除直接左递归
- 删除多余文法
消除左递归算法
- 输入:不含循环推倒(即形如 $A→^+A$ 的推导)和 $\epsilon$ 产生式的文法 G
- 输出:等价的无左递归文法
- 方法:
“A→Aα→AAα→AAAα→...→βα...α” 这里应该是 “A→Aα→Aαα→Aααα→...→βα...α” 吧
是的,已修正,谢谢 @(大拇指)