⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ll1.cpp

📁 实现编译原理中LL1文法分析功能 编译原理课程中
💻 CPP
字号:
#include"stdio.h"
#include"iostream"
#include"string"
#include"fstream"
#include"ctype.h"
#define N 50

#include"word.h"
using namespace std;
#include"stack.h"

 
class Line{//存一行文法
public:
	char Vn;//非终结符
	string form[10];//产生式
	int f;//产生式个数
	Line()
	{f=0;}
};

class Gwf{//存一个文法的终结符和非终结符
	public:
	string Vn;//非终结符
	string Vt;//终结符
	int Nn;//非终结符
	int	Nt;//终结符个数
	Gwf(char *LLname){
		FILE *fp=fopen(LLname,"r");
		char ch=fgetc(fp);
		char buf[200];
		int i=1;
		while(ch!=EOF)
		{	buf[i++]=ch;
			ch=fgetc(fp);
		}
		buf[0]='\n';
		buf[i]='\0';
		fclose(fp);
		for(i=0;i<strlen(buf);i++){
			ch=buf[i];
			if(isspace(ch)){
				Vn.append(&buf[++i],1);				
			}
			else if(ch=='-'&&buf[i+1]=='>')
				i++;
			else if(isupper(ch)||ch=='|'||ch=='@')
				;//空操作
			else 
				Vt.append(&ch,1);
		}
		Vt.append("#");//结束符
		Nn=Vn.length();
		Nt=Vt.length();
	}
	int pos_n(char n){
		return Vn.find_first_of(n);
	}
	int pos_t(char t){
		return Vt.find_first_of(t);
	}
	bool isvt(char t){//t是终结符?
		if(Vt.find_first_of(t)==string::npos)
			return false;
		else return true;
	}
};

class FirstN{//用来存放一个非终结符的first集
public:
	int p;//第p个产生式
	char Vt;//终结符
	FirstN(){
		p=0;
		Vt='\0';
	}	
};

void readLL(char *LLname,Line *LL){//将文法存入Line LL[]中
	ifstream fin(LLname);
	string buf[N];
	int len=0;
	do{
		fin>>buf[len++];
	}while(!fin.eof());
	for(int i=0;i<len;i++){
		LL[i].Vn=buf[i].at(0);//读入非终结符
		buf[i].erase(0,3);//删除前三个,N->
		buf[i].append("|");
		while(!buf[i].empty()){
			int e=buf[i].find_first_of('|');
			LL[i].form[LL[i].f++].assign(buf[i],0,e);
			buf[i].erase(0,e+1);
		}//while
	}//for //dowhile
	fin.close();
}

///////////////以下求FIRST集///////////////////////

void copyfst(int n,int c,FirstN fst[N][N],int pt){//将fst的第c行复制到第n行后
	int n1=0;//n行的列标
	while(fst[n][n1].Vt!='\0')
		n1++;
	int c1=0;//n的列标
	while(fst[c][c1].Vt!='\0'){
		if(fst[c][c1].Vt=='@'){
			c1++;
			continue;
		}
		fst[n][n1].Vt=fst[c][c1++].Vt;
		fst[n][n1++].p=pt;
	}
}

void first(char n,Line *LL,Gwf GLL,FirstN fst[N][N],int *flag){//求n的FIRST
	int pn=0,pt=0;
	int i=0;
	pn=GLL.pos_n(n);//非终结符n在LL[]中的位置
	if(flag[pn]) return;//如果求过这个,则结束
	for(pt=0;pt<LL[pn].f;pt++){
		char ch;
		int pch;
		int k=0;
		int fg=0;
		do{//////
			ch=LL[pn].form[pt].at(k++);
			if(GLL.isvt(ch)||ch=='@'){//如果产生式的FIRST是@或者终结符,则存入
				fst[pn][i].p=pt;
				fst[pn][i].Vt=ch;
				i++;
			}//if
			else{ //如果是非终结符,则将非终结符的FIRST存入
				first(ch,LL,GLL,fst,flag);
				
				pch=GLL.pos_n(ch);//非终结符ch在LL[]中的位置
				copyfst(pn,pch,fst,pt);			
			}//else
			for(int pk=0;fst[pch][pk].Vt!='\0';pk++)
				if(fst[pch][pk].Vt=='@'){
					fg=1;break;
				}
		}//do
		while(fg);
	}//for
	flag[pn]=1;
}//first

