直接上代码 —— 语法分析程序

实验代码

#include<stdio.h>
#include<stdlib.h>
#define MaxRuleNum 8       //规则式数量
#define MaxVnNum 5         //非终结符数量
#define MaxVtNum 5         //终结符数量
#define MaxStackDepth 20
#define MaxPLength 20
#define MaxStLength 50     //当前要分析的字符串

typedef enum {false,true} bool;

struct pRNode /*产生式右部结构*/
{
 int rCursor; /*右部序号*/
 struct pRNode *next;
};

struct pNode /*产生式结点结构*/
{
 int lCursor; /*左部符号序号*/
 int rLength; /*右部长度*/
 /*注当rLength = 1 时,rCursor = -1为空产生式*/
 struct pRNode *rHead; /*右部结点头指针*/
};

char Vn[MaxVnNum + 1]; /*非终结符集*/
int vnNum;
char Vt[MaxVtNum + 1]; /*终结符集*/
int vtNum;
struct pNode P[MaxRuleNum]; /*产生式*/
int PNum; /*产生式实际个数*/
char buffer[MaxPLength + 1];
char ch; /*符号或string ch;*/
char st[MaxStLength]; /*要分析的符号串*/

struct collectNode /*集合元素结点结构*/
{
 int nVt; /*在终结符集中的下标*/
 struct collectNode *next;
};
struct collectNode* first[MaxVnNum + 1]; /*first集*/     //结构体指针数组
struct collectNode* follow[MaxVnNum + 1]; /*follow集*/   //结构体指针数组

int analyseTable[MaxVnNum + 1][MaxVtNum + 1 + 1];
/*预测分析表存放为产生式的编号,+1用于存放结束符,多+1用于存放#(-1)*/
int analyseStack[MaxStackDepth + 1]; /*分析栈*/
int topAnalyse; /*分析栈顶*/
/*int reverseStack[MaxStackDepth + 1]; /*颠倒顺序栈*/
/*int topReverse; /*倒叙栈顶*/

void Init();/*初始化*/
int IndexCh(char ch);
/*返回Vn在Vn表中的位置+100、Vt在Vt表中的位置,-1表示未找到*/
void InputVt(); /*输入终结符*/
void InputVn();/*输入非终结符*/
void ShowChArray(char* collect);/*输出Vn或Vt的内容*/
void InputP();/*产生式输入*/
bool CheckP(char * st);/*判断产生式正确性*/
void First(int U);/*计算first集,U->xx...*/
void AddFirst(int U, int nCh); /*加入first集*/
bool HaveEmpty(int nVn); /*判断first集中是否有空(-1)*/
void Follow(int V);/*计算follow集*/
void AddFollow(int V, int nCh, int kind);/*加入follow集,
 kind = 0表加入follow集,kind = 1加入first集*/
void ShowCollect(struct collectNode **collect);/*输出first或follow集*/
void FirstFollow();/*计算first和follow*/
void CreateAT();/*构造预测分析表*/
void ShowAT();/*输出分析表*/
void Identify(char *st);/*主控程序,为操作方便*/
/*分析过程显示操作为本行变换所用,与教程的显示方式不同*/
void InitStack();/*初始化栈及符号串*/
void ShowStack();/*显示符号栈中内容*/
void Pop();/*栈顶出栈*/
void Push(int r);/*使用产生式入栈操作*/

void main()
{
 char todo,ch;    //todo表示将要执行的操作是y还是n
 Init();
 InputVn();
 InputVt();
 InputP();
 getchar();
 FirstFollow();
 printf("所得first集为:");
 ShowCollect(first);
 printf("所得follow集为:");
 ShowCollect(follow);
 CreateAT();
 ShowAT();
 todo = 'y';
 while('y' == todo)
 {
  printf("\n是否继续进行句型分析?(y / n):");
  todo = getchar();
  while('y' != todo && 'n' != todo)    //用来过滤掉输入的不是y/n
  {
   printf("\n(y / n)? ");
   todo = getchar();
  }
  if('y' == todo)
  {
   int i;
   InitStack();
   printf("请输入符号串(以#结束) : ");
   ch = getchar();
   i = 0;
   while('#' != ch && i < MaxStLength)
   {
    if(' ' != ch && '\n' != ch)  //过滤掉空格和换行
    {
     st[i++] = ch;
    }
    ch = getchar();
   }
   if('#' == ch && i < MaxStLength)  //表示到达了字符串结尾
   {
    st[i] = ch;
    Identify(st);
   }
   else
    printf("输入出错!\n");
  }
 }
 getchar();
}
void Init()
{
 int i,j;
 vnNum = 0;
 vtNum = 0;
 PNum = 0;
 for(i = 0; i <= MaxVnNum; i++)
  Vn[i] = '\0';
 for(i = 0; i <= MaxVtNum; i++)
  Vt[i] = '\0';
 for(i = 0; i < MaxRuleNum; i++)
 {
  P[i].lCursor = -1;   //左部符号序号初始化为int类型 -1 (数组下标从0开始)
  P[i].rHead = NULL;
  P[i].rLength = 0;
 }
 for(i = 0; i <= MaxPLength; i++)
  buffer[i] = '\0';
 for(i = 0; i < MaxVnNum; i++)  //因为其为指针数组,所以数组中存放的是指针,初始化为NULL
 {
  first[i] = NULL;
  follow[i] = NULL;
 }
 for(i = 0; i <= MaxVnNum; i++)      //按行列初始化预测分析表
 {
  for(j = 0; j <= MaxVtNum + 1; j++)   //按理来说,行是非终结符,列是终结符+#,但是这里定义的MaxVnNum和MaxVtNum相同,实际中还是需要注意
   analyseTable[i][j] = -1;
 }
}
/*返回Vn在Vn表中的位置+100、Vt在Vt表中的位置,-1表示未找到*/
int IndexCh(char ch)
{
 int n;
 n = 0; /*is Vn?*/
 while(ch != Vn[n] && '\0' != Vn[n])  //判断是否已经在非终结符数组里,若不在则n++
  n++;
 if('\0' != Vn[n])   //若在则返回地址
  return 100 + n;
 n = 0; /*is Vt?*/
 while(ch != Vt[n] && '\0' != Vt[n])   //判断是否已经在终结符数组里,若不在则n++
  n++;
 if('\0' != Vt[n])  //若在则返回地址
  return n;
 return -1;  //若不在则返回-1
}
/*输出Vn或Vt的内容*/
void ShowChArray(char* collect)
{
 int k = 0;
 while('\0' != collect[k])
 {
  printf(" %c ", collect[k++]);
 }
 printf("\n");
}
/*输入非终结符*/
void InputVn()
{
 int inErr = 1;
 int n,k;
 char ch;
 while(inErr)
 {
  printf("\n请输入所有的非终结符,注意:");
  printf("请将开始符放在第一位,并以#号结束:\n");
  ch = ' ';
  n = 0;
  /*初始化数组*/
  while(n < MaxVnNum)
  {
   Vn[n++] = '\0';
  }
  n = 0;
  while(('#' != ch) && (n < MaxVnNum))   //当没有到字符串结尾
  {
   if(' ' != ch && '\n' != ch && -1 == IndexCh(ch))  //过滤掉空格换行和已经在数组中出现的字符
   {
    Vn[n++] = ch;
    vnNum++;
   }
   ch = getchar();
  }
  Vn[n] = '#'; /*以“#”标志结束用于判断长度是否合法*/
  k = n; /*k用于记录n以便改Vn[n]='\0'*/
  if('#' != ch)
  {
   if( '#' != (ch = getchar()))   //如果不是以#结尾,则一直从键盘输入
   {
    while('#' != (ch = getchar()))
     ;
    printf("\n符号数目超过限制!\n");
    inErr = 1;
    continue;
   }
  }
  /*正确性确认,正确则,执行下下面,否则重新输入*/
  Vn[k] = '\0';
  ShowChArray(Vn);
  ch = ' ';
  while('y' != ch && 'n' != ch)
  {
   if('\n' != ch)
   {
    printf("输入正确确认?(y/n):");
   }
   scanf("%c", &ch);
  }
  if('n' == ch)
  {
   printf("录入错误重新输入!\n");
   inErr = 1;
  }
  else
  {
   inErr = 0;
  }
 }
}
/*输入终结符*/
void InputVt()
{
 int inErr = 1;
 int n,k;
 char ch;
 while(inErr)
 {
  printf("\n请输入所有的终结符,注意:");
  printf("以#号结束:\n");
  ch = ' ';
  n = 0;
  /*初始化数组*/
  while(n < MaxVtNum)
  {
   Vt[n++] = '\0';
  }
  n = 0;
  while(('#' != ch) && (n < MaxVtNum))
  {
   if(' '!= ch && '\n' != ch && -1 == IndexCh(ch))
   {
    Vt[n++] = ch;
    vtNum++;
   }
   ch = getchar();
  }
  Vt[n] = '#'; /*以“#”标志结束*/
  k = n; /*k用于记录n以便改Vt[n]='\0'*/
  if('#' != ch)
  {
   if( '#' != (ch = getchar()))
   {
    while('#' != (ch = getchar()))
    printf("\n符号数目超过限制!\n");
    inErr = 1;
    continue;
   }
  }
  /*正确性确认,正确则,执行下下面,否则重新输入*/
  Vt[k] = '\0';
  ShowChArray(Vt);
  ch =' ';
  while('y' != ch && 'n' != ch)
  {
   if('\n' != ch)
   {
    printf("输入正确确认?(y/n):");
   }
   scanf("%c", &ch);
  }
  if('n' == ch)
  {
   printf("录入错误重新输入!\n");
   inErr = 1;
  }
  else
  {
   inErr = 0;
  }
 }
}
/*产生式输入*/
void InputP()
{
 char ch;
 int i = 0, n,num;
 printf("请输入文法产生式的个数:");
 scanf("%d", &num);
 PNum = num;
 getchar(); /*消除回车符*/
 printf("\n请输入文法的%d个产生式,并以回车分隔每个产生式:", num);
 printf("\n");
 while(i < num)
 {
  printf("第%d个:", i);
  /*初始化*/
  for(n =0; n < MaxPLength; n++)
   buffer[n] = '\0';
  /*输入产生式串*/
  ch = ' ';
  n = 0;
  while('\n' != (ch = getchar()) && n < MaxPLength)
  {
   if(' ' != ch)
    buffer[n++] = ch;
  }
  buffer[n] = '\0';
/*  printf("%s", buffer);*/
  if(CheckP(buffer))
  {
   /*填写入产生式结构体*/
   struct pRNode *pt;
   struct pRNode *qt;
   P[i].lCursor = IndexCh(buffer[0]);   //将文法开始符送到规则式左部
   pt=(struct pRNode*)malloc(sizeof(struct pRNode));
   pt->rCursor = IndexCh(buffer[3]);    //产生式的形式是S->AbC……  所以buffer[1]和buffer[2]不用送
   pt->next = NULL;
   P[i].rHead = pt;
   n = 4;       //n用来记录buffer中当前元素下标
   while('\0' != buffer[n])  //当规则式还不为空的话 继续
   {
    qt=(struct pRNode *)malloc(sizeof(struct pRNode));
    qt->rCursor = IndexCh(buffer[n]);
    qt->next = NULL;
    pt->next = qt;
    pt = qt;
    n++;
   }
   P[i].rLength = n - 3;   //规则式右部的长度等于总长度减去(文法开始符 - > )即减去3
   i++;
   /*调试时使用*/
  }
  else
   printf("输入符号含非法在成分,请重新输入!\n");
 }
}
/*判断产生式正确性*/
bool CheckP(char * st)
{
 int n;
 if(100 > IndexCh(st[0]))   //规则式第一个是非终结符 前面Vn返回的是n+100 这里用来区分和检查 如果规则式左部是终结符则报错
  return false;
 if('-' != st[1])
  return false;
 if('>' != st[2])
  return false;
 for(n = 3; '\0' != st[n]; n ++)
 {
  if(-1 == IndexCh(st[n]))   //如果没有在符号表中找到也是报错
   return false;
 }
 return true;
}
/*====================first & follow======================*/
/*计算first集,U->xx...*/
void First(int U)
{
 int i,j;
 for(i = 0; i < PNum; i++)
 {
  if(P[i].lCursor == U)
  {
   struct pRNode* pt;
   pt = P[i].rHead;
   j = 0;
   while(j < P[i].rLength)
   {
    if(100 > pt->rCursor)   //表示为终结符
    {
     /*注:此处因编程出错,使空产生式时
     rlength同样是1,故此处同样可处理空产生式*/
     AddFirst(U, pt->rCursor);
     break;
    }
    else
    {
     if(NULL == first[pt->rCursor - 100])  //表示为非终结符 且还没有求first集合 则求first集合
     {
      First(pt->rCursor);
     }
     AddFirst(U, pt->rCursor);    //把其所求得的first集合加到U
     if(!HaveEmpty(pt->rCursor))  //如果其first集合中没有空则不用继续求了
     {
      break;
     }
     else  //如果其first集合为空,则继续求下一个first
     {
      pt = pt->next;
     }
    }
    j++;
   }
   if(j >= P[i].rLength) /*当产生式右部都能推出空时*/
    AddFirst(U, -1);
  }
 }
}
/*加入first集*/
void AddFirst(int U, int nCh) /*当数值小于100时nCh为Vt*/
/*当处理非终结符时,AddFirst不添加空项(-1)*/
{
 struct collectNode *pt, *qt;
 int ch; /*用于处理Vn*/
 pt = NULL;
 qt = NULL;
 if(nCh < 100)  // 表示其为终结符
 {
  pt = first[U - 100];
  while(NULL != pt)
  {
   if(pt->nVt == nCh)
    break;
   else
   {
    qt = pt;
    pt = pt->next;
   }
  }
  if(NULL == pt) //表示规则式右部第一个不是终结符
  {
   pt = (struct collectNode *)malloc(sizeof(struct collectNode));
   pt->nVt = nCh;
   pt->next = NULL;
   if(NULL == first[U - 100])
   {
    first[U - 100] = pt;
   }
   else
   {
    qt->next = pt; /*qt指向first集的最后一个元素*/
   }
   pt = pt->next;
  }
 }
 else
 {
  pt = first[nCh - 100];
  while(NULL != pt)
  {
   ch = pt->nVt;
   if(-1 != ch)
   {
    AddFirst(U, ch);
   }
   pt = pt->next;
  }
 }
}
/*判断first集中是否有空(-1)*/
bool HaveEmpty(int nVn)
{
 if(nVn < 100) /*为终结符时(含-1),在follow集中用到*/
  return false;
 struct collectNode *pt;
 pt = first[nVn - 100];
 while(NULL != pt)
 {
  if(-1 == pt->nVt)
   return true;
  pt = pt->next;
 }
 return false;
}
/*计算follow集,例:U->xVy,U->xV.(注:初始符必含#——"-1")*/
void Follow(int V)
{
 int i;
 struct pRNode *pt ;
 if(100 == V) /*当为初始符时*/
  AddFollow(V, -1, 0 );
 for(i = 0; i < PNum; i++)
 {
  pt = P[i].rHead;
  while(NULL != pt && pt->rCursor != V) /*注此不能处理:U->xVyVz的情况*/
   pt = pt->next;
  if(NULL != pt)
  {
   pt = pt->next; /*V右侧的符号*/
   if(NULL == pt) /*当V后为空时V->xV,将左符的follow集并入V的follow集中*/
   {
    if(NULL == follow[P[i].lCursor - 100] && P[i].lCursor != V)
    {
     Follow(P[i].lCursor);
    }
    AddFollow(V, P[i].lCursor, 0);
   }
   else /*不为空时V->xVy,(注意:y->),调用AddFollow加入Vt或y的first集*/
   {
    while(NULL != pt && HaveEmpty(pt->rCursor))
    {
AddFollow(V, pt->rCursor, 1); /*y的前缀中有空时,加如first集*/
     pt = pt->next;
    }
    if(NULL == pt) /*当后面的字符可以推出空时*/
    {
     if(NULL == follow[P[i].lCursor - 100] && P[i].lCursor != V)
     {
      Follow(P[i].lCursor);
     }
     AddFollow(V, P[i].lCursor, 0);
    }
    else /*发现不为空的字符时*/
    {
     AddFollow(V, pt->rCursor, 1);
    }
   }
  }
 }
}
/*当数值小于100时nCh为Vt*/
/*#用-1表示,kind用于区分是并入符号的first集,还是follow集
kind = 0表加入follow集,kind = 1加入first集*/
void AddFollow(int V, int nCh, int kind)
{
 struct collectNode *pt, *qt;
 int ch; /*用于处理Vn*/
 pt = NULL;
 qt = NULL;
 if(nCh < 100) /*为终结符时*/
 {
  pt = follow[V - 100];
  while(NULL != pt)
  {
   if(pt->nVt == nCh)
    break;
   else
   {
    qt = pt;
    pt = pt->next;
   }
  }
  if(NULL == pt)
  {
   pt = (struct collectNode *)malloc(sizeof(struct collectNode));
   pt->nVt = nCh;
   pt->next = NULL;
   if(NULL == follow[V - 100])
   {
    follow[V - 100] = pt;
   }
   else
   {
    qt->next = pt; /*qt指向follow集的最后一个元素*/
   }
   pt = pt->next;
  }
 }
 else /*为非终结符时,要区分是加first还是follow*/
 {
  if(0 == kind)
  {
   pt = follow[nCh - 100];
   while(NULL != pt)
   {
    ch = pt->nVt;
    AddFollow(V, ch, 0);
    pt = pt->next;
   }
  }
  else
  {
   pt = first[nCh - 100];
   while(NULL != pt)
   {
    ch = pt->nVt;
    if(-1 != ch)
    {
     AddFollow(V, ch, 1);
    }
    pt = pt->next;
   }
  }
 }
}
/*输出first或follow集*/
void ShowCollect(struct collectNode **collect)
{
 int i;
 struct collectNode *pt;
 i = 0;
 while(NULL != collect[i])
 {
  pt = collect[i];
  printf("\n%c:\t", Vn[i]);
  while(NULL != pt)
  {
   if(-1 != pt->nVt)
   {
    printf(" %c", Vt[pt->nVt]);
   }
   else
    printf(" #");
   pt = pt->next;
  }
  i++;
 }
 printf("\n");
}
/*计算first和follow*/
void FirstFollow()
{
 int i;
 i = 0;
 while('\0' != Vn[i])
 {
  if(NULL == first[i])
   First(100 + i);
  i++;
 }
 i = 0;
 while('\0' != Vn[i])
 {
  if(NULL == follow[i])
   Follow(100 + i);
  i++;
 }
}
/*=================构造预测分析表,例:U::xyz=============*/
void CreateAT()
{
 int i;
 struct pRNode *pt;
 struct collectNode *ct;
 for(i = 0; i < PNum; i++)
 {
  pt = P[i].rHead;
  while(NULL != pt && HaveEmpty(pt->rCursor))
  {
   /*处理非终结符,当为终结符时,定含空为假跳出*/
   ct = first[pt->rCursor - 100];
   while(NULL != ct)
   {
    if(-1 != ct->nVt)
     analyseTable[P[i].lCursor - 100][ct->nVt] = i;
    ct = ct->next;
   }
   pt = pt->next;
  }
  if(NULL == pt)
  {
   /*NULL == pt,说明xyz->,用到follow中的符号*/
   ct = follow[P[i].lCursor - 100];
   while(NULL != ct)
   {
    if(-1 != ct->nVt)
     analyseTable[P[i].lCursor - 100][ct->nVt] = i;
    else /*当含有#号时*/
     analyseTable[P[i].lCursor - 100][vtNum] = i;
    ct = ct->next;
   }
  }
  else
  {
   if(100 <= pt->rCursor) /*不含空的非终结符*/
   {
    ct = first[pt->rCursor - 100];
    while(NULL != ct)
    {
     analyseTable[P[i].lCursor - 100][ct->nVt] = i;
     ct = ct->next;
    }
   }
   else /*终结符或者空*/
   {
    if(-1 == pt->rCursor) /*-1为空产生式时*/
    {
     ct = follow[P[i].lCursor - 100];
     while(NULL != ct)
     {
      if(-1 != ct->nVt)
       analyseTable[P[i].lCursor - 100][ct->nVt] = i;
      else /*当含有#号时*/
       analyseTable[P[i].lCursor - 100][vtNum] = i;
      ct = ct->next;
     }
    }
    else /*为终结符*/
    {
     analyseTable[P[i].lCursor - 100][pt->rCursor] = i;
    }
   }
  }
 }
}
/*输出分析表*/
void ShowAT()
{
 int i,j;
 printf("构造预测分析表如下:\n");
 printf("\t|\t");
 for(i = 0; i < vtNum; i++)
 {
  printf("%c\t", Vt[i]);
 }
 printf("#\t\n");
 printf("- - -\t|- - -\t");
 for(i = 0; i <= vtNum; i++)
  printf("- - -\t");
 printf("\n");
 for(i = 0; i < vnNum; i++)
 {
  printf("%c\t|\t", Vn[i]);
  for(j = 0; j <= vtNum; j++)
  {
   if(-1 != analyseTable[i][j])
    printf("R(%d)\t", analyseTable[i][j]);
   else
    printf("error\t");
  }
  printf("\n");
 }
}
/*=================主控程序=====================*/
void Identify(char *st)
{
 int current,step,r; /*r表使用的产生式的序号*/
 printf("\n%s的分析过程:\n", st);
 printf("步骤\t分析符号栈\t当前指示字符\t使用产生式序号\n");

 step = 0;
 current = 0; /*符号串指示器*/
 printf("%d\t",step);
 ShowStack();
 printf("\t\t%c\t\t- -\n", st[current]);
 while('#' != st[current])
 {
  if(100 > analyseStack[topAnalyse]) /*当为终结符时*/
  {
   if(analyseStack[topAnalyse] == IndexCh(st[current]))
   {
    /*匹配出栈,指示器后移*/
    Pop();
    current++;
    step++;
    printf("%d\t", step);
    ShowStack();
    printf("\t\t%c\t\t出栈、后移\n", st[current]);
   }
   else
   {
    printf("%c-%c不匹配!", analyseStack[topAnalyse], st[current]);
    printf("此串不是此文法的句子!\n");
    return;
   }
  }
  else /*当为非终结符时*/
  {
   r = analyseTable[analyseStack[topAnalyse] - 100][IndexCh(st[current])];
   if(-1 != r)
   {
    Push(r); /*产生式右部代替左部,指示器不移动*/
    step++;
    printf("%d\t", step);
    ShowStack();
    printf("\t\t%c\t\t%d\n", st[current], r);
   }
   else
   {
    printf("无可用产生式,此串不是此文法的句子!\n");
    return;
   }
  }
 }
 if('#' == st[current])
 {
  if(0 == topAnalyse && '#' == st[current])
  {
   step++;
   printf("%d\t", step);
   ShowStack();
   printf("\t\t%c\t\t分析成功!\n", st[current]);
   printf("%s是给定文法的句子!\n", st);
  }
  else
  {   while(topAnalyse > 0)
   {    if(100 > analyseStack[topAnalyse]) /*当为终结符时*/
    {     printf("无可用产生式,此串不是此文法的句子!\n");
     return;
    }
    else
    {     r = analyseTable[analyseStack[topAnalyse] - 100][vtNum];
     if(-1 != r)
     {      Push(r); /*产生式右部代替左部,指示器不移动*/
      step++;
      printf("%d\t", step);
      ShowStack();
      if(0 == topAnalyse && '#' == st[current])
      {       printf("\t\t%c\t\t分析成功!\n", st[current]);
       printf("%s是给定文法的句子!\n", st);
      }
      else
       printf("\t\t%c\t\t%d\n", st[current], r);     }
     else
     {      printf("无可用产生式,此串不是此文法的句子!\n");
      return;     }
    }
   }
  }
 }
}
/*初始化栈及符号串*/
void InitStack()
{ int i;
 /*分析栈的初始化*/
 for(i = 0; i < MaxStLength; i++)
  st[i] = '\0';
 analyseStack[0] = -1; /*#(-1)入栈*/
 analyseStack[1] = 100; /*初始符入栈*/
 topAnalyse = 1;
}
/*显示符号栈中内容*/
void ShowStack()
{ int i;
 for(i = 0; i <= topAnalyse; i++)
 {  if(100 <= analyseStack[i])
   printf("%c", Vn[analyseStack[i] - 100]);
  else
  {   if(-1 != analyseStack[i])
    printf("%c", Vt[analyseStack[i]]);
   else
    printf("#");
  }
 }
}
/*栈顶出栈*/
void Pop()
{ topAnalyse--;
}
/*使用产生式入栈操作*/
void Push(int r)
{ int i;
 struct pRNode *pt;
 Pop();
 pt = P[r].rHead;
 if(-1 == pt->rCursor) /*为空产生式时*/
  return;
 topAnalyse += P[r].rLength;
 for(i = 0; i < P[r].rLength; i++)
 {  /*不为空产生式时*/
  analyseStack[topAnalyse - i] = pt->rCursor;/*逆序入栈*/
  pt = pt->next;
 }/*循环未完时pt为空,则说明rLength记录等出错*/
}


运行结果

在这里插入图片描述

在这里插入图片描述

实验小结

① 起初我没有一点头绪,所以看了老师的代码,但是第一步复制粘贴到codeblocks就有一点点问题,一直是报302错误,我就想着是换行或者空格错误,然后我就把代码复制粘贴到了Notepad++里,进行了相应的检查和替换,后来成功解决这个问题。(一开始我在“视图”里面“显示所有字符”,还以为是换行的问题,后来替换了还是报错,才发现是空格问题)

在这里插入图片描述

② 了解到了英文都是半角,中文是全角,而我们写代码的时候,用到的基本是半角。之前以为是换行问题,是因为,之前有了解到,Linux换行符是\n, Windows换行符是\r\n, 如果在windows编的程序,拿到linux运行会出bug,反之同理。

③ 成功解决了上一个问题后,又出现了下面的问题,一直是undeclared(first use in this function)和expected expression before ‘)’token,但是我看了都是单看那一句是没有语法错误的,我就又去看了pRNode的定义。

④ 我在分号前面加了pRNode,但还是报错,想着以前都是这样没错呀,再仔细一看才发现了这个问题。以前写数据结构代码时,经常是使用typedef struct,所以可能没有注意到这个问题,在c语言中,struct pRNode,那么在后面的分号前面定义的是变量名,如果要定义的话,必须使用struct pRNode,如果在第一次更改基础上,即分号前面加了pRNode之后,再在struct前面加了typedef,就可以这样使用了。

在这里插入图片描述

⑤ LL1文法,在进行句型分析时,分析过程实质上是:首先需要根据select构造LL1分析表;其次在符号栈中,取出栈顶:若是非终结符则与束流匹配,读取LL1分析表:若有,则规则式右部逆序进入符号栈;若无,则报错;若取出栈顶后是终结符,则终结符与束流中的终结符匹配,出栈,依次循环,直到遇到#结束。

⑥ 仔细看这段代码,虽然比较长,但是整个层次比较清晰,和我们学习数据结构时的,图中的邻接表很像。在存储规则式时,非终结符在一个数组里,终结符在一个数组里,规则式左部是非终结符,其由左部符号下标,右部长度和右部结点头指针三个部分组成,规则式右部是一系列字符串,其由右部序号,指向右部的指针两个部分构成。学习了数据结构后,再来学习这,根据可视化,就很容易理解了。

⑦ 在代码测试时,有一些细节问题,比如,空规则式,直接是B->即可,然后在first集合中,空字符是用#表示的;在输入完规则式后,还需要输入换行,才能显示结果;输入非终结符或者终结符组合或者句型判断输入的字符串时,都需要以#结尾;每次输入完后,还会让你判断y/n,如果输入其他的,会一直让你输入y/n,直到正确为止等等,整个实验工程量浩大,自己在写的时候,还有很多细节需要注意,学到了很多。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值