为了写实验,重新回顾一下CFG和左递归
1、上下文无关文法
(1) 上下文无关文法(CFG,Context Free Grammar)
顾名思义就是与上下文无关,不考虑上下文的语境,可以将它单独拿出进行分析、解释。
(2)上下文无关文法包含的四个部分:
一组非终结符(VN)、一组终结符号(VT)、一组产生式(P)、一个开始符号(S)。
例:G1=(VN,VT,P,S)
其中:VN={E},VT={i,+,*
},S=E,P={E->i,E->E+E,E->E*
E}
如果产生式有共同的左部,如->,->,可简写为->|,其中,分别称为的一个候选式
将上面的产生式写成E->i|E+E|E*E
的形式,最后可转换为E->i+i|i*i
- 终结符(Terminator):是组成语言的基本符号。顾名思义就是到了结尾的符号,是不可再分的具有独立意义的基本符号。(emm,说白了就是不能继续进行替换的符号,如例中最后的形式,i即为终结符)
- 非终结符(Nonterminal):用来表示语法范畴,如表达式、函数。(还可以继续进行替换的符号,如最后的E->i+i,可以用E表示加法和乘法)
- 产生式(production):所谓产生式是定义语法范畴的一种书写规则。也被称为重写规则,可以用一个符号串替换另一个符号串。(如E->i,E->E+E;E可以用i和E+E进行替换)
- 开始符号(start):特别的非终结符,代表所定义的语言中的最终的语法范畴。
(3)上下文无关文法的定义
文法G是一个四元组,G=(VN,VT,P,S),其中VN,VT分别是非空有限的非终结符号集合终结符号集,VN VT = ,P是产生式集,SVN称为文法的识别符号或开始符号。开始符号S必须在某个产生式的左部出现一次。
2、递归
(1)递归产生式:
形如:
A->xAy, x,y(VTVN)*,AV~N
的产生式称为递归产生式
(2)左递归产生式
- 直接左递归
在递归产生式的基础上,若x = (即候选式的第一个字符与开始符号相同,进行替换时,右边确定为y,左边则是一个A的递归),有
A->Ay
这个称为直接递归产生式
- 间接左递归
间接左递归:每一条产生式都不是直接左递归,但经过多次推导可以得出直接左递归,则为间接左递归
例:
A->Bb
B->A|a
替换后:A->Ab|ab
(3)右递归产生式
- 直接右递归
在递归产生式的基础上,若y = (即候选式的最后一个字符与开始符号相同,进行替换时,左边确定为x,右边则是一个A的递归),有
A->xA
这个称为直接右递归产生式
- 间接右递归
3、消除直接左递归
(1)方法
直接改写法
U -> Ux | y
U -> yU’
U’ -> xU’ |
(2)例
A -> [B
B -> X] | BA
X -> Xa|Xb|a|b
消除后结果
A -> [B
B -> X]B’
B’ -> AB’ |
X -> aX’ | bX’
X’ -> aX’ | bX’ |
4、消除间接左递归
(1)方法
1、将文法G的所有非终结符整理成某一顺序U1,U2…,Un
2、开始符号从后往前走for( i : 1 到 n)
for(j : 1 到 i - 1)
将产生式Ui -> Ujα1 | Ujα2…替换为
Ui -> β1α1 | β1α2 | β2α1 | β2α2 | … | βmα2
(其中Uj -> β1 | β2 | … | βm)
(2)例
A -> Bcd
B -> Ce | f
C -> Ab | c
分析:
开始符号为A、B;从后往前,故U1 = C,U2 = B,U3=A
i = 2,j = 1时:U2 -> U1α
将B -> Ce | f 替换为 B -> Abe | ce | f
U1为C,α1为Ab
,α2为c
; 含有开始符号除去后为α
U2为B,β1为Ce
,β2为f
; Uj的候选式即为β
将α与β组合 再加上 不含U1的部分(f),即Abe | ce | f
B -> Abe | ce | f
i = 3,j = 2U3 -> U2α
将A -> Bcd 替换为 A -> Abecd | cecd | fcd
U3为A,α为Bcd
;
U2为B,β1为Abe
,β2为ce
,β2为f
;
将α与β组合,即Abecd | cecd | fcd
消除后结果
A -> Abecd | cecd | fcd
5、代码实现
[编译原理-左递归的消除-QT/C++]()
6、结
emm,还好对这个内容重新看了一下,不然都没有发现我代码中的逻辑错误
文中有一些知识的解释是自己理解的,不一定对,学艺不精-_-||