当前位置:   article > 正文

编译原理(一) Chomsky文法的判断方法及C++代码实现_chomsky生成文法编程实现“我爱人工智能”这句话的生成过程

chomsky生成文法编程实现“我爱人工智能”这句话的生成过程

一、明确定义


  • 0型文法:对任一产生式α→β,都有α∈(VN∪VT)+, β∈(VN∪VT)*
  • 1型文法:对任一产生式α→β,都有|β|≥|α|, 仅仅 α→ε除外
  • 2型文法:对任一产生式α→β,都有α∈VN , β∈(VN∪VT)*
  • 3型文法:任一产生式α→β的形式都为A→aB或A→a,其中A∈VN,B∈VN,a∈VT。上述叫做右线性文法,另有左线性文法,二者等价。

二、基本思路


  • 0型文法 
    • 首先字符串的是,是全符号集的一个正闭包,那么包含符号集中所有符号的一个任一组合,但不包含元素。
    • 字符串的是,是全符号集的一个闭包,那么它比会多一个元素。
    • 那么我们想要判断一个文法是否为0型文法,只需要判断左侧非空即可
    • 任何0型语言都是递归可枚举的,故0型语言又称递归可枚举集
  • 1型文法 
    • 首先1型文法必须是0型文法
    • 1型文法除了这一个特例外,其他情况都满足的长度大于的长度
    • 1型文法也叫作上下文相关文法
  • 2型文法 
    • 首先2型文法必须是1型文法
    • 2型文法左边必须是一个非终结字符
    • 2型文法也叫做上下文无关文法
  • 3型文法 
    • 首先3型文法必须是2型文法
    • 3型文法必须是线性文法
    • 也就是在A,B为非终结符,a是终结符的情况下,产生式只满足如下两种形式(如下为右线性的例子): 

