编译原理实验二:预测分析算法的设计与实现

实验二 预测分析算法的设计与实现

一、实验目的
通过预测分析算法的设计与实现,加深对自上而下语法分析方法的理解,尤其是对自上而下分析条件的理解。

二、实验要求
输入文法及待分析的输入串,输出其预测分析过程及结果。

三、实验步骤

  1. 参考数据结构
    (1)/定义产生式的语法集结构/
typedef struct{
    char formula[200];//产生式
}grammarElement;
grammarElement  gramOldSet[200];//原始文法的产生式集

(2)/变量定义/

  char terSymbol[200];//终结符号
     char non_ter[200];//非终结符号
     char allSymbol[400];//所有符号
     char firstSET[100][100];//各产生式右部的FIRST集
     char followSET[100][100];//各产生式左部的FOLLOW集
     int M[200][200];//分析表
  1. 判断文法的左递归性,将左递归文法转换成非左递归文法。(该步骤可以省略,直接输入非左递归文法)。

3.根据文法求FIRST集和FOLLOW集。
(1)/求 First 集的算法/

begin
if  X为终结符()
        在所有产生式中查找X所在的产生式
        if  产生式右部第一个字符为终结符或空(即X®a(aÎ )或X®e)
         then 把a或e加进FIRST(X)
        if 产生式右部第一个字符为非终结符 then
             if产生式右部的第一个符号等于当前字符 then
                跳到下一条产生式进行查找
              if 当前非终结符还没有求其FIRST集 then
                 查找它的FIRST集并标识此符号已求其FIRST集
         求得结果并入到X的FIRST集
         if  当前产生式右部符号可推出空字且当前字符不是右部的最后一个字符
         then  获取右部符号下一个字符在所有字符集中的位置
         if  此字符的FIRST集还未查找 then
          找其FIRST集,并标其查找状态为1
          把求得的FIRST集并入到X的FIRST集
          if  当前右部符号串可推出空且是右部符号串的最后一个字符(即产生式为X® ,若对一切1£ i£ k,均有e ÎFIRST( ),则将eÎ符号加进FIRST(X))  then 把空字加入到当前字符X的FIRST集
          else
                不能推出空字则结束循环
        标识当前字符X已查找其FIRST集。
end

(2)/求 FOLLOW 集的算法/

begin
   if  X为开始符号 then # ÞFOLLOW(X) 
   对全部的产生式找一个右部含有当前字符X的产生式
   if X在产生式右部的最后(形如产生式A®aX) then
       查找非终结符A是否已经求过其FOLLOW集.避免循环递归
       if  非终结符A已经求过其FOLLOW集 then
            把FOLLOW(A)中的元素加入FOLLOW(X)
            继续查下一条产生式是否含有X
       else
            求A的FOLLOW集,并标记为A已求其FOLLOW集
    else if X不在产生式右部的最后(A®aBb) then
           if  右部X后面的符号串b能推出空字e then
                     查找b是否已求过其FOLLOW集.避免循环递归
                     if 已求过b的FOLLOW集 then
                 把FOLLOW(A)中的元素加入FOLLOW(B)
                    结束本次循环
              else if b不能推出空字 then
                     求 FIRST(b)FIRST(b)中所有非空元素加入到FOLLOW(B)中
     标识当前要求的非终结符X的FOLLOW集已求过
        end

4.构造预测分析表。
5.构造总控程序。
6.对给定的输入串,给出分析过程及结果。

代码
(1)变量及函数的定义

//定义一个非终结符的结构体 
typedef struct{
	char left;//非终结符 
	int rcount;//右边式子数量 
	char right[200][200];//右边 
	int firstcount;
	int followcount;
	char First[200];//first集合 
	char Follow[200];//follow集合 
}grammar;
grammar gramSet[200];//产生式集(直接输入LL(1)文法) 

//变量的定义 
int gramcount=0;//产生式数量初始化 
int tersymcount=0;//终结符数量初始化 
int nontercount=0;//非终结符数量初始化 

char startsym;//文法开始符号 
char terSymbol[200];//终结符号
char nonter[200];//非终结符号
string table[200][200];//分析表
char test[500];//要处理的字符串 

map<char, bool> isfirsted;//该终结符是否已经求过其first集
map<char, bool> isfollowed;//是否求过follow集 

//本实验中使用'$'代替符号ε
 
//函数的定义
void read();//读入数据 
bool judgesymbol(char ch);//判断终结符和非终结符
void symbolsort(char ch);//字符归类
void First(char sym);//求sym的first集 
void Addfirst(char sym, char ch);//first(ch)并入first(sym) 
void Follow(char sym);//求sym的follow集 
void Addfollow(char sym, char  ch);//follow(ch)并入follow(sym) 
void AddfirstTofollow(char sym, char  ch);//将ch的first加入sym的follow中
bool Nonullinfirst(char ch);//判断一个非终结符的first中是否有$
void CreateForecastTable();//创建预测分析表 
void Show();//打印预测分析表 
void MainControl();//主控程序

(2)读入数据

void read()
{
	char str[100];
	while(1)
	{
		cin>>str;
		if(str[0]=='#')
		   break;
		gramSet[gramcount].left=str[0];
		symbolsort(str[0]);//处理左边 
		for(int i=3;i<strlen(str);i++)//右边从str[3]处开始;str的0-2位=‘E->’ 
		{
			int j=0;
			char ter[100];
			while(str[i]!='|'&&str[i]!='\0')
			{
				symbolsort(str[i]);//处理右边 
				 ter[j++]=str[i++];	
			}
			ter[j]='\0';
			strcpy(gramSet[gramcount].right[gramSet[gramcount].rcount],ter);
			gramSet[gramcount].rcount++;
		} 
		gramcount++;	
	}
}

(3)求FIRST集

void First(char sym)
{
	int i;
	for(i=0;i<gramcount;i++)
	{
		if(gramSet[i].left==sym)
		   break;//找到了该非终结符的位置 
	} 
	//处理每个产生式 
	for(int j=0;j<gramSet[i].rcount;j++)
	{	
	    int last=0;
		for(int s=0;s<strlen(gramSet[i].right[j]);s++)
		{
		int status=0;//判断是否继续获取下一个字符 
		char ch=gramSet[i].right[j][s];//获取字符 
		
		//字符为终结符或$ 
		if(judgesymbol(ch))
		{
			int flag=0;
			for (int n=0; n<gramSet[i].firstcount;n++)
			{
				if (gramSet[i].First[n] == ch)
				{
					flag = 1;//已在first集中 
					break;
				}
			}
			if(flag==0){
				gramSet[i].First[gramSet[i].firstcount++]=ch;//把终结符或$ 加进FIRST集 
			}
			break;
				
		}
		//字符ch为非终结符
		else 
		{
			if(!isfirsted[ch])//还没有求过ch的first集 
				First(ch);
			//找到ch在Set中的位置p 
			int p;
			for(p=0;p<gramcount;p++) 
			{
				if(gramSet[p].left==ch)
				  break;	
			}
			if(!Nonullinfirst(ch))//包含$
			{
				status=1;//需要进入循环,继续获取下一个字符 
				if(s+1==strlen(gramSet[i].right[j]))
				   last=1;	
			}
			
		    //将first(ch)加入到first(sym)中(除了$) 
			Addfirst(sym,ch);	    		
		}
		if(status==0)
			break;
		}	
		// 右边符号串可推出是空,将$加入 
		if(last==1)
	    {
		     int flag=0;
		     for (int n=0; n<gramSet[i].firstcount;n++)
		   	{
	     	   if (gramSet[i].First[n] == '$')
			   {
				  flag = 1;//已在first集中 
				  break;
			    }
		    }
		   	if(flag==0)
				gramSet[i].First[gramSet[i].firstcount++]='$';//把$ 加进FIRST集 
	    }	
	}
	isfirsted[sym]=true;
}
//将first(ch)加入到first(sym)中(除了$) 
void Addfirst(char sym,char ch)
{
	int s1,s2;
	int c1,c2;
	//找到sym的位置 
	for(s1=0;s1<gramcount;s1++)
	{
		if(gramSet[s1].left==sym)
		   break; 
	}
	//找到ch的位置 
	for(c1=0;c1<gramcount;c1++)
	{
		if(gramSet[c1].left==ch)
		   break; 
	}
	for(c2=0;c2<gramSet[c1].firstcount;c2++)
	{
		int flag=0;
		for(s2=0;s2<gramSet[s1].firstcount;s2++)
		{
			if(gramSet[s1].First[s2]==gramSet[c1].First[c2])
			{
				flag=1;
				break;//已存在 
		    } 	 
		}
		//first(ch)并入first(sym) 
		if(flag==0&&gramSet[c1].First[c2]!='$')
		{	
		gramSet[s1].First[gramSet[s1].firstcount++]=gramSet[c1].First[c2];
		}
	
	}
}

(4)求FOLLOW集

//Follow集
 void Follow(char sym)
 {
 	int p;
 	for(p=0;p<gramcount;p++)
	 {
 		if(gramSet[p].left==sym)
 	       break;
	 }
	 //是开始符号,需要加入'#' 
 	if(sym==startsym)
 	{
 		gramSet[p].Follow[gramSet[p].followcount++]='#';
	}
	//对全部的产生式找一个右部含有当前字符x的产生式 
	for(int i=0;i<gramcount;i++)
	{
		for(int j=0;j<gramSet[i].rcount;j++)
		{
			for(int k=0;k<strlen(gramSet[i].right[j]);k++)
			{
				if(gramSet[i].right[j][k]==sym)
				{
				   //X在产生式右部的最后(形如产生式A->aX),把FOLLOW(A)中的元素加入FOLLOW(X)
				   if(k+1==strlen(gramSet[i].right[j]))
				   {
				   	char ch=gramSet[i].left;
				   	if(sym!=ch)
					   {
					   	if(!isfollowed[ch])
					   	     Follow(ch);
						Addfollow(sym,ch); //follow(ch)加入follow(sym) 	
					   }
				   }
				   // X不在产生式右部的最后(A->aXB )
				   else
				   {
				   	 int last=0;//标记:判断B能否推出$ 
				   	//遍历B字符串中所有字符
					   for(int b=k+1;b<strlen(gramSet[i].right[j]);b++) 
					   {
					   	char ch=gramSet[i].right[j][b];
					   	//终结符直接加入follow(sym)
						   if(judgesymbol(ch))
						   {
						   	int flag=0;
						   	for(int n=0;n<strlen(gramSet[p].Follow);n++)
						   	{
						   	   if(gramSet[p].Follow[n]==ch)
								  {
								  	 flag=1;
								  	 break;
								  }	
							}
							if(flag==0)
							    gramSet[p].Follow[gramSet[p].followcount++]=ch;
							break;
						   } 
						  //非终结符 
						    else 
						    {
						     	AddfirstTofollow(sym,ch);
						       //ch的first中不含空值 
						       if(Nonullinfirst(ch))
						       {
						    	break;
							    }
							    else
							   {
								last++;
						    	}	
							}
					   }
					   if(last+k+1==strlen(gramSet[i].right[j]))
					   {
					   	char ch=gramSet[i].left;
					   	if(!isfollowed[ch])
					   	     Follow(ch);
					   	Addfollow(sym,ch);
					   }
				   }
				
				}
			}
		}
	}
	isfollowed[sym]=true;
 }
 //将follow(ch)加入follow(sym) 
void Addfollow(char sym,char ch)
{
	int  s1,s2;
	int  c1,c2;
	for(s1=0;s1<gramcount;s1++)//找到sym的位置 
	{
		if(gramSet[s1].left==sym)
		   break;
	}
	for(c1=0;c1<gramcount;c1++)//找到ch的位置 
	{
		if(gramSet[c1].left==ch)
		   break;
	}
	for(c2=0;c2<gramSet[c1].followcount;c2++)
	{
		int flag=0;
		for(s2=0;s2<gramSet[s1].followcount;s2++)
		{
			if(gramSet[s1].Follow[s2]==gramSet[c1].Follow[c2])
			{
				flag=1;
				break;
			}
		}
		if(flag==0)
		   gramSet[s1].Follow[gramSet[s1].followcount++]=gramSet[c1].Follow[c2];
	
	}
}
//first(ch)并入follow(sym)
void AddfirstTofollow(char sym, char ch)
{
	int  s1,s2;
	int  c1,c2;
	for(s1=0;s1<gramcount;s1++)
	{
		if(gramSet[s1].left==sym)
		   break;
	}
	for(c1=0;c1<gramcount;c1++)
	{
		if(gramSet[c1].left==ch)
		   break;
	}
	for(c2=0;c2<gramSet[c1].firstcount;c2++)
	{
		int flag=0;
		for(s2=0;s2<gramSet[s1].followcount;s2++)
		{
			if(gramSet[s1].Follow[s2]==gramSet[c1].First[c2])
			{
				flag=1;
				break;
			}
		}
		if(flag==0&&gramSet[c1].First[c2]!='$')
		   gramSet[s1].Follow[gramSet[s1].followcount++]=gramSet[c1].First[c2];
	
	}
}

(5)创建预测分析表

//创建预测分析表 
void CreateForecastTable()
{
	int row=nontercount+1;
	int col=tersymcount+2;
    for(int i=0;i<tersymcount;i++)
	{
		if(terSymbol[i]=='$')
		{
		 col=tersymcount+1;
		 break;	
		}
		  
	} 
	//分析表初始化
	table[0][0]=" ";
	table[0][col-1]="#";
	//放入终结符表头,即第0行 
	int j=1;
	for(int i=0;i<tersymcount;i++)
	{
		if(terSymbol[i]!='$')
		{
		 table[0][j++]=terSymbol[i];	
		}
		  
	} 
	//放入非终结符表头,即第0列 
	for(int j=0;j<gramcount;j++)
	{
		table[j+1][0]=gramSet[j].left;
	}
	//table内容初始化
	for(int i=1;i<row;i++)
	{
		for(int j=1;j<col;j++)
		{
			table[i][j]="ERR";
		}
    }   
    //开始分析,填充表的内容 
	for(int i=1;i<row;i++)
	{
		for(int j=1;j<col;j++)
		{
		   for(int k=0;k<gramSet[i-1].rcount;k++)//遍历一个非终结符A的所有产生式 ,A->α 
		   {
		   	int last=0;
		   	for(int m=0;m<strlen(gramSet[i-1].right[k]);m++)//遍历第k个产生式的右部所有字符 
		   	{
		   	char ch=gramSet[i-1].right[k][m];
		   	if(judgesymbol(ch))//如果是终结符 
		   	{
		   		if(table[0][j][0]==ch)//如果表的第0行第j列的终结符a与ch匹配 
		   		   {
		   		   	char h=gramSet[i-1].left;//非终结符 
		   		   	string str1=string(1,h);//转换成字符串 
		   		   	string str2=gramSet[i-1].right[k];//产生式右部 
		   		   	string str=str1+"->"+str2;//连接成一个完整的产生式 
		   		   	table[i][j]=str;//放入表中 
					}
				if(ch=='$')//如果遇到了$,检查a是否在follow(A)中 
				{
					for(int f=0;f<gramSet[i-1].followcount;f++)
						{
							if(table[0][j][0]==gramSet[i-1].Follow[f])//在follow集中 
							{
								char h=gramSet[i-1].left;
		   		    	        string str1=string(1,h);
		   		            	string str2=gramSet[i-1].right[k];
		   		    	        string str=str1+"->"+str2;
		   		    	        table[i][j]=str;//将该产生式放入表中 
						        break;
							}
						}
				}	
			break;
			}
			else//遇到了非终结符
			{
				//找到该非终结符ch在gramSet集中的位置 
				int p;
				for(p=0;p<gramcount;p++)
				{
					if(ch==gramSet[p].left)
					{
						break;
					}
				}
				//检查a是否在first(ch)中 
				for(int n=0;n<gramSet[p].firstcount;n++)
				{
					if(table[0][j][0]==gramSet[p].First[n])//在first(ch)中 
					{
				    	char h=gramSet[i-1].left;
		   		    	string str1=string(1,h);
		   		    	string str2=gramSet[i-1].right[k];
		   		    	string str=str1+"->"+str2;
		   		    	table[i][j]=str;//把该产生式放入表中 
						break;
					}
				}
				if(Nonullinfirst(ch))
				{
					break;
				}
				else
				{
					last++;
				}
				
			}
		   		
			}
			if(last==strlen(gramSet[i-1].right[k]))//First(α)中有$ 
			{
				for(int f=0;f<gramSet[i-1].followcount;f++)//检查a是否在follow(A)中 
                {
                 if(table[0][j][0]==gramSet[i-1].Follow[f])//在follow(A)中 
                   {
                    char h=gramSet[i-1].left;
                     string str1=string(1,h);
                     string str2=gramSet[i-1].right[k];
                     string str=str1+"->"+str2;
                     table[i][j]=str;//将产生式放入表中 
                      break;
                   }
                 }
			}
		  
		   }
		}
	}


 } 
 

(6)总控程序

void MainControl()
{
	int flag=1;
	string str[100];//存储所用产生式 
	int row=nontercount+1;
	int col=tersymcount+2;
	//存在$的情况下,总列数等于终结符个数加1 
	for(int i=0;i<tersymcount;i++)
	{
		if(terSymbol[i]=='$')
		{
		 col=tersymcount+1;
		 break;	
		}	  
	} 
	
	stack<char>Stack;
	Stack.push('#');//将#压入栈 
	Stack.push(gramSet[0].left);//开始符号入栈 
	char X;//存放栈顶元素 
	char a;//存放输入串当前分析符号 
	char instack[100];//存储符号栈里的符号串 
	int posstack=0;//定位X的位置 
	int pos=0;//定位a的位置 
	int step=0;//步骤序号 
	for(int i=0;i<100;i++)
		instack[i]='\0';//字符串初始化 
	instack[0] = '#';
	instack[1] = gramSet[0].left;
	posstack = 1;
	cout << endl;
	
	cout<<"步骤\t符号栈\t\t输入串\t\t所用产生式"<<endl;
	while(flag==1)
	{
		cout<<step++<<"\t";//打印步骤序号
		
		cout<<instack<<"\t\t";//打印当前符号栈 
		
		for(int i=pos;i<strlen(test);i++)//打印当前输入串 
			cout<<test[i];
		cout<<"\t\t";
  		cout<<str[step-1];//打印所用产生式 
		a=test[pos];
		X=Stack.top();//获取栈顶元素 
		Stack.pop();//弹出栈顶元素 
		instack[posstack]='\0';
		posstack--;
		if(X=='#')
		{
			if(a=='#')//此时分析成功 
			{
				flag=0;	
			}
			else
			{
				flag=-1;
			}
		}
		else if(judgesymbol(X))//如果栈顶的是终结符 
		{
			if(X==a)//匹配 
			{
				pos++;//位置后移,需读入下一个字符 
				a=test[pos];
			}
			else
			{
				flag=-2;	
			}
		}
		else//栈顶为非终结符 ,在分析表中查找 
		{
			int p1;
			int p2;
			//找到table[X,a] 
			for(p1=1;p1<row;p1++)
			{
				if(table[p1][0][0]==X)
				   break;
			}
			for(p2=1;p2<col;p2++)
			{
				if(table[0][p2][0]==a)
				   break;
			}
			 //判断一下table[p1][p2]内存放的是否是error 
			if(table[p1][p2]=="error")
			{
				flag=-2;
			}
			else
			{
				char ch;
			for(int i=table[p1][p2].length()-1;i>=3;i--)
			{
				ch=table[p1][p2][i];
				if(ch=='$')
				    break;
				Stack.push(ch);
				instack[++posstack]=ch;
			}
			str[step]=table[p1][p2];	
			}
		
		}
		cout<<endl;
	}
	if(flag==0)
	    cout<<"successful !"<<endl;
	else if(flag==-1)
	    cout<<"分析失败"<<endl; 
	else if(flag==-2)
	    cout<<"error"<<endl;
 } 

完整代码

#include <bits/stdc++.h>
using namespace std;

