实验目的:
通过程序设计,深入理解利用LL(1)方法进行自顶向下语法分析的过程,提高对数据结构的设计能力和编写程序、调试程序的能力。
实验原理和内容:
- 结合算法实现的需要定义存储文法和LL(1)分析表的数据结构;
- 采用C语言或JAVA语言编程完成LL(1)语法分析过程,判断一个给定的符号串是否能够被该文法接受;
- 有针对性地选择符号串对所编写的语法分析程序进行测试和调试。
话不多说,上代码:
/*
1.S->MH
2.S->a
3.H->LSo
4.H->$
5.K->dML
6.K->$
7.L->eHf
8.M->K
9.M->bLM
*/
#include<bits/stdc++.h>
using namespace std;
const int N=100;
/**********************************************************/
/* 定义变量 */
/**********************************************************/
stack <char> input,sta;//定义输入流栈,语法栈
char ch[N]; //暂存字符串
int len;//记录字符串的长度
int LL[5][7]={2,1,1,1,1,-1,1,
1,-1,-1,3,4,4,4,
-1,-1,5,6,6,-1,6,
-1,-1,-1,7,-1,-1,-1,
-1,9,8,8,8,-1,8};//数字化的分析表
/**********************************************************/
/* 函数声明 */
/**********************************************************/
void init();//初始化栈
bool is_terminal(char ch);// 判断是否为终结符
int nTerminal_int(char ch);//获取非终结符对应的数组下标
int terminal_int(char ch); //获取终结符对应的数组下标
void LL1(stack <char> input,stack <char> sta);//LL(1)分析
void display(); //打印
/**********************************************************/
/* 主函数 */
/**********************************************************/
int main()
{
display();//打印文法以及LL(1)预测表
cout<<"请输入要识别的字符串(以#结束):";
while(cin>>ch[len]&&ch[len++]!='#');//读入字符串
init();//初始化栈
LL1(input,sta);//LL(1)语法分析
return 0;
}
/**********************************************************/
/* 初始化函数 */
/**********************************************************/
void init()
{
//初始化语法栈
sta.push('#');
sta.push('S');
//初始化输入流栈
for(int i=len-1;i>=0;i--)
input.push(ch[i]);
}
/**********************************************************/
/* 判断是否为终结符 */
/**********************************************************/
bool is_terminal(char ch)
{
switch(ch)
{
case 'S':
case 'H':
case 'K':
case 'L':
case 'M': return false;//非终结符
case 'a':
case 'b':
case 'd':
case 'e':
case 'o':
case 'f':
case '#':return true;//终结符
default: cout<<"Unaccept!"<<endl;exit(0);
}
}
/**********************************************************/
/* 获取非终结符对应的数组下标 */
/**********************************************************/
int nTerminal_int(char ch)
{
int x;
switch(ch)//获取非终结符对应的数组下标
{
case 'S':x=0;break;
case 'H':x=1;break;
case 'K':x=2;break;
case 'L':x=3;break;
case 'M':x=4;break;
default: cout<<"Unaccept!"<<endl;exit(0);
}
return x;
}
/**********************************************************/
/* 获取终结符对应的数组下标 */
/**********************************************************/
int terminal_int(char ch)
{
int x;
switch(ch)//获取终结符对应的数组下标
{
case 'a':x=0;break;
case 'b':x=1;break;
case 'd':x=2;break;
case 'e':x=3;break;
case 'o':x=4;break;
case 'f':x=5;break;
case '#':x=6;break;
default: cout<<"Unaccept!"<<endl;exit(0);
}
return x;
}
/**********************************************************/
/* LL(1)文法 */
/**********************************************************/
void LL1(stack <char> input,stack <char> sta)
{
char in,s;//in用于记录输入流的栈顶字符,s用于记录语法栈的栈顶字符
in=input.top();
s=sta.top();
int next;//用于标记下一个文法
while(s!='#')
{
// cout<<"in="<<in<<endl;
// cout<<"sta="<<s<<endl;
//语法栈中遇到终结符
if(is_terminal(s))
{
if(in==s)//语法栈栈顶和输入流栈顶字符相同,同时出栈
{
input.pop();
sta.pop();
}
else//如果都为终结符且不等,则说明不能识别该终结符
{
cout<<"Unaccept!"<<endl;
exit(0);
}
}
//语法栈中遇到非终结符
else
{
sta.pop();//语法栈出栈,接下来进行入栈操作
next=LL[nTerminal_int(s)][terminal_int(in)];//获取对应下一个文法的标号
// cout<<"next="<<next<<endl;
switch(next)//进行入栈操作
{
case 1:sta.push('H');sta.push('M');break;
case 2:sta.push('a');break;
case 3:sta.push('o');sta.push('S');sta.push('L');break;
case 4:break;
case 5:sta.push('L');sta.push('M');sta.push('d');break;
case 6:break;
case 7:sta.push('f');sta.push('H');sta.push('e');break;
case 8:sta.push('K');break;
case 9:sta.push('M');sta.push('L');sta.push('b');break;
case -1:cout<<"unaccept!"<<endl; exit(0);
}
}
//获取语法栈和输入流栈顶位置的字符
in=input.top();
s=sta.top();
}
//结束遍历后,若语法栈和输入流都为结束符#,说明该文法能接收该字符串
if(in=='#'&&s=='#')
cout<<"Accept!"<<endl;
else cout<<"Unaccept!"<<endl;
}
/**********************************************************/
/* 打印函数 */
/**********************************************************/
void display()
{
cout<<"------------文法------------"<<endl;
cout<<"\t 1.S->MH"<<endl;
cout<<"\t 2.S->a"<<endl;
cout<<"\t 3.H->LSo"<<endl;
cout<<"\t 4.H->$"<<endl;
cout<<"\t 5.K->dML"<<endl;
cout<<"\t 6.K->$"<<endl;
cout<<"\t 7.L->eHf"<<endl;
cout<<"\t 8.M->K"<<endl;
cout<<"\t 9.M->bLM"<<endl;
cout<<"----------------------------LL(1)预测表-------------------------"<<endl;
cout<<"\t a \t b \t d \t e \t o \t f \t #"<<endl;
cout<<"----------------------------------------------------------------"<<endl;
cout<<"S |\tS->a\tS->MH\tS->MH\tS->MH\tS->MH\t\tS->MH"<<endl;
cout<<"H |\t\t\t\tH->LSo\tH->$\tH->$\tH->$"<<endl;
cout<<"K |\t\t\tK->dML\tK->$\tK->$\t\tK->$"<<endl;
cout<<"L |\t\t\t\tL->eHf" <<endl;
cout<<"M |\t\tM->bLM\tM->K\tM->K\tM->K\t\tM->K"<<endl;
}
运行结果: