MENU

消除左递归

November 21, 2018 • Read: 6380 • 编译原理阅读设置

在进行语法分析的过程中,我们需要根据文法构建语法分析树。如果分析树构建成功则说明语法正确,反之语法错误。因此,如何构建一棵语法分析树非常重要

构建语法分析树有两种方式,一种是自上而下的分析方法(由根部开始构建语法分析树),另一种是自下而上的分析方法。本文采用的是自上而下的分析方法

自上而下的分析方法存在一个问题:文法中存在左递归怎么办?

什么是左递归?假设存在一个文法 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 步

  1. 将递归链上的非终结符逐级带入产生直接左递归
  2. 消除直接左递归
  3. 删除多余文法

消除左递归算法

  • 输入:不含循环推倒(即形如 $A→^+A$ 的推导)和 $\epsilon$ 产生式的文法 G
  • 输出:等价的无左递归文法
  • 方法:

Last Modified: August 25, 2020
Archives Tip
QR Code for this page
Tipping QR Code
Leave a Comment

2 Comments
  1. Kaji Kaji

    “A→Aα→AAα→AAAα→...→βα...α” 这里应该是 “A→Aα→Aαα→Aααα→...→βα...α” 吧

    1. mathor mathor

      @Kaji 是的,已修正,谢谢 @(大拇指)