/*本程序是递归下降分析法中预测分析法的实现,文法从文件中读入,程序可以根据产生式自动求出FIRST集和FOLLOW集,并自动构造预测分析表M[][][],欢迎各位大虾批评指正*/
/*
所用文法:
E->TA
A->+TA
A->`
T->FB
B->*FB
B->`
F->(E)
F->
*/i
/*结束符号是$;
空字符串是`;
vn[]中第一个字符是开始符号;
FIRST集、FOLLOW集和分析表M的字符顺序和vt[]及vn[]一致
*/
#include<iostream>
#include<stdio.h>
#include<fstream>
#include<malloc.h>
using namespace std;
#define OK 1
#define ERROR 0
#define N 200
#define Y 20
int vtnum,vnnum,pronum;
int FIRST[N][N];
int FOLLOW[N][N];
char M[N][N][N];
char vt[N];
char vn[N];
char old[N][N];//用于存储产生式
char stack[N]={'/0'};//为堆栈赋初值
int sp=0;//栈顶指针
int p1=0;//输入句型指针
bool HaveEmpty(char);
int addfirst(char,char);
int addfollow(char,char,int);
int first(char);
int follow(char);
int printf_ff();
int InitAnalysis();
int analysis();
int printf_table();
int control();
int main()
{
int i,j;
ifstream in("input1.txt",ios_base::in);//读文件,从文件中读入pronum,vtnum,vnnum以及产生式
for(i=0;i<N;i++)
for(j=0;j<N;j++)
old[i][j]='/0';
in>>pronum>>vnnum>>vtnum;
in>>vn;
in>>vt;
for(i=0;i<pronum;i++)
in>>old[i];//将产生式存入old[][]
for(i=0;i<vnnum;i++)
for(j=0;j<=vtnum;j++)
FIRST[i][j]=0;//初始化FIRST集
for(i=0;i<vnnum;i++)
first(vn[i]);//对每个vn求FIRST集
for(i=0;i<vnnum;i++)
for(j=0;j<=vtnum;j++)
FOLLOW[i][j]=0;//初始化FOLLOW集
for(i=0;i<vnnum;i++)
follow(vn[i]);//对每个vn求FOLLOW集
printf_ff();
InitAnalysis();
analysis();
printf_table();
control();
printf("/n谢谢使用!/n");
return OK;
}
//求一个非终结符U的FIRST集,FIRST集的符号顺序和vn,vt相同
int first(char U)
{
int i,j,k,m,p,flag;
for(i=0;i<pronum;i++)
{
if(old[i][0]==U)//找到U所对应的产生式
{
p=1;
if(old[i][p]=='`')//产生式右部为空
{
for(j=0;j<vnnum;j++)
{
if(vn[j]==U)
break;
}
FIRST[j][vtnum]=1;
}
else//产生式右部非空
{
while(old[i][p]!='/0')
{
for(j=0;j<vtnum;j++)//判断右部首字符的类型
{
if(vt[j]==old[i][p])
break;
}
if(j<vtnum)//右部首字符是终结符
{
addfirst(U,old[i][p]);
break;
}
else//非终结符
{
for(k=0;k<vnnum;k++)
{
if(vn[k]==old[i][p])
break;
}
flag=0;
for(m=0;m<=vtnum;m++)
{
if(FIRST[k][m]==1)
{
flag=1;
break;
}
}
if(flag==0)//FIRST集未被求过
first(old[i][p]);
addfirst(U,old[i][p]);
if(HaveEmpty(old[i][p]))//首字符FIRST集是否含空,如果是,向后继续,否则跳出while循环
p++;
else
break;
}
}
}
}
}
return OK;
}
//加入FIRST集
int addfirst(char U,char c)
{
int i,j,k,m;
for(i=0;i<vtnum;i++)
{
if(vt[i]==c)
break;
}
if(i<vtnum)
{
for(j=0;j<vnnum;j++)
{
if(vn[j]==U)
break;
}
FIRST[j][i]=1;
}
else
{
for(j=0;j<vnnum;j++)
{
if(vn[j]==U)
break;
}
for(m=0;m<vnnum;m++)
{
if(vn[m]==c)
break;
}
for(k=0;k<=vtnum;k++)//把空字符加入
{
if(FIRST[m][k]==1)
FIRST[j][k]=1;
}
}
return OK;
}
//判断FIRST集中是否包含空字符
bool HaveEmpty(char c)
{
int i,j;
for(i=0;i<vtnum;i++)//如果是终结符,返回false
{
if(vt[i]==c)
break;
}
if(i<vtnum)
return false;
else
{
for(j=0;j<vnnum;j++)
{
if(vn[j]==c)
break;
}
if(FIRST[j][vtnum]==1)
return true;
else
return false;
}
}
//求一个非终结符U的FOLLOW集
int follow(char U)
{
int i,j,k,p,flag;
char ch;
FOLLOW[0][vtnum]=1;//把$加入开始符
for(i=0;i<pronum;i++)
{
p=1;
while(old[i][p]!='/0'&&old[i][p]!=U)//在产生式右部找寻U
p++;
if(old[i][p]==U)
{
ch=old[i][p++];//p指向U的下一个字符
if(old[i][p]=='/0')//如果U是右部最后一个字符,把左部的FOLLOW集加
{
for(j=0;j<vnnum;j++)
{
if(old[i][0]==vn[j])
break;
}
flag=0;
for(k=0;k<=vtnum;k++)
{
if(FOLLOW[j][k]==1)
{
flag=1;
break;
}
}
if(flag==0&&old[i][0]!=U)//左部FOLLOW集未被求过,左部字符和U不同
follow(old[i][0]);
addfollow(U,old[i][0],0);
}
else//U不是最后一个字符
{
while(HaveEmpty(old[i][p])&&old[i][p]!='/0')//判断U的下一个字符old[i][p]是否包含空,如果含空,除把FIRST(old[i][p])加入外,还应把FOLLOW(old[i][0])加入,并考虑old[i][p+1]
{
addfollow(U,old[i][p],1);
for(j=0;j<vnnum;j++)
{
if(old[i][0]==vn[j])
break;
}
flag=0;
for(k=0;k<=vtnum;k++)
{
if(FOLLOW[j][k]==1)
{
flag=1;
break;
}
}
if(flag==0&&old[i][0]!=U)
follow(old[i][0]);
addfollow(U,old[i][0],0);
p++;
}
if(!HaveEmpty(old[i][p]))//如果FIRST(old[i][p])不含空,就只把FIRST(old[i][p])加入
addfollow(U,old[i][p],1);
}
}
}
return OK;
}
//加入FOLLOW集,kind=0表示将FOLLOW加入,kind=1表示将FIRST加入
int addfollow(char U,char c,int kind)
{
int i,j,k,m;
for(i=0;i<vtnum;i++)
{
if(vt[i]==c)
break;
}
if(i<vtnum)
{
for(j=0;j<vnnum;j++)
{
if(vn[j]==U)
break;
}
FOLLOW[j][i]=1;
}
else
{
if(kind==0)
{
for(j=0;j<vnnum;j++)
{
if(vn[j]==U)
break;
}
for(m=0;m<vnnum;m++)
{
if(vn[m]==c)
break;
}
for(k=0;k<=vtnum;k++)
{
if(FOLLOW[m][k]==1)
FOLLOW[j][k]=1;
}
}
else
{
for(j=0;j<vnnum;j++)
{
if(vn[j]==U)
break;
}
for(m=0;m<vnnum;m++)
{
if(vn[m]==c)
break;
}
for(k=0;k<vtnum;k++)//不把空字符加入
{
if(FIRST[m][k]==1)
FOLLOW[j][k]=1;
}
}
}
return OK;
}
//输出FIRST和FOLLOW
int printf_ff()
{
int i,j;
printf("注:1代表在集合中,0代表不在集合中/nFIRST集为:/n ");
for(i=0;i<vtnum;i++)
printf("%c ",vt[i]);
printf("` /n");
for(i=0;i<vnnum;i++)
{
printf("%c ",vn[i]);
for(j=0;j<=vtnum;j++)
printf("%d ",FIRST[i][j]);
printf("/n");
}
printf("/nFOLLOW集为:/n ");
for(i=0;i<vtnum;i++)
printf("%c ",vt[i]);
printf("$ /n");
for(i=0;i<vnnum;i++)
{
printf("%c ",vn[i]);
for(j=0;j<=vtnum;j++)
printf("%d ",FOLLOW[i][j]);
printf("/n");
}
return OK;
}
//初始化预测分析表
int InitAnalysis()
{
int i,j;
for(i=0;i<vnnum;i++)
for(j=0;j<=vtnum;j++)
{
M[i][j][0]='0';
M[i][j][1]='/0';
}
return OK;
}
//构造预测分析表
int analysis()
{
int i,j,k,m,n,x,z,p;
for(x=0;x<pronum;x++)
{
if(old[x][1]!='`')//如果右部非空
{
for(i=0;i<vtnum;i++)
{
if(vt[i]==old[x][1])
break;
}
if(i<vtnum)
{
for(j=0;j<vnnum;j++)
{
if(vn[j]==old[x][0])
break;
}
p=1;
k=0;
while(old[x][p]!='/0')
{
M[j][i][k]=old[x][p];
k++;
p++;
}
M[j][i][k]='/0';
}
else
{
for(m=0;m<vnnum;m++)
{
if(vn[m]==old[x][1])
break;
}
for(j=0;j<vnnum;++j)
{
if(vn[j]==old[x][0])
break;
}
for(z=0;z<vtnum;z++)
{
if(FIRST[m][z]==1)
{
p=1;
k=0;
while(old[x][p]!='/0')
{
M[j][z][k]=old[x][p];
k++;
p++;
}
M[j][z][k]='/0';
}
}
}
}
else//产生式右部是空
{
for(m=0;m<vnnum;m++)
{
if(old[x][0]==vn[m])
break;
}
for(n=0;n<=vtnum;n++)
{
if(FOLLOW[m][n]==1)
{
M[m][n][0]='`';
}
}
}
}
return OK;
}
//输出预测分析表
int printf_table()
{
int i,j,k,m;
printf("%c",M[0][1][1]);
printf("/n预测分析表为:/n");;
printf(" ");
for(i=0;i<vtnum;i++)
{
printf("%c ",vt[i]);
}
printf("$ /n");
for(i=0;i<vnnum;i++)
{
printf("%c ",vn[i]);
for(j=0;j<=vtnum;++j)
{
for(k=0;M[i][j][k]!='/0';k++)
{
printf("%c",M[i][j][k]);
}
for(m=1;m<=10-k;++m)
printf(" ");
}
printf("/n");
}
return OK;
}
//总控程序
int control()
{
int i,j,k,m,n,x,flag=0;
char c1[20]={'/0'};
char c2;//c1存放待分析字符串的当前字符,c2存放已弹出的栈顶元素
stack[sp++]='$';
stack[sp++]=vn[0];
printf("/n请输入要分析的句型(以$结尾):");
cin>>c1;
printf("/n分析过程:/n分析栈 输入串 所用规则 ");
while(c1[p1]!='/0')
{
printf("/n");
for(i=0;stack[i]!='/0';i++)
printf("%c",stack[i]);
for(k=0;k<Y-i;k++)
printf(" ");//输出栈内情况
m=0;
for(i=p1;c1[i]!='/0';i++)
{
printf("%c",c1[i]);
m++;
}
for(i=0;i<Y-m;i++)
printf(" ");//输出当前字符串
c2=stack[sp-1];
stack[sp-1]='/0';
sp--;//弹出栈顶元素,并把栈顶后一位赋值为'/0',sp指向栈顶后一位
for(i=0;i<vtnum;i++)
{
if(c2==vt[i])
break;
}
if(i<vtnum)
{
if(c2==c1[p1])
p1++;
else
break;
}
else
{
if(c2=='$')
{
if(c1[p1]==c2)
{
flag=1;//运行成功,跳出
break;
}
else
break;
}
else
{
for(m=0;m<vnnum;m++)
{
if(vn[m]==c2)
break;
}
for(n=0;n<vtnum;n++)
{
if(vt[n]==c1[p1])
break;
}
if(M[m][n][0]=='0')
break;
else
{
if(M[m][n][0]!='`')//逆序压入,忽略空字符,输出所用规则
{
printf("%c->",vn[m]);
for(k=0;M[m][n][k]!='/0';k++)
{
printf("%c",M[m][n][k]);
}
for(j=0;j<Y-k;j++)
printf(" ");
for(x=k-1;x>=0;x--)
{
stack[sp++]=M[m][n][x];
stack[sp]='/0';
}
}
}
}
}
}
if(flag==1)
printf("/n/nSucceed,您输入的句型符合该文法!/n");
else
printf("/n/nError,您输入的句型和文法不符!/n");
return OK;
}
/*
txt文件格局
8 5 5
ETFAB
i+*()
ETA
A+TA
A`
TFB
B*FB
B`
F(E)
Fi
(i+i)$
*/