编译原理LL(1)文法的简单实现

LL(1)的实现:

1.输入文法

2.求first集

3.求follow集

4.求select集

5.分析串

求各个集合的过程:

1、判断各非汇总结符是否可以推出空

   (1)将各非终结符出示状态置为“未知”

   (2)按顺序扫描各产生式右部。分为下面几种情况:

        a、若遇到符号“ε”,检查左部非终结符状态,若不是“空”,将其置为“空”,继续扫描下一产生式;

        b、若遇到终结符,检查左部非终结符状态,若为“未知”,将其置为“非空”,继续扫描下一产生式;

        c、若遇到非终结符,检查该非终结符状态,若为“未知”,则跳过当前产生式,扫描下一产生式;若为“非空”,检查左部非终结符状态,若为“未知”,将其置为“非空”,继续扫描下一产生式;

若为“空”,继续扫描本产生式的下一符号;

        d、若遇到“\0”,检查左部非终结符状态,若不是“空”,将其置为“空”,继续扫描下一产生式;

        e、若上述a,b,c,d过程引起了非终结符状态的改变,则跳到(2)处继续循环,否则跳出循环,判断结束。

2、求非终结符的first集

扫描以要求first集的非终结符为左部的各产生式的右部,分为下面几种情况:

     A、若遇到终结符,将该终结符加入左部非终结符的first集,继续扫描下一产生式;

     B、若遇到符号“ε”,将“ε”加入左部非终结符的first集,继续扫描下一产生式;

  C、若遇到非终结符,将该非终结符的  first集 {ε} 加入左部非终结符的first集,然后检查该非终结符是否可以推出空,若可以为空,则扫描本产生式的下一符号;若不为空,则继续扫描下一产生式;

     D、若遇到“\0”,将“ε”加入左部非终结符的first集,继续扫描下一产生式;

3、求某一非终结符的FOLLOW集

   (1)在产生式右部找到该非终结符,扫面它后面的符号,分为下面几种情况:

   A、若是终结符,则将该终结符加入该非终结符的folow集;

   B、若是非终结符,将该非终结符的  first集 {ε} 加入该非终结符的folow集,然后检查该非终结符是否可以推出空,若可以为空,则扫描本产生式的下一符号;

   C、若是“\0”,则将该产生式的左部非终结符的follow集加入它的follow集。

   (2)在产生式的右部继续查找该非终结符,若找到,转(1)步。

4、求某产生式的select集

   扫描产生式的右部,分为下面几种情况:

  1. 若是终结符,则将该终结符加入该产生式的select集;
  2. 若是“ε”,将左部非终结符的follow集加入该产生式的select集;
  3. 若是非终结符,将该非终结符的  first集 {ε} 加入该产生式的select集,然后检查该非终结符是否可以推出空,若可以为空,则扫描本产生式的下一符号;
  4. 若是“\0”,则将该产生式的左部非终结符的follow集加入该产生式的select集。

具体实现:

#include<iostream>
#include<map>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<string.h>
using namespace std;
char chan[100][50];
string S;
unordered_map<char,int> mp;
unordered_map<char,int> mpx;
unordered_set <char> Fir[50];
unordered_set <char> Foll[50];
unordered_set <char> Sele[50];
stack<char> st;
int fei;    //非终结符数量
int cntchan;  //产生式数量
int Cal[50][50]; //预测分析表
int f[50]; //能否推出空的标记数组
void mune();
void input();
void output();
void JudgeIsNull();
void displayNULL();
void First();
void displayFirst();
void Follow();
void displayFollow();
void Select();
void displaySele();
void Analyse();
int main()
{
	int sel;
	while(1)
	{
		mune();
		cin>>sel;
		switch(sel)
		{
			case 1:
				input();
				break;
			case 2:
				output();
				break;
			case 3:
				displayNULL();
				break;
			case 4:
				displayFirst();
				break;
			case 5:
				displayFollow();
				break;
			case 6:
				displaySele();
				break;
			case 7:
				Analyse();
				break;
		}
		system("cls");
	}

}
void mune()
{
	printf("1.输入LL(1)文法\n");
	printf("2.显示输入的LL(1)文法\n");
	printf("3.判定非终结符是否为空\n");
	printf("4.输出非终结符的First集\n");
	printf("5.输出非终结符的Follow集\n");
	printf("6.输出产生式的Sellect集\n");
	printf("7.分析过程演示\n");
}
void input()
{
	cntchan=0; //此处考虑新增产生式,而非从头开始
	system("cls");
	int n;
	int k=1;
	printf("输入文法产生式的个数:");
	cin>>n;
	printf("输入各产生式(每行一条,空用'@'表示)中间用'->'隔开,如 A->b:\n");
	for(int i=0; i<n; i++)
	{
		printf("%d) ",i);
		cin>>chan[i];
		if(!mp[chan[i][0]])
			mp[chan[i][0]]=k++;
		cntchan++;
	}
	JudgeIsNull();
	First();
	Follow();
	Select();
	system("pause");
}
void output()
{
	system("cls");
	for(int i=0; i<cntchan; i++)
		cout<<chan[i]<<endl;
	system("pause");
}
void JudgeIsNull()
{
	/*
	1、判断各非汇总结符是否可以推出空
	(1)将各非终结符出示状态置为"未知"
	(2)按顺序扫描各产生式右部。分为下面几种情况:
	    a、若遇到符号"ε",检查左部非终结符状态,若不是"空",将其置为"空",继续扫描下一产生式;
	    b、若遇到终结符,检查左部非终结符状态,若为"未知",将其置为"非空",继续扫描下一产生式;
	    c、若遇到非终结符,检查该非终结符状态,若为"未知",则跳过当前产生式,扫描下一产生式;若为"非空",检查左部非终结符状态,若为"未知",将其置为"非空",继续扫描下一产生式;
		若为"空",继续扫描本产生式的下一符号;
	    d、若遇到"\0",检查左部非终结符状态,若不是"空",将其置为"空",继续扫描下一产生式;
	    e、若上述a,b,c,d过程引起了非终结符状态的改变,则跳到(2)处继续循环,否则跳出循环,判断结束。
	2、求非终结符的first集
	扫描以要求first集的非终结符为左部的各产生式的右部,分为下面几种情况:
	 A、若遇到终结符,将该终结符加入左部非终结符的first集,继续扫描下一产生式;
	 B、若遇到符号"ε",将"ε"加入左部非终结符的first集,继续扫描下一产生式;
	 C、若遇到非终结符,将该非终结符的  first集- {ε} 加入左部非终结符的first集,然后检查该非终结符是否可以推出空,若可以为空,则扫描本产生式的下一符号;若不为空,则继续扫描下一产生式;
	 D、若遇到"\0",将"ε"加入左部非终结符的first集,继续扫描下一产生式;

	*/
	//0->空  1->非空  -1->未知

	int i,j;
	for(i=1; i<=cntchan; i++)
		f[i]=-1;
	while(1)
	{
		for(i=0; i<cntchan; i++)
		{
			int indexA=mp[chan[i][0]];
			for(j=3; j<strlen(chan[i]); j++)
			{
				if(chan[i][j]=='@')
				{
					f[indexA]=0;
					break;
				}
				if(chan[i][j]<'A'||chan[i][j]>'Z')
				{
					if(f[indexA]==-1)
						f[indexA]=1;
					break;
				}
				if(chan[i][j]>='A'&&chan[i][j]<='Z')
				{
					if(f[mp[chan[i][j]]]==-1)
						break;
					if(f[mp[chan[i][j]]]==1)
					{
						if(f[indexA]==-1)
							f[indexA]=1;
						break;
					}
					else if(f[mp[chan[i][j]]]==0)
						continue;
				}
			}
			if(j==strlen(chan[i]))//  \0
				if(f[indexA]!=0)
					f[indexA]=0;
		}
		for(i=0; i<cntchan; i++)
			if(f[mp[chan[i][0]]]==-1)
				break;
		if(i==cntchan)
			break;
	}
	unordered_map<char,int> :: iterator it;
	for(it=mp.begin(); it!=mp.end(); it++)
		fei++;
}
void displayNULL()
{
	unordered_map<char,int> :: iterator it;
	for(it=mp.begin(); it!=mp.end(); it++)
		printf("%c->%d\n",it->first,f[it->second]);
	system("pause");
}
void First()
{
//	JudgeIsNull();
	/*
	2、求非终结符的first集
	扫描以要求first集的非终结符为左部的各产生式的右部,分为下面几种情况:
	 A、若遇到终结符,将该终结符加入左部非终结符的first集,继续扫描下一产生式;
	 B、若遇到符号“ε”,将“ε”加入左部非终结符的first集,继续扫描下一产生式;
	  C、若遇到非终结符,将该非终结符的  first集— {ε} 加入左部非终结符的first集,
	  然后检查该非终结符是否可以推出空,若可以为空,则扫描本产生式的下一符号;若不为空,则继续扫描下一产生式;
	 D、若遇到 “\0” ,将“ε”加入左部非终结符的first集,继续扫描下一产生式;
	*/
	int J[50];
	int i,j;
	Foll[mp[chan[0][0]]].insert('#');
	while(1)
	{
		for(i=1; i<=fei; i++)
			J[i]=Fir[i].size();
		for(i=0; i<cntchan; i++)
		{
			char left=chan[i][0];
			int indexL=mp[left];
			int len=strlen(chan[i]);
		//	Foll[indexL].insert('#');
			for(j=3; j<len; j++)
			{
				char now=chan[i][j];
				int indexR=0;
				if(now>='A'&&now<='Z')
					indexR=mp[now];
				if(now<'A'||now>'Z') //终结符 a
				{
					Fir[indexL].insert(now);
					break;
				}
				if(now=='@')
				{
					Fir[indexL].insert(now);
					break;
				}
				if(now>='A'&&now<='Z')//非终结符
				{
					if(Fir[indexR].find('@')!=Fir[indexR].end())
						Fir[indexR].erase(Fir[indexR].find('@'));
					Fir[indexL].insert(Fir[indexR].begin(),Fir[indexR].end());
					if(f[indexR]==0)
						continue;
					if(f[indexR]==1)
						break;
				}
			}
			if(j==len)	// \0
				Fir[indexL].insert('@');
		}
		int ff=0;
		for(i=1; i<=fei; i++)
			if(J[i]!=Fir[i].size())
				ff=1;
		if(ff==0)
			break;
	}
}
void displayFirst()
{
	for(auto ii : mp)
	{
		int index = ii.second;
		printf("First(%c) = { ",ii.first);
		for(auto it : Fir[index])
			printf("%c ",it);
		printf("}\n");
	}
	system("pause");
}
void Follow()
{
//	First();
	/*
	3、求某一非终结符的FOLLOW集
	(1)在产生式右部找到该非终结符,扫面它后面的符号,分为下面几种情况:
	A、若是终结符,则将该终结符加入该非终结符的folow集;
	B、若是非终结符,将该非终结符的  first集— {ε} 加入该非终结符的folow集,
		然后检查该非终结符是否可以推出空,若可以为空,则扫描本产生式的下一符号;
	C、若是“\0”,则将该产生式的左部非终结符的follow集加入它的follow集。
	(2)在产生式的右部继续查找该非终结符,若找到,转(1)步。
	*/
	int i,j;
	int J[50];
	while(1)
	{
		for(i=1; i<=fei; i++)
			J[i]=Foll[i].size();
		for(auto ii : mp)
		{
			int index = ii.second;
			char now = ii.first;
			for(i=0; i<cntchan; i++)
			{
				int len = strlen(chan[i]);
				int indexL = mp[chan[i][0]];
				int ff=0;
				for(j=3; j<len; j++)
				{
					if(ff==1||chan[i][j]==now)
					{
						char c = chan[i][j+1];
						int indexc = 0;
						if(c==0) // \0
						{
							Foll[index].insert(Foll[indexL].begin(),Foll[indexL].end());
							break;
						}
						if(c>='A'&&c<='Z') //非终结符
						{
							indexc = mp[c];
							if(Fir[indexc].find('@')!=Fir[indexc].end())
								Fir[indexc].erase(Fir[indexc].find('@'));
							Foll[index].insert(Fir[indexc].begin(),Fir[indexc].end());
							if(f[indexc] == 0)
							{
								ff=1;
								continue;
							}
							else
								break;
						}
						if(c<'A'||c>'Z')//终结符
						{
							Foll[index].insert(c);
							break;
						}
					}
				}
			}
		}
		int fff=0;
		for(i=1; i<=fei; i++)
			if(J[i]!=Foll[i].size())
				fff=1;
		if(fff==0)
			break;
	}
}
void displayFollow()
{
	for(auto ii : mp)
	{
		int index = ii.second;
		printf("Follow(%c) = { ",ii.first);
		for(auto it : Foll[index])
			printf("%c ",it);
		printf("}\n");
	}
	system("pause");
}
void Select()
{
	/*
	4、求某产生式的select集
	扫描产生式的右部,分为下面几种情况:
	(1)若是终结符,则将该终结符加入该产生式的select集;
	(2)若是“ε”,将左部非终结符的follow集加入该产生式的select集;
	(3)若是非终结符,将该非终结符的  first集— {ε} 加入该产生式的select集,
	然后检查该非终结符是否可以推出空,若可以为空,则扫描本产生式的下一符号;
	(4)若是“\0”,则将该产生式的左部非终结符的follow集加入该产生式的select集。
	*/
	int i,j,index;
	for(i=0; i<cntchan; i++)
	{
		int indexL = mp[chan[i][0]];
		int len = strlen(chan[i]);
		for(j=3; j<len; j++)
		{
			char c = chan[i][j];
			if(c=='@')
			{
				Sele[i].insert(Foll[indexL].begin(),Foll[indexL].end());
				break;
			}
			if(c <'A'||c>'Z')
			{
				printf("\n%c\n",c);
				Sele[i].insert(c);
				break;
			}
			if(c>='A'&&c<='Z')
			{
				index = mp[c];
				if(Fir[index].find('@')!=Fir[index].end())
					Fir[index].erase(Fir[index].find('@'));
				Sele[i].insert(Fir[index].begin(),Fir[index].end());
				if(f[index]==0)
					continue;
				else
					break;
			}
		}
		if(j==len)
			Sele[i].insert(Foll[indexL].begin(),Foll[index].end());
	}
}
void displaySele()
{

	for(int i=0; i<cntchan; i++)
	{
		printf("SELECT(%s)\t= { ",chan[i]);
		for(auto it : Sele[i])
			printf("%c ",it);
		printf("}\n");
	}
	system("pause");
}
void Analyse()
{
	int i,j,k=1;
	for(i=0; i<50; i++)
		for(j=0; j<50; j++)
			Cal[i][j]=-1;
	for(i=0; i<cntchan; i++)
	{
		int len=strlen(chan[i]);
		for(j=3; j<len; j++)
			if((chan[i][j]<'A'||chan[i][j]>'Z')&&!mpx[chan[i][j]])
				mpx[chan[i][j]]=k++;
	}
	mpx['#']=k;
	for(k=0; k<cntchan; k++)
	{
		int i = mp[chan[k][0]];
		for(auto ii : Sele[k])
		{
			int j = mpx[ii];
			Cal[i][j] = k;
		}
	}
	string now ;//模拟输出串
	cin>>S;
	//处理字符串,结尾加 #
	S+='#';
	//初始化栈
	now+='#';
	now+=chan[0][0];
	st.push('#');
	st.push(chan[0][0]);
	int ind = 0;
	k=1;
	printf("步骤\t分析栈\t剩余输入串\t推导产生式或匹配\n");
	while(1)
	{
		printf("%d\t",k++);
		cout<<now<<'\t'<<S.substr(ind,S.size()-ind)<<'\t'<<'\t';
		if(S[ind]!='#') //当剩余串不为空
		{
			char Top = st.top();
			char Sheng = S[ind];
			if(Top == Sheng) //匹配
			{
				printf("'%c'匹配\n",Top);
				st.pop();
				ind++;
				now = now.substr(0,now.size()-1);
				continue;
			}
			int indexT = 0;
			int indexS = 0;
			if(Top >= 'A'&& Top <= 'Z') //分析栈顶为非终结符
				indexT = mp[Top];
			else
				indexT = mpx[Top];
			if(Sheng >= 'A'&& Sheng <= 'Z') //剩余串头为非终结符
				indexS = mp[Sheng];
			else
				indexS = mpx[Sheng];
			if(Cal[indexT][indexS]==-1) //不匹配
			{
				printf("分析错误!\n");
				break;
			}
			else                    //匹配
			{
				char ss[50];
				strcpy(ss,chan[Cal[indexT][indexS]]);
				printf("%s\n",ss);
				st.pop();
				now = now.substr(0,now.size()-1);
				if(ss[strlen(ss)-1]!='@')
				{
					for(i=strlen(ss)-1; i>=3; i--)
					{
						st.push(ss[i]);
						now+=ss[i];
					}
				}
			}
		}
		else
		{
			if(st.size()!=1) //当剩余串为空,分析栈不空时
			{
				char Top = st.top();
				char Sheng = '@';

				int indexT = mp[Top];
				if(f[indexT]==0)
				{
					printf("%c->@\n",Top);
				}
				st.pop();
				now = now.substr(0,now.size()-1);
			}
			else if(st.top()==S[ind])
			{
				printf("接受\n");
				break;
			}
			else
			{
				printf("分析错误\n");
				break;
			}
		}

	}
	system("pause");
}
/*
E->TX
X->+TX
X->@
T->FY
Y->*FY
Y->@
F->i
F->(E)
*/

//  -std=c++11 

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值