当前位置:   article > 正文

c语言 预备实验1文法的读入和输出 编译原理_文法的存储c语言代码

文法的存储c语言代码

本文章实现内容:

1、设计一个表示文法的数据结构;
2、从文本文件中读入文法,利用定义的数据结构存放文法,并输出;

文法定义的4个部分:
 G( Vn, Vt, S, P)
Vn文法的非终结符号集合,在实验中用大写的英文字母表示;

Vt文法的终结符号集合,在实验中用小写的英文字母表示; 

s开始符号,在实验中是Vn集合中的一个元素;

产生式,分左部和右部,左部为非终结符号中的一个,右部为终结符号或非终结符号组成的字符串,如S->ab|c

输入数据举例:

编辑一个文本文件 text.txt,在文件中输入如下内容:

  1. S->Qc;
  2. S->c;
  3. Q->Rb;
  4. Q->b;
  5. R->Sa;
  6. R->a;

上述文法整理后的输出形式: 

  1. S->Qc|c
  2. Q->Rb|b
  3. R->Sa|a
  4. 终结符:c b a

代码如下:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #define N 50 // 符号的最大数目
  4. #define char_len 5 // 符号的最大长度+1
  5. #define symbol_len 21 // 产生式符号的最大长度+1
  6. typedef struct non_terminal *Nonterminal;
  7. struct non_terminal { // 非终结符结构体
  8. char name[char_len]; // 字符
  9. char production[N][symbol_len]; // 产生式们
  10. };
  11. typedef struct data *grammar;
  12. struct data{ // 文法结构体
  13. // 因为看长度都是找到指向为空的指针说明结束,所以要初始化
  14. // 第一个就是开始符,没有溢出警告,N可以设大点,留点盈余
  15. Nonterminal Vn[N]; // 非终结符包含产生式
  16. // 终结符里没有空,所有空用@代替
  17. char Vt[N]; // 终结符,假定都是一个字
  18. };
  19. // 生成一个初始化后的文法框架
  20. grammar new_grammar()
  21. {
  22. int i;
  23. grammar x = (grammar)malloc(sizeof(struct data)); // 文法框架
  24. for(i=0;i<N;i++)
  25. {
  26. x->Vt[i]='\0';
  27. x->Vn[i]=NULL;
  28. }
  29. return x;
  30. }
  31. // 读入文法函数,一行一行读文件,生成文法
  32. void Generative_grammar(char* str,grammar my_grammar)
  33. {
  34. int t=0,i=0,j=0,k=0;
  35. char front[char_len],behind[symbol_len]; //产生式的前端和后端
  36. while(1)
  37. {
  38. if(str[i]=='\0'||str[i]=='\n'||str[i]==';') // 读到字符串结尾就结束
  39. {
  40. if(t) // 正确录入了前后端
  41. {
  42. behind[j] = '\0'; // 先来个结束符
  43. for(i=0;i<N;i++) // 后面用不到i了,在这做个遍历标记
  44. {
  45. if(my_grammar->Vn[i]==NULL) // 没找到,就建一个
  46. {
  47. my_grammar->Vn[i]=(Nonterminal)malloc(sizeof(struct non_terminal));
  48. for(j=0;j<char_len;j++)
  49. {
  50. my_grammar->Vn[i]->name[j] = front[j];
  51. if(front[j]=='\0')
  52. break;
  53. }
  54. for(j=0;j<N;j++) // 初始化产生式
  55. {
  56. my_grammar->Vn[i]->production[j][0]='\0';
  57. }
  58. break;
  59. }
  60. if(strcmp(my_grammar->Vn[i]->name,front)==0) //找到首部位置
  61. {
  62. break;
  63. }
  64. }
  65. // 到这里i就指向了需要更改的位置了,给他添加产生式
  66. for(j=0;j<N;j++) // 找一个空的位置
  67. {
  68. if(my_grammar->Vn[i]->production[j][0]=='\0')
  69. {
  70. t=0;
  71. for(k=0;k<symbol_len;k++)
  72. {
  73. if(behind[k]=='|')
  74. {
  75. my_grammar->Vn[i]->production[j][k-t] = '\0';
  76. j++;
  77. t=k+1;
  78. continue;
  79. }
  80. my_grammar->Vn[i]->production[j][k-t] = behind[k];
  81. if(behind[k]=='\0')
  82. break;
  83. }
  84. break;
  85. }
  86. }
  87. }
  88. break;
  89. }
  90. if(str[i]=='-'&&str[i+1]=='>') // 前端后端分界点
  91. {
  92. t=1; // 前后端标志更改,
  93. front[j] = '\0'; // 来个结束符
  94. j=0; // 计数器归零
  95. i+=2; // 跳过这两个
  96. continue;
  97. }
  98. if(t) // 当前在后端
  99. {
  100. behind[j]=str[i]; // 记录当前符号
  101. j++; // 位置标记右移
  102. }
  103. else // 当前在前端
  104. {
  105. front[j]=str[i]; // 记录当前符号
  106. j++; // 位置标记右移
  107. }
  108. i++;
  109. }
  110. }
  111. // 给出文法,提取出终结符
  112. void get_Vt(grammar my_grammar)
  113. {
  114. int i,j,k,ii,jj,kk,t,maxjj;
  115. for(i=0;i<N;i++) // i第一层遍历非终结符
  116. {
  117. if(my_grammar->Vn[i]==NULL)
  118. break;
  119. for(j=0;j<N;j++) // j第一层遍历产生式
  120. {
  121. if(my_grammar->Vn[i]->production[j][0]=='\0')
  122. break;
  123. else // 遍历每一个产生式,找出终结符存到Vt
  124. {
  125. for(k=0;k<symbol_len;k++) // 遍历该产生式
  126. {
  127. if(my_grammar->Vn[i]->production[j][k]=='\0')
  128. break;
  129. maxjj = 0;//最长的非终结符
  130. for(ii=0;ii<N;ii++) // 在所有非终结符中找有没有它
  131. {
  132. if(my_grammar->Vn[ii]==NULL)
  133. break;
  134. else
  135. {
  136. if(my_grammar->Vn[ii]->name[0]==my_grammar->Vn[i]->production[j][k])
  137. {
  138. t=1;
  139. for(jj=1;jj<char_len;jj++)
  140. {
  141. if(my_grammar->Vn[ii]->name[jj]=='\0')
  142. break;//到头了
  143. if(my_grammar->Vn[ii]->name[jj]!=my_grammar->Vn[i]->production[j][k+jj])
  144. {
  145. t=0;//这个不是
  146. break;
  147. }
  148. }
  149. if(t&&maxjj<jj) // 找到了,且比之前长
  150. {
  151. maxjj=jj;
  152. }
  153. }
  154. }
  155. }
  156. for(kk=0;kk<N;kk++) // 看看非终结符集有没有
  157. {
  158. t=0;
  159. if(my_grammar->Vt[kk]=='\0')
  160. break;
  161. if(my_grammar->Vt[kk]==my_grammar->Vn[i]->production[j][k])
  162. {
  163. t=1;//找到了
  164. break;
  165. }
  166. }
  167. if(t)
  168. continue;
  169. if(maxjj==0) //走到这里,最大jj是0时,终结符和非终结符都没有
  170. {
  171. my_grammar->Vt[kk]=my_grammar->Vn[i]->production[j][k];
  172. }
  173. else
  174. {
  175. k=k+maxjj-1;
  176. }
  177. }
  178. }
  179. }
  180. }
  181. }
  182. // 文法的输出函数
  183. void Output_grammar(grammar my_grammar)
  184. {
  185. int i,j;
  186. for(i=0;i<N;i++)
  187. {
  188. if(my_grammar->Vn[i]==NULL)
  189. break;
  190. printf("%s->",my_grammar->Vn[i]->name);
  191. for(j=0;j<N;j++)
  192. {
  193. if(my_grammar->Vn[i]->production[j][0]=='\0')
  194. break;
  195. if(j!=0)
  196. printf("|");
  197. printf("%s",my_grammar->Vn[i]->production[j]);
  198. }
  199. printf("\n");
  200. }
  201. printf("终结符:");
  202. for(i=0;i<N;i++)
  203. {
  204. if(my_grammar->Vt[i]=='\0')
  205. break;
  206. printf("%c ",my_grammar->Vt[i]);
  207. }
  208. }
  209. int main()
  210. {
  211. FILE *p=fopen("text.txt","r"); //只读打开文件
  212. if(p==NULL) // 没有文件提示
  213. {
  214. printf("缺少文件“text.txt”");
  215. exit(0);
  216. }
  217. char str[N];
  218. grammar my_grammar = new_grammar();
  219. while(fgets(str, N, p) != NULL) // 一行一行读取
  220. {
  221. Generative_grammar(str,my_grammar);
  222. }
  223. fclose(p); // 关闭文件
  224. get_Vt(my_grammar);
  225. Output_grammar(my_grammar);
  226. }

同样支持这样的输入:

  1. S->Qc|c|cc|da|Q1
  2. Q->Rb|b|V
  3. R->Sa|a|cV2
  4. Q1->aa|bd
  5. V2->d|Q2
  6. Q2->a
  7. V->V2|e

结果:

  1. S->Qc|c|cc|da|Q1
  2. Q->Rb|b|V
  3. R->Sa|a|cV2
  4. Q1->aa|bd
  5. V2->d|Q2
  6. Q2->a
  7. V->V2|e
  8. 终结符:c d a b e

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/319543
推荐阅读
相关标签
  

闽ICP备14008679号