LL(1)语法分析器的实现
LL(1)分析器是由LL(1)分析表、语法符号栈和总控程序组成的。实现LL(1)分析器的首要步骤便是构造语法分析表,而语法分析表的构造要借助于头符号集First(α)和后继符号集Follow(A),所以问题的主要矛盾便成为如何实现First集和Follow集的求取。
1. First集的求取
First(x)有两种情况,第一种情况是x属于终极符和非终极符的并集(即x是单个符号),另外一种情况是x属于终极符和非终极符的闭包(即x=x1x2x3…).
①x属于单个字符:
.若x∈Vt,则First(x) = { x };
.若 x 属于Vn且有产生式x -> a…(a∈Vt),则将a加入First(x);
.若x -> 空符,则把空符也加进去;
.若x -> Y…,Y∈(Vn),则把 First(Y) - 空符 加入First(x)中;
.特别的,若x -> Y1Y2…Yk… ,判断First(Yi)是否能加入First(x)是看所有的 j < i First(Yj)是否含有空符,若所有的First(Yj)都含有空符才能将First(Yi) - 空符加入First(x),最后如果所有的First(Yi)含有空符才把空符加入到First(x)中去。
.
[注解]First(x) = { x 能推导出的所有终极符的集合(包含空符)}
先把第一种情况的First(x)代码实现出来:思路跟定义一致,需要注意的是处理
x->Y1Y2Y3…Yk这种情况,解决方法是First(Y1)-空符直接加进去即可,对于以后的每一个First(Yi)如果flag == 1,说明前面的所有First(Yj)都是含有空符的,所以是可以加进去的,然后判断此First(Yi)是否含有空符,从而决定是否还要继续下去。
void Fset::Full_First(char ch){
//First集
int tag = 0; //记录能够推导出空符的Yi的个数
int flag = 0; //判断是否能够推导出空符
if(IsVn(ch)){
//是非终极符的情况
for(int i = 0;i < length;i++)//i代表的是产生式的个数
{
if(gram[i].name==ch)//所求first(x)的x为 产生式的头部
{
for(int j=0;j<gram[i].tuidao.size();j++)
{
//对此产生式的右部进行操作
if(!IsVn(gram[i].tuidao[j]) && j == 0)//如果是终结符,则直接压入 x->a... x属于Vn
{
first[Get_Nindex(ch)].insert(gram[i].tuidao[j]);//向first(x)中加入此非终极符
break; //保证只加一个
}
else if(IsVn(gram[i].tuidao[j]))
{
//如果是非终结符,则压入该非终结符的除了空集以外的元素
Full_First(gram[i].tuidao[j]); //先求出此非终极符的first集
set<char>::iterator it; //遍历此非终极符的first集
for(it = first[Get_Nindex(gram[i].tuidao[j])].begin();it!=first[Get_Nindex(gram[i].tuidao[j])].end();it++)
{
if(*it=='$')
flag = 1; //判断是否含有空符 即能否推导出空符
else
first[Get_Nindex(ch)].insert(*it);
}
if(flag == 0){
break;
} //有不能推导出空符的直接结束即可 前面的保证一定有空符的
else
{
tag += flag;
flag = 0;
}
}
}
if(tag == gram[i].tuidao.size())
{
//最后判断空集是否应该被压入
first[Get_Nindex(ch)].insert('$');
}
}
}
}
else{
//x为终极符,直接令first(x)={ch}
first[vnl + Get_Tindex(ch)].insert(ch);
}
}
②x∈x1x2…xk:
.先将First(x1) - 空符加进First(x);
.此后对于每一个first(xi)如果所有的First(j) j<i都含有空符才能将First(xi) - 空符加入First(x);
.如果所有的First(xi)都含有空符,才可以将空符加入到First(x)中
.跟上面的最后一种情况差不多,直接来看代码
void Fset::Max_First(string ch, int pos){
//first(x) x为多个符号的乘积 pos是用来支出存放的位置
int flag = 0, tag = 0;
//对待终极符和非终极符需要查找不同的位置
if(IsVn(ch[0]))
{
//先求第一个字符的first集
set<char>::itera