//定义一个非终结符的结构体 
typedef struct{
	char left;//非终结符 
	int rcount;//右边式子数量 
	char right[200][200];//右边 
	int firstcount;
	int followcount;
	char First[200];//first集合 
	char Follow[200];//follow集合 
}grammar;
grammar gramSet[200];//产生式集(直接输入LL(1)文法) 

//变量的定义 
int gramcount=0;//产生式数量初始化 
int tersymcount=0;//终结符数量初始化 
int nontercount=0;//非终结符数量初始化 

char startsym;//文法开始符号 
char terSymbol[200];//终结符号
char nonter[200];//非终结符号
string table[200][200];//分析表
char test[500];//要处理的字符串 

map<char, bool> isfirsted;//该终结符是否已经求过其first集
map<char, bool> isfollowed;//是否求过follow集 

//本实验中使用'$'代替符号ε
 
//函数的定义
void read();//读入数据 
bool judgesymbol(char ch);//判断终结符和非终结符
void symbolsort(char ch);//字符归类
void First(char sym);//求sym的first集 
void Addfirst(char sym, char ch);//first(ch)并入first(sym) 
void Follow(char sym);//求sym的follow集 
void Addfollow(char sym, char  ch);//follow(ch)并入follow(sym) 
void AddfirstTofollow(char sym, char  ch);//将ch的first加入sym的follow中
bool Nonullinfirst(char ch);//判断一个非终结符的first中是否有$
void CreateForecastTable();//创建预测分析表 
void Show();//打印预测分析表 
void MainControl();//主控程序


int main(int argc, char** argv) {
	cout<<"输入文法: 以'#'结束"<<endl;
	read();
	startsym=gramSet[0].left;//开始符号 
	cout<<"输入串(以'#'结束)为:"<<endl;
	cin>>test;
	for(int i=0;i<gramcount;i++)
	{
		First(gramSet[i].left);
	}
	for(int i=0;i<gramcount;i++)
	{
		Follow(gramSet[i].left);
	}
	cout<<endl;
	cout<<"first集如下:"<<endl;
	for(int i=0;i<gramcount;i++)
	{
		cout<<"FIRST("<<gramSet[i].left<<")"<<": ";
		for(int j=0;j<gramSet[i].firstcount;j++)
	     	cout<<gramSet[i].First[j]<<" ";
		cout<<endl;
	}
	cout<<endl;
	cout<<"follow集如下:"<<endl;
	for(int i=0;i<gramcount;i++)
	{
		cout<<"FOLLOW("<<gramSet[i].left<<")"<<": ";
		for(int j=0;j<gramSet[i].followcount;j++)
	     	cout<<gramSet[i].Follow[j]<<" ";
		cout<<endl;
	}
	cout<<endl;
	cout<<"预测分析表如下:"<<endl;
	CreateForecastTable();
	Show();
	cout<<endl;
	cout<<"预测分析步骤如下:"<<endl;
	MainControl();

	return 0;
}

