编译原理—算符优先分析法C++代码实现

前言:

      写算法的时候,也搜索了不少大佬的笔记,感觉有些复杂,不太容易看懂。但还是借鉴了不少思想,再结合自己的所学,成功运行。本次设计的存储结构简单易懂,且适合新手,目前实现了FirstVt集,LastVt以及算符优先分析表的构造,主要还是利用从各自的构造思想入手。

算符优先分析法是一种自底向上的语法分析方法。在算符文法中,任何一个规则右部都不存在两个非终结符相邻的情况。通过比较两个相继出现的终结符a,b的优先级,然后借助优先级关系,来确定句型的可归约串并进行归约。通过构造FIRSTVT集和LASTVT集来构造算符优先分析表,从表中可以看出各终结符的优先关系。

主要概念:

FirstVt集如何构造:

若P→a…或P→Qa…, 则a属于FIRSTVT(P)

若P→Q…, 则FIRSTVT(Q)加到FIRSTVT(P)

直至FIRSTVT(P)不再增大。

LastVt构造:

若P→...a或P→…aQ, 则a属于LASTVT(P);

若P→...Q, 则LASTVT(Q)含于LASTVT(P);

直至LASTVT(P)不再增大。

 算符优先分析表构造:

1) ‘=’关系

-若出现了A →…ab…或A →…aBb, 则a=b;

2)‘<’关系

-求出每个非终结符B的FIRSTVT(B),

-若A→…aB…,则 任意b∈FIRSTVT(B),a<b;

3)‘>’关系

-求出每个非终结符B的LASTVT(B),

-若A→…Bb…,则 任意a∈LASTVT(B),a>b

存储结构设计 :

#include<iostream>
#include<vector>
using namespace std;
#include<string.h>
struct inf{
	char ter;//首非终结符 
	bool e;//是否产生空字符 
	string nonter;
}; 
vector <inf> v;//产生式集合 
char a[10];
string T="";//非终结符集合 
string Vt="";//终结符集合 
string firstvt[20];
string lastvt[20];
char table[50][50];//算符优先关系表 

源代码:

(涉及到将文法转化为产生式。即将  E->aB|c  变为    E->aB   E->c)

//选择20、填空20、判断10、程序阅读25、设计题25  数据可视化 nowpy应用于机器学习 文件操作 pandas  
#include<iostream>
#include<vector>
using namespace std;
#include<string.h>
struct inf{
	char ter;//首非终结符 
	bool e;//是否产生空字符 
	string nonter;
}; 
vector <inf> v;//产生式集合 
char a[10];
string T="";//非终结符集合 
string Vt="";//终结符集合 
string firstvt[20];
string lastvt[20];
char table[50][50];//算符优先关系表 
void add();
//将文法转为产生式 
string produce(string str){
	inf infi;
    infi.ter = str[0];
	infi.e=false;
	int i = 3;
	for(int k=i;k<str.length();k++){
		if(str[k]=='|'){
			infi.nonter.append(str.substr(i,k-i));
			i=str.length(); 
			if(str[i]!=' '&&str[i]!='@'){
				inf ind;
				ind.ter=str[0];
				ind.e=false;
				ind.nonter.append(str.substr(k+1,str.length()-1));
				v.push_back(ind);
			}
		}
		else if(str[k]=='@'){
			infi.e=true; 
		i= k+2;
		k++;
		}
	} 
	if(i < str.length()){ //处理形如  E-》TB 
	infi.nonter.append(str.substr(i));
	}
	for(int k=3;k<str.length();k++){
	if((str[k]>='!'&&str[k]<='/'&&str[k]!='|')||(str[k]>='a'&&str[k]<='z')){
		Vt+=str[k];
	} 
    }
	v.push_back(infi);
	T=T+str[0]; 
	return infi.nonter;
}
//求firstvt集
void add_firstvt(int p,char ch){//对每一行产生式求 
	for(int i=0;i<v.size();i++){
		inf e= v[i];
		if(ch==e.ter){
		char str=e.nonter[0];
		int lo = e.nonter.find(str);
		char str2;
		//A->a...,则a属于 firstvt(A)
		if((str >= 'a'&&str <= 'z')||(str>='('&&str<='+')){
			firstvt[p] += str;
		}
		//A->Qa... ,则a属于 firstvt(A)
		if(lo+1<=e.nonter.length()-1){
			str2=e.nonter[1];
		if(str>='A'&&str<='Z'){
			if((str2 >= 'a'&&str <= 'z')||(str2>='!'&&str2<='/'))
		    firstvt[p] += str2;
			}
		}
		//A->B...,则firstvt(A)+=firstvt(B) 
		else if((str >= 'A'&&str <= 'Z')&&str!=e.ter&&str!=e.ter){
			int j = T.find(str);
			add_firstvt(j,str);
			firstvt[p].append(firstvt[j].substr(0));
			firstvt[j]="";
		}
	}
	}
} 
求last集 
void add_lastvt(int p,char a){
for(int i=0;i<v.size();i++){
		inf e= v[i];
		if(a==e.ter){
		char str=e.nonter[e.nonter.length()-1];
		int lo = e.nonter.find(str);
		char str2;
		//A->...a,则a属于 lastvt(A)
		if((str >= 'a'&&str <= 'z')||(str>='('&&str<='+')){
			lastvt[p] += str;
		}
		//A->...aQ ,则a属于 lastvt(A)
		if(lo!=0){
			str2=e.nonter[e.nonter.length()-2];
		if(str>='A'&&str<='Z'){
			if((str2 >= 'a'&&str <= 'z')||(str2>='!'&&str2<='/'))
		    lastvt[p] += str2;
			}
		}
		//A->...B,则lastvt(A)+=lastvt(B) 
		else if((str >= 'A'&&str <= 'Z')&&str!=e.ter&&str!=e.ter){
			int j = T.find(str);
			add_lastvt(j,str);
			lastvt[p].append(lastvt[j].substr(0));
			lastvt[j]="";
		}
	}
	}
}

