PageRenderTime 57ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/LL1_Parser/first.cpp

https://github.com/rjsikarwar/compiler
C++ | 255 lines | 174 code | 38 blank | 43 comment | 24 complexity | 592a9dbbe9ff9310a96f42be4f882b3f MD5 | raw file
  1. #include<iostream>
  2. using namespace std;
  3. #include<fstream>
  4. #include<sstream>
  5. #include<cstring>
  6. #include"first.h"
  7. /*Returns 0 if not non-terminal else returns 1*/
  8. int check_non_term(char non_term [][20],char term[],int n)
  9. {
  10. for(int i=0;i<n;i++)
  11. if(!strcmp(non_term[i],term))
  12. return 1;
  13. return 0;
  14. }
  15. /*Adds a string 'term' to first list ,and increments number of such terms*/
  16. void add_first(first f_list[], char start[],char term[],int n,int k)
  17. {
  18. for(int i=0;i<n;i++)
  19. {
  20. if(!strcmp(f_list[i].start,start))
  21. {
  22. f_list[i].prod_id[f_list[i].num]=k;
  23. strcpy(f_list[i].flist[f_list[i].num++],term);
  24. }
  25. }
  26. }
  27. /*Returns index of the particular string 'term' in the first list , i.e. whether index of the non-terminal with which the production starts ,if not found returns -1*/
  28. int index_check(first f_list[],char term[],int n)
  29. {
  30. for(int i=0;i<n;i++)
  31. if(!strcmp(f_list[i].start,term))
  32. return i;
  33. return -1;
  34. }
  35. /* Checks whether a particular string 'term' exists in the array of strings , returns 1 if exists else returns 0*/
  36. int exists_in_arr(char arr1[][20],char term[],int n)
  37. {
  38. for(int i=0;i<n;i++)
  39. if(!strcmp(arr1[i],term))
  40. return 1;
  41. return 0;
  42. }
  43. /*The following algorithm is used to compute FIRST:
  44. 1> In the first run of the production list, all productions leading to a first term as a terminal i.e. say S->aB where S is a non-terminal, 'a' is a terminal . All such productions are checked as completed, i.e. no further need to assess them. Incorporate such terminals in first of corresponding start symbols (non-terminals ).
  45. 2> Repeat the following(3-5) till no. of checked productions match the total no. of productions, note 'chk' variable denotes number of checked productions.
  46. 3> For every production S->ABC.... ,where A is a non-terminal check whether productions starting with 'A' are complete or not, if complete then incorporate FIRST(A) - epsilon into FIRST(S) by checking whether they already exist in FIRST(S) or not.
  47. 4> If epsilon exists in FIRST(A) then also add FIRST(B)-epsilon into FIRST(S) and so on.
  48. 5> Only if epsilon exists in FIRST(A),FIRST(B),FIRST(C) such that C is the ending term of the production add epsilon to FIRST(S).
  49. */
  50. void compute_first(int k, int i,prod production[],char non_term [][20] ,first f_list[],int num_non)
  51. {
  52. k=1;
  53. int chk=0;
  54. int d_it=1;
  55. int ch=0;
  56. // cout<<"i = "<<i<<endl;
  57. while(chk<i-2)
  58. {
  59. d_it=1;
  60. rec:
  61. if(d_it>production[k].dcount){chk++;continue;}
  62. if(production[k].check!=1)
  63. {
  64. // cout<<"chk = "<<chk<<" Checking k = "<<k<<"d_it = "<<d_it<<endl<<endl;
  65. int in=index_check(f_list,production[k].deriv[d_it],num_non);
  66. // cout<<"non-term = "<<production[k].deriv[d_it]<<" index = "<<in<<endl;
  67. if(check_non_term(non_term,production[k].deriv[d_it],num_non)!=1)
  68. {
  69. add_first(f_list,production[k].start,production[k].deriv[d_it],num_non,k);
  70. // cout<<"Added "<<production[k].deriv[1]<<" to "<<production[k].start<<endl;
  71. // cout<<"Marking production "<<k<<endl;
  72. production[k].check=1;
  73. chk++;
  74. }
  75. else
  76. {
  77. for(int l=0;l<f_list[in].occ_iter;l++)
  78. {
  79. int p_in= f_list[in].occ[l].val;
  80. // cout<<"Production to check = "<<p_in<<endl;
  81. if(production[p_in].check==1)
  82. {
  83. // cout<<"Checking production "<<p_in<<" starting with "<<production[p_in].start<<endl;
  84. for(int j=0;j<f_list[in].num;j++)
  85. {
  86. int in_1=index_check(f_list,production[k].start,num_non);
  87. // cout<<production[k].start<<" : "<<in_1<<endl;
  88. // cout<<"Checking whether "<<f_list[in].flist[j]<<" exists in "<<f_list[in_1].start<<endl;
  89. if(exists_in_arr(f_list[in_1].flist,f_list[in].flist[j],f_list[in_1].num) ==0)
  90. {
  91. f_list[in_1].prod_id[f_list[in_1].num]=k;
  92. strcpy(f_list[in_1].flist[f_list[in_1].num++],f_list[in].flist[j]);
  93. //----- chk++;
  94. // cout<<"Added xx "<<f_list[in].flist[j]<<" to "<<production[k].start<<endl;
  95. }
  96. }
  97. if(exists_in_arr(f_list[in].flist,(char *)"epsilon",f_list[in].num))
  98. {
  99. d_it++;
  100. goto rec;
  101. }
  102. chk++;
  103. // cout<<"Marking production "<<k<<endl;
  104. production[k].check=1;
  105. break;
  106. }
  107. }
  108. }
  109. }
  110. k++;
  111. // cout<<"chk = "<<chk<<" k = "<<k<<endl;
  112. if(k>i-2)k=1;
  113. }
  114. // cout<<"final chk = "<<chk<<endl;
  115. }
  116. void generate_first(char *filename,first *f_list,prod production[],int *num,int *num_prod,char non_term[][20],char start[20],char terminal[][20],int *num_term)
  117. {
  118. fstream f; /*opening a filestream f */
  119. f.open(filename,ios::in);
  120. char line[100];
  121. int i=0;
  122. f.getline(line,100); /*The first line is meant for defining the list of non-terminals (space separated) */
  123. stringstream s;
  124. s<<line;
  125. char junk[20];
  126. s>>junk;
  127. while(s>>non_term[i++])
  128. {
  129. strcpy(f_list[i-1].start,non_term[i-1]);
  130. f_list[i-1].num=0;
  131. }
  132. int num_non=i; //num_non =No. of non terminals
  133. s.clear();
  134. f.getline(line,100); /*The third line in the input file is meant for defining the start symbol in the grammar */
  135. s<<line;
  136. int t=0;
  137. s>>junk;
  138. while(s>>terminal[t++])
  139. {
  140. strcpy(f_list[t-1].start,non_term[t-1]);
  141. f_list[t-1].num=0;
  142. }
  143. *num_term=t; //num_term =No. of terminals
  144. s.clear();
  145. f.getline(line,100); /*The third line in the input file is meant for defining the start symbol in the grammar */
  146. s<<line;
  147. s>>junk>>start;
  148. i=0;
  149. while(f)
  150. {
  151. f.getline(line,100); /*Extracting linewise from the filestream */
  152. stringstream s; /*Building a stringstream object to read the line word by word */
  153. s<<line; /*Copy the line into the stringstream s */
  154. char str[100]; /*Temporary buffer to hold the string */
  155. int j=0;
  156. while(s>>str) /*Start manipulating the stringstream object */
  157. {
  158. if(j==0) /*The beginning of the line is always denoted by the Start symbol */
  159. {
  160. strcpy(production[i].start,str);
  161. int in=index_check(f_list,str,num_non);
  162. int iter=f_list[in].occ_iter++;
  163. f_list[in].occ[iter].val=i;
  164. production[i].dcount=0;
  165. production[i].check=0;
  166. }
  167. else if(!strcmp("|",str)) /*Incase of '|' a new production rule is created with the same start symbol */
  168. {
  169. strcpy(production[i+1].start,production[i].start);
  170. int in=index_check(f_list,production[i].start,num_non);
  171. int iter=f_list[in].occ_iter++;
  172. f_list[in].occ[iter].val=i+1;
  173. production[i+1].dcount=0;
  174. production[i].check=0;
  175. i++;
  176. j=1;
  177. }
  178. else if(strcmp("->",str)) /*Ignore '->' , for all other strings ,incorporate them into deriv list of production*/
  179. {
  180. strcpy(production[i].deriv[j-1],str);
  181. production[i].dcount++;
  182. }
  183. j++;
  184. }
  185. i++;
  186. }
  187. int k=1;
  188. /*Displaying the production list has been commented out , uncomment if you wish to see the list of productions */
  189. /*
  190. cout<<"Production list\n";
  191. while(k<i-1)
  192. {
  193. cout<<production[k].start<<" -> ";
  194. int j=0;
  195. while(j++<production[k].dcount)
  196. {
  197. cout<<production[k].deriv[j]<<" ";
  198. }
  199. cout<<endl;
  200. k++;
  201. }
  202. */
  203. compute_first(k, i,production,non_term ,f_list,num_non); /*Calling compute_first function */
  204. /*Displaying the first table */
  205. cout<<"FIRST TABLE \n";
  206. for(k=0;k<num_non-1;k++)
  207. {
  208. cout<<f_list[k].start<<" : ";
  209. for(int j=0;j<f_list[k].num;j++)
  210. cout<<f_list[k].flist[j]<<" corresponding to production "<<f_list[k].prod_id[j]<<" , ";
  211. cout<<endl;
  212. }
  213. *num=num_non;
  214. *num_prod=i-1;
  215. } /*End */