//读入数据 
void read()
{
	char str[100];
	while(1)
	{
		cin>>str;
		if(str[0]=='#')
		   break;
		gramSet[gramcount].left=str[0];
		symbolsort(str[0]);//处理左边 
		for(int i=3;i<strlen(str);i++)//右边从str[3]处开始;str的0-2位=‘E->’ 
		{
			int j=0;
			char ter[100];
			while(str[i]!='|'&&str[i]!='\0')
			{
				symbolsort(str[i]);//处理右边 
				 ter[j++]=str[i++];	
			}
			ter[j]='\0';
			strcpy(gramSet[gramcount].right[gramSet[gramcount].rcount],ter);
			gramSet[gramcount].rcount++;
		} 
		gramcount++;	
	}
}
//判断终结符和非终结符
bool judgesymbol(char ch)
{
	if(ch>='A'&&ch<='Z')
		return false;
    return true;
}
//字符归类
void symbolsort(char ch)
{
	if(!judgesymbol(ch))
	{
		int flag=0;
		for (int i= 0;i<nontercount; i++)
		{
			if (ch==nonter[i])
			{
				flag=1;
				break;//已在非终结符集中 
			}
		}
		if(flag==0)
		{
			nonter[nontercount++]=ch;
			isfirsted.insert(pair<char, bool>(ch, false));
			isfollowed.insert(pair<char,bool>(ch, false));
		}
	}
	else
	{
		int flag=0;
		for (int i=0;i<tersymcount; i++)
		{
			if (ch==terSymbol[i])
			{
				flag = 1;
				break;//已在终结符集中 
			}
		}
		if (flag==0)
		{
			terSymbol[tersymcount++]=ch;
		}
	}
}
//求FIRST集
void First(char sym)
{
	int i;
	for(i=0;i<gramcount;i++)
	{
		if(gramSet[i].left==sym)
		   break;//找到了该非终结符的位置 
	} 
	//处理每个产生式 
	for(int j=0;j<gramSet[i].rcount;j++)
	{	
	    int last=0;
		for(int s=0;s<strlen(gramSet[i].right[j]);s++)
		{
		int status=0;//判断是否继续获取下一个字符 
		char ch=gramSet[i].right[j][s];//获取字符 
		
		//字符为终结符或$ 
		if(judgesymbol(ch))
		{
			int flag=0;
			for (int n=0; n<gramSet[i].firstcount;n++)
			{
				if (gramSet[i].First[n] == ch)
				{
					flag = 1;//已在first集中 
					break;
				}
			}
			if(flag==0){
				gramSet[i].First[gramSet[i].firstcount++]=ch;//把终结符或$ 加进FIRST集 
			}
			break;
				
		}
		//字符ch为非终结符
		else 
		{
			if(!isfirsted[ch])//还没有求过ch的first集 
				First(ch);
			//找到ch在Set中的位置p 
			int p;
			for(p=0;p<gramcount;p++) 
			{
				if(gramSet[p].left==ch)
				  break;	
			}
			if(!Nonullinfirst(ch))//包含$
			{
				status=1;//需要进入循环,继续获取下一个字符 
				if(s+1==strlen(gramSet[i].right[j]))
				   last=1;	
			}
			
		    //将first(ch)加入到first(sym)中(除了$) 
			Addfirst(sym,ch);	    		
		}
		if(status==0)
			break;
		}	
		// 右边符号串可推出是空,将$加入 
		if(last==1)
	    {
		     int flag=0;
		     for (int n=0; n<gramSet[i].firstcount;n++)
		   	{
	     	   if (gramSet[i].First[n] == '$')
			   {
				  flag = 1;//已在first集中 
				  break;
			    }
		    }
		   	if(flag==0)
				gramSet[i].First[gramSet[i].firstcount++]='$';//把$ 加进FIRST集 
	    }	
	}
	isfirsted[sym]=true;
}
//将first(ch)加入到first(sym)中(除了$) 
void Addfirst(char sym,char ch)
{
	int s1,s2;
	int c1,c2;
	//找到sym的位置 
	for(s1=0;s1<gramcount;s1++)
	{
		if(gramSet[s1].left==sym)
		   break; 
	}
	//找到ch的位置 
	for(c1=0;c1<gramcount;c1++)
	{
		if(gramSet[c1].left==ch)
		   break; 
	}
	for(c2=0;c2<gramSet[c1].firstcount;c2++)
	{
		int flag=0;
		for(s2=0;s2<gramSet[s1].firstcount;s2++)
		{
			if(gramSet[s1].First[s2]==gramSet[c1].First[c2])
			{
				flag=1;
				break;//已存在 
		    } 	 
		}
		//first(ch)并入first(sym) 
		if(flag==0&&gramSet[c1].First[c2]!='$')
		{	
		gramSet[s1].First[gramSet[s1].firstcount++]=gramSet[c1].First[c2];
		}
	
	}
}
//Follow集
 void Follow(char sym)
 {
 	int p;
 	for(p=0;p<gramcount;p++)
	 {
 		if(gramSet[p].left==sym)
 	       break;
	 }
	 //是开始符号,需要加入'#' 
 	if(sym==startsym)
 	{
 		gramSet[p].Follow[gramSet[p].followcount++]='#';
	}
	//对全部的产生式找一个右部含有当前字符x的产生式 
	for(int i=0;i<gramcount;i++)
	{
		for(int j=0;j<gramSet[i].rcount;j++)
		{
			for(int k=0;k<strlen(gramSet[i].right[j]);k++)
			{
				if(gramSet[i].right[j][k]==sym)
				{
				   //X在产生式右部的最后(形如产生式A->aX),把FOLLOW(A)中的元素加入FOLLOW(X)
				   if(k+1==strlen(gramSet[i].right[j]))
				   {
				   	char ch=gramSet[i].left;
				   	if(sym!=ch)
					   {
					   	if(!isfollowed[ch])
					   	     Follow(ch);
						Addfollow(sym,ch); //follow(ch)加入follow(sym) 	
					   }
				   }
				   // X不在产生式右部的最后(A->aXB )
				   else
				   {
				   	 int last=0;//标记:判断B能否推出$ 
				   	//遍历B字符串中所有字符
					   for(int b=k+1;b<strlen(gramSet[i].right[j]);b++) 
					   {
					   	char ch=gramSet[i].right[j][b];
					   	//终结符直接加入follow(sym)
						   if(judgesymbol(ch))
						   {
						   	int flag=0;
						   	for(int n=0;n<strlen(gramSet[p].Follow);n++)
						   	{
						   	   if(gramSet[p].Follow[n]==ch)
								  {
								  	 flag=1;
								  	 break;
								  }	
							}
							if(flag==0)
							    gramSet[p].Follow[gramSet[p].followcount++]=ch;
							break;
						   } 
						  //非终结符 
						    else 
						    {
						     	AddfirstTofollow(sym,ch);
						       //ch的first中不含空值 
						       if(Nonullinfirst(ch))
						       {
						    	break;
							    }
							    else
							   {
								last++;
						    	}	
							}
					   }
					   if(last+k+1==strlen(gramSet[i].right[j]))
					   {
					   	char ch=gramSet[i].left;
					   	if(!isfollowed[ch])
					   	     Follow(ch);
					   	Addfollow(sym,ch);
					   }
				   }
				
				}
			}
		}
	}
	isfollowed[sym]=true;
 }
 //将follow(ch)加入follow(sym) 
