www.pudn.com > yufafenxi_ll(1).rar > bianyi.c


学编译原理时写的一个语法分析程序 
分类:C/C++技术交流 
 
 一.[目的要求] 
 
① 对输入文法,由程序自动构造FIRST FOLLOW集  
② 对输入文法,由程序自动生成它的LL(1)分析表; 
③ 对于给定的输入串,应能判断识别该串是否为给定文法的句型。 
 
二.[题目分析] 
 
该程序可分为如下几步: 
(1)读入文法  
(2)判断正误  
(3)若无误,判断是否为LL(1)文法  
(4)若是,构造分析表; 
(5)由总控算法判断输入符号串是否为该文法的句型。 
 
  
 
      
 
  
 
[源程序清单] 
#include 
#include 
#include 
int count=0;              /*分解的产生式的个数*/ 
int number;               /*所有终结符和非终结符的总数*/ 
char start;               /*开始符号*/ 
char termin[50];          /*终结符号*/ 
char non_ter[50];         /*非终结符号*/ 
char v[50];               /*所有符号*/ 
char left[50];            /*左部*/ 
char right[50][50];       /*右部*/ 
char first[50][50],follow[50][50];       /*各产生式右部的FIRST和左部的FOLLOW集合*/ 
char first1[50][50];      /*所有单个符号的FIRST集合*/ 
char select[50][50];      /*各单个产生式的SELECT集合*/ 
char f[50],F[50];         /*记录各符号的FIRST和FOLLOW是否已求过*/ 
char empty[20];           /*记录可直接推出^的符号*/ 
char TEMP[50];            /*求FOLLOW时存放某一符号串的FIRST集合*/ 
int validity=1;           /*表示输入文法是否有效*/ 
int ll=1;                 /*表示输入文法是否为LL(1)文法*/ 
int M[20][20];            /*分析表*/ 
char choose;              /*用户输入时使用*/ 
char empt[20];            /*求_emp()时使用*/ 
char fo[20];              /*求FOLLOW集合时使用*/ 
 
