右句型 γ \gamma γ的句柄是一个产生式的右部 β \beta β,并且该句柄 β \beta β通过产生式 A → β A\rightarrow\beta A→β归约后,得到的是最右推导中的前一个句型。
右句型:所有在最右推导中出现的句型都是右句型。
? S ⇒ r m S \Rightarrow _ { r m } S⇒rm aABe ⇒ r m \Rightarrow _ { r m } ⇒rm aAde ⇒ r m \Rightarrow _ { r m } ⇒rm aAbcde ⇒ r m \Rightarrow _ { r m } ⇒rm abbcde
文法为
S → S \rightarrow S→ aABe
A → A b c ∣ b { A \rightarrow A b c | b } A→Abc∣b
B → d B \rightarrow d B→d
abbcde中的第一个b通过 A → b A\rightarrow b A→b归约后得到aAbcde,是最右推导的前一个句型,所以第一个b是句柄。而第二个b通过 A → b A\rightarrow b A→b归约后得到aAAcde,不是最右推导的前一个句型,所以第二个b不是句柄。(栗子中加粗部分为句柄)
移进-归约冲突:既可以移进又可以归约时,无法决定。
归约-归约冲突:当不止一个产生式可以归约,无法决定对哪个产生式进行归约。
活前缀:右句型的前缀,该前缀不超过最右句型句柄的右端。
在移进-归约分析中,出现在栈中的串都是活前缀。
? S ⇒ ∗ r m γ A w ⇒ r m γ β w \mathcal { S } \Rightarrow * _ { r m } \gamma A w \Rightarrow _ { r m } \gamma \beta w S⇒∗rmγAw⇒rmγβw
γ β \gamma \beta γβ的任意前缀(包括 ε \varepsilon ε和 γ β \gamma \beta γβ本身)都是活前缀,这里的 β \beta β是句柄。
L表示从左到右扫描输入串,R表示最右推导。分为LR(0)/SLR(1)、LR(1)、LALR三种。
LR(0)闭包函数closure(I)
LR(0)状态转换函数goto(I, X)
I状态集中所有形如 [ A → α ⋅ X β ] [ A \rightarrow \alpha \cdot X \beta ] [A→α⋅Xβ]的产生式对应的产生式 [ A → α X ⋅ β ] [ A \rightarrow \alpha X \cdot \beta ] [A→αX⋅β]的LR(0)闭包。X为终结符或非终结符。
? S → S \rightarrow S→ aABe ; A → A b c ∣ b { A \rightarrow A b c | b } A→Abc∣b ; B → d B \rightarrow d B→d
对于 I 0 : S ′ → S I_0: S' \rightarrow S I0:S′→S; S → ⋅ a A B e S \rightarrow \cdot aABe S→⋅aABe
I 1 = g o t o ( I 0 , a ) : I_1=goto(I_0, a): I1=goto(I0,a): S → a ⋅ A B e S \rightarrow a \cdot ABe S→a⋅ABe; A → ⋅ A b c A \rightarrow \cdot Abc A→⋅Abc; A → ⋅ b A \rightarrow \cdot b A→⋅b
识别文法G活前缀的DFA通过下面的方式构造:
状态i从 I i I_i Ii构造,它的action函数如下确定:
如果出现动作冲突,那么该文法就不是SLR(1)的。
构造状态i的goto函数:
对所有的非终结符A,如果goto( I i I_i Ii,A)= I j I_j Ij, 那么goto[i, A]= j j j。
不能由上面两步定义的条目都为error。
每个SLR(1)文法都不是二义的,但是,有许多非二义的文法不是SLR(1),文法描述能力弱。SLR(1)是在构造完DFA的LR(0)项目集之后才应用预测符号的,即对需要归约的产生式,当其遇到产生式左部非终结符的FOLLOW集中的终结符时才进行归约,而在LR(0)的构造中没有考虑预测。
基本步骤同SLR一样,只在第二步和第三步时有所不同,只说不同的地方。
使用LR(1)文法,1表示项目 [ A → α ⋅ β , a ] [A \rightarrow \alpha \cdot \beta , a] [A→α⋅β,a]中搜索符的长度。
LR(1)闭包函数closure(I)
搜索符b的集合是FOLLOW(B)的一个子集。
LR(1)状态转换函数goto(I, X)
I状态集中所有形如 [ A → α ⋅ X β , b ] [ A \rightarrow \alpha \cdot X \beta,b ] [A→α⋅Xβ,b]的产生式对应的产生式 [ A → α X ⋅ β , b ] [ A \rightarrow \alpha X \cdot \beta,b ] [A→αX⋅β,b]的LR(1)闭包。X为终结符或非终结符。注意这里的搜索符集b是直接由前面对应的项目抄过来的。
识别文法G活前缀的DFA通过下面的方式构造:
基本同SLR,不同点在于:在action函数中,如果有归约,SLR是根据左部非终结符的FOLLOW集决定进行归约;LR(1)是根据搜索符决定进行归约。
LR(1)文法描述能力较强,但是由于状态数目多,分析表较大。
LALR是在SLR(1)和LR(1)之间进行了文法描述能力与分析表紧凑程度之间做的折中。
合并识别LR(1)文法的活前缀的DFA中的同心项目集。
略去搜索符后相同的项目集。
? B → ⋅ b B B \rightarrow \cdot b B B→⋅bB 和 B → ⋅ b B , b / a B \rightarrow \cdot b B ,b / a B→⋅bB,b/a
同心集的合并不会引起新的移进-归约冲突。
?如果同心集中有移进-归约冲突 [ A → α ⋅ , a / b ] \left[ A \rightarrow \alpha \cdot, a / b \right] [A→α⋅,a/b] [ B → β ⋅ a γ , c / d ] [ B \rightarrow \beta \cdot a \gamma , c / d ] [B→β⋅aγ,c/d],当面对输入符号a时不知道该移进还是归约。合并前的项目集应该有 [ A → α ⋅ , x ] \left[ A \rightarrow \alpha \cdot, x \right] [A→α⋅,x] [ B → β ⋅ a γ , y ] [ B \rightarrow \beta \cdot a \gamma , y ] [B→β⋅aγ,y],肯定有个x为a,所以一定存在移进-归约冲突,说明合并之前就存在移进-归约冲突了。
同心集的合并有可能产生新的归约-归约冲突。
?合并前项目集 [ A → c ⋅ , d ] [A \rightarrow c \cdot, d] [A→c⋅,d] [ B → c ⋅ , e ] [B \rightarrow c \cdot, e] [B→c⋅,e]和 [ A → c ⋅ , e ] [A \rightarrow c \cdot, e] [A→c⋅,e] [ B → c ⋅ , d ] [B \rightarrow c \cdot, d] [B→c⋅,d],合并后为
[ A → c ⋅ , e / d ] [A \rightarrow c \cdot, e/d] [A→c⋅,e/d] [ B → c ⋅ , d / e ] [B \rightarrow c \cdot, d/e] [B→c⋅,d/e],此时就产生了新的归约-归约冲突。