LL(1)文法分析代码

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

   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、若是终结符,则将该终结符加入该非终结符的follow集;

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

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

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

4、求某产生式的select

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

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

水题,直接上代码

#include<bits/stdc++.h>
using namespace std;
string str[50];
int n;
set<char> s[200];
set<char> follow[200];
map<char,string> mp_fei;
map<string , set<char> > select;
string analy[200][200] ;
int flagflag=0;
void judge(){
	for(int i=0;i<n;i++){//1)将各非终结符出示状态置为"未知"
		mp_fei[str[i][0]]="weizhi";
	}
	int flag=1;int p=0; 
	//2)按顺序扫描各产生式右部。分为下面几种情况:
	while(1){ //   e、若上述a,b,c,d过程引起了非终结符状态的改变,则跳到(2)处继续循环,否则跳出循环,判断结束。
		if(flag==0) break;
		p++;
		flag=0;
		for(int i=0;i<n;i++){
			for(int j=3;j<=str[i].size();j++){
				if(str[i][j]=='@'){//a、若遇到符号"ε",检查左部非终结符状态,若不是"空",将其置为"空",继续扫描下一产生式;
					if(mp_fei[str[i][0]]!="null"){
						mp_fei[str[i][0]]="null";
						flag=1;
					}
					break;
					
				}//b、若遇到终结符,检查左部非终结符状态,若为"未知",将其置为"非空",继续扫描下一产生式;
				else if(str[i][j]=='\0'){//d
					if(mp_fei[str[i][0]]!="null"){
						mp_fei[str[i][0]]="null";
						flag=1;	
						break;
					} 
				}
				else if((str[i][j]<'A'||str[i][j]>'Z')){
					if(mp_fei[str[i][0]]=="weizhi"){
						mp_fei[str[i][0]]="notnull";
						flag=1;
					}
					break;
				}//	c、若遇到非终结符,检查该非终结符状态,若为"未知",则跳过当前产生式,扫描下一产生式;
				//若为"非空",检查左部非终结符状态,若为"未知",将其置为"非空",继续扫描下一产生式;
				//若为"空",继续扫描本产生式的下一符号;
				else if(str[i][j]>='A'&&str[i][j]<='Z'){//c
					if(mp_fei[str[i][j]]=="weizhi") break;
					else if(mp_fei[str[i][j]]=="notnull"){
						if(mp_fei[str[i][0]]=="weizhi") {
							mp_fei[str[i][0]]="notnull";
							flag=1;
						}
						break;
					}
					else if(mp_fei[str[i][0]]=="null")	continue;
				}//d、若遇到"\0",检查左部非终结符状态,若不是"空",将其置为"空",继续扫描下一产生式;
			}
		}
	}

}
void first(){
	for(int z=0;z<n;z++){
		for(int i=0;i<n;i++){
		for(int j=3;j<=str[i].size();j++){
			//A、若遇到终结符,将该终结符加入左部非终结符的first集,继续扫描下一产生式;
			//B、若遇到符号"ε",将"ε"加入左部非终结符的first集,继续扫描下一产生式;
			if((str[i][j]<'A'||str[i][j]>'Z')&&str[i][j]!='\0'){
			//	printf(" i==%d j==%d  \n",i,j);
				s[str[i][0]].insert(str[i][j]);
				break;
			}
			//C、若遇到非终结符,将该非终结符的  first集- {ε} 加入左部非终结符的first集,
			else if(str[i][j]>='A'&&str[i][j]<='Z'){
			//	printf("feifeifei i==%d j==%d  \n",i,j);
					set<char> :: iterator it;
					for(it = s[str[i][j]].begin(); it != s[str[i][j]].end(); it++ ){
						if(*it!='@') {
							s[str[i][0]].insert(*it);
						} 
						
					}
					//然后检查该非终结符是否可以推出空,若可以为空,则扫描本产生式的下一符号;若不为空,则继续扫描下一产生式;
					if(mp_fei[str[i][j]]=="null")  continue;
					else break;
			}
			//D、若遇到"\0",将"ε"加入左部非终结符的first集,继续扫描下一产生式;
			else if(str[i][j]=='\0'){
				s[str[i][0]].insert('@');
				break;
			}
		}
	}
	}
}
	