三、代码实现:


  • 提供两个实现方案: 
    • 根据产生式,自己判断,然后判断文法的类型,支持产生式的缩写版本,是最早实现的版本,可能代码的安排上有些混乱,冗余代码也比较多
  1. #include<iostream>
  2. #include<string>
  3. #include <cstdlib>
  4. #include <cstdio>
  5. #include <map>
  6. #include <vector>
  7. #include <cctype>
  8. using namespace std;
  9. typedef struct CSS
  10. {
  11. string left;
  12. string right;//定义产生式的右部
  13. }CSS;
  14. bool Zero (CSS *p, int n)
  15. {
  16. int i,j;
  17. for(i=0;i<n;i++)//循环n次,即遍历所有产生式
  18. {
  19. for(j=0;j<p[i].left.length();j++)//遍历产生式左部每一个字符
  20. {
  21. if(p[i].left[j]>='A'&&p[i].left[j]<='Z')//判断字符是否是非终结符
  22. break;
  23. }
  24. if(j==p[i].left.length())
  25. {
  26. cout<<"该文法不是0型文法"<<endl;
  27. return 0;
  28. break;
  29. }
  30. }
  31. if(i==n)
  32. return 1;//如果每个产生时都能找到非终结符
  33. }
  34. bool First(CSS *p , int n )//判断1型文法
  35. {
  36. int i;
  37. if(Zero(p,n)) //先判断是否是0型文法
  38. {
  39. for(i=0;i<n;i++)
  40. {
  41. if((p[i].left.length()>p[i].right.length())&&p[i].right.length()!=NULL)//判断产生式左部长度是否大于右部
  42. break;
  43. }
  44. if (i == n )
  45. return 1;
  46. else
  47. {
  48. cout<<"该文法是0型文法"<<endl;
  49. return 0;
  50. }
  51. }
  52. else
  53. return 0;
  54. }
  55. bool Second( CSS*p,int n)//判断2型文法
  56. {
  57. int i;
  58. if(First(p,n))//同上,先判断低级文法是否成立
  59. {
  60. for(i=0;i<n;i++)//同上,遍历所有文法产生式
  61. {
  62. if((p[i].left.length()!=1)||!(p[i].left[0]>='A'&&p[i].left[0]<='Z'))
  63. break;
  64. }
  65. if(i==n)
  66. return 1;
  67. else
  68. {
  69. cout<<"该文法是1型文法"<<endl;
  70. return 0;
  71. }
  72. }
  73. else
  74. return 0;
  75. }
  76. void Third(CSS *p,int n)//判断3型文法
  77. {
  78. int i;
  79. if(Second(p,n))//同上,先判断是否是2型文法
  80. {
  81. for(i=0;i<n;i++)//同上,遍历文法所有的产生式
  82. {
  83. if((p[i].right.length()==0)||(p[i].right.length()>=3)||(p[i].right[0]>='A'&&p[i].right[0]<='Z'))//判断产生式右部字符个数是否在12之间,判断右部第一个字符是否是非终结符
  84. break;
  85. }
  86. if(i==n)
  87. {
  88. for(i=0;i<n;i++)
  89. {
  90. if(p[i].right.length()==2)
  91. {
  92. if(!(p[i].right[1]>='A'&&p[i].right[1]<='Z'))
  93. break;
  94. }
  95. }
  96. if(i==n)
  97. {
  98. cout<<"该文法属于3型文法"<<endl;
  99. }
  100. else
  101. cout<<"该文法属于2型文法"<<endl;
  102. }
  103. else
  104. cout<<"该文法属于2型文法"<<endl;
  105. }
  106. else
  107. cout<<"结束"<<endl;
  108. }
  109. int main ( )
  110. {
  111. CSS *p = new CSS[100];
  112. map<char,bool> dic;
  113. map<char,bool> dic2;
  114. vector<char> VN;
  115. vector<char> VT;
  116. string input1,input2,input3;
  117. cout <<"请输入文法:"<<endl;
  118. cin >> input1;
  119. cout << "请输入VN: "<<endl;
  120. cin >> input2;
  121. for ( int i = 0 ; i < input2.length() ; i++ )
  122. if ( isalnum ( input2[i] ) )
  123. {
  124. VN.push_back ( input2[i] );
  125. dic[input2[i]]=true;
  126. }
  127. cout <<"请输入产生式规则的个数:"<<endl;
  128. int n;
  129. cin >> n;
  130. cout <<"请输入产生式规则:"<<endl;
  131. int cnt = 0;
  132. for ( int i = 0 ; i < n ; i++ )
  133. {
  134. input3.erase ();
  135. cin >> input3;
  136. bool flag = false;
  137. for ( int j = 0 ; j < input3.length() ; j++ )
  138. if ( input3[j] =='|' ) flag = true;
  139. if ( flag )
  140. {
  141. string temp;
  142. int j;
  143. for ( j = 0 ; j < input3.length(); j++ )
  144. {
  145. if ( input3[j] ==':' )
  146. {
  147. temp = input3.substr(0,j);
  148. j = j+3;
  149. break;
  150. }
  151. }
  152. for ( int k =j ; k < input3.length() ; k++ )
  153. {
  154. if ( isalnum ( input3[k] ) )
  155. {
  156. p[cnt].left = temp;
  157. int tt = k;
  158. for ( ;tt < input3.length(); tt++ )
  159. if ( input3[tt]=='|' ) break;
  160. if ( input3[tt] == '|' ) tt--;
  161. p[cnt].right = input3.substr( k , tt-k+1 );
  162. if ( dic[input3[k]] == false )
  163. {
  164. VT.push_back ( input3[k] );
  165. dic[input3[k]] = true;
  166. }
  167. cnt++;
  168. k = tt;
  169. }
  170. }
  171. continue;
  172. }
  173. for ( int j = 0 ; j < input3.length() ; j++ )
  174. {
  175. if ( input3[j]== ':' )
  176. {
  177. p[cnt].left=input3.substr(0,j);
  178. p[cnt].right=input3.substr(j+3,input3.length());
  179. cnt++;
  180. break;
  181. }
  182. }
  183. for ( int j = 0 ; j < input3.length() ; j++ )
  184. {
  185. if ( isalnum( input3[j] ) )
  186. {
  187. if ( dic[input3[j]] ) continue;
  188. VT.push_back ( input3[j] );
  189. dic[input3[j]] = true;
  190. }
  191. }
  192. }
  193. cout << input1 << " = ( {";
  194. for ( int i = 0 ; i < VN.size()-1 ; i++ )
  195. cout << VN[i] << ",";
  196. cout << VN[VN.size()-1] <<"},{";
  197. for ( int i = 0 ; i < VT.size()-1 ; i++ )
  198. cout << VT[i] << ",";
  199. cout << VT[VT.size()-1] << "},";
  200. cout << "P," << input1[2] << " )"<<endl;
  201. cout << "P : " << endl;
  202. vector<string> output;
  203. vector<string> head[500];
  204. string pre[500];
  205. for ( int i = 0 ; i < cnt ; i++ )
  206. {
  207. int x = p[i].left[0];
  208. head[x].push_back ( p[i].right );
  209. pre[x] = p[i].left;
  210. }
  211. for ( int i = 0 ; i < 500 ; i++ )
  212. {
  213. if ( head[i].size() == 0 ) continue;
  214. string temp = pre[i]+" ::= ";
  215. for ( int j = 0 ; j < head[i].size() ; j++ )
  216. {
  217. temp += head[i][j];
  218. if ( j != head[i].size() - 1 ) temp += " | ";
  219. }
  220. output.push_back ( temp );
  221. }
  222. for ( int i = 0 ; i < output.size() ; i ++ )
  223. cout << output[i] << endl;
  224. Third ( p , cnt );
  225. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 第二个版本则是代码和注释风格比较清楚的实现版本,是周末整理之后的一个缩减的版本,不支持缩写,需要提前设定字符集,但是给出了一个更良好的实现方案,适合理解这4种文法类型。
  1. #include <iostream>
  2. #include <cstdio>
  3. #include <algorithm>
  4. #include <string>
  5. #include <vector>
  6. #include <cstring>
  7. #include <cctype>
  8. using namespace std;
  9. const int VSIZE= 300;
  10. class Principle
  11. {
  12. public:
  13. string left;
  14. string right;
  15. Principle ( const char* , const char* );
  16. };
  17. //只考虑不包含varepsilon的情况,且所有元素均只包含一个字母
  18. vector<char> VN;//非终结符集
  19. vector<char> VT;//终结符集
  20. vector<Principle> principle;//产生式的集合
  21. int type[VSIZE];//每个字符的类型
  22. void init();//清理工作
  23. int get_type(char);//1代表是非终结符,2代表是终结符
  24. bool set_type(char,int);//设置一个字符的类型
  25. int get_result ( );//获得输入的文法的类型
  26. int main ( )
  27. {
  28. char buf[1000];
  29. char ** elements;
  30. while ( true )
  31. {
  32. puts("输入VN:");
  33. gets( buf );
  34. for ( int i = 0 ; i < strlen(buf); i++ )
  35. {
  36. char ch = buf[i];
  37. if ( !isupper(ch) ) continue;
  38. if ( get_type(ch) ) continue;
  39. VN.push_back ( ch );
  40. set_type(ch,1);
  41. }
  42. puts("输入VT:");
  43. gets( buf );
  44. for ( int i = 0 ; i < strlen(buf); i++ )
  45. {
  46. char ch = buf[i];
  47. if ( !islower(ch) ) continue;
  48. if ( get_type(ch) ) continue;
  49. VT.push_back ( ch );
  50. set_type(ch,2);
  51. }
  52. puts("输入产生式:(格式为[A::=...a...]), 输入\"exit\"作为结束");
  53. while ( true )
  54. {
  55. gets ( buf );
  56. if ( !strcmp(buf , "exit" ) ) break;
  57. int i;
  58. for ( i = 0 ; i < strlen(buf) ; i++ )
  59. if ( buf[i] == ':' )
  60. {
  61. buf[i] = 0;
  62. i = i+3;
  63. break;
  64. }
  65. principle.push_back ( Principle( buf , buf+i ) );
  66. printf ( "%s|%s|\n" , buf , buf+i );
  67. }
  68. int flag = get_result();
  69. switch ( flag )
  70. {
  71. case -1:
  72. puts("产生式中出现未知字符");
  73. break;
  74. case 0:
  75. puts("该文法为0型文法");
  76. break;
  77. case 1:
  78. puts("该文法为1型文法");
  79. break;
  80. case 2:
  81. puts("该文法为2型文法");
  82. break;
  83. case 3:
  84. puts("该文法为左线性型文法");
  85. break;
  86. case 4:
  87. puts("该文法为右线性型文法");
  88. break;
  89. }
  90. }
  91. return 0;
  92. }
  93. Principle::Principle ( const char*l , const char* r )
  94. {
  95. left = l;
  96. right = r;
  97. }
  98. //判断字符串是否包含未知字符
  99. bool hasError ( const string& s )
  100. {
  101. for ( int i = 0 ; i < s.length() ; i++ )
  102. if ( !get_type(s[i]) ) return true;
  103. return false;
  104. }
  105. //判断是否为0型文法
  106. bool isZero ( )
  107. {
  108. for ( int i = 0 ; i < principle.size() ; i++ )
  109. if ( hasError(principle[i].left) ) return false;
  110. else if ( hasError(principle[i].right)) return false;
  111. return true;
  112. }
  113. //判断一个0型文法是否为1型文法
  114. bool isOne ( )
  115. {
  116. for ( int i = 0 ; i < principle.size(); i++ )
  117. if ( principle[i].left.length() > principle[i].right.length() )
  118. return false;
  119. return true;
  120. }
  121. //判断一个1型文法是否为2型文法
  122. bool isTwo ( )
  123. {
  124. for ( int i = 0 ; i < principle.size() ; i++ )
  125. {
  126. string left = principle[i].left;
  127. if ( left.size() != 1 ) return false;
  128. if ( get_type(left[0]) != 1 ) return false;
  129. }
  130. return true;
  131. }
  132. //判断一个2型文法是否为左线性文法
  133. bool isLeftThree ()
  134. {
  135. for ( int i = 0 ; i < principle.size() ; i++ )
  136. {
  137. string right = principle[i].right;
  138. for ( int j = 1; j < right.length() ; j++ )
  139. if ( get_type(right[j]) != 2 ) return false;
  140. }
  141. return true;
  142. }
  143. //判断一个2型文法是否为右线性文法
  144. bool isRightThree ()
  145. {
  146. for ( int i = 0 ; i < principle.size() ; i++ )
  147. {
  148. string right = principle[i].right;
  149. for ( int j = 0 ; j < right.length()-1; j++ )
  150. if ( get_type(right[j]) != 2 )
  151. return false;
  152. }
  153. return true;
  154. }
  155. int get_result ( )
  156. {
  157. if ( !isZero() ) return -1;
  158. if ( !isOne() ) return 0;
  159. if ( !isTwo() ) return 1;
  160. if ( isLeftThree() ) return 3;
  161. if ( isRightThree() ) return 4;
  162. return 2;
  163. }
  164. void init ( )
  165. {
  166. VN.clear();
  167. VT.clear();
  168. principle.clear();
  169. memset ( type , 0 , sizeof ( type ) );
  170. }
  171. int get_type ( char ch )
  172. {
  173. return type[ch];
  174. }
  175. bool set_type ( char ch , int x )
  176. {
  177. type[ch] = x;
  178. return true;
  179. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/464200
推荐阅读
相关标签
  

闽ICP备14008679号