实验目的

运用简单优先语法分析的基本原理实现对于句子的语法分析

实验要求

1、文法及待分析符号串由用户输入
2、数据结构可自行设计

实验内容

1、任意输入一个文法,判断它是否为简单优先文法
2、如果是,请构造该文法对应的算符优先分析表
3、输入一个字符串,判断它是否为该文法的一个句子。

知识储备

首先要知道一些知识点

给出一个语法树:

简单效应分析R语言_算法


短语:

若S=*=>αAδ且A=+=>β,则称β是相对于非终结符A的句型αβδ的短语。

即:语法树中以非终结符的作为根的子树的叶子所组成的字符串。

如:ba是相对于非终结符A的句型AB的短语。句型baSb的短语有ba,a,Sb,baSb。

直接短语:
若S=*=>αAδ且A=>β,则称β是相对于非终结符A的句型αβδ的直接短语。

即:语法树中以非终结符的作为根的子树,它的孩子都是叶子,没有其他子树。

如:Sb是相对于非终结符B的句型AB的短语。句型baSb的短语有a,Sb。

句柄:
位于句型最左边的直接短语称为该句型的句柄。

即:位于语法树中最左边的直接短语。

如:句型baSb的句柄是a。

简单优先文法定义

一个文法是简单优先文法,需要满足以下两个条件:

在文法符号集中V,任意两个符号之间必须之后一种优先关系存在。(显然满足)
在文法中,两个产生式不能有相同的右部。

简单优先分析法的操作步骤

将输入输入串a1a2···an#依次压栈,不断比较栈顶符号ai和下一个待输入符号aj的优先级,若ai>·aj则进行下一步,否则重复此步骤。

意思是:停止条件是ai>·aj表示前面输入串一定比后面先归约,所以只需要在前面找句柄就行了。

栈顶符号ai即为句柄尾,从此处向左寻找句柄头ak,满足ak-1<·ak。

意思是:从后向前找ak-1<·ak表示ak之前的输入串一定比ai···ak后归约,由此确定现在就是要归约ai···ak。

由句柄ai···ak在文法中寻找右部为ai···ak的产生式;找到则将句柄替换为相应左部,找不到则说明该输入串不是该文法的句子。

重复以上步骤直到归约完成。

代码实现

数据结构设计

1.用数组来存储优先关系表。

简单效应分析R语言_归约_02

2.int judge(char *p,int k,char *psc);

*psc指向当前输入符号,*p和k表示为开始符号#,即p[k]=’#’&&k==1

简单效应分析R语言_算法_03

3.int find(int a,int b);
查找优先关系表,得出输入符号的优先关系。
4.int in_vt(char c);
将输入的符号转为数组,方便在find函数中查找符号之间的优先关系。

简单效应分析R语言_4s_04

#include<stdio.h>

int find(int a,int b)   //优先关系表
{
    int table[6][6] = {
                       1, -1, -1, -1, 1, 1,
                       1,  1, -1, -1, 1, 1,
                       1,  1,  2,  2, 1, 1,
                      -1,- 1, -1, -1, 0, 2,
                       1,  1,  2,  2, 1, 1,
                      -1, -1,- 1, -1, 2, 0
                      };

  return table[a-1][b-1];

}


int in_vt(char c)    //可以根据返回的数值去优先关系表里面查找优先关系
{                    //还可以判断是否是非终结符,不是非终结符返回0
   int n;

   switch(c)
   {
       case '+': n = 1; break;
       case '*': n = 2; break;
       case 'i': n = 3; break;
       case '(': n = 4; break;
       case ')': n = 5; break;
       case '#': n = 6; break;
       default : n = 0;
   }

   return n;

}




int judge(char *p,int k,char *psc)
{

        if(k == 1 && p[k] == '#' && (*psc == '+' || *psc == '*'))
        {
                printf("\n运算符前面没有操作数!\n");
                return 0;
        }
        if((*psc == '+' || *psc == '*') && (*(psc + 1) == '+' || *(psc + 1) == '*'))
        {
                printf("\n运算符号相邻!\n");
                return 0;
        }
        if(*psc == '#' && (*(psc - 1) == '+' || *(psc - 1) == '*'))
        {
                printf("\n运算符后面没有操作数!\n");
                return 0;
        }
        return 1;
}



int main()
{
   int  k;                   //栈顶指针
   char s[30] = {'\0'};      //分析栈
   char *ss;
   char in_c[50] = {'\0'};   //输入串
   char *psc;                //指向当前输入符号
   int  j;
   char q;
   int  flag;
   int  n;

while(1)
{

   printf("\n************************************\n");
   printf("请输入要归约的字符串(以‘#’结束):");
   scanf("%s",in_c);

   n = 1;          //记录步骤
   k = 1;
   s[k] = '#';
   s[k+1] = '\0';    //初始化
   ss = s + 1;       //指向栈底
   psc = in_c;


   printf("\n步骤\t栈内字符\t\t优先关系\t当前符号\t剩余输入串\t\t\t移进或归约\n");
   while(1)
   {
          if(judge(s,k,psc) == 0)
          {
                  printf("\n出错!\n");
                  break;
          }

          if(in_vt(s[k]))
              j = k;
          else
              j = k - 1;

          flag = find(in_vt(s[j]),in_vt(*psc));
          if(flag == 1)  //如果s[j] > 当前输入字符
          {
               do
               {
                   q = s[j];
                   if(in_vt(s[j-1]))
                        j--;
                   else
                        j = j - 2;
               }while(find(in_vt(s[j]),in_vt(q)) != -1);

               printf("(%d)\t%-24s>\t\t%c\t\t%-32s归约\n",n++,ss,*psc,psc+1);
               k = j + 1;
               s[k] = 'N';
               s[k+1] = '\0';
               continue;
          }
          else if(flag == -1)
               {
                   printf("(%d)\t%-24s<\t\t%c\t\t",n++,ss,*psc);
                   k++;
                   s[k] = *psc;
                   s[k+1] = '\0';
                   psc++;
                   printf("%-32s移进\n",psc);
                   continue;
               }
               else if(flag == 0)
                    {
                          if(s[j] == '#')
                          {
                               printf("(%d)\t%-24s=\t\t#\t\t\t\t\t\t接受\n",n,ss);
                               printf("\n归约成功!\n");
                               break;
                          }
                          else
                          {
                               printf("(%d)\t%-24s=\t\t%c\t\t",n++,ss,*psc);
                               k++;
                               s[k] = *psc;
                               s[k+1] = '\0';
                               psc++;
                               printf("%-32s移进\n",psc);
                               continue;
                          }
                     }
                     else
                     {
                          printf("(%d)\t%-24s无\t\t%c\t\t%-32s\\\n",n++,ss,*psc,psc+1);
                          printf("\n错误!\n");
                          break;
                     }

   }

}

 return 0;
}

运行结果
输入想要规约的字符串,以#号结尾:

简单效应分析R语言_4s_05

随后便会输出分析的表格,最后会输出规约的结果。

最后,其实存在一个问题,就是无法判断输入的文法是否为简单优先文法。