460 likes | 638 Views
LR 分析法. LR 分析法. 含义: L — 自左向右处理输入串; R — 最右推导的逆过程; LR 分析法的基本思想:规范归约过程中,记住 “ 历史 ” ,对未来 “ 展望 ” ,结合 “ 现实 ” LR 分析器 — 一个带栈的 DFA 。即:将 “ 历史 ” 和 “ 展望 ” 材料综合地抽象为某些 “ 状态 ” 。 任何时候,栈顶的状态都代表了整个历史和已推测出的展望。 LR 分析器的每一步工作都是由 栈顶状态 和 现行输入符号 所 唯一 确定; P100 LR 分析器模型 LR 分析器的工作过程 P100~101 (三元式)
E N D
LR分析法 含义:L—自左向右处理输入串;R—最右推导的逆过程; • LR分析法的基本思想:规范归约过程中,记住“历史”,对未来 “展望”,结合“现实” • LR分析器—一个带栈的DFA。即:将“历史”和 “展望”材料综合地抽象为某些“状态”。任何时候,栈顶的状态都代表了整个历史和已推测出的展望。 • LR分析器的每一步工作都是由栈顶状态和现行输入符号所唯一确定; • P100 LR分析器模型 • LR分析器的工作过程 P100~101(三元式) • LR分析优点:大多数上下文无关文法描述的程序语言都可用LR分析器识别,且比算符优先分析更广泛,效率也可以。缺点:手工工作量大,要借助自动产生分析程序的工具。
LR分析法分类 根据构造分析表的具体方法的不同: • LR(1)分析表:自左向右处理输入;R表示生成了最右推导;1表示先行1个符号。 • LR(0)分析表:先行符号出现在分析栈顶之后再检查它,不算作先行。 • SLR(1)分析表:对LR(1)的改进。 • LALR(1)分析表:比SLR(1)强,比LR(1)简单。
E + E T T F T F * F i3 i1 i2 例子:利用P101的LR分析表分析输入串i 1* i 2+i3
LR文法 定义:对于一个文法,如果能构造一张分析表,使得它的每个入口均是唯一确定的,就称该文法为LR文法。 特点:对于一个LR文法,当分析器对输入串进行自左至右扫描时,一旦句柄呈现于栈顶,就能及时对其进行规约。 LR(k)文法定义:对于一个LR文法,如果能用一个每步顶多向前检查k个输入符号的LR 分析器进行分析,就称该文法为LR(k)文法。 多数程序设计语言,k=0或1就足够了。
活前缀 字的前缀:该字的任意首部。 活前缀:规范句型的一个前缀,它不含句柄之后的任意符号。(在活前缀右边添加一些终结符后就成为一个规范句型了。) 在LR分析工作过程中的任意时候,栈里的文法符号(自栈底而上)X1X2…Xm应该构成活前缀,把输入串的剩余部分配上之后构成规范句型。 只要输入串的已扫描部分保持可归约成一个活前缀,那就意味着所扫描的部分没有错。 只要知道文法,就能构造出可以识别该文法所有活前缀的NFA。
LR(0)项目 LR(0)项目——文法G的每一个产生式的右部添加一个圆点称为G的一个LR(0)项目。 一个项目指明了在分析过程的某个时刻我们看到的产生式的多大一部分。 ⑴ S’→.E ⑵ S’→E . ⑶ E →. aA⑷ E → a.A ⑸ E → aA . ⑹ A → . cA ⑺ A → c.A⑻ A → cA . ⑼ A →. d ⑽ A → d. ⑾ E → .bB ⑿ E → b. B ⒀ E → b B. 14)B →. cB 15)B → c.B 16)B → cB. 17)B→. d 18)B→ d. 例如:文法5.7的所有LR(0)项目为: 文法:S’→E E → aA |bB A → cA |d B → cB |d
LR(0)项目的分类 1、归约项目: A → . 例如:5、8、10、18等 2、接收项目: S’ → . 例如: 2 3、移进项目: A → . a 例如:3、11、14 、 6 4、待约项目: A → . B 例如:4、12、15 ⑴ S’→.E ⑵ S’→E . ⑶ E →. aA⑷ E → a. A ⑸ E → aA . ⑹ A → . cA ⑺ A → c.A⑻ A → cA . ⑼ A →. d ⑽ A → d. ⑾ E → .bB ⑿ E → b. B ⒀ E → b B. 14)B →. cB 15)B → c.B 16)B → cB. 17)B→. d 18)B→ d.
对于一个文法,我们可以把其所有项目表示的状态构造为一个NFA,该NFA用来识别该文法所有的活前缀。对于一个文法,我们可以把其所有项目表示的状态构造为一个NFA,该NFA用来识别该文法所有的活前缀。 用词法分析中采用的子集法可以将NFA确定化DFA,该DFA的每个状态是一个项目集合,这些集合的全体就构成了该文法的LR(0)项目集规范族。
由具体的算法 得到最终的 某种LR分析表 拓广文法 LR(0) 项目集 规范族 DFA LR(0)项目 构造GO(I,X)= CLOSURE(J) LR分析表的构造 文法 NFA I={S’→.E }
(1)拓广 1、拓广:为了使“接受”状态易于识别,总把文法G进行拓广。目的是不让文法的开始符号出现在产生式的右边。 拓广的方法:引入文法中没有的非终结符S’,加入 S’→S
Xi i j i j i i X → A 从 画弧到所有A →状态 X→ X1X2 …Xi-1 Xi …Xn X→ X1X2 …Xi-1 Xi …Xn (2)根据LR(0)项目画NFA 规定“⑴ S’→.E”为唯一初态 ⑴ S’→.E ⑵ S’→E . ⑶ E →. aA⑷ E → a.A ⑸ E → aA . ⑹ A → . cA ⑺ A → c.A⑻ A → cA . ⑼ A →. d ⑽ A → d. ⑾ E → .bB ⑿ E → b.B ⒀ E → b B. 14)B →. cB 15)B → c.B 16)B → cB. 17)B→. d 18)B→ d . 最终得到文法5.6的NFA图 P106
6 9 a A 3 4 E 5 13 2 b B 11 12 17 14 ⑴ S’→.E ⑵ S’→E . ⑶ E →. aA⑷ E → a.A ⑸ E → aA . ⑹ A → . cA ⑺ A → c.A⑻ A → cA . ⑼ A →. d ⑽ A → d. ⑾ E → .bB ⑿ E → b. B ⒀ E → b B. 14)B →. cB 15)B → c.B 16)B → cB. 17)B→. d 18)B→ d. 1
DFA (3) NFA 由子集法得到该NFA所对应的DFA 结果为P106图5.7
c 8: 4: d 10: d c 2: A 6: a 0: E 1: B b 7: 3: d c d 11: 5: B 9: c 能识别文法5.7前缀的DFA P106图5.7 A (0) S’→E (1) E → aA (2) E → bB (3) A → cA (4) A → d (5) B → cB (6) B → d 项目集规范族C={I0,I1,I2 …I10,I11}
(4)构造LR(0)分析表 构造LR(0)分析表的算法P109 项目集规范族C={I0,I1,I2 … ,In} (1)Sj (4)j (2) rj (5)报错 (3)acc
c 8: 4: d 10: d c 2: A 6: a 0: E 1: B b 7: 3: d c d 11: 5: B 9: c A (0) S’→ E (1) E → aA(2) E → Bb (3) A → cA (4) A → d (5)B → cB (6) B→ d
例子:利用P109的LR(0)分析表 分析输入串bccd
由具体的算法 得到最终的 某种LR分析表 拓广文法 LR(0) 项目集 规范族 DFA LR(0)项目 构造GO(I,X)= CLOSURE(J) LR分析表的构造 文法 NFA I={S’→.E }
LR(0)项目集规范族的构造 LR(0)项目集规范族的构造方法(类比P50) 对文法G的每一个项目集I构造其CLOSURE(I) (1)I的任何项目都属于CLOSURE(I) (2)若A → . B属于CLOSURE(I),那么,对于任何关于B的产生式B →,项目B →.也属于CLOSURE(I)。 (3)反复执行上述2步直到CLOSURE(I)不再增加。
文法符号 状态集 例子:I={S’→.E} 对文法G的每一个项目集I构造其CLOSURE(I) (1)I的任何项目都属于CLOSURE(I) (2)若A → . B属于CLOSURE(I),那么,对于任何关于B的产生式B →,项目B →.也属于CLOSURE(I)。 CLOSURE(I)={S’→.E,E →. aA E →. bB}=I0 • 以I0为开始,逐步构造GO(I,X)= CLOSURE(J) J={任何形如A → X . 的项目| A → .X属于I} 先考察I0中圆点之后跟着a的项目,然后将圆点后移一个文法符号 ={E →a.A,A→.cA,A→.d} 例:GO(I0,a)= {E →a.A} CLOSURE( )
c 8: A 4: d 10: GO(I0 ,E)=I1 GO(I0 ,a)=I2 GO(I0 ,b)=I3 d c 2: A 6: a 0: E 1: B b 7: 3: d c d 11: 5: B 9: c I={ S’→.E } CLOSURE(I)=I0 …… GO(I2 ,c)=I4 GO(I2 ,A)=I6 GO(I2 ,d)=I10 GO(I3 ,c)=I5 GO(I3 ,B)=I7 GO(I3 ,d)=I9 …… 由GO(I,X)得到文法的 LR(0)项目集规范族 C={I0,I1,I2,I3 … ,I11}
4: 10: d c 2: A 6: a 0: E 1: B b 7: 3: c 5: c 8: d d d 11: B 9: c
构造LR(0)分析表的算法:P109 前提:项目集规范族C={I0,I1,,I2,,I3 … ,In},含S’→S的项目集为初态 (1)若项目A → . a属于Ik且GO( Ik ,a)= Ij a为终结符,则置ACTION[k,a]=sj ,表示把状态(j,a)移进栈; (2)若项目A → .属于Ik则对任何终结符a(包括#)置ACTION[k,a]=rj,表示用第j个产生式A → 进行归约; (3)若项目S’ →S .则置ACTION[k,#]= acc,表示“接受”; (4)若GO( Ik ,A)= Ij ,A为非终结符,则置GOTO[k,A]=j; (5)分析表中凡不能用1至4填入信息的空白个均置上“报错”(通常我们就空在那里)
作业:P134 5 文法: S → AS| b A → SA|a 1、拓广: (0) S’→ S(1) S → AS (2) S → b (3) A → SA(4) A → a 2、LR(0)项目: 1)S’→ .S2)S’→ S.3)S → . AS 4)S → A . S 5)S → AS . 6)S→ .b 7)S → b . 8)A → . SA 9)A → S . A 10)A → SA. 11) A →. a 12) A → a .
LR(0) 项目集 规范族 LR(0)项目 NFA DFA 1)S’→ .S2)S’→ S.3)S → . AS 4)S → A . S 5)S → AS . 6)S→ .b 7)S → b . 8)A → . SA 9)A → S . A 10)A → SA. 11) A →. a 12) A → a .
重命名后: I0 = {1,3,6,8,11} I1 = {2,3,6,8,9,11} I2 = {3,4,6,8,11} I3 = {3, 6,8,9,11} I4 = {3,4,6,8,10,11} I5 = {3,5,6,8,9,11} I6 = {12} I7 = {7}
3、用CLOSURE(I)求出LR(0)项目集规范族C CLOSURE({S’→.S})={S’→ .S,S →. AS,S→.b, A→. SA, A→. a} =I0 GO(I0 ,S)= CLOSURE({S’→S. ,A→ S. A}) = {S’→S. , A→ S. A, A→. SA, A→. a,S →. AS,S→.b} = I1 GO(I0 ,A)= CLOSURE({S →A. S}) = {S →A. S,S →. AS,S→.b, A→. SA, A→. a}= I2 GO(I0 ,a)= CLOSURE({A→ a . })= {A → a . } = I3(归约项) GO(I0 ,b)= CLOSURE({S→b.})= {S → b.}= I4(归约项) GO(I1 ,S)= CLOSURE({A→S. A}) = {A→S. A ,A→.SA, A→. a, S→.AS,S→.b}= I5 GO(I1 , A)= CLOSURE({A→ SA . , S →A.S}) = {A→ SA . , S →A .S, A→. SA, S →. AS,S→.b, A→. a}= I6 GO(I1 ,a)= CLOSURE( {A→ a . } )= I3 (归约项) GO(I1 ,b)= CLOSURE( {S→b.} )= I4(归约项) GO(I2 ,S)= CLOSURE({S → AS., A→ S. A}) = {S → AS., A→ S.A, A→. SA, A→. a, S →. AS,S→.b}= I7 GO(I2 , A)= CLOSURE({S →A .S} )=I2 GO(I2 , a)= I3 GO(I2 ,b)= I4 GO(I5 , A)= CLOSURE({S →A .S, A→ SA .}) = I7 GO(I5 , S)= CLOSURE({A→ S . A })= I5 GO(I5 ,a)= I3 GO(I5 ,b)= I4
GO(I6 ,S)= CLOSURE({S →AS. , A→S. A})= I7 GO(I6 ,A)= CLOSURE({S →A .S})= I2 GO(I6 ,a)= I3 GO(I6 ,b)= I4 GO(I7 ,A)= CLOSURE({S →A .S, A→ SA .})= I6 GO(I7 ,S)= CLOSURE({A→S. A}) = I5 GO(I7 ,a)= I3 GO(I7 ,b)= I4 LR(0)项目集规范族C: C={I0, I1, I2, I3, I4, I5 ,I6 ,I7 },其中 I0 ={S’→ .S,S →. AS,S→.b, A→. SA, A→. a} I1 = {S’→S. , A→ S. A, A→. SA, A→. a,S →. AS,S→.b} I2 = {S →A . S,S →. AS,S→.b, A→. SA, A→. a} I3 = {A → a . } (归约项) I4 = {S → b . } (归约项) I5 = {A→ S.A , A→. SA, A→.a , S →. AS,S→.b ,} I6 = {A→ SA . , S →A .S, A→. SA, S →. AS,S→.b} I7 = {S → AS., A→ S.A, A→. SA, A→. a, S →. AS,S→.b} 所以,不存在冲突,是LR(0)文法。
LR(0)文法定义 LR(0)文法定义:如果DFA中的每个状态不存在(1)即含移进项目又含归约项目; (2)或者含有多个归约项目, 就称该文法为LR(0)文法。 (LR(0)项目规范族中的每个项目集不包含任何冲突项目。) 对于LR(0)文法,可直接根据其项目集规范族和活前缀识别自动机的状态转换函数构造出LR(0)分析表。 例子:见P107~109
GO(I,X) CLOSURE(J) LR(0) 项目集 规范族 LR(0) 分析表 拓广 文法 LR(0) 项目 I={S’→.E} • 由I={S’ →.E}开始求得CLOSURE(I)=I0 • 对文法G的每一个项目集I构造其CLOSURE(I) • (1)I的任何项目都属于CLOSURE(I) • (2)若A → .B属于CLOSURE(I),则对任何关于B的项目B →.也属于CLOSURE(I)。 • 由GO(I,X)得到文法的LR(0)项目集规范族 • C={I0 , I1,I2,I3 … ,I11} • 构造LR(0)分析表的算法P109项目集规范族C={I1,I2,I3 … ,In} • (1)Sj (2) rj (3)acc(4)j(5)报错 文法
练习:求拓广文法G的LR(0)项目集规范族C (P111) (0) S’→ E(1) E → E+T (2) E →T (3) T → T * F (4) T → F (5) F → (E) (6) F → i 开始:I={ S’→.E } CLOSURE(I)={S’→.E,E→.E+T,E →.T,T →.T * F ,F→.(E) ,F →. i, T → . F}=I0 GO(I0 ,E)=CLOSURE({S’→E. ,E→E . +T}) = {S’→E. ,E→E . +T} = I1 GO(I0 ,T)=CLOSURE({E →T .,T →T . * F }) = {E →T .,T →T . * F } = I2 GO(I0 ,F)=CLOSURE({T → F . }) = {T → F . }= I3 GO(I0 ,( )=CLOSURE({F→ (. E) }) ={F→ (. E) ,E→.E+T,E →.T,T →.T * F , T →.F,F→.(E) ,F →. i}= I4 GO(I0 ,i)=CLOSURE({F → i .}) = {F → i .}= I5
存在的问题 归约项 移进项 I1 = {S’→E. , E→E . +T} I2 = {E →T . , T →T . * F } I9 = {E→E+T . , T →T .* F} “移进--归约”冲突
SLR(1)解决办法 移进项 归约项 归约项 • 冲突 :I={X → .b,A → . ,B → .} 例如:I1 = {S’→E . , E→E . +T},I2 = {E →T . , T →T . * F } • 推广到一般情况:一个LR(0)项目集I: {移进项: A1→ .a11,A2→ .a22,… ,Am→ .amm, 归约项: B1 → . ,B2 → . ,… ,Bn → . } • 解决——SLR(1)解决办法: (1){a1, a2 … , am} (2) FOLLOW(Bi)是否两两不相交 检查现行输入符号a与上述n+1个集合: 1)若a=ai,则移进;2)若a 属于FOLLOW(Bi),则用Bi→归约;
(P111) 例子5.11: (0) S’→ E(1) E → E+T (2) E →T (3) T → T * F (4) T → F (5) F → (E) (6) F → i 因为:对于I2= {E →T .,T →T . * F } E →T .是归约项,且FOLLOW(E)={#,),+} 所以:当状态I2面临输入符号为#,)或+时,应用产生式E →T归约,当面临输入符号为*时,则移进。
冲突可用 SLR(1) 方法解决 LR(0) 项目集 规范族 SLR(1) 分析表 是否存在 冲突 GO(I,X) CLOSURE(J) 拓广 文法 构造SLR分析表 • 对于任何一个文法G,用如下办法构造其SLR(1)分析表 文法 (1)sj ,表示把状态(j,a)移进栈; (2)若项目A→ . 属于Ik,对任何终结符a FOLLOW(A),置ACTION[k,a]=rj,表示用第j个产生式A→ 归约; (注意:在LR(0)分析表中是对任何终结符a(包括#)置Ik行均为rj,) (3)若项目S’ →S .则置ACTION[k,#]= acc,表示“接受”; (4)若GO( Ik ,A)= Ij ,A为非终结符,则置GOTO[k,A]=j; (5) “报错”
I1 = {S’→E. , E→E . +T} I2 = {E →T . , T →T . * F } I9 = {E→E+T . , T →T .* F} 例子:构造文法5.8的 SLR(1)分析表P101图5.5 P112 图5.8 识别活前缀的自动机 FOLLOW(T) FOLLOW(F) FOLLOW(E)
文法 冲突是否能 用SLR(1) 方法解决 LR(0) 项目集 规范族 是否存在 冲突 GO(I,X) CLOSURE(J) 拓广 文法 SLR(1)文法 • SLR(1)文法——具有SLR(1)分析表的文法;数字1的含义是,在分析过程中,顶多只要向前看一个符号。 • 使用SLR(1)分析表的分析器叫SLR分析器。 • 每个SLR(1)文法都是无二义的,但无二义的文法不一定就是SLR(1)文法; • 如何判断一个文法是否为SLR(1)文法?
文法 冲突是否能 用SLR(1) 方法解决 LR(0) 项目集 规范族 是否存在 冲突 GO(I,X) CLOSURE(J) 拓广 文法 例子:判断文法5.9是否为SLR(1)文法(P113图5.5) 1、拓广: (0) S’→ S(1) S → L=R (2) S → R (3) L → *R (4) L → i (5) R →L 2、 LR(0)项目集规范族:图5.9 3、判断是否存在冲突: 因为:对于I2= {S → L . =R , R →L.} S → L . =R 是移进项,R →L .是归约项,而FOLLOW(R)={#,=} 所以:当状态I2面临输入符号为=时,无法确定是用产生式R →L.归约,还是该移进=,因此该文法不是SLR(1)文法。
例子:判断文法G是否为SLR(1)文法? 并说明理由。 文法G(S):S → BB B → aB|b 1、拓广: (0) S’→ S(1) S → BB (2) B → aB (3) B → b 2、LR(0)项目 1)S’→ .S2)S’→ S.3)S → .BB 4)S → B.B 5)S → BB . 6)B → .aB 7)B → a.B 8)B → aB. 9)B → .b 10)B → b . 3、用CLOSURE(I)求出LR(0)项目集规范族C CLOSURE({S’→.S})={S’→ .S,S→ .BB,B→ .aB,B→.b}=I0 GO(I0 ,S)= CLOSURE({S’→S.})= {S’→ S.}= I1(归约项) GO(I0 ,B)= CLOSURE({S→B.B})= {S→B.B,B→.aB,B→.b}= I2 GO(I0 ,a)= CLOSURE({B→a.B})= {B→a.B ,B→.aB,B→.b}= I3 GO(I0 ,b)= CLOSURE({B→b.})= {B→b.}= I4 (归约项) GO(I2 ,B)= CLOSURE({S→BB.})= {S→BB.}= I5 (归约项) GO(I2 ,a)= CLOSURE({B→a.B})= {B→a.B,B→.aB, B→.b}= I3 GO(I2 ,b)= CLOSURE( {B→b.})= {B→b.}= I4 (归约项) GO(I3 ,B)= CLOSURE({B→aB.})= I6;GO(I3 ,a)= I3;GO(I3 ,b)= I4
B B I1: I5: S I2: I0: b a b I4: a b I3: a B I6: 4、判断是否存在冲突: LR(0)项目集规范族C={I0, I1, I2, I3, I4, I5 ,I6 } I0 ={S’→ .S,S→ .BB,B →.aB,B →.b} I1 = {S’→ S.} (归约项) I2 = {S →B.B,B →.aB,B →.b} I3 = {B →a.B ,B →.aB,B →.b} I4 = {B →b.} (归约项) I5= {S →BB.} (归约项) I6 ={B →aB.})(归约项) 结论:不存在冲突,所以该文法 是LR(0)文法,不是SLR(1)文法。
作业:P134 5.(1)(2)(3) 7、