/******************************************* 
 判断一个字符是否在指定字符串中 
********************************************/ 
int in(char c,char *p) 
{ 
 int i; 
 if(strlen(p)==0) 
  return(0); 
 for(i=0;;i++) 
 {  
  if(p[i]==c) 
   return(1);       /*若在,返回1*/ 
  if(i==strlen(p)) 
      return(0);       /*若不在,返回0*/ 
 } 
} 
/******************************************* 
 得到一个不是非终结符的符号 
********************************************/ 
char c() 
{ 
 char c='A'; 
    while(in(c,non_ter)==1) 
  c++; 
 return(c); 
} 
/******************************************* 
 分解含有左递归的产生式 
********************************************/ 
void recur(char *point) 
{                     /*完整的产生式在point[]中*/ 
    int j,m=0,n=3,k; 
 char temp[20],ch; 
 ch=c();           /*得到一个非终结符*/ 
 k=strlen(non_ter); 
 non_ter[k]=ch; 
 non_ter[k+1]='\0'; 
 for(j=0;j<=strlen(point)-1;j++) 
 {  
  if(point[n]==point[0]) 
  {                          /*如果‘|’后的首符号和左部相同*/ 
   for(j=n+1;j<=strlen(point)-1;j++) 
   { 
       while(point[j]!='|'&&point[j]!='\0') 
        temp[m++]=point[j++]; 
    left[count]=ch; 
    memcpy(right[count],temp,m); 
    right[count][m]=ch; 
    right[count][m+1]='\0'; 
    m=0; 
    count++; 
    if(point[j]=='|') 
    { 
     n=j+1; 
     break; 
    } 
   } 
  } 
  else 
  {                          /*如果‘|’后的首符号和左部不同*/ 
   left[count]=ch; 
   right[count][0]='^'; 
   right[count][1]='\0'; 
   count++; 
   for(j=n;j<=strlen(point)-1;j++) 
   { 
       if(point[j]!='|') 
           temp[m++]=point[j]; 
       else 
    { 
        left[count]=point[0]; 
        memcpy(right[count],temp,m); 
        right[count][m]=ch; 
        right[count][m+1]='\0'; 
     printf(" count=%d ",count); 
     m=0; 
        count++; 
    } 
   } 
            left[count]=point[0]; 
      memcpy(right[count],temp,m); 
      right[count][m]=ch; 
        right[count][m+1]='\0'; 
   count++; 
      m=0; 
  } 
 } 
} 
/******************************************* 
 分解不含有左递归的产生式 
********************************************/ 
void non_re(char *point) 
{ 
    int m=0,j; 
 char temp[20]; 
 for(j=3;j<=strlen(point)-1;j++) 
 { 
     if(point[j]!='|') 
      temp[m++]=point[j]; 
  else 
  { 
      left[count]=point[0]; 
      memcpy(right[count],temp,m); 
      right[count][m]='\0'; 
   m=0; 
   count++; 
  } 
 } 
    left[count]=point[0]; 
    memcpy(right[count],temp,m); 
    right[count][m]='\0'; 
    count++; 
 m=0; 
} 
/******************************************* 
 读入一个文法 
********************************************/ 
char grammer(char *t,char *n,char *left,char right[50][50]) 
{ 
 char vn[50],vt[50]; 
 char s; 
 char p[50][50]; 
 int i,j,k; 
 printf("\n请输入文法的非终结符号串:"); 
    scanf("%s",vn); 
 getchar(); 
    i=strlen(vn); 
    memcpy(n,vn,i); 
 n[i]='\0'; 
 printf("请输入文法的终结符号串:"); 
    scanf("%s",vt); 
 getchar(); 
    i=strlen(vt); 
    memcpy(t,vt,i); 
 t[i]='\0'; 
    printf("请输入文法的开始符号:"); 
 scanf("%c",&s); 
 getchar(); 
 printf("请输入文法产生式的条数:"); 
    scanf("%d",&i); 
 getchar(); 
    for(j=1;j<=i;j++) 
 { 
  printf("请输入文法的第%d条(共%d条)产生式:",j,i); 
  scanf("%s",p[j-1]); 
        getchar(); 
 } 
    for(j=0;j<=i-1;j++) 
  if(p[j][1]!='-'||p[j][2]!='>') 
  { printf("\ninput error!"); 
      validity=0; 
   return('\0'); 
        }            /*检测输入错误*/ 
   for(k=0;k<=i-1;k++) 
   {                        /*分解输入的各产生式*/ 
        if(p[k][3]==p[k][0]) 
            recur(p[k]); 
  else 
      non_re(p[k]); 
 } 
 return(s); 
} 
/******************************************* 
 将单个符号或符号串并入另一符号串 
********************************************/ 
void merge(char *d,char *s,int type) 
{                 /*d是目标符号串,s是源串,type=1,源串中的‘ ^ ’一并并入目串; 
                type=2,源串中的‘ ^ ’不并入目串*/ 
    int i,j; 
 for(i=0;i<=strlen(s)-1;i++) 
 { 
        if(type==2&&s[i]=='^') 
   ; 
  else 
  { 
   for(j=0;;j++) 
   { 
       if(j=0) 
            { 
       first[i][0]='^'; 
       first[i][1]='\0'; 
   } 
   else 
   { 
    TEMP[0]='^'; 
    TEMP[1]='\0'; 
   } 
  } 
  else 
  {  
   for(j=0;;j++) 
    if(v[j]==p[0]) 
     break; 
   if(i>=0) 
   { 
       memcpy(first[i],first1[j],strlen(first1[j])); 
       first[i][strlen(first1[j])]='\0'; 
   } 
   else 
   { 
    memcpy(TEMP,first1[j],strlen(first1[j])); 
    TEMP[strlen(first1[j])]='\0'; 
   } 
        } 
 } 
 else                      /*如果右部为符号串*/ 
 { 
  for(j=0;;j++) 
   if(v[j]==p[0]) 
    break; 
  if(i>=0) 
            merge(first[i],first1[j],2); 
  else 
   merge(TEMP,first1[j],2); 
  for(k=0;k<=length-1;k++) 
  { 
   empt[0]='\0'; 
   if(_emp(p[k])==1&&k=0) 
        merge(first[i],first1[m],2); 
    else 
     merge(TEMP,first1[m],2); 
   } 
            else if(_emp(p[k])==1&&k==length-1) 
   { 
                 
    temp[0]='^'; 
    temp[1]='\0'; 
    if(i>=0) 
        merge(first[i],temp,1);    
    else 
     merge(TEMP,temp,1); 
   } 
   else if(_emp(p[k])==0) 
    break; 
  } 
 } 
} 
/******************************************* 
 求各产生式左部的FOLLOW 
********************************************/ 
void FOLLOW(int i) 
{ 
 int j,k,m,n,result=1; 
 char c,temp[20]; 
 c=non_ter[i];             /*c为待求的非终结符*/ 
 temp[0]=c; 
 temp[1]='\0'; 
 merge(fo,temp,1); 
 if(c==start) 
 {                         /*若为开始符号*/ 
  temp[0]='#'; 
  temp[1]='\0'; 
  merge(follow[i],temp,1); 
 } 
    for(j=0;j<=count-1;j++) 
 { 
  if(in(c,right[j])==1)     /*找一个右部含有c的产生式*/ 
  { 
   for(k=0;;k++) 
    if(right[j][k]==c) 
     break;       /*k为c在该产生式右部的序号*/ 
            for(m=0;;m++) 
    if(v[m]==left[j]) 
     break;        /*m为产生式左部非终结符在所有符号中的序号*/ 
   if(k==strlen(right[j])-1) 
   {              /*如果c在产生式右部的最后*/ 
    if(in(v[m],fo)==1) 
    { 
     merge(follow[i],follow[m],1); 
     continue; 
                } 
    if(F[m]=='0') 
    { 
     FOLLOW(m); 
     F[m]='1'; 
    } 
    merge(follow[i],follow[m],1); 
   } 
   else  
   {              /*如果c不在产生式右部的最后*/ 
    for(n=k+1;n<=strlen(right[j])-1;n++) 
    {  
     empt[0]='\0'; 
     result*=_emp(right[j][n]); 
    } 
    if(result==1) 
    {         /*如果右部c后面的符号串能推出^*/ 
                    if(in(v[m],fo)==1) 
     {           /*避免循环递归*/ 
      merge(follow[i],follow[m],1); 
      continue; 
     } 
     if(F[m]=='0') 
     { 
         FOLLOW(m); 
         F[m]='1'; 
     } 
        merge(follow[i],follow[m],1); 
    } 
    for(n=k+1;n<=strlen(right[j])-1;n++) 
                    temp[n-k-1]=right[j][n];        
    temp[strlen(right[j])-k-1]='\0'; 
    FIRST(-1,temp); 
    merge(follow[i],TEMP,2); 
   } 
  } 
 } 
 F[i]='1'; 
} 
 
