编译原理之LL(1)语法分析实验(附完整C/C++代码与测试)

这篇具有很好参考价值的文章主要介绍了编译原理之LL(1)语法分析实验(附完整C/C++代码与测试)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

编译原理语法分析实验源代码,计算机核心课程,编译原理

一、实验内容与要求

  • 先从键盘读入要分析的文法,由程序自动构造FIRST、FOLLOW 集以及SELECT集合,判断是否为LL (1)文法。

分析文法为G[E]:

(0)E→ TE’  

(1)E’→ +TE’

(2)E’→ε   

(3)T→ FT’

(4)T’→ *FT’  

(5)T’→ε    

(6)F→ (E)  

 (7)F→a

  • 若符合LL (1)文法,由程序自动构造LL (1)分析表;
  • 由算法判断给定的输入符号串a*(a+a)是否为该文法的句型。

二、实验代码

#include<iostream>
#include<stdio.h>
#include<vector>
#include<string>
#include<stack>
#include<map>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include <bits/ios_base.h>
using namespace std;
map<char,int>getnum;
vector<char>getzf;  
vector<string>proce(10);
vector<string>first(20);
vector<string>follow(20);
int table[100][100];      //预测分析表
int num;
int numv;//终结符的数量-1
char j[2];

//读取终结符、非终结符与产生式 
void  read()
{
	char c;
	int i=0;
	int n=0;
	cout<<"******************************LL(1)语法分析****************************"<<endl; 
	cout<<"注意:E'用H代替,T‘用J代替,空串用@代替 "<<endl;
	cout<<"请输入产生式的集合(空用'@'表示),输入一条产生式后换行,最后以'end'结束:"<<endl;
	string ss;
	string dd;
	int j=0;
	int y=0;
	while(cin>>ss&&ss!="end")
	{		 
		dd.clear();
		dd+=ss[0];
		proce[j]+=dd;
		for(i=3;i<ss.length();i++)
		{	
			if(ss[i]!='|'){
				dd.clear();
				dd+=ss[i];
				proce[j]+=dd;
		    } 
			else{
			dd.clear();
			dd+=ss[0];
			dd+=ss[++i];
			proce[++j]+=dd;
		}	
	}
	j++;
}
getnum['#']=0;//#代表结束标志 
//	getzf[0]='#';没有定义数组大小的时候这样输入是错误的 
getzf.push_back('#');
//终结符压栈 
for(int i=0;i<proce.size();i++)
{
	for(int k=0;k<proce[i].length();k++)
	{
		if(proce[i][k]!='-'&&proce[i][k]!='|')
		{
			if(proce[i][k]<64||proce[i][k]>90)
			{
			 	 for( y=0;y<getzf.size();y++){
				 	if(proce[i][k]==getzf[y]) 
					  break;
				 }
				 if(y==getzf.size()&&k!=2){//这里让k!=2是不让第三位置的>进去 
				 getnum[proce[i][k]]=++n;
				 getzf.push_back(proce[i][k]);
				}
			}
		}	  
	}
}
 getnum['@']=++n;
 numv=n;//终结符的数量等于当前n的值 
 getzf.push_back('@');
 //非终结符压栈 
	for(int i=0;i<proce.size();i++)
	{
		for(int k=0;k<proce[i].length();k++)
		{
			if(proce[i][k]!='-'&&proce[i][k]!='|'&&proce[i][k]!='>')
			{
				if(proce[i][k]>64&&proce[i][k]<91)
				{
				 	 for( y=0;y<getzf.size();y++){
					 	if(proce[i][k]==getzf[y]) 
						  break;
					 }
					 if(y==getzf.size()){
					 getnum[proce[i][k]]=++n;
					 num=n;//终结符加非终结符的数量等于当前i的值 
					 getzf.push_back(proce[i][k]);
					}
				}
			}	  
		}
	}
}

//给终结符的first数组赋值
void get_firstT()
{
	int i;//不能在下面int 
	//先给终结符的first数组赋值
	for( i=1;i<=numv;i++) 
	{
			itoa(i,j,10);
    		first[i]=j;//之前写的是first[i].push_back(j[0])是错的,字符串数组的输入不需要加下标,且如果是j[0]一个字符不能装到一个字符串当中去 
	}
}

