编译原理,C语言实现LR(0)分析(扩展文法的生成、项目集规范簇的生成、ACTION GOTO表的生成、句子的分析)

简介: 注:代码生成的项目集规范簇、ACTION GOTO表的顺序可能和课本、教材、参考答案的顺序不同,但这并不影响分析过程的正确性,毕竟机器是按规律办事的😄

注:代码生成的项目集规范簇、ACTION GOTO表的顺序可能和课本、教材、参考答案的顺序不同,但这并不影响分析过程的正确性,毕竟机器是按规律办事的😄

主函数已经把功能分的很清晰,代码注释也很详细,如阅读代码,可先在主函数查看,再到子函数逐一查看

演示

演示所用文法和句子

文法

E->E-T

E->T

T->T*F

T->F

F->-F

F->a

待分析句子

a–a*a

(1)根据提示输入文法的个数

2345_image_file_copy_249.jpg

(2)输入文法

回车,然后依此输入文法

2345_image_file_copy_250.jpg

2345_image_file_copy_251.jpg

(3)扩展文法的生成、项目集规范簇的生成、ACTION GOTO表的生成

回车后扩展文法的生成、项目集规范簇的生成、ACTION GOTO表的生成

扩展文法

2345_image_file_copy_252.jpg

项目集规范簇

2345_image_file_copy_253.jpg

ACTION GOTO表

2345_image_file_copy_254.jpg

(3)分析句子

根据提示输入分析串

2345_image_file_copy_255.jpg

(4)生成分析过程

输入分析串后回车

2345_image_file_copy_256.jpg

思路

其实思路比较简单,只是实现起来较为繁琐。

1.输入文法

2.进行项目集规范簇的构建

(1)采用链表进行生成存储,因为生成个数不确定

(2)采用双重循环,外循环进行In的遍历,内循环进行项目的遍历

(3)结束条件为遍历到最后一个项目为止,也就是无法再生成

3.根据项目集规范簇生成ACTION表和GO表

(1)将输入的文法进行拆分为终结符与非终结符,非终结符做action表的行标,终结符做goto表的行标

(2)将项目集规范簇的In中的n做列标

(3)在action表中用正数代表移进,负数代表归约,999代表接受,goto表用数字代表是哪条文法

(4)双重循环遍历项目集规范簇进行action goto表的生成

(5)外循环遍历每个I,内循环查询这个I是哪些I生成的,因为一个I可以通过多个I生成

4.通过查找ACTION和GO表进行句子的分析

源代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct GLR_CSS{
  int num;//条的编号 
  char left;//产生式左边
  char right[30];//产生式右边 
  int dot;//用于存储点的位置 
  struct GLR_CSS *next; 
}CSS; 
typedef struct GLR{
  int I_01;//存放自己是I几
  int I_02;//存放是经过I几通过输入c变换过来的 
  char c; //I01输入c到I02
  struct GLR_CSS *css;//头指针 
  int num;//产生式的个数
  struct GLR *next; 
}LR;
char g[100][20];
int n;//文法的条数 
char at[100];//存储终结符
int at_num=0; //用于记录at数组的长度 
char gt[100];//存储非终结符 
char gt_01[100][2];//第一个存储非终结符,第二个存储记录 
int gt_num=0;//用于记录gt数组的长度 
LR lr;//用于存储输入的文法 
LR *I; 
LR *Ips;//存储头结点 
LR *Ipf;//存储最后一个结点
int act_gt[100][100]; 
char str[100];//需要分析的输入串 
int str_num;//分析串栈的指针 
int fhz[100];//符号栈 
int fhz_num;//符号栈的指针 
//接收输入的文法 
void get_g(){
  int i;
  printf("请输入文法的条数:");
  scanf("%d",&n); 
  getchar();
  for(i=0;i<n;i++){
    printf("(%d)",i+1);
    gets(g[i]);
  }
} 
//查重action表 
void action_01(char c){
  if(at_num==0){//没有直接放 
    at[at_num]=c; 
    at_num++;
  }else{//有,查重 
    int i;
    int flag=0;
    for(i=0;i<at_num;i++){
      if(at[i]==c){
        flag=1;
      }
    } 
    if(flag==0){//没有 
      at[at_num]=c;
      at_num++; 
    }
  }
}
//找出action表 
void action(){//找action序列(非大写)
  int i; //遍历每一条 
  int j;//遍历每一条的每一个 
  int len;
  for(i=0;i<n;i++){
    len=strlen(g[i]);
    for(j=0;j<len;j++){
      if(g[i][j]=='-'&&g[i][j+1]=='>'){//排除->(排除箭头,也就是“定义为”) 
        j++;
        continue;
      }else{
        if(g[i][j]<65||g[i][j]>90){//终结符的范围 
          action_01(g[i][j]); //放入at数组,//该函数用于检测是否重复
        }
      }
    }
  }
  at[at_num]='#';
  at_num++;
  at[at_num]='\0';
} 
//查重goto表 
void gotoo_01(char c){
  if(gt_num==0){//没有直接放 
    gt[gt_num]=c; 
    gt_num++;
  }else{//有,查重 
    int i;
    int flag=0;
    for(i=0;i<gt_num;i++){
      if(gt[i]==c){
        flag=1;
      }
    } 
    if(flag==0){//没有 
      gt[gt_num]=c;
      gt_num++; 
    }
  }
}
//找出goto表 
void gotoo(){//找goto序列(大写)
  int i; //遍历每一条 
  int j;//遍历每一条的每一个 
  int len;
  for(i=0;i<n;i++){
    len=strlen(g[i]);
    for(j=0;j<len;j++){
      if(g[i][j]=='-'&&g[i][j+1]=='>'){//排除->(排除箭头,也就是“定义为”) 
        j++;
        continue;
      }else{
        if(g[i][j]>=65&&g[i][j]<=90){//非终结符的范围
          gotoo_01(g[i][j]); //放入gt数组,//该函数用于检测是否重复 
        } 
      }
    }
  }
  gt[gt_num]='\0';
}
void init_gt_01(){
  int i;
  for(i=0;i<gt_num;i++){
    gt_01[i][0]=gt[i];
    gt_01[i][1]=0;//未检测时为0; 
  }
}
//测试,输出结构体
void f(CSS *p){
  int i=1;
  while(p!=NULL){
    printf("(%d)%c->%s\n",i,p->left,p->right);
    printf("点:%d\n",p->dot);
    p=p->next;
    i++;
  }
} 
//将所有文法存储在lr变量中 
void lr_save(){
  lr.num=n;//存储初始文法的条数
  int i,j;
  int len;
  CSS *cssp,*cssk,*csst;
  cssp=(CSS*)malloc(sizeof(CSS));//头结点 
  cssk=cssp; 
  for(i=0;i<n;i++){
    len=strlen(g[i]);
    csst=(CSS*)malloc(sizeof(CSS));
    csst->num=i+1; //存储是第几条文法 
    csst->left=g[i][0];//存储左边
    int k=0;
    for(j=3;j<len;j++){
      csst->right[k]=g[i][j];
      k++; 
    }
    csst->right[k]='\0';
    cssk->next=csst;
    cssk=cssk->next;
  } 
  cssk->next=NULL;
  lr.css=cssp;
  //fff();//测试,输出函数 
}
//初始化I0;并初始头结点
void into_I0(){
  //空结点 
  Ips=(LR*)malloc(sizeof(LR));
  //临时结点
  LR *Ipt;
  Ipt=(LR*)malloc(sizeof(LR));
  //Ipt->num=1;//文法条数 
  //初始化第一个数据结点 
  Ipt->I_01=0;//I0
  //定义语句的临时结点 ,和转移结点 
  CSS *csst,*csss;
  //定义遍历的结点 
  CSS *cssk;
  cssk=lr.css->next;
  //语句的第一个空结点 
  Ipt->css=(CSS*)malloc(sizeof(CSS));
  csss=Ipt->css;
  //语句初始个数
  Ipt->num=0; 
  int bt=-1;
  /
  //E'->E
  bt++;//表达式的序号 
  csst =(CSS*)malloc(sizeof(CSS)); 
  //表达式的序号
  csst->num=bt; 
  //点的位置 
  csst->dot=0;
  //表达式左边
  csst->left='S';
  //表达式右边
  csst->right[0]=cssk->left; 
  csst->right[1]='\0';
  csss->next=csst;
  csss=csss->next;
    //cssk=cssk->next;  
  Ipt->num++;//语句条数加1 
  /
  while(cssk!=NULL){
    bt++;//表达式的序号 
    csst =(CSS*)malloc(sizeof(CSS)); 
    //表达式的序号
    csst->num=bt; 
    //点的位置 
    csst->dot=0;
    //表达式左边 复制 
    csst->left=cssk->left;
    //表达式右边复制 
    strcpy(csst->right,cssk->right); 
    csss->next=csst;
    csss=csss->next;
    cssk=cssk->next;
    Ipt->num++;//语句条数加1 
  }
  csss->next=NULL; 
  Ips->next=Ipt;//头 
  Ipf=Ips->next;//指向尾巴 
  Ipf->next=NULL;
  //fff();   
} 
int jc_gt_01(char c){//c处为0返回1,否则返回0 
  int i;
  for(i=0;i<gt_num;i++){
    if(gt_01[i][0]==c){
      if(gt_01[i][1]==0){
        return 1;
      }else{
        return 0;
      } 
    }
  } 
  return 0;
}
void fz_gt_01(int c){
  int i;
  for(i=0;i<gt_num;i++){
    if(gt_01[i][0]==c){
      gt_01[i][1]=1;      
    }
  } 
} 
void create_I(LR *lrr,CSS *css){
  //清空gt_01数组 
  init_gt_01();
  char s=css->right[css->dot];//当前移入的符号 
  //(1)遍历lrr结点所有表达式,生成新的I结点
  //开辟I结点存储空间 
  LR *ln=(LR*)malloc(sizeof(LR));
  ln->num=0;//文法初始条数 
  // 生成新表达式的csss
  CSS *csss,*csst;
  csss=(CSS*)malloc(sizeof(CSS));//头结点
  ln->css=csss;//链上带头结点
  csss->next=NULL; 
  //遍历每条表达式的临时变量 
  CSS *lt=lrr->css->next;
  while(lt!=NULL){
    if(lt->right[lt->dot]==s){//点后面是要移入的符号 
      csst=(CSS*)malloc(sizeof(CSS));//开辟一个表达式的存储空间 
      csst->next=NULL;//next复制NULL
      csst->left=lt->left;
      strcpy(csst->right,lt->right);
      csst->dot=lt->dot+1;
      csss->next=csst;
      csss=csss->next;
      ln->num++; 
    }
    lt=lt->next;
  } 
  //(2)判断新结点的每个表达式后是否是终结符,若不是则新添加 
  //csss目前指向最后一个
  CSS *csss01=ln->css->next;
  CSS *csss02; 
  //char pre='a'; 
  while(csss01!=NULL){//循环目前生成的表达式 
    if(csss01->right[csss01->dot]>=65&&csss01->right[csss01->dot]<=90&&jc_gt_01(csss01->right[csss01->dot])==1){//非终结符判断条件
      //printf("ssssssssssss\n");
      csss02=Ips->next->css->next;//I0的所有表达式 
      while(csss02!=NULL){
        if(csss02->left==csss01->right[csss01->dot]){
          csst=(CSS*)malloc(sizeof(CSS));//开辟一个表达式的存储空间 
          csst->next=NULL;//next复制NULL
          csst->left=csss02->left;
          strcpy(csst->right,csss02->right);
          csst->dot=csss02->dot;
          csss->next=csst;
          csss=csss->next;
          ln->num++;
        }
        csss02=csss02->next;
      }
      fz_gt_01(csss01->right[csss01->dot]);
    }
    csss01=csss01->next; 
  } 
  //(3)查重
  LR *Ipt01=Ips->next;
  CSS *csss03;
  CSS *csss04;
  int flag=0;
  while(Ipt01!=NULL){
    if(Ipt01->num==ln->num){//语法条数相等才有相同的可能性
      csss03=Ipt01->css->next;
      flag=0;
      while(csss03!=NULL){
        csss04=ln->css->next;
        while(csss04!=NULL){
          if(csss04->left==csss03->left&&csss04->dot==csss03->dot&&strcmp(csss03->right,csss04->right)==0){
            flag++;
          } 
          csss04=csss04->next;
        } 
        csss03=csss03->next;
      }
      if(flag==ln->num){//重复了 
        return;
      } 
    }
    Ipt01=Ipt01->next;
  }
  //加到末尾
  ln->I_01=Ipf->I_01+1;
  ln->I_02=lrr->I_01;
  ln->c=s;
  Ipf->next=ln;
  Ipf=Ipf->next;
  Ipf->next=NULL;
  /*printf("-------------------\n");
  printf("这是I(%d)\n",ln->I_01);
  printf("I(%d)输入%c变成\n",ln->I_02,ln->c);
  printf("表达式为:\n");
  f(ln->css->next);
  printf("-------------------\n"); */ 
}
//将所有项目I0---In列出 
void lr_analyse(){
  LR *Ipt_01;//用于遍历 
  LR *Ipt_02; //用于开辟新结点
  CSS *csst_01;//遍历
  CSS *csst_02; 
  Ipt_01=Ips->next;
  // lr_analyse_exit()==1
  while(1){//项目列表的最后一个所有语法的点都在最后面则退出 ,遍历I列表,每次一个 
    csst_01=Ipt_01->css->next;//In的第一个产生式子的位置 
    while(csst_01!=NULL){//当前I的第j个表达式点后移,产生新的 
    //移动点
    //
    //printf("222222222\n");
      if(csst_01->dot==strlen(csst_01->right)){//已经完了 
        csst_01=csst_01->next;
        continue; 
      }else{
        //printf("-------当前遍历的是I(%d)的%c->%s语句-------\n",Ipt_01->I_01,csst_01->left,csst_01->right);
        create_I(Ipt_01,csst_01);//传入当前I的所有表达式的头,和当前语句 
      }
      csst_01=csst_01->next;
    } 
    //printf("11111111111122222222222222222222222222");
    if(Ipt_01->I_01==Ipf->I_01){
      break;
    }else{
      Ipt_01=Ipt_01->next;
      //printf("11111111111111111111111111\n");
    }
  }
}
void acc_form(){
  act_gt[1][strlen(at)-1]=999;
}
//检测是不是lt02移入lt01->c,变成lt01
void goto_form_01(LR *lt01,LR *lt02,char c){
  CSS *csst01;
  csst01=lt02->css->next;//lt02的第一条语句
  //移入后的新语句头 
  CSS *csst02; 
  csst02=(CSS*)malloc(sizeof(CSS));
  csst02->next=NULL;
  //移动临时变量
  CSS *csst03,*csst04;
  csst03=csst02;
  while(csst01!=NULL){
    if(csst01->right[csst01->dot]==c){
      //printf("77888888999\n");
      //申请空间 
      csst04=(CSS*)malloc(sizeof(CSS));
      //填写表达式左边数据 
      csst04->left=csst01->left;
      //右边数据 
      strcpy(csst04->right,csst01->right);
      //点 
      csst04->dot=csst01->dot+1;
      csst04->next=NULL;
      csst03->next=csst04;
      csst03=csst03->next; 
    }
    csst01=csst01->next;
  } 
  //查看csst02是否与lt01表达式相同
  int flag=0;
  csst02=csst02->next;
  /*printf("=======这是csst02=======\n");
  f(csst02);
  printf("=======这是csst02=======\n");*/
  CSS *csst05;
  while(csst02!=NULL){
    csst05=lt01->css->next;
    while(csst05!=NULL){
      //printf("777777777\n");
      if(csst05->left==csst02->left&&csst05->dot==csst02->dot&&strcmp(csst05->right,csst02->right)==0){
        flag++;
      }
      csst05=csst05->next;
    }
    csst02=csst02->next;
  } 
  //printf("flag==%d,lt01->num=%d\n",flag,lt01->num);
  if(flag==lt01->num){
    //说明lt02移入c,变成lt01
    //纵坐标
    int h=lt02->I_01;
    //横坐标
    int x;
    int i;
    for(i=0;i<gt_num;i++){
      if(gt[i]==c){
        x=i;
      }
    } 
    act_gt[h][at_num+x]=lt01->I_01;
  }
  //移入 
}
void goto_form(){
  //遍历除I0所有LR->c为大写的
  LR *lt01;
  lt01=Ips->next->next;//I1
  LR *lt02;//I0
  while(lt01!=NULL){
    if(lt01->c>=65&&lt01->c<=90){//lt01是由某个状态移入c变成的 
      lt02=Ips->next;//从I0,开始 
      while(lt02!=NULL){
        //检测是不是lt02移入lt01->c,变成lt01 
        goto_form_01(lt01,lt02,lt01->c);//并填写goto表 
        lt02=lt02->next;
      }
    }
    lt01=lt01->next;
  } 
}
void action_r_form_01(int h,CSS *csst){//(纵坐标,当前表达式)在I0中找到,并填表 
  CSS *csst01=Ips->next->css;
  while(csst01!=NULL){
    if(csst01->left==csst->left&&strcmp(csst01->right,csst->right)==0){
      int num=csst01->num*(-1);//编号 
      //填表
      int i;
      for(i=0;i<at_num;i++){
        act_gt[h][i]=num;
      }
    }
    csst01=csst01->next;
  }
}
void action_r_form(){
  //遍历I1开始
  //如果In的某条文法的点在最后,则在I0的css中找对应的编号 ,(除left=S的情况,因为这个是acc) 
  LR *lt01=Ips->next->next;
  CSS *csst01;
  while(lt01!=NULL){
    csst01=lt01->css->next;
    while(csst01!=NULL){
      if(csst01->left!='S'&&csst01->dot==strlen(csst01->right)){
        action_r_form_01(lt01->I_01,csst01);//在I0中找到,并填表 
      }
      csst01=csst01->next;
    }
    lt01=lt01->next;
  } 
}
//检测是不是lt02移入lt01->c,变成lt01
void action_s_form_01(LR *lt01,LR *lt02,char c){
  init_gt_01();//清空gt_01数组 
  CSS *csst01;
  csst01=lt02->css->next;//lt02的第一条语句
  //移入后的新语句头 
  CSS *csst02; 
  csst02=(CSS*)malloc(sizeof(CSS));
  csst02->next=NULL;
  //移动临时变量
  CSS *csst03,*csst04;
  csst03=csst02;
  while(csst01!=NULL){
    if(csst01->right[csst01->dot]==c){
      //printf("77888888999\n");
      //申请空间 
      csst04=(CSS*)malloc(sizeof(CSS));
      //填写表达式左边数据 
      csst04->left=csst01->left;
      //右边数据 
      strcpy(csst04->right,csst01->right);
      //点 
      csst04->dot=csst01->dot+1;
      csst04->next=NULL;
      csst03->next=csst04;
      csst03=csst03->next;
      //printf("%c",csst04->right[csst04->dot]);  
    }
    //printf("qqqqqqqqqqqqqqqqqqqq\n");
    csst01=csst01->next;
  } 
  //将csst02中的非终结符在I0中找出,现在csst03所指最后一个表达式 
  CSS *csst02_01=csst02->next;
  while(csst02_01!=NULL){
    char cc=csst02_01->right[csst02_01->dot];
    if(cc>=65&&cc<=90&&jc_gt_01(cc)==1){
      //遍历I0
      CSS *cssi0=Ips->next->css->next;
      while(cssi0!=NULL){
          if(cssi0->left==cc){
            //申请空间 
            csst04=(CSS*)malloc(sizeof(CSS));
            //填写表达式左边数据 
            csst04->left=cssi0->left;
            //右边数据 
            strcpy(csst04->right,cssi0->right);
            //点 
            csst04->dot=cssi0->dot;
            csst04->next=NULL;
            csst03->next=csst04;
            csst03=csst03->next; 
          }
          cssi0=cssi0->next;
        }
        fz_gt_01(cc); 
    }
    csst02_01=csst02_01->next;
  } 
  //查看csst02是否与lt01表达式相同
  int flag=0;
  csst02=csst02->next;
  /*printf("=======这是csst02=======\n");
  f(csst02);
  printf("=======这是csst02=======\n");*/
  /*if(lt01->I_01==3){
    printf("这是I3,,I%d正在与他比较\n",lt02->I_01);
    printf("生成的东西为:\n");
    f(csst02);
    printf("%c\n",lt01->c);
  }*/ 
  CSS *csst05;
  while(csst02!=NULL){
    csst05=lt01->css->next;
    while(csst05!=NULL){
      //printf("777777777\n");
      if(csst05->left==csst02->left&&csst05->dot==csst02->dot&&strcmp(csst05->right,csst02->right)==0){
        flag++;
      }
      csst05=csst05->next;
    }
    csst02=csst02->next;
  } 
  //printf("flag==%d,lt01->num=%d\n",flag,lt01->num);
  if(flag==lt01->num){
    //说明lt02移入c,变成lt01
    //纵坐标
    int h=lt02->I_01;
    //横坐标
    int x;
    int i;
    for(i=0;i<at_num;i++){
      if(at[i]==c){
        x=i;
      }
    } 
    act_gt[h][x]=lt01->I_01;
  }
  //移入 
}
void action_s_form(){
  //遍历除I0所有LR->c为非大写的,也就是终结符 
  LR *lt01;
  lt01=Ips->next->next;//I1
  LR *lt02;//I0
  while(lt01!=NULL){
    if(lt01->c<65||lt01->c>90){//lt01是由某个状态移入c变成的 
      lt02=Ips->next;//从I0,开始 
      while(lt02!=NULL){
        //检测是不是lt02移入lt01->c,变成lt01 
        action_s_form_01(lt01,lt02,lt01->c);//并填写goto表 
        lt02=lt02->next;
      }
    }
    lt01=lt01->next;
  } 
}
void output_action_goto(){
  int i;
  int j;
  int k;
  int q;
  int w;
  printf("--------ACTION-------------------GOTO-------\n"); 
  printf(" 状态");
  for(q=0;q<at_num;q++){
    printf("%5c",at[q]);
  } 
  for(k=0;k<gt_num;k++){//goto表的表头 
    printf("%5c",gt[k]);
  } 
  printf("\n");
  for(i=0;i<=Ipf->I_01;i++){
    printf("%5d",i);//状态
    //输出action表的值 
    for(w=0;w<at_num;w++){
      if(act_gt[i][w]==999){
        printf("  acc");
        continue;
      }
      if(act_gt[i][w]<0){
        printf("   R%d",act_gt[i][w]*-1);
        continue;
      }
      if(act_gt[i][w]>0){
        printf("   S%d",act_gt[i][w]);
        continue;
      }
      printf("%5c",' ');
    } 
    //输出goto表的值 
    for(j=0;j<gt_num;j++){
      if(act_gt[i][at_num+j]==0){
        printf("%5c",' ');
      }else{
        printf("%5d",act_gt[i][at_num+j]);
      } 
    }
    printf("\n");
  }
} 
void anction_goto_form(){
  //(1)填写acc-->999
  acc_form(); 
  //(2) 填写goto()表,输入大写 
  goto_form();
  //(3)填写r负数
  action_r_form();
   //printf("wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww\n");
  //(4)填写s正数 
  action_s_form();
  //printf("-----------------%d\n",lt->I_01); 
  output_action_goto();//输出acion_goto表 
}
void output_lr_analyse(){
  LR *lt=Ips->next;
  while(lt!=NULL){
    printf("当前是I(%d),有%d条语句,输入字符是%c\n",lt->I_01,lt->num,lt->c);
    printf("语句为:\n");
    f(lt->css->next); 
    lt=lt->next;
  }
} 
void get_string(){
  printf("请输入分析串:");
  gets(str);
  str[strlen(str)+1]='\0'; 
  str[strlen(str)]='#';
  //puts(str);
}
int jc_lr_form(int h,char c){
  int i;
  int flag=0;//记录是action表的内容还是goto表的内容 
  int x;
  //遍历action 
  for(i=0;i<at_num;i++){
    if(at[i]==c){
      x=i;
      flag=1;//action表
      break; 
    }
  }
  for(i=0;i<gt_num;i++){
    if(gt[i]==c){
      x=at_num+i;
      flag=2;
      break;
    }
  }
  if(flag==1){//在action中 
    if(act_gt[h][x]>0&&act_gt[h][x]!=32){
      //S
      return act_gt[h][x];
    } 
    if(act_gt[h][x]<0){
      return act_gt[h][x];
      //r
    }
    if(act_gt[h][x]==999){
      //接受 
      return 9999;
    }
    if(act_gt[h][x]==32){
      //出错 
      return 2222;
    }
  }
  if(flag==2){//说明在goto表中 
    if(act_gt[h][x]!=32){//状态转移 
        return act_gt[h][x]+1000;
    }else{
      //出错 
      return 2222;
    } 
  } 
  if(flag==0){
    //出错 
    return 2222;
  }
} 
void out_fhz(){
  printf("符号栈:");
  int i;
  for(i=0;i<=fhz_num;i++){
    if(fhz[i]<=0){
      printf("%d",fhz[i]*-1);
    }else{
      //printf("ggggggggggggggggggggggggggggggggg");
      printf("%c",fhz[i]);
    }
  }
  printf("          ");
}
void out_str(){
  printf("当前输入:");
  int i;
  for(i=str_num;i<strlen(str);i++){
    printf("%c",str[i]);
  }
  printf("          ");
}
//找标号为num的表达式 
CSS* guiyue(int num){
  CSS *p=Ips->next->css->next;
  while(p!=NULL){
    if(p->num==num){
      return p;
    }
    p=p->next;
  } 
}
void lr_process(){
  //初始符号栈#0
  fhz[fhz_num]='#';
  //printf("------>%c",fhz[fhz_num]);
  fhz_num++;
  fhz[fhz_num]=0*(-1);//状态(用负数来表示状态,将状态与符号区分开来) 
  //fhz_num++;
  while(1){
    //查看符号栈栈顶元素,和串的栈顶元素
    //查分析表
     int sr_num=jc_lr_form(fhz[fhz_num]*-1,str[str_num]);//(状态,输入) 
     //sr_num==2222//出差错
     if(sr_num==2222){
      printf("出错,不可识别\n");
      break; 
     }
     //sr_num>0&&sr_num<1000  移进
     if(sr_num>0&&sr_num<1000){
      out_fhz();//输出栈内容 
      out_str(); //当前输入
      if(sr_num==999){
        printf("接收accept\n"); 
        break; 
      }else{
        printf("移进:S%d\n",sr_num); 
      }
      //先移入符号,再移入状态
      //移入符号 
      fhz_num++;//符号栈指针+1 
      fhz[fhz_num]=str[str_num];
      str_num++;//输入串指针后移 
      //移入状态 
      fhz_num++;
      fhz[fhz_num]=sr_num*-1; 
     }
     if(sr_num<0){//归约 
      out_fhz();//输出栈内容 
      out_str(); //当前输入
      //在I0中找标号为sr_num*-1的  //sr_num*-1,要归约的表达式
      CSS *csst01=guiyue(sr_num*-1);
      printf("归约:R%d(%c->%s)\n",sr_num*-1,csst01->left,csst01->right); 
       //fhz指针后移一位,换成csst01->left
       fhz_num=fhz_num-2*strlen(csst01->right)+1;
       fhz[fhz_num]=csst01->left;
       int zt=jc_lr_form(fhz[fhz_num-1]*-1,fhz[fhz_num]);
       //printf("%d\n",zt); 
       if(zt>1000&&zt<2000){
        fhz_num++;
        fhz[fhz_num]=(zt-1000)*-1;
       }else{
        if(zt==9999){
          printf("acc,接收\n");
          break;
        }else{
          printf("出错,不可识别\n");
          break;
        }
       }
     }
     //sr_num==9999 //接受
     if(sr_num==9999){
      printf("acc,接收\n");
      break;
     }
  }
}
int main(){
  get_g();//文法的输入 
  action();//找action序列(非大写) 
  gotoo();//找大写非终结符
  init_gt_01();//初始化gt_01表 
  lr_save(); //存储输入的文法在变量lr中
  into_I0();//初始化I0;并初始头结点 
  printf("===================开始分析=====================\n");
  printf("=====================I(0)为=====================\n");
  f(Ips->next->css->next);
  printf("================================================\n");
  lr_analyse(); //项目集规范族 Ips是头指针 
  //清屏函数 
  //system("cls");
  output_lr_analyse();//输出项目集 
  printf("======================ACTION GOTO表==========================\n");
  anction_goto_form();//构造LR分析表,并输出
  //输入分析串
  get_string(); 
  lr_process(); 
  return 0;
} 
相关文章
|
5月前
|
前端开发 C语言
C语言06-HelloWorld执行流程分析
C语言06-HelloWorld执行流程分析
C语言06-HelloWorld执行流程分析
|
4月前
|
编译器 C语言
C语言中的goto语句
C语言中的goto语句C语言中的goto语句 goto语句是C语言(及许多其他早期编程语言)中的一个控制流语句,它允许程序无条件地跳转到程序中的另一个位置。goto语句后面跟着一个标签(label),该标签是程序中某个语句之前的一个标识符。当执行到goto语句时,程序会立即跳转到与该标签相关联的语句处继续执行。 1. 基本概念与工作原理 基本概念:goto语句通过标签来指定跳转的目标位置。标签是一个以冒号:结尾的标识符,它可以放在程序中的任何语句之前(除了函数定义和变量声明的开始)。 工作原理:当执行到goto语句时,程序会查找与goto语句中指定的标签相匹配的标识符,并跳转到该标签所在的位置
|
4月前
|
存储 C语言
【C语言】基础刷题训练4(含全面分析和代码改进示例)
【C语言】基础刷题训练4(含全面分析和代码改进示例)
|
22天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
52 1
|
1月前
|
C语言 Windows
C语言课设项目之2048游戏源码
C语言课设项目之2048游戏源码,可作为课程设计项目参考,代码有详细的注释,另外编译可运行文件也已经打包,windows电脑双击即可运行效果
32 1
|
2月前
|
编译器 C语言
初识C语言:扩展世界观,选择语句之行
初识C语言:扩展世界观,选择语句之行
|
3月前
|
SQL 关系型数据库 C语言
PostgreSQL SQL扩展 ---- C语言函数(三)
可以用C(或者与C兼容,比如C++)语言编写用户自定义函数(User-defined functions)。这些函数被编译到动态可加载目标文件(也称为共享库)中并被守护进程加载到服务中。“C语言函数”与“内部函数”的区别就在于动态加载这个特性,二者的实际编码约定本质上是相同的(因此,标准的内部函数库为用户自定义C语言函数提供了丰富的示例代码)
|
4月前
|
C语言
【C语言刷题训练】——第7节(含代码与分析思路)
【C语言刷题训练】——第7节(含代码与分析思路)
|
4月前
|
存储 C语言
【C语言】鹏哥C语言刷题训练营——第5节内容笔记(含代码全面分析和改进,讲解)
【C语言】鹏哥C语言刷题训练营——第5节内容笔记(含代码全面分析和改进,讲解)
|
6月前
|
C语言
C语言实战项目——学生试卷分数统计
C语言实战项目——学生试卷分数统计