/******************************************* 
 判断读入文法是否为一个LL(1)文法 
********************************************/ 
int ll1() 
{ 
    int i,j,length,result=1; 
 char temp[50]; 
 for(j=0;j<=49;j++) 
 {                            /*初始化*/ 
  first[j][0]='\0'; 
     follow[j][0]='\0'; 
  first1[j][0]='\0'; 
  select[j][0]='\0'; 
  TEMP[j]='\0'; 
  temp[j]='\0'; 
  f[j]='0'; 
  F[j]='0'; 
 } 
 for(j=0;j<=strlen(v)-1;j++) 
     first2(j);                /*求单个符号的FIRST集合*/ 
 printf("\nfirst1:"); 
 for(j=0;j<=strlen(v)-1;j++) 
  printf("%c:%s  ",v[j],first1[j]); 
    printf("\nempty:%s",empty); 
 printf("\n:::\n_emp:"); 
 for(j=0;j<=strlen(v)-1;j++) 
        printf("%d  ",_emp(v[j])); 
 for(i=0;i<=count-1;i++) 
     FIRST(i,right[i]);          /*求FIRST*/ 
 printf("\n"); 
 for(j=0;j<=strlen(non_ter)-1;j++) 
    {                               /*求FOLLOW*/ 
  if(fo[j]==0) 
  { 
   fo[0]='\0'; 
      FOLLOW(j); 
  } 
    } 
 printf("\nfirst:"); 
 for(i=0;i<=count-1;i++) 
     printf("%s ",first[i]); 
 printf("\nfollow:"); 
    for(i=0;i<=strlen(non_ter)-1;i++) 
     printf("%s ",follow[i]); 
 for(i=0;i<=count-1;i++) 
 {                          /*求每一产生式的SELECT集合*/ 
        memcpy(select[i],first[i],strlen(first[i])); 
        select[i][strlen(first[i])]='\0'; 
  for(j=0;j<=strlen(right[i])-1;j++) 
   result*=_emp(right[i][j]); 
  if(strlen(right[i])==1&&right[i][0]=='^') 
   result=1; 
  if(result==1) 
  {  
   for(j=0;;j++) 
    if(v[j]==left[i]) 
     break; 
   merge(select[i],follow[j],1); 
  } 
 } 
 printf("\nselect:"); 
 for(i=0;i<=count-1;i++) 
     printf("%s ",select[i]); 
 memcpy(temp,select[0],strlen(select[0])); 
 temp[strlen(select[0])]='\0'; 
 for(i=1;i<=count-1;i++) 
 {                 /*判断输入文法是否为LL(1)文法*/ 
        length=strlen(temp); 
  if(left[i]==left[i-1]) 
  { 
   merge(temp,select[i],1); 
   if(strlen(temp)=0;n--) 
                        S[p++]=right[m][n]; 
        S[q+strlen(right[m])]='\0'; 
    } 
   } 
  } 
     printf("\nS:%s str:",S); 
  for(p=j;p<=strlen(str)-1;p++) 
   printf("%c",str[p]); 
  printf(" "); 
 } 
} 
 
