构造LL(1)文法的递归下降子程序

构造LL(1)文法的递归下降子程序

1、要求

  • 输入:LL(1)文法
  • 输出:递归下降子程序
  • 如:文法G[S]:
    S→AaS|BbS|d
    A→a
    B→ε|e
  • 若输入:aad
    则输出:
    S→AaS
    A→a
    S→d
    句子结构正确!
  • 若输入:aas
    则输出:
    S→AaS
    A→a
    syntax error
    句子结构错误!

2、分析

  1. 输入一个LL(1)文法到字符串数组中
  2. 根据文法计算相应First集、Follow集和Select集
  3. 根据Select集进行设计相应的算法结构
  4. 输入一个表达式
  5. 将该表达式使用上述算法进行推导
  6. 若能够完整推导出,则输出推导过程;若不能推出,则输出错误

3、实验原理

首先我们需要知道如何才能够对其进行设计算法结构?由表达式如何确定相应的文法推导公式?这时select集就能够很好解决该问题。
关于select集及其相关的first集和follow集具体含义和求解方法请看另一篇博客First、Follow、Select
通过select集合即可实现。
如文法G[S]:
S→AaS|BbS|d
A→a
B→ε|e
由另一篇博客可以很快得出select集:
select(S->AaS)=first(A)={a}
select(S->BbS)={first(B)-{ε}}∪first(b)={e,b}
select(S->d)=first(d)={d}
select(A->a)=first(a)={a}
select(B->ε)=first(ε)={ε}
select(B->e)=first(e)={e}
然后就可根据select集进行设计算法。
再算法中就不进行求解select集,默认已经获得select集

4、算法设计

我们大体上将其分成两部分,非终结符和终结符

  1. 从初始符S开始,若表达式第一个字符为a,则表明调用S->AaS产生式,接着跳转到A,终结符,S;若表达式第一个字符为b或e,则表明调用S->BbS,接着跳转到B,终结符,S;若表达式第一个字符为d,则跳转至终结符。
  2. 若跳至A:则表明调用A->a,跳至终结符
  3. 若跳至B:进行判断,若当前判断字符为b,则表明调用B->ε,无操作;若当前判断字符为e,则表明调用B->c,调至终结符。
  4. 若跳至终结符:则将该终结符和当前判断字符进行比较,若相同,则继续,若不同,则输出有错。
  5. 所有执行完毕,若当前判断字符为#,则表明表达式所有字符均以匹配,反之,则不匹配。

5、实验过程

  1. 初始化,输入待判断的表达式:
 //初始化,输入LL(1)文法和待判断表达式 
void Init(){
	int i;
	cout<<"LL(1)文法为:"<<endl;
	cout<<"S->AaS|BbS|d"<<endl;
	cout<<"A->a"<<endl;
	cout<<"B->ε|e"<<endl;
	cout<<"输入表达式:"<<endl;
	for(i=0;;i++){//LL(1)文法已#结尾 
		cin>>str[i];
		if(str[i]=='#')
		break;
	}
	n=i;
	S();//转入判断 
}
  1. 初始符S:
//左边非终结符S 
void S(){
	switch(str[temp]){
		case 'a':
			cout<<"S->AaS"<<endl;
			A();
			Match('a');
			S();
			break;
		case 'b':
		case 'e':
			cout<<"S->BbS"<<endl;
			B();
			Match('b');
			S();
			break;
		case 'd':
			cout<<"S->d"<<endl;
			Match('d');
			break;
	    default:
	    	cout<<"syntax error"<<endl;
		 
	}		
}
  1. 非终结符A:
//左边非终结符A 
void A(){
	cout<<"A->a"<<endl;
	Match('a');
}
  1. 非终结符B:
//左边非终结符B 
void B(){
	if(str[temp]=='b')
	cout<<"B->ε"<<endl;
	else if(str[temp]=='e'){
    	cout<<"B->e"<<endl;
		Match('e');
	}
	else
	cout<<"syntax error"<<endl;
}

  1. 终结符
//进行字符串匹配的判断 
void Match(char ss){//终结符的匹配 
	if(str[temp]!=ss)
	cout<<"syntax error"<<endl;
	else
	temp++;
}

  1. 判断,确定该表达式是否符合:
//判断,该表达式是否匹配 
void Judge(){
	if(str[temp]=='#')//判断是否表达式已全部处理 
	cout<<"句子结构正确!"<<endl;
	else
	cout<<"句子结构错误!"<<endl;
}

6、结果展示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

7、源代码

代码已经过编译,可直接使用

#include<iostream>
using namespace std;
 
//全局变量 
char str[10];//存储待判断表达式 
int n;//存储表达式行数 
int temp=0;//当前匹配字符 
int k=0;//中止符 

void S();//左侧非终结符S 
void A();//左侧非终结符A 
void B();//左侧非终结符B 
void Match(char);//判断字符的匹配 

//初始化,输入LL(1)文法和待判断表达式 
void Init(){
	int i;
	cout<<"LL(1)文法为:"<<endl;
	cout<<"S->AaS|BbS|d"<<endl;
	cout<<"A->a"<<endl;
	cout<<"B->ε|e"<<endl;
	cout<<"输入表达式:"<<endl;
	for(i=0;;i++){//LL(1)文法已#结尾 
		cin>>str[i];
		if(str[i]=='#')
		break;
	}
	n=i;
	S();//转入判断 
}

//左边非终结符S 
void S(){
	switch(str[temp]){
		case 'a':
			cout<<"S->AaS"<<endl;
			A();
			Match('a');
			S();
			break;
		case 'b':
		case 'e':
			cout<<"S->BbS"<<endl;
			B();
			Match('b');
			S();
			break;
		case 'd':
			cout<<"S->d"<<endl;
			Match('d');
			break;
	    default:
	    	k=1; 
	    	cout<<"syntax error"<<endl;
		 
	}		
}

//左边非终结符A 
void A(){
	cout<<"A->a"<<endl;
	Match('a');
}

//左边非终结符B 
void B(){
	if(str[temp]=='b')
	cout<<"B->ε"<<endl;
	else if(str[temp]=='e'){
    	cout<<"B->e"<<endl;
		Match('e');
	}
	else{
		k=1;
		cout<<"syntax error"<<endl;
	}
}

//进行字符串匹配的判断 
void Match(char ss){//终结符的匹配 
	if(str[temp]!=ss){
		k=1;
    	cout<<"syntax error"<<endl;
    }
	else
	temp++;
}

//判断,该表达式是否匹配 
void Judge(){
	if(str[temp]=='#'&&k==0)//判断是否表达式已全部处理 
	cout<<"句子结构正确!"<<endl;
	else
	cout<<"句子结构错误!"<<endl;
}

//主函数 
int main(){
	Init();//初始化 
	Judge();//判断 
} 











如有任何问题,请留言说明,24小时内回复。谢谢!
在这里插入图片描述

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值