void follow_follow(){
	for(int z=0;z<n;z++){
		for(int i=0;i<n;i++){
			//(1)在产生式右部找到该非终结符,扫描它后面的符号,分为下面几种情况:
			//(2)在产生式的右部继续查找该非终结符,若找到,转(1)步。
			for(int e=3;e<str[i].size();e++){
				if(str[i][e]>='A'&&str[i][e]<='Z'){
					for(int j=e+1;j<=str[i].size();j++){
					//若是终结符,则将该终结符加入该非终结符的follow集;
						if((str[i][j]<'A'||str[i][j]>'Z')&&str[i][j]!='\0'){
							follow[str[i][e]].insert(str[i][j]);
							break;
						}//若是非终结符,将该非终结符的  first集- {ε} 加入该非终结符的folow集,
						//然后检查该非终结符是否可以推出空,若可以为空,则扫描本产生式的下一符号;
						else if(str[i][j]>='A'&&str[i][j]<='Z'){
							set<char> :: iterator it;
							for(it = s[str[i][j]].begin();it!=s[str[i][j]].end();it++){
								if(*it!='@')
								follow[str[i][e]].insert(*it);
							}
							if(mp_fei[str[i][j]]!="null") break; 
						}//若是"\0",则将该产生式的左部非终结符的follow集加入它的follow集。
						else if(str[i][j]=='\0'){
							set<char> :: iterator it;
							for(it = follow[str[i][0]].begin();it!=follow[str[i][0]].end();it++){
								if(*it!='@')
								follow[str[i][e]].insert(*it);
							//	printf("*it===%c\n",*it);
							}
						}
					}
				} 
			}
		}
	}

}
void select_select(){ 
	for(int i=0;i<n;i++){
		//扫描产生式的右部,分为下面几种情况:
		for(int j=3;j<=str[i].size();j++){
//			(1)	若是终结符,则将该终结符加入该产生式的select集;
			
			if((str[i][j]<'A'||str[i][j]>'Z')&&str[i][j]!='\0'&&str[i][j]!='@'){
				select[str[i]].insert(str[i][j]);
				break; 
			}//(2)	若是"ε",将左部非终结符的follow集加入该产生式的select集;
			//(4)	若是"\0",则将该产生式的左部非终结符的follow集加入该产生式的select集。
			else if(str[i][j]=='@'||str[i][j]=='\0'){
				set<char> :: iterator it;
				for(it = follow[str[i][0]].begin();it!=follow[str[i][0]].end();it++){
					select[str[i]].insert(*it) ;
				}
			}//(3)	若是非终结符,将该非终结符的  first集- {ε} 加入该产生式的select集,
			//然后检查该非终结符是否可以推出空,若可以为空,则扫描本产生式的下一符号;
			else if(str[i][j]>='A'&&str[i][j]<='Z'){
				set<char> :: iterator it;
				for(it = s[str[i][j]].begin();it!=s[str[i][j]].end();it++){
					if(*it!='@')
					select[str[i]].insert(*it);
				}
				if(mp_fei[str[i][j]]!="null") break; 
			} 
		}
	}
} 
void menu(){
	printf("\n\n\n                LL(1)语法分析演示程序\n");
		printf("             1.输入LL(1)文法\n");
		printf("             2.显示输入的LL(1)文法\n");
		printf("             3.判断终结符是否为空\n");
		printf("             4.输出非终结符的FIRST集\n");
		printf("             5.输出非终结符的FOLLOW集\n");
		printf("             6.输出非终结符的SELECT集\n");
		printf("             7.分析过程演示\n");
		printf("         请输入你想要的操作:");
}
void inputt(){
	system("cls");
	printf("输入文法产生式的个数(<=50):");
	scanf("%d",&n);
	for(int i=0;i<50;i++){
		str[i].clear();
	}
	for(int i=0;i<n;i++){
		printf("(%d):",i); 
		cin>>str[i]; 
	}
	select.clear();
	mp_fei.clear();	
	for(int i=0;i<200;i++){
		s[i].clear();	
		follow[i].clear();
	}
	flagflag=0;
	judge();
	first();
	follow_follow();
	select_select();
	system("pause");
}
void outputt(){
	system("cls");
	printf("\n\n\n");
	for(int i=0;i<n;i++)
		cout<<"       "<<str[i]<<endl;
	system("pause");
}

















