编译原理--语法分析:基础,LL

上下文无关文法的正式定义

一个上下文无关文法由终结符号,非终结符号,一个开始符号,一组产生式组成.
1.终结符号是组成串的基本符号.
2.非终结符号是表示串的集合的语法变量.
3.一个文法中,某个非终结符号被指定为开始符号.
这个符号表示的串集合就是这个文法生成的语言.
4.一个文法的产生式描述了将终结符号和非终结符号组合成串的方法.

符号表示约定

1.终结符号
a.字母表前面的小写字母
b.运算符号
c.标点符号
d.数字
e.黑体字符串
2.非终结符号
a.字母表中排在前面的大写字母
b.字母S
c.小写,斜体名字
3.其他
a.字母表后面的大写字母表示文法符号,即可能是终结符号,也可能是非终结符号
b.字母表后的小写字母,表示可能为空的终结符号串
c.小写希腊字母,表示可能为空的文法符号串.

推导

如果S=>^{*}α,其中S是文法G的开始符号,说α是G的一个句型.
一个句型可能既含终结符号,又含非终结符号,也可能是空串.
G的一个句子是不含非终结符号的句型.
可由文法生成的语言称为上下文无关语言.
1.最左推导
选择每个句型的最左非终结符号,进行推导.
2.最右推导
选择每个句型的最右非终结符号,进行推导

语法分析树和推导

基础:α_{1} = A的语法分析树是标号为A的单个结点
归纳步骤:设已经构造了一棵结果为α_{i-1}=X_{1}...X_{k}的语法分析树.
每个文法符号X_{i}可以是非终结符号,也可是终结符号.
设α_{i}是将α_{i-1}中的某个非终结符号X_{j}替换为β=Y_{1}...Y_{m}得到的句型.
为模拟此步骤,
在当前语法分析树中找出左起第j个非ε叶子结点.
这个结点标号为X_{j}.
向这个叶子结点添加m个子结点,从左边开始分别将这些子结点标号为
Y_{1},...,Y_{m}.
作为特殊情况,如m=0,则β=ε,给第j个叶子结点加上一个标号为ε的子结点.

二义性

如一个文法可为某个句子生成多棵语法分析树,它就是二义性的.

左递归的消除

立即左递归消除
设A->Aα_{1} | ... | Aα_{m} | β_{1} | ... | β_{n}
其中β_{i}都不以A开头.
替换为
A->β_{1}A' | ... | β_{n}A'
A'->α_{1}A' | ... | α_{m}A' | ε

消除左递归
输入:没有环或ε产生式的文法G
输出:等价的无左递归文法
算法:
按某顺序将非终结符号排序为A_{
    
    1}, ..., A_{
    
    n}
for(1到n的每个i)
{
    
    
	for(1到i-1的每个j)
	{
    
    
		将每个形如A_{
    
    i}->A_{
    
    j}γ的产生式替换为产生式组
		A_{
    
    i}->δ_{
    
    1}γ|...|δ_{
    
    k}γ,
		其中A_{
    
    j}->δ_{
    
    1}|...|δ_{
    
    k}是所有的A_{
    
    j}产生式
	}
	消除A_{
    
    i}产生式之间的立即左递归
}

递归下降的语法分析

void A()
{
    
    
	选择一个A产生式,A->X_{
    
    1}...X_{
    
    k};
	for(i = 1 to k)
	{
    
    
		if(X_{
    
    i}是一个非终结符号)
			X_{
    
    i}();
		else if(X_{
    
    i}等于当前输入符号a)
			读入下一输入符号;
		else /*发生一个错误*/;
	}
}
可以为上述过程加入回溯.这样允许按某个产生式展开失败时,可以继续尝试下一个

FIRST和FOLLOW

计算各个文法符号X的FIRST(X)时,不断应用如下规则,
直到没新的终结符号或ε可被加入到任何FIRST集合为止.
1.如X是一个终结符号,则FIRST(X)=X
2.如X->ε是一个产生式,将ε加入FIRST(X)
3.如有产生式X->Y_{1}...Y_{m},FIRST(Y_{1})加入X.
ε在FIRST(Y_{1})中时,继续将FIRST(Y_{2})加入X.以此类推.

计算所有非终结符号A的FOLLOW(A)集合时,不断应用如下规则,
直到再没新的终结符号可被加入任意FOLLOW集合为止.
1.$加入FOLLOW(S)
2.如有产生式A->αBβ,
则FIRST(β)中除ε外的所有符号都在FOLLOW(B).
FIRST(β)含ε,则FOLLOW(A)加入FOLLOW(B)
3.如有产生式A->αB,
则FOLLOW(A)加入FOLLOW(B).

LL(1)文法

不断对非终结符号依据下一终结符号进行无二义性展开的过程.

构造一个预测分析表
输入:文法G
输出:预测分析表M
方法:对文法G的每个产生式A->α,进行如下处理
1.对FIRST(α)中的每个终结符号a,将A->α加入M[A, a]
2.如ε在FIRST(α)中,则对FOLLOW(A)中的每个终结符号b,
将A->α加入M[A, b].
如ε在FIRST(α)中,且$在FOLLOW(A)中,
也将A->α加入M[A, $].

完成上述后,若M[A, a]没产生式,将其设为error.

非递归的预测分析

表驱动的预测语法分析
输入:一个串ω,文法G的预测分析表M
输出:如ω在L(G)中,输出ω的一个最左推导;否则,给出一个错误提示.
方法:最初,语法分析器格局如下:
输入缓冲区是ω$,G的开始符号S位于栈顶,下面是$.
设置ip使它指向ω的第一个符号,其中ip是输入指针
令X=栈顶符号
while(X != $)
{
    
    
	if(X等于ip所指向的符号a)
		执行栈的弹出操作,将ip向前移动一个位置
	else if(X是一个终结符号)
		error()
	else if(M[X, a]是一个报错条目)
		error()
	else if(M[X, a]=X->Y_{
    
    1}...Y_{
    
    k})
	{
    
    
		输出产生式X->Y_{
    
    1}...Y_{
    
    k}
		弹出栈顶符号
		将Y_{
    
    k}...Y_{
    
    1}压入栈中,Y_{
    
    1}位于栈顶
	}
	令X=栈顶符号
}

猜你喜欢

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