void first_all(Line *LL,Gwf GLL,FirstN fst[N][N]){//求所有非终结符的FIRST集	
	int flag[N]={0};//标记第N个非终结符是否求过FIRST
	int i;
	char n;
	for(i=0;i<GLL.Nn;i++){
		n=GLL.Vn.at(i);
		first(n,LL,GLL,fst,flag);
	}//for
}

//////////////////以下求FOLLOW////////////////////////
int Flagchg;//用来标记FOLLOW是否改变

void uniqueflw(int pn,char flw[N][N]){//将flw[pn][]唯一化
	char ch[N]={'\0'};
	int i=0,j=0;
	while(flw[pn][i]!='\0'){
		char e=flw[pn][i];
		if(e!='@'&&strchr(ch,e)==NULL)
			ch[j++]=e;
		i++;
	}//while	
	strncpy(flw[pn],ch,N);	
}

void addfirst(char n,char b,Gwf GLL,FirstN fst[N][N],char flw[N][N]){//将FIRST(b)加入FOLLOW(n)
	int pn=GLL.pos_n(n);
	char buf[N];
	strcpy(buf,flw[pn]);//改变前的flw[pn]->buf
	int i=strlen(flw[pn]);//查找FOLLOW(N)的最后位置
	if(GLL.isvt(b))//如果b是终结符则直接加入FOLLOW(n)
		flw[pn][i]=b;
	else{//如果不是,将FIRST(b)加入FOLLOW(n)
		int j=0;
		int pb=GLL.pos_n(b);
		while(fst[pn][j].Vt!='\0')
			flw[pn][i++]=fst[pb][j++].Vt;
	}//else
	uniqueflw(pn,flw);
	if(strcmp(flw[pn],buf))
		Flagchg=1;
}


void addfirst_all(Line *LL,Gwf GLL,FirstN fst[N][N],char flw[N][N]){//判断所有A->anb,将FIRST(b)加入FOLLOW(n)
	int i,j,k;//循环变量
	for(i=0;i<GLL.Nn;i++)//fori
		for(j=0;j<LL[i].f;j++){//forj
			int l=LL[i].form[j].length();
			for(k=0;k<l-1;k++){//fork
				char n=LL[i].form[j].at(k);
				char b=LL[i].form[j].at(k+1);
				addfirst(n,b,GLL,fst,flw);
			}//endk
		}//endj//endi
}

bool addfollow(int i,char n,Gwf GLL,FirstN fst[N][N],char flw[N][N]){//flw[i][]加入FOLLOW(n)
	int pn=GLL.pos_n(n);
	if(pn==i)
		return false;
	char buf[N];
	strcpy(buf,flw[pn]);//改变前的flw[pn]->buf
	if(GLL.isvt(n))
		;
	else{		
		strcat(flw[pn],flw[i]);
		uniqueflw(pn,flw);
		if(strcmp(flw[pn],buf))
		Flagchg=1;
	}
	int k=0;
	while(fst[pn][k].Vt!='\0'){
		if(fst[pn][k].Vt=='@')
			return true;//如果@属于n的FIRST,返回真
		k++;
	}	
	return false;
}

void addfollow_all(Line *LL,Gwf GLL,FirstN fst[N][N],char flw[N][N]){//判断所有A->an,将FOLLOW(A)加入FOLLOW(n)
	int i,j;
	for(i=0;i<GLL.Nn;i++)//fori
		for(j=0;j<LL[i].f;j++){//forj
			int len=LL[i].form[j].length()-1;
			char n=LL[i].form[j].at(len);
			while(addfollow(i,n,GLL,fst,flw))//直到最后的不能为空
				n=LL[i].form[j].at(--len);
		}//endj//endi
}

void follow_all(Line *LL,Gwf GLL,FirstN fst[N][N],char flw[N][N]){//求所有非终结符的FOLLOW
	flw[0][0]='#';//将;(即#)置于开始符号的FOLLOW中
	addfirst_all(LL,GLL,fst,flw);//对于所有A->anb,将FIRST(b)加入FOLLOW(n)
	Flagchg=1;
	while(Flagchg){//如果follow有改变就一直执行
		Flagchg=0;
		addfollow_all(LL,GLL,fst,flw);
	}
}

///////////////以下求预测分析表/////////////////////

void forecast(FirstN fst[N][N],char flw[N][N],Line *LL,Gwf GLL,string Mtb[N][N]){//将预测分析表存入Mtb中
	int i,j,c;
	for(i=0;i<GLL.Nn;i++){
		j=0;
		char t=fst[i][j].Vt;
		int pt;
		while(t!='\0'){			
			pt=fst[i][j].p;
			if(t!='@'){
				c=GLL.pos_t(t);//i行c列
				Mtb[i][c]=LL[i].form[pt];
			}else{
				int pf=0;
				while(flw[i][pf]!='\0'){
					char ft=flw[i][pf];
					c=GLL.pos_t(ft);
					Mtb[i][c]=LL[i].form[pt];
					pf++;
				}//while
			}//if else
			j++;
			t=fst[i][j].Vt;
		}//while
	}//for		
}

////////////以下进行词法分析///////////////////////

void error(Stack S,char *expi,int j){//出错分析
	cout<<"错误"<<flush;
	char s=S.get(S.top); 	
	char e=expi[j];
	if(s==')')///栈顶为'('
		switch (e){
			case '#':cout<<"。语法错误:';'前缺少'"<<s<<"'"<<flush;  break;
		}
	if(s=='E')
		switch(e){
			case '+':
			case '*': cout<<"。非法使用符号:"<<e<<flush; break;
		}
	if(s=='F')
		switch(e){
			case '+':
			case '*':
			case ')': cout<<"。非法使用符号:"<<e<<flush; break;
		}
	cout<<endl;	
}

void analyse(char exp[N][N],string Mtb[N][N],Gwf GLL,char *expname){//进行预测分析
	ifstream fin(expname);
	Stack S;
	char start=GLL.Vn.at(0);
	char x;//用于比较
	for(int i=0;strlen(exp[i]);i++){//对exp的每一行
		S.push('#');
		S.push(start);
		string buf;//用来缓存一行代码
		int fa=1;
		int j=0;//exp[i][j]
		while(fa){
			S.pop(x);
			if(x=='@') 
				continue;
			if(GLL.isvt(x)&&x!='#'){//如果是终结符//if1
				if(x==exp[i][j])//if3
					j++;
				else {
					fin>>buf;
					cout<<buf<<endl;
					error(S,exp[i],j);
					fa=0;
				}//end if3
			}//end if1
			else if(x=='#'){//如果是#//if3
				if(x==exp[i][j]){//if2					
					fin>>buf;
					cout<<buf<<endl;
					cout<<"正确"<<endl;
					fa=0;//分析结束
				}else{
					fin>>buf;
					cout<<buf<<endl;
					error(S,exp[i],j);
					fa=0;
				}//else if//end if2
			}//end if3
			else{//如果是非终结符
				int pn=GLL.pos_n(x);//在Mtb中的行号
				int pt=GLL.pos_t(exp[i][j]);//在Mtb中的列号
				if(!Mtb[pn][pt].empty())//如果分析表Mtb中相应的位置不为空
					S.pushstr(Mtb[pn][pt]);//则入栈
				else{//否则,报错
					fin>>buf;
					cout<<buf<<endl;
					error(S,exp[i],j);
					fa=0;
				}
			}
			
		}//while
	}//for i
	fin.close();		
}


/////////////以下为主函数////////////////////////
void main(){
	char *LLname="LL.txt";//文法文件名
	char *expname="expression.txt";//代码文件名
	Gwf GLL(LLname);//将文法的Vn,Vt及个数存入GLL
	Line LL[N];//存文法
	readLL(LLname,LL);//将文法结构读入LL
	FirstN fst[N][N];//存FIRST集
	first_all(LL,GLL,fst);//求FIRST
	char flw[N][N]={'\0'};//存FOLLWS集
	follow_all(LL,GLL,fst,flw);//求FOLLOW
	string Mtb[N][N];//存预测分析表
	forecast(fst,flw,LL,GLL,Mtb);//求预测分析表
	char exp[N][N]={'\0'};//存经词法翻译过的代码
	word(expname,exp);//求翻译后的代码
	analyse(exp,Mtb,GLL,expname);	
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -