编译原理--语法分析:LR(1)

规范LR(1)项

对LR(0)中本来需要归约的行为,再往前看一步,考察归约后,
下一步是否会报错.
入股归约后下一步不会报错,按LR(0)进行归约.
否则,不进行归约.

正式地将,
可行前缀&有效项是LR(0)的概念.

说LR(1) 项 [A->α.β, a]对于一个 可行前缀γ 有效的条件是
存在一个推导 S=>^{*}_{rm} δAω =>_{rm} δαβω,其中
1.γ = δα,且
2.要么a是ω的第一个符号,要么ω为ε且a等于$

如果在遇到a,对A按αβ进行归约,
归约后Aa必须是合法的.

LR(1)对可行前缀解释和LR(0)一致,
对可行前缀的有效项,进一步提供了一个终结符号.
因为LR(1)会对可行前缀,继续接受0个或多个文法符号可以按有效项进行归约的行为,
多看一步.
即看归约后的句型,结合下一待处理终结符号是否会报错.
不同终结符号下结果可能是不同的.
所以,有效项需要结合每个可能出现的终结符号,给出关于此终结符号下的结果.

构造LR(1)项集

基本和LR(0)项集族相同.
需修改CLOSURE和GOTO.

考虑对某些 可行前缀γ 有效的项集合中的一个形如[A->α.Bβ, a]的项,
则必然存在一个最右推导
S=>^{*}_{rm} δAax =>_{rm} δαBβax,
其中γ = δα.
假设βax推导出终结符号串by,
则对某个形如B->η的产生式,
有推导S=>^{*}_{rm} γBby =>_{rm} γηby.
因此,[B->.η, b]是 γ 的有效项.

LR(0)可行前缀
可行前缀的有效项,
意味着,继续接收有效项.后的0个或多个文法符号后,
应该按有效项产生式进行一次归约.

LR(1)项集族的构造方法

输入:一个增广文法G'
输出:LR(1)项集族,其中的每个项集对文法G'的一个或多个可行前缀有效
方法:
过程CLOSURE和GOTO,及用于构造项集的主例程items
SetOfItems CLOSURE(I)
{
    
    
	repeat
		for(I中的每个项[A->α., a])
			for(G'中的每个产生式B->γ)
				for(FIRST(βa)中的每个终结符号b)[B->.γ, b]加入到集合I中
	until 不能向I中加入更多的项
	return I
}

SetOfItems GOTO(I, X)
{
    
    
	将J初始化为空集
	for(I中的每个项[A->α., a])
		将项[A->α., a]加入到集合J中
	return CLOSURE(J)
}

void items(G')
{
    
    
	将C初始化为{
    
    CLOSURE}({
    
    [S'->.S, $]})
	repeat
		for(C中的每个项集I)
			for(每个文法符号X)
				if(GOTO(I, X)非空且不在C中)GOTO(I, X)加入C中
	until 不再有新的项集加入到C中
}

规范LR(1)语法分析表

规范LR语法分析表的构造
输入:一个增广文法
输出:G'的规范LR语法分析表的函数ACTION和GOTO
方法:
1.构造G'的LR(1)项集族C'={I_{0}, ..., I_{n}}
2.语法分析器的状态i根据I_{i}构造得到
状态i的语法分析动作按下面规则确定
a.如 [A->α.aβ, b] 在I_{i}中,
且GOTO(I_{i}, a) = I_{j}
则ACTION[i, a]为移入j.
b.如 [A->α., a] 在I_{i}中,
且A != S',
则ACTION[i, a]为 归约A->α
c.如 [A->α., a] 在I_{i}中,
且A == S',[a应该是$]
则ACTION[i, a]为 接收

如存在冲突,
说明对文法G,按LR(1)对其进行语法分析是不可行的.
3.状态i相对于各个非终结符号A的goto转换按以下规则得到
如GOTO(I_{i}, A) = I_{j},则GOTO[i, A] = j
4.没按2,3,得到的条目为报错
5.初始状态由含[S'->.S, $]的项集构造得到.

二义性文法

有些文法允许存在个别会导致二义性产生式,
可能理解上,实现上更友好.
此时,在语法分析实现时,可以对个别产生式特殊处理,
来消除二义性同时获得该文法理解上,实现上的优势.

猜你喜欢

转载自blog.csdn.net/x13262608581/article/details/123604541