void judge_1(){
	system("cls");
		map<char,string> :: iterator it;
		for(it=mp_fei.begin();it!=mp_fei.end();it++){
		cout<<it->first<<"---------";
		if(it->second=="null") printf("1\n\n");
		else printf("0\n\n");
//		cout<<it->second<<endl;
//		it->second<<endl;
	}
	system("pause");

}
void first_1(){
	system("cls");
	set<char> :: iterator it;
	for(int i='A';i<='Z';i++){
//		printf("s[i].size=====%d",s[i].size());
		if(!s[i].empty()){
			printf("     First(%c): {",i);
			for(it = s[i].begin();it!=s[i].end();it++){
				printf(" %c ",*it);
			}
			printf("}\n\n");
		}
	}
	system("pause");
}
	
void follow_follow_1(){
	system("cls");
	set<char> :: iterator it;
	for(int i='A';i<='Z';i++){
		int f=0;
//		printf("s[i].size=====%d",s[i].size());
		for(int j=0;j<n;j++){
			if(i==str[j][0]) f=1;
		}
		if(!follow[i].empty()||f==1){
			follow[i].insert('#');
			printf("     Follow(%c): {",i);
			for(it = follow[i].begin();it!=follow[i].end();it++){
				printf(" %c ",*it);
			}
			printf(" }\n\n");
		}
	}

	system("pause");
}
void select_select_1(){ 
	system("cls");
	map<string , set<char> > :: iterator it;
	for(it = select.begin();it!=select.end();it++){
		cout<<"       SELECT("<<it->first<<")= {";
		set<char> :: iterator it1;
		for(it1 = it->second.begin();it1!=it->second.end();it1++){
			printf(" %c ",*it1);
		}
		printf(" }\n\n");
	}
	int flag=0;
	for(int i=0;i<n;i++){
		for(int j=i+1;j<n;j++){
			if(str[i][0]==str[j][0]){
				vector<int> ANS;
    			set_intersection(select[str[i]].begin(),select[str[i]].end(),select[str[j]].begin(),select[str[j]].end(),inserter(ANS,ANS.begin()));
				if(!ANS.empty()){
					flag=1;
				}
			}
		}
	}
	if(flag==0) printf("是LL(1)文法!\n");
	else {
		printf("不是LL(1)文法!\n");
		flagflag=1;
	}
	system("pause");
} 
void analyse(){
/*
	    步骤    分析栈  剩余串  产生式或匹配
        1       #E      i+i*i#  E->TR
        2       #RT     i+i*i#  T->FQ
        3       #RQF    i+i*i#  F->i
        4       #RQi    i+i*i#  匹配
        5       #RQ     +i*i#   Q->@
        6       #R      +i*i#   R->+TR
        7       #RT+    +i*i#   匹配
        8       #RT     i*i#    T->FQ
        9       #RQF    i*i#    F->i
        10      #RQi    i*i#    匹配
        11      #RQ     *i#     Q->*FQ
        12      #RQF*   *i#     匹配
        13      #RQF    i#      F->i
        14      #RQi    i#      匹配
        15      #RQ     #       Q->@
        16      #R      #       R->@
        17      #       #       接受
*/
	system("cls");
	if(flagflag==1) {
		printf("\n\n		该文法不是LL(1)文法!!不能进行LL(1)分析!!!");
		system("pause");
		return ;
	}
	printf("请输入要分析的符号串(以#结束):");
	string chuan;
	cin>>chuan;
	for(int i=0;i<200;i++){
		for(int j=0;j<200;j++){
			analy[i][j]="null";
		}
	}
	map<string , set<char> > :: iterator it;
	for(it = select.begin();it!=select.end();it++){
		set<char> :: iterator it1;
		string ss = it->first.substr(3,it->first.size());
		for(it1 = it->second.begin();it1!=it->second.end();it1++){
			analy[it->first[0]][*it1]=ss;
//			cout<<"sit->first[0]==="<<it->first[0]<<"    *it1==="<<*it1<<"      analy==="<<analy[it->first[0]][*it1]<<endl;
		}
	}
	for(it = select.begin();it!=select.end();it++){
		if(it->first[3]=='@'){
			analy[it->first[0]]['#']="@";
		}
	} 
	printf("        步骤    分析栈  剩余串   产生式或匹配\n"); 
	string st ="";
	st= st+"#"+str[0][0];
	int k1=1;
	int k2=0;
	int k3=0;
	string zuizou="";
	string tuidao[20];
	for(int i=0;i<20;i++){
		tuidao[i]="";
	}
	int flag_jieshou=0;
	while(1){
		k3++;
		tuidao[k3]+=zuizou;
		for(int i=st.size()-1;i>0;i--){
			tuidao[k3]+=st[i];
		}
		printf("        %-4d    ",k3);
		cout<<std::left<<setw(8)<<st;
		cout<<std::left<<setw(8)<<chuan;
		char c = st[st.size()-1];
		st = st.substr(0,st.size()-1); 
		if(chuan[k2]=='#'&&c=='#') {
			cout<<std::left<<setw(12)<<"接受"<<endl;
			flag_jieshou=1;
			break; 
		}
		if(c==chuan[0]){
			cout<<std::left<<setw(12)<<"匹配"<<endl;
			zuizou+=chuan[0];
			chuan=chuan.substr(1,chuan.size());
			continue; 
		}
		string ss=analy[c][chuan[0]];
		if(ss=="null"){
			cout<<std::left<<setw(12)<<"分析出错!"<<endl;
			system("pause");
			return ;
		}
		
		string s1="";
		s1=s1+c+"->"+ss;
		cout<<std::left<<setw(12)<<s1<<endl;
		for(int i=ss.size()-1;i>=0;i--){
			st=st+ss[i];
		}
		
		if(ss=="@") {
			st= st.substr(0,st.size()-1);
		}
	}
	int zzz=0;
	if(flag_jieshou){
		printf("\n最左推导:\n");
		for(int i=1;i<=k3;i++){
			if(tuidao[i]==""||tuidao[i]==tuidao[i-1]) continue;
			if(zzz){
				printf("=>");
			}
			cout<<tuidao[i];
			zzz=1;
		} 
		printf("\n\n");
	}
	system("pause");
}

