软件构造——实验五 算符优先分析法
【实验目的】
掌握算符优先分析法的原理,利用算符优先分析法将赋值语句进行语法分析。
【实验内容】
(1)输入一个文法根据算符优先分析法,将表达式进行语法分析,判断一个表达式是否为算符优先文法
(2)输入一个句子进行分析
【实验要求】
1、根据文法求FIRSTVT集和LASTVT集
给定一个上下文无关文法,根据算法设计一个程序,求文法中每个非终结符的FirstVT 集和LastVT 集。
可参考算法描述如下:
/*求 FirstVT 集的算法*/
PROCEDURE insert(P,a);
IF not F[P,a] then
begin
F[P,a] = true; //(P,a)进栈
end;
Procedure FirstVT;
Begin
for 对每个非终结符 P和终结符 a do
F[P,a] = false
for 对每个形如 P a…或 P→Qa…的产生式 do
Insert(P,a)
while stack 非空
begin
栈顶项出栈,记为(Q,a)
for 对每条形如 P→Q…的产生式 do
insert(P,a)
end;
end.
同理,可构造计算LASTVT的算法。
2、构造算符优先分析表
依据文法和求出的相应FirstVT和 LastVT 集生成算符优先分析表。
参考算法描述如下:
for 每个形如 P->X1X2…Xn的产生式 do
for i =1 to n-1 do
begin
if Xi和Xi+1都是终结符 then
Xi = Xi+1
if i<= n-2, Xi和Xi+2 是终结符, 但Xi+1 为非终结符 then
Xi = Xi+2
if Xi为终结符, Xi+1为非终结符 then
for FirstVT 中的每个元素 a do
Xi < a ;
if Xi为非终结符, Xi+1为终结符 then
for LastVT 中的每个元素 a do
a > Xi+1 ;
end
3、构造控制程序
参考 算法描述如下:
stack S;
k = 1; //符号栈S的使用深度
S[k] = ‘#’
REPEAT
把下一个输入符号读进a中;
If S[k] VT then j = k else j = k-1;
While S[j] > a do
Begin
Repeat
Q = S[j];
if S[j-1] VT then j = j-1 else j = j-2
until S[j] < Q;
把S[j+1]…S[k]归约为某个N,并输出归约为哪个符号;
K = j+1;
S[k] = N;
end of while
if S[j] < a or S[j] = a then
begin k = k+1; S[k] = a end
else error //调用出错诊察程序
until a = ‘#’
4、对给定的表达式,给出准确与否的分析过程
5、给出表达式的计算结果。
【实验结果】
图为参考,要求包含firstvt和lastvt集,算符优先表或优先函数表及句子分析过程。
实验截图:
代码:
1 Mian.cpp: 2 #include <stdio.h> 3 #include <math.h> 4 #include <string.h> 5 #include <stdlib.h> 6 #include <iostream> 7 #include <sstream> 8 #include <algorithm> 9 #include <set> 10 #include <queue> 11 #include <stack> 12 #include <map> 13 #include <bitset> 14 #pragma comment(linker, "/STACK:102400000,102400000") 15 typedef long long LL; 16 const int inf = 0x3f3f3f3f; 17 const double pi = acos(-1.0); 18 const double esp = 1e-6; 19 using namespace std; 20 21 const int Maxn = 110; 22 const int maxn = 20; 23 char str[maxn][Maxn];//输入文法 24 char st[maxn];//输入串 25 char stac[maxn];//模拟栈的数组 26 char nstr[maxn][maxn];//储存转化文法 27 char mstr[maxn][maxn]; 28 char fin[maxn];//存储终结符 29 char firstvt[maxn][maxn], lastvt[maxn][maxn]; 30 char cmp[maxn][maxn];//存储表中的比较符 31 int firstflag[maxn], lastflag[maxn];//非终结符的firstvt,lastvt是否求出 32 int fcnt[maxn], lcnt[maxn];//非终结符firsvt和lastvt的个数 33 int is_fin(char c) { //判断终结符 34 for (int i = 0; fin[i] != '\0'; i++) { 35 if (fin[i] == c) 36 return 1; 37 } 38 return 0; 39 } 40 int site(char c) { //求在表中的下标 41 for (int i = 0; fin[i] != '\0'; i++) { 42 if (fin[i] == c) 43 return i; 44 } 45 } 46 47 void get_firstvt(char s, int t) { //求s非终结符的firstvt值 48 int i, j, ii, jj, tt; 49 for (i = 0; i<t; i++) { 50 if (str[i][0] == s) 51 break; 52 } 53 if (!firstflag[i]) { 54 int k = fcnt[i]; 55 for (j = 0; str[i][j] != '\0'; j++) { 56 if (j == 2 || str[i][j] == '|') { 57 if (is_fin(str[i][j + 1])) { 58 firstvt[i][k++] = str[i][j + 1]; 59 } 60 else { 61 if (is_fin(str[i][j + 2])) { 62 firstvt[i][k++] = str[i][j + 2]; 63 } 64 if (str[i][j + 1] != s) { 65 get_firstvt(str[i][j + 1], t); 66 for (ii = 0; ii<t; ii++) { 67 if (str[ii][0] == str[i][j + 1]) 68 break; 69 } 70 for (jj = 0; jj<fcnt[ii]; jj++) { 71 for (tt = 0; tt<k; tt++) { 72 if (firstvt[i][tt] == firstvt[ii][jj]) 73 break; 74 } 75 if (tt == k) { 76 firstvt[i][k++] = firstvt[ii][jj]; 77 } 78 } 79 } 80 } 81 } 82 } 83 firstvt[i][k] = '\0'; 84 fcnt[i] = k; 85 firstflag[i] = 1; 86 } 87 } 88 89 void output_firstvt(int T) { //输出firstvt集 90 for (int i = 0; i<T; i++) { 91 get_firstvt(str[i][0], T); 92 } 93 for (int i = 0; i<T; i++) { 94 printf("Firstvt[%c]:", str[i][0]); 95 for (int j = 0; j<fcnt[i]; j++) { 96 printf("%c ", firstvt[i][j]); 97 } 98 puts(""); 99 } 100 } 101 102 void get_lastvt(char s, int t) { //求s非终结符的lastvt值 103 int i, j, ii, jj, tt; 104 for (i = 0; i<t; i++) { 105 if (str[i][0] == s) 106 break; 107 } 108 if (!lastflag[i]) { 109 int k = lcnt[i]; 110 for (j = 0; str[i][j] != '\0'; j++) { 111 if (str[i][j + 1] == '|' || str[i][j + 1] == '\0') { 112 if (is_fin(str[i][j])) { 113 lastvt[i][k++] = str[i][j]; 114 } 115 else { 116 if (is_fin(str[i][j - 1])) { 117 lastvt[i][k++] = str[i][j - 1]; 118 } 119 if (str[i][j] != s) { 120 get_lastvt(str[i][j], t); 121 for (ii = 0; ii<t; ii++) { 122 if (str[ii][0] == str[i][j]) 123 break; 124 } 125 for (jj = 0; jj<lcnt[ii]; jj++) { 126 for (tt = 0; tt<k; tt++) { 127 if (lastvt[i][tt] == lastvt[ii][jj]) 128 break; 129 } 130 if (tt == k) { 131 lastvt[i][k++] = lastvt[ii][jj]; 132 } 133 } 134 } 135 } 136 } 137 } 138 lastvt[i][k] = '\0'; 139 lcnt[i] = k; 140 lastflag[i] = 1; 141 } 142 } 143 144 void output_lastvt(int T) { //输出lastvt集 145 for (int i = 0; i<T; i++) { 146 get_lastvt(str[i][0], T); 147 } 148 for (int i = 0; i<T; i++) { 149 printf("Lastvt[%c]:", str[i][0]); 150 for (int j = 0; j<lcnt[i]; j++) { 151 printf("%c ", lastvt[i][j]); 152 } 153 puts(""); 154 } 155 } 156 157 void get_table(int T, int cnt) { //得到表 158 int x = 0, y = 0; 159 int i, j, ii, jj; 160 for (i = 0; i<T; i++) { 161 for (j = 0; str[i][j] != '\0'; j++) { 162 if (str[i][j] != '|') 163 nstr[x][y++] = str[i][j]; 164 else if (str[i][j] == '|') { 165 nstr[x][y] = '\0'; 166 x++; 167 y = 0; 168 nstr[x][y++] = str[i][0]; 169 nstr[x][y++] = '-'; 170 nstr[x][y++] = '>'; 171 } 172 } 173 nstr[x][y] = '\0'; 174 x++; 175 y = 0; 176 } 177 //对于S1->#S#; 178 char a = '#'; 179 cmp[site(a)][site(a)] = '='; 180 for (i = 0; i<fcnt[0]; i++) { 181 cmp[site(a)][site(firstvt[0][i])] = '<'; 182 } 183 for (i = 0; i<lcnt[0]; i++) { 184 cmp[site(lastvt[0][i])][site(a)] = '>'; 185 } 186 //对于初始的文法 187 for (i = 0; i<x; i++) { 188 for (j = 3; nstr[i][j + 1] != '\0'; j++) { 189 if (is_fin(nstr[i][j]) && is_fin(nstr[i][j + 1])) 190 cmp[site(nstr[i][j])][site(nstr[i][j + 1])] = '='; 191 if (is_fin(nstr[i][j]) && !is_fin(nstr[i][j + 1]) && is_fin(nstr[i][j + 2]) && nstr[i][j + 2] != '\0') 192 cmp[site(nstr[i][j])][site(nstr[i][j + 2])] = '='; 193 if (!is_fin(nstr[i][j]) && is_fin(nstr[i][j + 1])) { //对于非终结符在终结符之前 194 for (ii = 0; ii<T; ii++) { 195 if (str[ii][0] == nstr[i][j]) 196 break; 197 } 198 for (jj = 0; jj<lcnt[ii]; jj++) 199 cmp[site(lastvt[ii][jj])][site(nstr[i][j + 1])] = '>'; 200 } 201 if (is_fin(nstr[i][j]) && !is_fin(nstr[i][j + 1])) { //对于终结符在非终结符之前 202 for (ii = 0; ii<T; ii++) { 203 if (str[ii][0] == nstr[i][j + 1]) 204 break; 205 } 206 for (jj = 0; jj<fcnt[ii]; jj++) 207 cmp[site(nstr[i][j])][site(firstvt[ii][jj])] = '<'; 208 } 209 } 210 } 211 for (i = 0; fin[i] != '\0'; i++) 212 printf("\t%c", fin[i]); 213 puts(""); 214 for (i = 0; i<cnt; i++) { 215 printf("%c\t", fin[i]); 216 for (j = 0; j<cnt; j++) { 217 if (cmp[i][j] != 0) 218 printf("%c\t", cmp[i][j]); 219 else 220 printf(" \t"); 221 } 222 puts(""); 223 } 224 225 } 226 void output(int i, int j, char *str) { 227 printf("\t"); 228 for (int ii = i; ii <= j; ii++) 229 printf("%c", str[ii]); 230 } 231 232 int isDX(char c) 233 { 234 if (c >= 'A'&&c <= 'Z') 235 return 1; 236 return 0; 237 } 238 void exchange() 239 { 240 int ecnt = 0; 241 for (int i = 0; i<10; i++) { 242 int mcnt = 0; 243 for (int j = 3; nstr[i][j] != '\0'; j++) { 244 if (isDX(nstr[i][j]) && strlen(nstr[i]) != 4) 245 mstr[ecnt][mcnt++] = 'N'; 246 else if (!isDX(nstr[i][j])) 247 mstr[ecnt][mcnt++] = nstr[i][j]; 248 else { 249 break; 250 } 251 } 252 mstr[ecnt][mcnt] = '\0'; 253 if (strlen(mstr[ecnt]) != 0) 254 ecnt++; 255 } 256 } 257 int get_process(char *st)// 258 { 259 exchange(); 260 int len = strlen(st); 261 int t = 0;//栈内元素的个数 262 int i = 0, j; 263 int bz = 1; 264 stac[0] = '#'; 265 while (st[i] != '\0') { 266 if (is_fin(stac[t])) j = t; 267 else j = t - 1; 268 int a = site(stac[j]); 269 int b = site(st[i]); 270 if (cmp[a][b] == '<' || cmp[a][b] == '=') { 271 printf("\t%d", bz++); 272 output(0, t, stac); 273 printf("\t%c", cmp[a][b]); 274 printf("\t%c", st[i]); 275 output(i + 1, len - 1, st); 276 printf("\t移进"); 277 puts(""); 278 t++; 279 stac[t] = st[i]; 280 i++; 281 } 282 else if (cmp[a][b] == '>') { 283 printf("\t%d", bz++); 284 output(0, t, stac); 285 printf("\t%c", cmp[a][b]); 286 printf("\t%c", st[i]); 287 output(i + 1, len - 1, st); 288 printf("\t归约"); 289 puts(""); 290 int ii, jj, kk; 291 int flag = 0; 292 for (ii = t; ii >= 0; ii--) { 293 for (jj = 0; jj<maxn; jj++) { 294 int lee = strlen(mstr[jj]); 295 int kkn = 0; 296 for (kk = lee - 1; kk >= 0; kk--) { 297 if (stac[ii] == mstr[jj][kk]) { 298 ii--; 299 kkn++; 300 } 301 else 302 break; 303 } 304 if (strlen(mstr[jj]) == kkn) { 305 t = ii + 1; 306 stac[t++] = 'N'; 307 stac[t] = '\0'; 308 t--; 309 flag = 1; 310 break; 311 } 312 else { 313 ii = ii + kkn; 314 } 315 } 316 if (!flag) { 317 printf("\t错误"); 318 return 0; 319 } 320 else { 321 if (t == 1 && st[i] == '#') { 322 printf("\t%d", bz++); 323 output(0, t, stac); 324 printf("\t="); 325 printf("\t%c", st[i]); 326 output(i + 1, len, st); 327 printf("\t接受"); 328 return 1; 329 } 330 break; 331 } 332 } 333 } 334 } 335 } 336 int main() { 337 int T; 338 int cnt = 0;//终结符的个数 339 for (int i = 0; i < 10; i++) 340 cout << "*********"; 341 cout << endl; 342 cout << "周博(20173599)" << endl; 343 for (int i = 0; i < 10; i++) 344 cout << "*********"; 345 cout << endl; 346 memset(firstflag, 0, sizeof(firstflag)); 347 memset(lastflag, 0, sizeof(lastflag)); 348 memset(cmp, 0, sizeof(cmp)); 349 cout << "请输入文法规则数:"; 350 cin >> T; 351 cout << "请输入文法规则:" << endl; 352 for (int i = 0; i < T; i++) { 353 cin >> str[i]; 354 fcnt[i] = lcnt[i] = 0; 355 } 356 //让输入的格式化 357 int oo = 0; 358 int mm = T; 359 //int column = sizeof(str[0]) / sizeof(char); 360 char str_str[maxn][Maxn];//输入文法 361 for (int i = 0; i < maxn; i++) { 362 for (int j = 0; j<Maxn; j++) 363 { 364 str_str[i][j] = '\0'; 365 } 366 } 367 for (int i = 0; i < mm; i++) { 368 for (int j = 0; str[i][j] != '\0'; j++) 369 { 370 str_str[i][j] = str[i][j]; 371 } 372 } 373 int TT = T; 374 for (int i = 0; i<mm; i++) { 375 for (int j = 0; str_str[i][j] != '\0'; j++) 376 { 377 int column = 0; 378 for (column = 0; str_str[i][column] != '\0'; column++) 379 { 380 381 } 382 column += 1; 383 if (str_str[i][j] == '>') 384 { 385 oo = j; 386 387 } 388 if (str_str[i][j] == '|') 389 { 390 char str_f[Maxn]; 391 for (int qq = 0; qq < column; qq++) 392 { 393 str_f[qq] = str_str[i][qq]; 394 } 395 for (int qq = j; qq < column; qq++) 396 { 397 str_str[i][qq] = '\0'; 398 } 399 400 401 402 TT = TT + 1; 403 for (int qq = 0; qq < oo + 1; qq++) 404 { 405 str_str[TT-1][qq] = str_f[qq]; 406 } 407 int mid = oo + 1; 408 for (int qq = j + 1; qq < column; qq++) 409 { 410 str_str[TT - 1][mid] = str_f[qq]; 411 mid = mid + 1; 412 } 413 for (int qq = 0; qq < column; qq++) 414 { 415 cout << str_str[TT - 1][qq]; 416 } 417 break; 418 } 419 } 420 421 } 422 cout << endl; 423 for (int i = 0; i < TT; i++) 424 { 425 cout << i + 1 << ": " << str_str[i] << endl; 426 } 427 for (int i = 0; i<T; i++) { 428 for (int j = 0; str[i][j] != '\0'; j++) { 429 if ((str[i][j]<'A' || str[i][j]>'Z') && (str[i][j] != '-'&&str[i][j] != '>') && str[i][j] != '|') 430 fin[cnt++] = str[i][j]; 431 } 432 } 433 fin[cnt++] = '#'; 434 fin[cnt] = '\0'; 435 cout << "FIRSTUT集为:" << endl; 436 output_firstvt(T); 437 cout << endl; 438 cout << "LASTUT集为:" << endl; 439 output_lastvt(T); 440 cout << "算符优先分析表如下:" << endl; 441 get_table(T, cnt); 442 cout << "请输入文法输入符号以#结束:"; 443 //scanf("%s", st); 444 cin >> st; 445 get_process(st); 446 int a; 447 cin >> a; 448 return 0; 449 }