//给非终结符的first数组赋值
string get_firstF(int *a)
{//犯了一个错误,下面的a没有加* 
	for(int i=0;i<proce.size();i++)
	{
		if(getnum[proce[i][0]]==*a)
		{
	   		if(getnum[proce[i][1]]<=numv)
			{
				itoa(getnum[proce[i][1]],j,10); 
				first[*a]+=j;
			}
			else
			{ 
				//first[getnum[proce[i][0]]].clear();
				first[getnum[proce[i][0]]]=get_firstF(&getnum[proce[i][1]]);
			}
	} 	
	}
	return first[*a]; 
} 

//求follow集 
void  get_follow(int *a){
//犯了一个错误,以stirng开头但是没有返回值 
	int i,j1;
	int flag=0;
	for(i=0;i<proce.size();i++)
	{
		for(j1=1;j1<proce[i].length();j1++)
		{
			if(getnum[proce[i][j1]]==*a)//这地方应该是j1我写成了k 
			{
			if(j1==proce[i].length()-1)
				{
				if(getnum[proce[i][j1]]!=getnum[proce[i][0]])
				follow[*a]+=follow[getnum[proce[i][0]]]; 
			}
			else 
			{
			if(getnum[proce[i][j1+1]]<=numv)	
				{
						itoa(getnum[proce[i][j1+1]],j,10);
						follow[*a]+=j;
				}
			else
				{
					for(int jj=0;jj<first[getnum[proce[i][j1+1]]].size();jj++) 
					{
						if(atoi(&first[getnum[proce[i][j1+1]]][jj])==numv)//等于空时
						follow[*a]+=follow[getnum[proce[i][0]]];
						else
						follow[*a]+=first[getnum[proce[i][j1+1]]][jj];
					}
					flag=1;//标志位,如果已经找到*a后面的非终结符就可以停止了 
			}
		}
		}
		 } 
		 
		 	if(flag==1) break; //停止寻找 
	}
}


//求预测分析表
void get_table()          
{
	memset(table,-1,sizeof(table));//刚开始tableM没有初始化,导致本该是空格的地方出现E->TA 
   for(int i=0;i<proce.size();i++)   //扫所有产生式
   {
       if(proce[i][1]=='@')     //直接推出空字的,特判下(follow集=产生式左边的vn中元素填)
          {
             string flw=follow[getnum[proce[i][0]]];
             for(int k=0;k<flw.size();k++)
             {
               table[getnum[proce[i][0]]][flw[k]-'0']=i;
             }
          }
       string temps=first[getnum[proce[i][1]]];
       for(int j=0;j<temps.size();j++)               //考察first集
       {
       	if(atoi(&temps[j])!=numv) 
       	{
               // table[getnum[proce[i][0]]][atoi(&temps[j])]=i;//atoi不能这么用,他表示的是从当前位一直到末位 
              table[getnum[proce[i][0]]][temps[j]-'0']=i;
           }
           else                                     //有空字的,考察follw集
           {
               string flw=follow[getnum[proce[i][1]]];
              for(int k=0;k<flw.size();k++)
             {
                 table[getnum[proce[i][0]]][flw[k]-'0']=i;
             }
           }
       }
   }
}

//由对应下标获得对应产生式
string get_proce(int i) 
{
    if(i<0)return " ";    //无该产生式
    string ss;
    ss+=proce[i][0];
    ss+="->";		//把->要加上 
    for(int j=1;j<proce[i].size();j++)
       ss+=proce[i][j];
   return ss;
}

//输出预测分析表 
void print_table()
{
    cout<<"该文法对应的预测分析表如下:"<<endl;
    cout<<"________________________________________________________"<<endl;
   for(int i=0;i<numv;i++)
      cout<<'\t'<<getzf[i];
      cout<<endl;
   for(int i=numv+1;i<=num;i++)
    {
    	cout<<endl<<"________________________________________________________"<<endl;
       cout<<getzf[i];
       for(int j=0;j<numv;j++)
       {
           cout<<'\t'<<get_proce(table[i][j])<<"";
       }
    }
    	cout<<endl<<"________________________________________________________"<<endl;
     cout<<endl;
}

