关于编译原理基础概念可参考
关于下列代码的基础数据结构参见
一、 消除直接左递归
设P -> Pα1 | Pα2 | ... | Pαn | β1 | β2 | ... |βm
其中每个α不为ε(ε就是空,什么都没有的意思,类似null),每个β不以P开头。
则非终结符P可改写为
P -> β1P’ | β2P’ | ... | βmP’
P’ -> α1P’ | α2P’ | ... | αnP’ | null
解释:原来的P展开就是βxαi..αiαj..αj...αt..αt的形式,即某个β开头,各种阿尔法跟随的一个串。所以与改写形式所表达的东西是一样的。
二、 消除间接左递归
给定文法G,若G不含回路(P经过若干步推导又得到P)且不含以ε为右部的产生式。
则其消除左递归的算法如下:
- 对G的非终结符按任意顺序排列,如A1, A2, A3, ... , An
- for (i = 1; i <= n; i++) for (j = 1; j <= i - 1; j++) { 把形如Ai -> Ajγ的产生式改写成Ai -> δ1γ | δ2γ | ... | δkγ的形式,其中Aj -> δ1 | δ2 | ... | δk是关于Aj的全部规则 消除Ai规则中的直接左递归 }
- 简化由上一步得到的文法,即去掉多余的规则
三、 FIRST集
若文法G为二型文法且不含左递归,则G的非终结符的每个候选式α的终结首符集FIRST(α)为FIRST(α) = { a | α经过0或多步推导为a...的形式,其中a∈VT }
解读:FIRST集的含义是:候选式经过推导,最后就是一个终结符的串,推导过程不同,会有多个不同的串(可能是无限个),这些串里的第一个字符组成的集合就是这个候选式的FIRST集。有了这个FIRST集,就可以知道这个候选式是否能匹配接下来要解析的单词流了。
四、 FOLLOW集
设上下文无关文法(二型文法)G,开始符号为S,对于G中的任意非终结符A,其FOLLOW(A) = { a | S 经过0或多步推导会出现 ...Aa...的形式,其中a∈VT或#号 }
解读:FOLLOW集的含义是:G的一切句型中,能够紧跟着非终结符A之后的一切终结符或井号#。#是当出现 ...A 这样的情况,即A为最后一个字符。
五、 构造FOLLOW集的算法
- 令#∈FOLLOW(S)
- 若文法G中有形如A –> αBβ的规则,且β≠ε,则将FIRST(β)中的一切非终结符加入FOLLOW(B)
- 若文法G中有形如A -> αB或A -> αBβ的规则,且ε∈FIRST(β),则将FOLLOW(A)中的全部元素加入FOLLOW(B)
- 反复使用前两条规则,直到所有的FOLLOW集都没有改变。
六、 构造LL(1)分析表的算法
输入:文法G
输出:G的LL(1)分析表M(Ax, ay),其中A为非终结符,a为终结符
算法:
- 求出G的FIRST集和FOLLOW集
- for (G的每个产生式 A -> γ1 | γ2 | ... | γm){ if (a ∈ FIRST(γi)) 置 M(A, a) 为 “A -> γi” if (ε ∈ FIRST(γi)) for (每个 a ∈ FOLLOW(A)) 置 M(A, a)为 “A -> γi”(实际上此处的γi都是ε)}置所有无定义的 M(A, a)为出错。