int main(){
	while(1){
		system("cls");
		menu();
		int x;cin>>x; 
		switch(x){
				case 1:
				  inputt();
				  break;
				case 2:
				  outputt();
				  break;
				case 3:
				  judge_1();
				  break;
				case 4:
				  first_1();
					break;
				case 5:
				  follow_follow_1();
				  break;	
				case 6:
				  select_select_1();
				  break;
				case 7:
				  analyse();
				  break;
			}
	}
	 
} 
/*测试用例
8

E->TR

R->+TR

R->@

T->FQ

Q->*FQ

Q->@

F->i

F->(E)



i+i*i#



10

S->AB

S->bC

A->@

A->b

B->@

B->aD

C->AD

C->b

D->aS

D->c
*/

 

 

 

 

  • 6
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
LL(1)文法分析器的C++代码如下: ``` #include <iostream> #include <string> #include <stack> #include <map> using namespace std; // 定义文法符号类型 enum SymbolType { TERMINAL, // 终结符 NONTERMINAL // 终结符 }; // 定义文法符号结构体 struct Symbol { SymbolType type; // 符号类型 string name; // 符号名称 }; // 定义产生式结构体 struct Production { Symbol left; // 产生式左部 vector<Symbol> right; // 产生式右部 }; // 定义LL(1)文法分析器类 class LL1Parser { public: LL1Parser(vector<Production> productions, Symbol startSymbol, vector<Symbol> terminals, vector<Symbol> nonterminals, map<Symbol, map<Symbol, Production>> parsingTable) : productions(productions), startSymbol(startSymbol), terminals(terminals), nonterminals(nonterminals), parsingTable(parsingTable) {} // 分析函数 bool parse(string input) { stack<Symbol> symbolStack; symbolStack.push(Symbol{ TERMINAL, "$" }); // 压入结束符 symbolStack.push(startSymbol); // 压入开始符号 int i = 0; while (!symbolStack.empty()) { Symbol topSymbol = symbolStack.top(); symbolStack.pop(); if (topSymbol.type == TERMINAL) { if (topSymbol.name == "$" && input[i] == '$') { return true; // 分析成功 } else if (topSymbol.name == string(1, input[i])) { i++; } else { return false; // 分析失败 } } else if (topSymbol.type == NONTERMINAL) { Production production = parsingTable[topSymbol][Symbol{ TERMINAL, string(1, input[i]) }]; if (production.left.name != "") { for (int j = production.right.size() - 1; j >= 0; j--) { symbolStack.push(production.right[j]); } } else { return false; // 分析失败 } } } return false; // 分析失败 } private: vector<Production> productions; // 产生式集合 Symbol startSymbol; // 开始符号 vector<Symbol> terminals; // 终结符集合 vector<Symbol> nonterminals; // 终结符集合 map<Symbol, map<Symbol, Production>> parsingTable; // LL(1)分析表 }; // 测试代码 int main() { // 定义文法符号 Symbol E{ NONTERMINAL, "E" }; Symbol T{ NONTERMINAL, "T" }; Symbol F{ NONTERMINAL, "F" }; Symbol plus{ TERMINAL, "+" }; Symbol minus{ TERMINAL, "-" }; Symbol multi{ TERMINAL, "*" }; Symbol div{ TERMINAL, "/" }; Symbol lparen{ TERMINAL, "(" }; Symbol rparen{ TERMINAL, ")" }; Symbol id{ TERMINAL, "id" }; Symbol num{ TERMINAL, "num" }; // 定义产生式 vector<Production> productions{ { E, { T, plus, E } }, { E, { T, minus, E } }, { E, { T } }, { T, { F, multi, T } }, { T, { F, div, T } }, { T, { F } }, { F, { lparen, E, rparen } }, { F, { id } }, { F, { num } } }; // 定义开始符号 Symbol startSymbol = E; // 定义终结符集合和终结符集合 vector<Symbol> terminals{ plus, minus, multi, div, lparen, rparen, id, num }; vector<Symbol> nonterminals{ E, T, F }; // 定义LL(1)分析表 map<Symbol, map<Symbol, Production>> parsingTable{ { E, { { id, productions[0] }, { num, productions[0] }, { lparen, productions[0] }, { plus, productions[0] }, { minus, productions[1] }, { multi, Production{ Symbol{ NONTERMINAL, "" }, {} } }, { div, Production{ Symbol{ NONTERMINAL, "" }, {} } }, { rparen, Production{ Symbol{ NONTERMINAL, "" }, {} } }, { Symbol{ TERMINAL, "$" }, productions[0] } } }, { T, { { id, productions[3] }, { num, productions[3] }, { lparen, productions[3] }, { plus, Production{ Symbol{ NONTERMINAL, "" }, {} } }, { minus, Production{ Symbol{ NONTERMINAL, "" }, {} } }, { multi, productions[3] }, { div, productions[3] }, { rparen, Production{ Symbol{ NONTERMINAL, "" }, {} } }, { Symbol{ TERMINAL, "$" }, productions[3] } } }, { F, { { id, productions[7] }, { num, productions[8] }, { lparen, productions[6] }, { plus, Production{ Symbol{ NONTERMINAL, "" }, {} } }, { minus, Production{ Symbol{ NONTERMINAL, "" }, {} } }, { multi, Production{ Symbol{ NONTERMINAL, "" }, {} } }, { div, Production{ Symbol{ NONTERMINAL, "" }, {} } }, { rparen, Production{ Symbol{ NONTERMINAL, "" }, {} } }, { Symbol{ TERMINAL, "$" }, Production{ Symbol{ NONTERMINAL, "" }, {} } } } } }; // 创建LL(1)文法分析LL1Parser parser(productions, startSymbol, terminals, nonterminals, parsingTable); // 测试分析函数 string input = "id+id*id$"; bool result = parser.parse(input); if (result) { cout << "分析成功" << endl; } else { cout << "分析失败" << endl; } return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值