本文章实现内容:
1、设计一个表示文法的数据结构;
2、从文本文件中读入文法,利用定义的数据结构存放文法,并输出;
文法定义的4个部分:
G( Vn, Vt, S, P)
Vn文法的非终结符号集合,在实验中用大写的英文字母表示;
Vt文法的终结符号集合,在实验中用小写的英文字母表示;
s开始符号,在实验中是Vn集合中的一个元素;
产生式,分左部和右部,左部为非终结符号中的一个,右部为终结符号或非终结符号组成的字符串,如S->ab|c
输入数据举例:
编辑一个文本文件 text.txt,在文件中输入如下内容:
S->Qc;
S->c;
Q->Rb;
Q->b;
R->Sa;
R->a;
上述文法整理后的输出形式:
S->Qc|c
Q->Rb|b
R->Sa|a
终结符:c b a
代码如下:
#include <stdio.h>
#include <string.h>
#define N 50 // 符号的最大数目
#define char_len 5 // 符号的最大长度+1
#define symbol_len 21 // 产生式符号的最大长度+1
typedef struct non_terminal *Nonterminal;
struct non_terminal { // 非终结符结构体
char name[char_len]; // 字符
char production[N][symbol_len]; // 产生式们
};
typedef struct data *grammar;
struct data{ // 文法结构体
// 因为看长度都是找到指向为空的指针说明结束,所以要初始化
// 第一个就是开始符,没有溢出警告,N可以设大点,留点盈余
Nonterminal Vn[N]; // 非终结符包含产生式
// 终结符里没有空,所有空用@代替
char Vt[N]; // 终结符,假定都是一个字
};
// 生成一个初始化后的文法框架
grammar new_grammar()
{
int i;
grammar x = (grammar)malloc(sizeof(struct data)); // 文法框架
for(i=0;i<N;i++)
{
x->Vt[i]='\0';
x->Vn[i]=NULL;
}
return x;
}
// 读入文法函数,一行一行读文件,生成文法
void Generative_grammar(char* str,grammar my_grammar)
{
int t=0,i=0,j=0,k=0;
char front[char_len],behind[symbol_len]; //产生式的前端和后端
while(1)
{
if(str[i]=='\0'||str[i]=='\n'||str[i]==';') // 读到字符串结尾就结束
{
if(t) // 正确录入了前后端
{
behind[j] = '\0'; // 先来个结束符
for(i=0;i<N;i++) // 后面用不到i了,在这做个遍历标记
{
if(my_grammar->Vn[i]==NULL) // 没找到,就建一个
{
my_grammar->Vn[i]=(Nonterminal)malloc(sizeof(struct non_terminal));
for(j=0;j<char_len;j++)
{
my_grammar->Vn[i]->name[j] = front[j];
if(front[j]=='\0')
break;
}
for(j=0;j<N;j++) // 初始化产生式
{
my_grammar->Vn[i]->production[j][0]='\0';
}
break;
}
if(strcmp(my_grammar->Vn[i]->name,front)==0) //找到首部位置
{
break;
}
}
// 到这里i就指向了需要更改的位置了,给他添加产生式
for(j=0;j<N;j++) // 找一个空的位置
{
if(my_grammar->Vn[i]->production[j][0]=='\0')
{
t=0;
for(k=0;k<symbol_len;k++)
{
if(behind[k]=='|')
{
my_grammar->Vn[i]->production[j][k-t] = '\0';
j++;
t=k+1;
continue;
}
my_grammar->Vn[i]->production[j][k-t] = behind[k];
if(behind[k]=='\0')
break;
}
break;
}
}
}
break;
}
if(str[i]=='-'&&str[i+1]=='>') // 前端后端分界点
{
t=1; // 前后端标志更改,
front[j] = '\0'; // 来个结束符
j=0; // 计数器归零
i+=2; // 跳过这两个
continue;
}
if(t) // 当前在后端
{
behind[j]=str[i]; // 记录当前符号
j++; // 位置标记右移
}
else // 当前在前端
{
front[j]=str[i]; // 记录当前符号
j++; // 位置标记右移
}
i++;
}
}
// 给出文法,提取出终结符
void get_Vt(grammar my_grammar)
{
int i,j,k,ii,jj,kk,t,maxjj;
for(i=0;i<N;i++) // i第一层遍历非终结符
{
if(my_grammar->Vn[i]==NULL)
break;
for(j=0;j<N;j++) // j第一层遍历产生式
{
if(my_grammar->Vn[i]->production[j][0]=='\0')
break;
else // 遍历每一个产生式,找出终结符存到Vt
{
for(k=0;k<symbol_len;k++) // 遍历该产生式
{
if(my_grammar->Vn[i]->production[j][k]=='\0')
break;
maxjj = 0;//最长的非终结符
for(ii=0;ii<N;ii++) // 在所有非终结符中找有没有它
{
if(my_grammar->Vn[ii]==NULL)
break;
else
{
if(my_grammar->Vn[ii]->name[0]==my_grammar->Vn[i]->production[j][k])
{
t=1;
for(jj=1;jj<char_len;jj++)
{
if(my_grammar->Vn[ii]->name[jj]=='\0')
break;//到头了
if(my_grammar->Vn[ii]->name[jj]!=my_grammar->Vn[i]->production[j][k+jj])
{
t=0;//这个不是
break;
}
}
if(t&&maxjj<jj) // 找到了,且比之前长
{
maxjj=jj;
}
}
}
}
for(kk=0;kk<N;kk++) // 看看非终结符集有没有
{
t=0;
if(my_grammar->Vt[kk]=='\0')
break;
if(my_grammar->Vt[kk]==my_grammar->Vn[i]->production[j][k])
{
t=1;//找到了
break;
}
}
if(t)
continue;
if(maxjj==0) //走到这里,最大jj是0时,终结符和非终结符都没有
{
my_grammar->Vt[kk]=my_grammar->Vn[i]->production[j][k];
}
else
{
k=k+maxjj-1;
}
}
}
}
}
}
// 文法的输出函数
void Output_grammar(grammar my_grammar)
{
int i,j;
for(i=0;i<N;i++)
{
if(my_grammar->Vn[i]==NULL)
break;
printf("%s->",my_grammar->Vn[i]->name);
for(j=0;j<N;j++)
{
if(my_grammar->Vn[i]->production[j][0]=='\0')
break;
if(j!=0)
printf("|");
printf("%s",my_grammar->Vn[i]->production[j]);
}
printf("\n");
}
printf("终结符:");
for(i=0;i<N;i++)
{
if(my_grammar->Vt[i]=='\0')
break;
printf("%c ",my_grammar->Vt[i]);
}
}
int main()
{
FILE *p=fopen("text.txt","r"); //只读打开文件
if(p==NULL) // 没有文件提示
{
printf("缺少文件“text.txt”");
exit(0);
}
char str[N];
grammar my_grammar = new_grammar();
while(fgets(str, N, p) != NULL) // 一行一行读取
{
Generative_grammar(str,my_grammar);
}
fclose(p); // 关闭文件
get_Vt(my_grammar);
Output_grammar(my_grammar);
}
同样支持这样的输入:
S->Qc|c|cc|da|Q1
Q->Rb|b|V
R->Sa|a|cV2
Q1->aa|bd
V2->d|Q2
Q2->a
V->V2|e
结果:
S->Qc|c|cc|da|Q1
Q->Rb|b|V
R->Sa|a|cV2
Q1->aa|bd
V2->d|Q2
Q2->a
V->V2|e
终结符:c d a b e