void Addfollow(char sym,char ch)
{
	int  s1,s2;
	int  c1,c2;
	for(s1=0;s1<gramcount;s1++)//找到sym的位置 
	{
		if(gramSet[s1].left==sym)
		   break;
	}
	for(c1=0;c1<gramcount;c1++)//找到ch的位置 
	{
		if(gramSet[c1].left==ch)
		   break;
	}
	for(c2=0;c2<gramSet[c1].followcount;c2++)
	{
		int flag=0;
		for(s2=0;s2<gramSet[s1].followcount;s2++)
		{
			if(gramSet[s1].Follow[s2]==gramSet[c1].Follow[c2])
			{
				flag=1;
				break;
			}
		}
		if(flag==0)
		   gramSet[s1].Follow[gramSet[s1].followcount++]=gramSet[c1].Follow[c2];
	
	}
}
//first(ch)并入follow(sym)
void AddfirstTofollow(char sym, char ch)
{
	int  s1,s2;
	int  c1,c2;
	for(s1=0;s1<gramcount;s1++)
	{
		if(gramSet[s1].left==sym)
		   break;
	}
	for(c1=0;c1<gramcount;c1++)
	{
		if(gramSet[c1].left==ch)
		   break;
	}
	for(c2=0;c2<gramSet[c1].firstcount;c2++)
	{
		int flag=0;
		for(s2=0;s2<gramSet[s1].followcount;s2++)
		{
			if(gramSet[s1].Follow[s2]==gramSet[c1].First[c2])
			{
				flag=1;
				break;
			}
		}
		if(flag==0&&gramSet[c1].First[c2]!='$')
		   gramSet[s1].Follow[gramSet[s1].followcount++]=gramSet[c1].First[c2];
	
	}
}
//判断一个非终结符的first中是否有空,没有'$'返回1 
bool Nonullinfirst(char ch)
{
	int p;
	for(p=0;p<gramcount;p++)
	{
		if(gramSet[p].left==ch)
		   break;
	}
	int flag=1;
	for(int i=0;i<strlen(gramSet[p].First);i++)
	{
		if(gramSet[p].First[i]=='$')
		{
			flag=0;
			break;
		}
	}
	return flag;
}
//创建预测分析表 
void CreateForecastTable()
{
	int row=nontercount+1;
	int col=tersymcount+2;
    for(int i=0;i<tersymcount;i++)
	{
		if(terSymbol[i]=='$')
		{
		 col=tersymcount+1;
		 break;	
		}
		  
	} 
	//分析表初始化
	table[0][0]=" ";
	table[0][col-1]="#";
	//放入终结符表头,即第0行 
	int j=1;
	for(int i=0;i<tersymcount;i++)
	{
		if(terSymbol[i]!='$')
		{
		 table[0][j++]=terSymbol[i];	
		}
		  
	} 
	//放入非终结符表头,即第0列 
	for(int j=0;j<gramcount;j++)
	{
		table[j+1][0]=gramSet[j].left;
	}
	//table内容初始化
	for(int i=1;i<row;i++)
	{
		for(int j=1;j<col;j++)
		{
			table[i][j]="ERR";
		}
    }   
    //开始分析,填充表的内容 
	for(int i=1;i<row;i++)
	{
		for(int j=1;j<col;j++)
		{
		   for(int k=0;k<gramSet[i-1].rcount;k++)//遍历一个非终结符A的所有产生式 ,A->α 
		   {
		   	int last=0;
		   	for(int m=0;m<strlen(gramSet[i-1].right[k]);m++)//遍历第k个产生式的右部所有字符 
		   	{
		   	char ch=gramSet[i-1].right[k][m];
		   	if(judgesymbol(ch))//如果是终结符 
		   	{
		   		if(table[0][j][0]==ch)//如果表的第0行第j列的终结符a与ch匹配 
		   		   {
		   		   	char h=gramSet[i-1].left;//非终结符 
		   		   	string str1=string(1,h);//转换成字符串 
		   		   	string str2=gramSet[i-1].right[k];//产生式右部 
		   		   	string str=str1+"->"+str2;//连接成一个完整的产生式 
		   		   	table[i][j]=str;//放入表中 
					}
				if(ch=='$')//如果遇到了$,检查a是否在follow(A)中 
				{
					for(int f=0;f<gramSet[i-1].followcount;f++)
						{
							if(table[0][j][0]==gramSet[i-1].Follow[f])//在follow集中 
							{
								char h=gramSet[i-1].left;
		   		    	        string str1=string(1,h);
		   		            	string str2=gramSet[i-1].right[k];
		   		    	        string str=str1+"->"+str2;
		   		    	        table[i][j]=str;//将该产生式放入表中 
						        break;
							}
						}
				}	
			break;
			}
			else//遇到了非终结符
			{
				//找到该非终结符ch在gramSet集中的位置 
				int p;
				for(p=0;p<gramcount;p++)
				{
					if(ch==gramSet[p].left)
					{
						break;
					}
				}
				//检查a是否在first(ch)中 
				for(int n=0;n<gramSet[p].firstcount;n++)
				{
					if(table[0][j][0]==gramSet[p].First[n])//在first(ch)中 
					{
				    	char h=gramSet[i-1].left;
		   		    	string str1=string(1,h);
		   		    	string str2=gramSet[i-1].right[k];
		   		    	string str=str1+"->"+str2;
		   		    	table[i][j]=str;//把该产生式放入表中 
						break;
					}
				}
				if(Nonullinfirst(ch))
				{
					break;
				}
				else
				{
					last++;
				}
				
			}
		   		
			}
			if(last==strlen(gramSet[i-1].right[k]))//First(α)中有$ 
			{
				for(int f=0;f<gramSet[i-1].followcount;f++)//检查a是否在follow(A)中 
                {
                 if(table[0][j][0]==gramSet[i-1].Follow[f])//在follow(A)中 
                   {
                    char h=gramSet[i-1].left;
                     string str1=string(1,h);
                     string str2=gramSet[i-1].right[k];
                     string str=str1+"->"+str2;
                     table[i][j]=str;//将产生式放入表中 
                      break;
                   }
                 }
			}
		  
		   }
		}
	}


 } 
 