//打印栈中元素
void print_stack(stack<char>sta){
	int length=sta.size();//栈中元素数目
	vector<char>temp;
	for(int i=0;i<length;i++){
		//cout<<sta.top();
		temp.push_back(sta.top());
		sta.pop();
	} 
	for(int j=length-1;j>=0;j--){
		cout<<temp[j];
		
	}
	cout<<"\t\t";
} 

//打印判定串的当前元素
void print_string(string str,int index){
	int length=str.size();
	for(int i=index;i<length;i++){
		cout<<str[i];
	}
	cout<<'#';
	cout<<"\t\t";
}


//分析word符号串的合法性(关键)
string word;
bool analyze()       
{
    stack<char>sta;//分析栈 
    sta.push('#');  //#最先进栈 
	sta.push(proce[0][0]);//将开始符压入分析栈中进行初始化 
    int i=0;
	int count=1;//步骤计数  
    printf("步骤\t\t分析栈\t\t判定串\t\t使用规则\n");//表头 
    while(!sta.empty())
    {
       cout<<count<<"\t\t";
       print_stack(sta);//打印当前分析栈 
       print_string(word,i);//打印当前判定串 
       int cur=sta.top();//取出分析栈的栈顶元素 
       sta.pop();
       if(cur==word[i])       //如果分析栈的栈顶元素与判定串的第一个元素相同(即是终结符的话),则匹配成功,分析栈弹出栈顶元素 
       {
           i++;
           printf("匹配出栈\n");
       }
       else  if(cur=='#')   //如果分析栈的栈顶元素为#则表面分析结束
       {
           return 1;
       }
       else  if(table[getnum[cur]][getnum[word[i]]]!=-1) //查找对应的预测分析表 
       {
 
           int k=table[getnum[cur]][getnum[word[i]]];
           cout<<proce[k][0]<<"->";
           for(int j=1;j<proce[k].size();j++)
               cout<<proce[k][j];
           cout<<endl;
           //将使用的产生式逆序加入分析栈中,以取代上一个出栈的元素 
           for(int j=proce[k].size()-1;j>0;j--)  
                {  if(proce[k][j]!='@')
                   sta.push(proce[k][j]);
                }
       }
       else     
       {
           return 0;
       }
       count++;
    }
    return 1;
}


//输入待判断的符号串 
void scanf()  
{
	cout<<"请输入待判定的符号串:";
    cin>>word;
    cout<<"判断分析表如下:"<<endl; 
    if(analyze())
        cout<<endl<<"综上:该符号串有效,是该文法的句型!"<<endl;
    else   
		cout<<endl<<"出错,该符号串不是该文法的句型!"<<endl;
}


int main()
{
	int k;
	int j;
	read();
	//终结符的first集 
	get_firstT();
	//非终结符的first集 
	for(k=numv+1;k<=num;k++) //犯了一个错误,numv的位置写成7 
	{
		get_firstF(&k);
	}

		follow[numv+1]+='0'; //这地方加的是0而不是# 
		for(k=numv+1;k<=num;k++) //犯了一个错误,numv的位置写成7 
	{
		 get_follow(&k);
	}
     cout<<endl;  
     get_table();
     print_table();
     scanf();	
     return 0;
}
/*测试数据: 
注意:E'用H代替,T‘用J代替,空串用@代替 
E->TH
H->+TH
H->@
T->FJ
J->*FJ
J->@
F->(E)
F->a
end
*/

三、实验结果

编译原理语法分析实验源代码,计算机核心课程,编译原理

编译原理语法分析实验源代码,计算机核心课程,编译原理END.

 文章来源地址https://www.toymoban.com/news/detail-759665.html

