1.1 R(1)项目集族
1.1.1 LR(1)的定义
该定义来自《编译原理及实践》(Kenneth C Louden)
定义1:(LR(1)第一部分定义)
假设有LR(1)项目[A - > α•Xγ, a],其中X是任意符号(终结符和非终结符),那么X有一个到项目[A - > αX•γ, a]的转换。
这个定义实际与WACC对应的的部分是4.2.1节21行CSymbol* CItem::Go(CItem & goItem,CLanguage &L)函数。如果Item为[A - > α•Xγ, a],那么go函数返回X(类型为CSymbol*),goItem为[A - > αX•γ, a]。在后面会有单独一节将该函数。请注意,在LR(1)中,如果两个项目先行符号不同,即使规则和圆点位置相同,这两个项目会分到不同的状态中,而LALR(1)就不这样。
定义2:(LR(1)第二部分定义,也叫闭包定义)
假设有LR(1)项目[A - > α•Bγ,a],其中B是一个非终结符,那么对于每个产生式B –>β和在First(γa)中的每个记号b都有项目[B->•β,b]的ε转换。
这个定义就是计算LR(1)的epsilon闭包,它与4.2.1节的epsilon闭包计算相似。注意它与LR(0)不同的地方,就是闭包的先行符号的计算,First(γa)所得到的b就是闭包项的先行符号。对应WACC的代码ComputerEClosure 函数和ComputerEPrecs 函数。LALR(1)生成的epsilon闭包的方式与LR(1)是一样的,4.2.2节给出的例子Test4同样也可以适用这个定义。
同样适用前面那个例子:
A1->A
A->( A )
A->a
构造LR(1)分析,可以得到如下状态图:
可以看到,与LR(0)文法生成的图表 48相比,图表 410状态有9个,规模比LR(0)大。
1.1.2 LR(1)分析方法
根据DFA可以构造分析算法。一般LR(1)分析算法如下:
(1) 若项目[A→α•aβ, b]属于Ik且GO(Ik,a)= Ij,a为终结符,则置ACTION[k,a]为“把状态j和符号a移进栈”,简记为“sj”。
(2) 若项目[A→α•, a]属于Ik,则置ACTION[k,a]为“用产生式A→α归约”,简记为“rj”;其中假定A→α为文法G’的第j个产生式。
(3) 若项目[S’→S•, $]属于Ik,则置ACTION[k, $]为“接受”,简记为“acc”。
(4) 若GO(Ik, A)= Ij,则置GOTO[k,A]=j。
(5) 分析表中凡不能用规则1到4填入信息的空白栏均填上“出错标志”。
根据该分析算法,得出图表 410所对应的分析表。
状态 |
输 入 |
GoTo |
|||
( |
a |
) |
$ |
A |
|
0 |
S2 |
S3 |
1 |
||
1 |
接受 |
||||
2 |
S5 |
S6 |
4 |
||
3 |
R2 |
||||
4 |
S7 |
||||
5 |
S5 |
S6 |
8 |
||
6 |
R2 |
||||
7 |
R1 |
||||
8 |
S9 |
||||
9 |
R1 |
图表 411