编译原理实验——预测分析法

/*本程序是递归下降分析法中预测分析法的实现,文法从文件中读入,程序可以根据产生式自动求出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)$

*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值