//将空转符去掉,添加新的产生式 
void add(){
	int vsize=v.size();
	for(int i=0;i<vsize;i++){
		if(v[i].e){
			for(int j=0;j<vsize;j++){
					int n=v[j].nonter.find(v[i].ter);
					if(n>=0){             //找到 
						inf ind;
						string str=v[j].nonter;
						ind.e=false;
						ind.ter=v[j].ter;
						ind.nonter.append(str.substr(0,n));
						v.push_back(ind);
						continue; 
						}
					}
					
			}	
	}	
	
}
void print(){	
	for(int i=0;i<v.size();i++){
		inf infd=v[i];
		for(int j=0;j<infd.nonter.size();j++){
		        cout<<infd.ter<<"->"<<infd.nonter<<"\t";
		        break;
		}
	}
	cout<<endl;
		for(int j=0;j<T.length();j++){
		add_firstvt(j,T[j]);
		}
		for(int j2=0;j2<T.length();j2++){
		add_lastvt(j2,T[j2]);		
		}
}
void printTable(){
	cout<<"\t";
	table[5][5]='=';
	for(int i=0;i<Vt.length();i++){
		cout<<Vt[i]<<"\t";
	}
	cout<<endl;
	for(int i=0;i<Vt.length();i++){
	cout<<Vt[i];
	for(int j=0;j<Vt.length();j++){
		cout<<"\t"<<table[i][j];
	}
	cout<<endl; 
}
}
int FindSub(char c){
	for (int i = 0; i < Vt.length(); i++) {
		if (Vt[i] == c) {
			return i;
		}
	}
	return -1;//#的下标
}
bool IsVt(char c) {//判断该字符是否为终结符
	for (int i = 0; i < Vt.length(); i++) {
		if (c == Vt[i]) {
			return true;
		}
	}
	return false;
}
void CreateTable() {//构建算符优先分析表
    inf id;
    id.ter='E';
    id.e=false;
    id.nonter="#E#";
    v.push_back(id);
	for (int i = 0; i < v.size(); i++) {//遍历每条产生式
	inf ind = v[i];
		for (int j = 0; j < ind.nonter.length(); j++) {//遍历每条产生式中符号 
			int len = ind.nonter.length(); 
				if (IsVt(ind.nonter[0])) {//Xi和Xi+1都是终结符P->...ab...
				int x,y;
				if(len>=2){
				if(IsVt(ind.nonter[1])){
					x = FindSub(ind.nonter[0]);
					y = FindSub(ind.nonter[1]);
					cout<<x<<y;
					table[x][y] = '=';
				}
					else if(len>=3&&ind.nonter[1]>='A'&&ind.nonter[1]<='Z'&&IsVt(ind.nonter[2])){ //aQb
					x = FindSub(ind.nonter[0]);
					y = FindSub(ind.nonter[2]);
					table[x][y] = '=';
					}
					}
				}//'='结束 
				//若A→…aB…,则 任意b∈FIRSTVT(B),a<b; 
				if(len>=2){
					if(IsVt(ind.nonter[j])){
					int x=FindSub(ind.nonter[j]);
					if(ind.nonter[j+1]>='A'&&ind.nonter[j+1]<='Z'){
							int lod = T.find(ind.nonter[j+1]);
							for (int m = 0; m < firstvt[lod].length(); m++) {
								int y = FindSub(firstvt[lod][m]);
								table[x][y] = '<';
				}
					}
				}
				}//'<'结束 
//				若A→…Bb…,则 任意a∈LASTVT(B),a>b
				if(ind.nonter[j]>='A'&&ind.nonter[j]<='Z'){
					if(j+1<=ind.nonter.length()-1){
					if(IsVt(ind.nonter[j+1])){
						int x=FindSub(ind.nonter[j+1]);
							int lod = T.find(ind.nonter[j]);
							for (int m = 0; m < lastvt[lod].length(); m++) {
								int y = FindSub(lastvt[lod][m]);
								table[y][x] = '>';//竖着看 
				}
					}
				}
	}
		}
	}
}
int main(){
	string BefSource[3]={{"E->E+T|T"},{"T->T*F|F"},{"F->(E)|i"}};
    for(int i=0;i<3;i++) {
	cout<<BefSource[i]<<endl;
	BefSource[i]=produce(BefSource[i]);
    }  
    cout<<"--------"<<endl;
    add();
	print(); 
	cout<<"--------"<<endl;
	cout<<"FirstVT集:"<<endl;
	for(int len = 0;len < T.length();len++){
		cout<<T[len]<<": "<<firstvt[len]<<" "<<endl;
	}
	 cout<<"--------"<<endl;
	 string foll[20];
	cout<<"LastVT集:"<<endl;
	for(int len = 0;len < T.length();len++){
		for(int j=0;j<lastvt[len].length();j++){
			if(foll[len].find(lastvt[len][j])==-1)
			foll[len]+=lastvt[len][j];
		}
		cout<<T[len]<<": "<<foll[len]<<" "<<endl;
	}
	Vt+='#';
	cout<<"算符优先关系表:"<<endl;
	CreateTable();
  	printTable();
}
  • 5
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
算符优先分析文法是一种工具,在编译的过程中,隶属于语法分析环节,却又与中间代码的生成息息相关,编译可以分为五个阶段:词法分析、语法分析、语义分析(中间代码的生成)、代码优化、目标代码生成。语法分析是指:在词法分析基础上,将单词符号串转化为语法单位(语法范畴)(短语、子句、句子、程序段、程序),并确定整个输入串是否构成语法上正确的程序。也就是说语法分析是检验输入串的语法是否正确,注意这里的语法正确,只是简单地符合自己定义的规范,而不能检测出运行时错误,比如"X/0",空指针错误,对象未初始化等错误。在这一个实验中,我将通过算符优先分析文法这一个工具,在语法分析的时候,顺便进行语义分析,也就是识别出语法单位,同时简要的将识别出的中间代码进行计算(目标代码的生成+运行),得到相应的结果,来检验自己设计的正确性。可以说题目虽然叫做算符优先分析文法,其实却是一个贯穿了“词法分析+语法分析+语义分析+中间代码优化+目标代码生成+运行”全过程的一个极具概括性的程序。如果能将这个程序得心应手的完成出来,我相信诸位对编译原理的掌握也算是炉火纯青了。时隔将近两年再来整理自己以前写过的实验报告,还是挺有感慨的,对一件东西感兴趣,原来影响还会如此深远,还记得自己当时连续六个小时全神贯注写出的实验报告,现在看看竟然写了五六十页,核心内容也有三四十页,不觉的感慨当年充满热情的时代慢慢的竟走出许久
算符优先分析法 C++ 编译原理 运行环境:Visual Studio 2005 #include "SStack.h" #include <iostream> #include <string> using namespace std; class Functor { private : char ** table; string ** production; string prog;//待分析字符串 int p;//字符指针 int num;//终结符个数 int num1;//产生式个数 SStack <char> stack; public: Functor(int m,int n,char ** T,string **prod,string pr) { num=m; num1=n; table=T; production=prod; prog=pr; p=0; stack.push('$'); } void traversal() { while(p<(prog.length())) { stack.display(); cout<<prog.substr(p)<<" "; char ch; if(Getnum(stack.gettop())) { ch=stack.gettop(); } else { ch=stack.getsecond(); } switch(compare(ch,prog[p])) { case 1: case 2:stack.push(prog[p]);p++;cout<<"移入"<<endl;break; case 3:reduct();cout<<"归约"<<endl;break; } } cout<<"分析成功!"<<endl; } int Getnum(char ch) { for(int i=1;i<num;i++) { if(ch==table[i][0]) { return i; } } return 0; } int compare(char col,char row) { int c=Getnum(col); int r=Getnum(row); switch( table[c][r]) { case '>': return 3;break; case '<': return 2;break; case '=': return 1;break; default:cout<<endl<<"输入串有误,程序将终止!"<<endl;system("pause");exit(0);break; } } void reduct() { //待定 string token=""; int temp; string str=""; if(!Getnum(stack.gettop())) { token+=stack.gettop(); stack.pop(); } char ch=stack.gettop(); str+=ch; temp=Haven(str); if(temp!=-1) { token+=production[temp][0]; } else { token+=ch; } stack.pop(); bool Nover=true; while(Nover) { if(Getnum(stack.gettop())) { if(compare(stack.gettop(),ch)==2) { Nover=false; } else { ch=stack.gettop(); str=""; str+=ch; temp=Haven(str); if(temp!=-1) { token+=production[temp][0]; } else { token+=ch; } stack.pop(); } } else { token+=stack.gettop(); stack.pop(); } } string token2=""; //cout<<token<<" "; for(int i=token.length()-1;i>=0;i--) { token2+=token[i]; } //cout<<token2<<endl; if(Haven(token2)!= -1) { stack.push(production[Haven(token2)][0][0]); } else { cout<<"输入串有误!分析终止!"<<endl; system("pause"); exit(0); } } int Haven(string temp) { for(int i=0;i<num1;i++) { int j=1; while(production[i][j]!="") { if(temp==production[i][j]) { return i; } j++; } } return -1; } public: ~Functor(void) { } };
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值