实验目的
运用简单优先语法分析的基本原理实现对于句子的语法分析
实验要求
1、文法及待分析符号串由用户输入
2、数据结构可自行设计
实验内容
1、任意输入一个文法,判断它是否为简单优先文法
2、如果是,请构造该文法对应的算符优先分析表
3、输入一个字符串,判断它是否为该文法的一个句子。
知识储备
首先要知道一些知识点
给出一个语法树:
短语:
若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.用数组来存储优先关系表。
2.int judge(char *p,int k,char *psc);
*psc指向当前输入符号,*p和k表示为开始符号#,即p[k]=’#’&&k==1
3.int find(int a,int b);
查找优先关系表,得出输入符号的优先关系。
4.int in_vt(char c);
将输入的符号转为数组,方便在find函数中查找符号之间的优先关系。
#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;
}
运行结果
输入想要规约的字符串,以#号结尾:
随后便会输出分析的表格,最后会输出规约的结果。
最后,其实存在一个问题,就是无法判断输入的文法是否为简单优先文法。