构造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、分析
- 输入一个LL(1)文法到字符串数组中
- 根据文法计算相应First集、Follow集和Select集
- 根据Select集进行设计相应的算法结构
- 输入一个表达式
- 将该表达式使用上述算法进行推导
- 若能够完整推导出,则输出推导过程;若不能推出,则输出错误
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、算法设计
我们大体上将其分成两部分,非终结符和终结符
- 从初始符S开始,若表达式第一个字符为a,则表明调用S->AaS产生式,接着跳转到A,终结符,S;若表达式第一个字符为b或e,则表明调用S->BbS,接着跳转到B,终结符,S;若表达式第一个字符为d,则跳转至终结符。
- 若跳至A:则表明调用A->a,跳至终结符
- 若跳至B:进行判断,若当前判断字符为b,则表明调用B->ε,无操作;若当前判断字符为e,则表明调用B->c,调至终结符。
- 若跳至终结符:则将该终结符和当前判断字符进行比较,若相同,则继续,若不同,则输出有错。
- 所有执行完毕,若当前判断字符为#,则表明表达式所有字符均以匹配,反之,则不匹配。
5、实验过程
- 初始化,输入待判断的表达式:
//初始化,输入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:
//左边非终结符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;
}
}
- 非终结符A:
//左边非终结符A
void A(){
cout<<"A->a"<<endl;
Match('a');
}
- 非终结符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;
}
- 终结符
//进行字符串匹配的判断
void Match(char ss){//终结符的匹配
if(str[temp]!=ss)
cout<<"syntax error"<<endl;
else
temp++;
}
- 判断,确定该表达式是否符合:
//判断,该表达式是否匹配
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小时内回复。谢谢!