到了这里,关于编译原理之LL(1)语法分析实验(附完整C/C++代码与测试)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 研究性学习专题 3_LL(1)语法分析设计原理与实现

    实现 LL(1)分析中控制程序(表驱动程序);完成以下描述赋值语句的 LL(1)文法的 LL(1)分析过程。重点 LL(1)分析方法和 LL(1)分析器的实现。G[S]: S→ V=E E→ TE’ E’→ ATE’ | e T→ FT’ T’→ MFT’ | E F→ (E) | i A→ + | - M→ * | / V→ i 设计说明:终结符号 i 为用户定义的简单变量,即

    2024年02月03日
    浏览(29)
  • 编译原理——语法分析器(C/C++代码实现)

    编写一个简单的LL(1)语法分析器。(注意:此实验是简化版的LL(1)文法,已给出预测分析表,不需要求FIRST和FOLLOW集,直接根据预测分析表编写程序即可) 根据编译原理理论课中学习的算术表达式文法,以及该文法LL(1)分析表,用C语言编写接受算术表达式为输入的语法

    2023年04月26日
    浏览(30)
  • 【编译原理】LL(1)分析法:C/C++实现

      🌈 个人主页: Sarapines Programmer 🔥  系列专栏: 《编译原理奇遇记》 🔖墨香寄清辞:空谷幽篁风动,梦中仙鹤月明。 辗转千秋豪情在,乘风翱翔志不移。 目录结构 1. 编译原理之LL(1)分析法概念 1.1 编译原理 1.2 LL(1)分析法 2. LL(1)分析法 2.1 实验目的 2.2 实验要求 2.3 实验内

    2024年02月02日
    浏览(30)
  • 编译原理——SLR(1)语法分析器(C/C++代码实现)

    设计、编制、实现并调试SLR(1)语法分析器,加深对语法分析的理解。 根据编译原理理论课中学习的算术表达式文法以及该文法的LR分析表,用C语言编写接受算术表达式为输入的语法分析器,以控制台(或文本文件,也可以结合词法分析器完成)为输入,控制台(或文件)

    2024年02月11日
    浏览(31)
  • 编译原理——语法分析

    原文链接请访问https://code-child.cn lm表示的是最左 例子 例子 比如求x的first集合,那么就是求的x—字符串,所有字符串首字母构成的集合 计算需要反复 算法 预测分析表 预测分析中的错误检测 预测分析中的错误恢复 例子: M表示预测分析表,A表示栈顶的非终结符,a表示当前

    2024年02月06日
    浏览(28)
  • 编译原理-6-LR语法分析器

    自顶向下的、不断归约的、基于句柄识别自动机的、适用于LR(∗) 文法的、LR(∗) 语法分析器 只考虑无二义性的文法 自底向上 构建语法分析树 根节点 是文法的起始符号 S S S 每个中间 非终结符节点 表示 使用它的某条产生式进行归约 叶节点 是词法单元$w$$ 仅包含终结符号与

    2024年02月05日
    浏览(34)
  • 编译原理2.3习题 语法制导分析[C++]

    图源:文心一言 编译原理习题整理~🥝🥝 作为初学者的我,这些习题主要用于自我巩固。由于是自学,答案难免有误,非常欢迎各位小伙伴指正与讨论!👏💡 第1版:自己的解题,与AI老师的判卷~🧩🧩 编辑: 梅头脑🌸  审核: 文心一言 题源: 龙书《编译原理》 Alfre

    2024年01月25日
    浏览(38)
  • 【编译原理】-- 递归下降语法分析设计原理与实现(C语言实现)

    本实验基于词法分析程序实现,可参考本人前面的文章。 目录 一、目标任务 二、程序功能描述 三、主要数据结构描述 四、程序结构描述 设计方法 First集和Follow集 递归子程序框图 函数定义及函数之间的调用关系 五、程序测试 测试用例1 测试结果1 测试用例2 测试结果2 测试

    2023年04月21日
    浏览(36)
  • 编译原理:算符优先分析实验

    什么是算符优先分析法 算符优先分析法是一种简单、直观的自下而上分析法 算符优先分析法就是仿照算术表达式的四则运算过程而设计的一种语法分析方法。 这种分析方法首先要规定运算符之间(确切地说终结符之间)的优先关系和结合性质,然后借助这种关系,比较相邻

    2024年02月06日
    浏览(26)
  • 编译原理语法分析器(C/C++)(LR1文法)

            来写语法分析器了,有可能是老师不一样也有可能是学校不一样,我要做的语法分析器复杂一点,额,现在想来也不复杂(可能)。         这一次的实验是要进行语法分析,是要用LL1或者递归下降分析法或LR分析法(LR0、LR1)设计语法分析程序。这次我也是先去百

    2024年02月07日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包