/******************************************* 
 一个用户调用函数 
********************************************/ 
void menu() 
{ 
 syntax(); 
 printf("\n是否继续?(y or n):"); 
 scanf("%c",&choose); 
 getchar(); 
 while(choose=='y') 
  {  
   menu(); 
  } 
} 
 
 
/******************************************* 
 主函数 
********************************************/ 
void main() 
{ 
 int i,j; 
 start=grammer(termin,non_ter,left,right);               /*读入一个文法*/ 
    printf("count=%d",count); 
 printf("\nstart:%c",start); 
 strcpy(v,non_ter); 
 strcat(v,termin); 
 printf("\nv:%s",v); 
 printf("\nnon_ter:%s",non_ter); 
    printf("\ntermin:%s",termin); 
 printf("\nright:"); 
 for(i=0;i<=count-1;i++) 
     printf("%s   ",right[i]);  
    printf("\nleft:"); 
 for(i=0;i<=count-1;i++) 
  printf("%c   ",left[i]);             
    if(validity==1) 
    validity=judge(); 
 printf("\nvalidity=%d",validity); 
 if(validity==1) 
 { 
        printf("\n文法有效"); 
  ll=ll1(); 
  printf("\nll=%d",ll); 
  if(ll==0) 
   printf("\n该文法不是一个LL1文法!"); 
  else 
  { 
      MM(); 
            printf("\n"); 
      for(i=0;i<=19;i++) 
          for(j=0;j<=19;j++) 
           if(M[i][j]>=0) 
            printf("M[%d][%d]=%d ",i,j,M[i][j]); 
      printf("\n"); 
      menu(); 
  } 
 } 
} 
 
 
你可以通过这个链接引用该篇文章:http://ningcoco8.bokee.com/tb.b?diaryId=14759671