//展示分析表
void Show()
  {
  	int row=nontercount+1;
	int col=tersymcount+2;
	//存在$的情况下,总列数等于终结符个数加1 
	for(int i=0;i<tersymcount;i++)
	{
		if(terSymbol[i]=='$')
		{
		 col=tersymcount+1;
		 break;	
		}	  
	} 
	//打印表的内容
	for(int k=0;k<col*11;k++)
		    cout<<"-";
	cout<<endl;
  	for(int i=0;i<row;i++)
  	{
  		for(int j=0;j<col;j++)
  		{
  			cout<<table[i][j];
  			for(int k=0;k<10-table[i][j].length();k++)
  			     cout<<" ";
  		    cout<<"|";
		}
		cout<<endl;
		 for(int k=0;k<col*11;k++)
		     cout<<"-";
		cout<<endl;
	}
  }
//主控程序
void MainControl()
{
	int flag=1;
	string str[100];//存储所用产生式 
	int row=nontercount+1;
	int col=tersymcount+2;
	//存在$的情况下,总列数等于终结符个数加1 
	for(int i=0;i<tersymcount;i++)
	{
		if(terSymbol[i]=='$')
		{
		 col=tersymcount+1;
		 break;	
		}	  
	} 
	
	stack<char>Stack;
	Stack.push('#');//将#压入栈 
	Stack.push(gramSet[0].left);//开始符号入栈 
	char X;//存放栈顶元素 
	char a;//存放输入串当前分析符号 
	char instack[100];//存储符号栈里的符号串 
	int posstack=0;//定位X的位置 
	int pos=0;//定位a的位置 
	int step=0;//步骤序号 
	for(int i=0;i<100;i++)
		instack[i]='\0';//字符串初始化 
	instack[0] = '#';
	instack[1] = gramSet[0].left;
	posstack = 1;
	cout << endl;
	
	cout<<"步骤\t符号栈\t\t输入串\t\t所用产生式"<<endl;
	while(flag==1)
	{
		cout<<step++<<"\t";//打印步骤序号
		
		cout<<instack<<"\t\t";//打印当前符号栈 
		
		for(int i=pos;i<strlen(test);i++)//打印当前输入串 
			cout<<test[i];
		cout<<"\t\t";
  		cout<<str[step-1];//打印所用产生式 
		a=test[pos];
		X=Stack.top();//获取栈顶元素 
		Stack.pop();//弹出栈顶元素 
		instack[posstack]='\0';
		posstack--;
		if(X=='#')
		{
			if(a=='#')//此时分析成功 
			{
				flag=0;	
			}
			else
			{
				flag=-1;
			}
		}
		else if(judgesymbol(X))//如果栈顶的是终结符 
		{
			if(X==a)//匹配 
			{
				pos++;//位置后移,需读入下一个字符 
				a=test[pos];
			}
			else
			{
				flag=-2;	
			}
		}
		else//栈顶为非终结符 ,在分析表中查找 
		{
			int p1;
			int p2;
			//找到table[X,a] 
			for(p1=1;p1<row;p1++)
			{
				if(table[p1][0][0]==X)
				   break;
			}
			for(p2=1;p2<col;p2++)
			{
				if(table[0][p2][0]==a)
				   break;
			}
			 //判断一下table[p1][p2]内存放的是否是error 
			if(table[p1][p2]=="error")
			{
				flag=-2;
			}
			else
			{
				char ch;
			for(int i=table[p1][p2].length()-1;i>=3;i--)
			{
				ch=table[p1][p2][i];
				if(ch=='$')
				    break;
				Stack.push(ch);
				instack[++posstack]=ch;
			}
			str[step]=table[p1][p2];	
			}
		
		}
		cout<<endl;
	}
	if(flag==0)
	    cout<<"successful !"<<endl;
	else if(flag==-1)
	    cout<<"分析失败"<<endl; 
	else if(flag==-2)
	    cout<<"error"<<endl;
 } 


结果
在这里插入图片描述

在这里插入图片描述

  • 3
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全糖去冰不加料

打赏一块钱💰也是钱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值