编译原理消除左递归(消除左递归笔记)

一、什么是左递归

在编译原理中,左递归指的是文法中存在左递归产生式的情况。左递归产生式指的是产生式中的某一非终结符A可以通过一系列产生式推导出自己,且A在推导过程中以A作为产生式的第一个符号,即A → Aα(α为任意符号串)。

例如,文法E → E + T | T中,E → E + T这个产生式就是一个左递归产生式,因为E在这个产生式中作为第一个符号。

二、左递归的问题

虽然左递归产生式可以用来描述某些语言的结构,但是在语法分析的时候会带来一定的麻烦。具体来说,处理左递归产生式时容易陷入无限递归的状态。

例如,对于文法E → E + T | T,如果我们采用自顶向下的递归下降算法,那么在处理E的时候会一直递归下去,直到栈溢出。

三、消除左递归的方法

3.1 直接左递归的消除

针对形如A → Aα1 | Aα2 | …… | Aαn这样的产生式,可以通过以下方法消除直接左递归:

A → Aα1 | Aα2 | …… | Aαn
变为
A → β1A' | β2A' | …… | βnA'
A' → α1A' | α2A' | …… | αmA' | ε

其中,A’为新的非终结符,α1,α2,…,αm为原产生式右部开头不含A的符号串,β1,β2,…,βn为原产生式右部除去α部分以外剩余部分,即α1,α2,…,αn之后的部分,ε表示空字符串。此时,原文法中的所有产生式都不含直接左递归。

3.2 间接左递归的消除

针对形如A → Bα这样的产生式,且存在B → Aβ这样的产生式,即B可以推导出A,并且A又可以推导出B,这就是间接左递归。可以通过以下方法消除间接左递归:

A → Bα | γ1 | …… | γn
B → Aβ1 | δ1 | …… | δm
变为
A → γ1A' | …… | γnA'
A' → β1A' | δ1A' | …… | δmA' | α1 | …… | αk | ε
B → α1A' | …… | αkA'

其中,A’为新的非终结符,α1,α2,…,αk为能够推导出某个终结符的非终结符集合,即F={X | X → x, x∈Vt},Vt为终结符集合,ε表示空字符串。

四、实际应用

下面以一个具体的例子来说明如何通过消除左递归改善语法分析。

假设有以下文法:

S → S + T | T
T → T * F | F
F → ( S ) | id

在这个文法中,S存在直接左递归产生式S → S + T。我们可以先将其消除:

S → TS'
S' → + TS' | ε
T → FT'
T' → * FT' | ε
F → ( S ) | id

然后,我们可以将这个文法转化为LL(1)文法。具体来说,我们可以先把每个符号的FOLLOW集合求出来:

FOLLOW(S) = {$, )}
FOLLOW(S') = FOLLOW(S) = {$, )}
FOLLOW(T) = {+, $, )}
FOLLOW(T') = FOLLOW(T) = {+, $, )}
FOLLOW(F) = {* , + , $, )}

可以发现,在FOLLOW(S)和FOLLOW(S’)中都含有$,说明我们可以通过S的FIRST集合来选择S → ε。具体来说,如果下一个符号是$或者)时,我们就使用S → ε来进行归约。因此,我们需要将FIRST(S’)加上$和),即:

FIRST(S') = + $ )

然后,我们可以根据FIRST和FOLLOW集合来构造预测分析表:

( ) id * + $
S S → TS’ S → TS’
S’ S’ → +TS’ S’ → ε S’ → ε S’ → ε
T T → FT’ T → FT’
T’ T’ → ε T’ → *FT’ T’ → ε T’ → ε
F F → (S) F → id

这样,我们就可以使用LL(1)分析器来分析符合这个文法的语句了。

五、总结

消除左递归是编译原理中比较基础的内容,对于语法分析有着重要的意义。在实际应用中,我们可以使用一些常见的算法,如上述的消除左递归的方法和构造LL(1)文法的方法来处理左递归情况,从而使得语法分析更加高效。

Published by

风君子

独自遨游何稽首 揭天掀地慰生平