一个简单编译器前端的实现
小记:
其实这个程序是编译原理这门课的综合实验,前段时间我申请免试又失败了,原因是有缺课,平时分不够,早上赖床现在尝到苦果我也是醉了……没办法,逼上梁山,只好攻克这个大boss以拿下免试资格。
选了一个最简单的文法,分析了1个多星期,终于决定开始要写的时候时间已经很紧了。
去实验室通宵了一晚,在宿舍熬了一晚,睡了3个小时就起来去验收了。还好是通过了,没白费劲。
不得不说,编译原理就是烧脑,知识点都比较抽象,如果数据结构和算法的基础打得不牢的话,实现起来会感到吃力。
再次感觉到了基础的重要性,这也是一个收获吧。
总的来说,相比较之前实现形式化的des加密算法,抽象的编译器更有难度,写完也更能让你感觉到提高。
ps:程序仅供参考,时间有限,没做太多测试。
功能:
给定一个简单语言的文法描述,本程序是该语言的编译器前端。
输入一个符合该文法规则的源文件,输出三地址形式的中间代码。
具体功能有词法分析,语法分析,分析流程显示,错误提示等。
程序运行结果:
源程序:
分析过程:
生成中间代码(三地址形式):
分析过程:
文法:
文法(消除左递归后)
Program->BEGIN Stmt-List END
Stmt-List->Stmt Stmt-List'
Stmt-List'->Stmt Stmt-List' | .
Stmt->Assign-stmt
Assign-stmt->ID = Expr
Expr->Term Expr'
Expr'->Add-Op Term Expr' | .
Term->Factor Term'
Term'->Multiple-Op Factor Term' | .
Factor->( Expr ) | ID | NUM
Add-Op->+ | -
Multiple-Op->* | /
FIRST集
First(Program)={BEGIN}
First(Stmt-List)={ID}
First(Stmt-List')={ ID,ε}
First(Stmt)={ ID}
First(Assign-stmt)={ ID}
First(Expr)={(,ID,NUM}
First(Expr')={+,-,ε}
First(Term)={(,ID,NUM}
First(Term')={*,/,ε}
First(Factor)={(,ID,NUM}
First(Add-Op)={+,-}
First(Multiple-Op)={*,/}
FOLLOW集
Follow(Program)={$}
Follow(Stmt-List)={END}
Follow(Stmt-List')={ END}
Follow(Stmt)={ ID,END}
Follow(Assign-stmt)={ ID,END }
Follow(Expr)={ ID,END ,)}
Follow(Expr')={ ID,END , )}
Follow(Term)={+,-, ID,END , )}
Follow(Term')={ +,-, ID,END , )}
Follow(Factor)={ *,/,+,-, ID,END , )}
Follow(Add-Op)={(,ID,NUM}
Follow(Multiple-Op)={ (,ID,NUM }
预测分析表:
代码:
1 //词法分析中' '代表空白字符,包括换行符,空格,制表符
2 //源程序格式:1、一行只能有一条语句;2、程序中可以有注释
3 #include <iostream>
4 #include <string.h>
5 #include <stdio.h>
6 #include <stack>
7 #include <stdlib.h>
8 using namespace std;
9
10 char src[1000010]; //存储源代码
11 char TokenList_kind[1010][100]; //词法单元流 之 类别
12 int TokenList_value[1010]; //词法单元流 之 值
13 char WordList[1010][100]; //符号表 -- 由token_value指向
14 int LineList[1010]; //记录每一个token对应的行数 -- 由token_value指向
15 int TokenListPoint; //词法单元流指针
16 int WordListPoint; //符号表指针
17
18 int WordsPoint; //语法分析时的词法单元流指针
19
20 int tmpcnt; //三地址语句中寄存器的编号
21
22 int ExpTable[11][8] = { //用 表驱动法 读取表达式 ,状态转换表
23 2, -1, 1, -1, -1, -1, -1, 9,
24 2, -1, -1, -1, -1, -1, -1, 9,
25 2, -1, -1, 3, -1, -1, -1, 9,
26 4, 5, -1, -1, -1, -1, -1, 9,
27 4, -1, 8, -1, 6, -1, 10, 9,
28 -1, 5, 8, -1, 6, -1, 10, 9,
29 4, 5, -1, -1, -1, 7, -1, 9,
30 4, 5, -1, -1, -1, -1, -1, 9,
31 -1, -1, -1, -1, -1, -1, -1, -1,
32 -1, -1, -1, -1, -1, -1, -1, -1,
33 -1, -1, 8, -1, 6, -1, 10, 9
34 };
35
36 /*
37 文法
38 1 Program->BEGIN Stmt-List END
39 2 Stmt-List->Stmt Stmt-List'
40 3 Stmt-List'->Stmt Stmt-List' | .
41 4 Stmt->Assign-stmt
42 5 Assign-stmt->ID = Expr
43 6 Expr->Term Expr'
44 7 Expr'->Add-Op Term Expr' | .
45 8 Term->Factor Term'
46 9 Term'->Multiple-Op Factor Term' | .
47 10 Factor->( Expr ) | ID | NUM
48 11 Add-Op->+ | -
49 12 Multiple-Op->* | /
50
51 预测分析表
52 非终结符号 输入符号
53 BEGIN ‘+’ ‘-’ ‘*’ ‘/’ ( ) ‘=’ ID NUM END $
54 Program 1
55 Stmt-List 2
56 Stmt-List' 3 .
57 Stmt 4
58 Assign-stmt 5
59 Expr 6 6 6
60 Expr' 7 7 . . .
61 Term 8 8 8
62 Term' . . 9 9 . . .
63 Factor 10_1 10_210_3
64 Add-Op 11_1 11_2
65 Multiple-Op 12_1 12_2
66 */
67
68 char PreTab[12][12][100]={ //存储预测分析表
69 {"BEGIN Stmt-List END","","","","","","","","","","",""},
70 {"","","","","","","","","Stmt Stmt-List'","","",""},
71 {"","","","","","","","","Stmt Stmt-List'","",".",""},
72 {"","","","","","","","","Assign-stmt","","",""},
73 {"","","","","","","","","ID = Expr","","",""},
74 {"","","","","","Term Expr'","","","Term Expr'","Term Expr'","",""},
75 {"","Add-Op Term Expr'","Add-Op Term Expr'","","","",".","",".","",".",""},
76 {"","","","","","Factor Term'","","","Factor Term'","Factor Term'","",""},
77 {"",".",".","Multiple-Op Factor Term'","Multiple-Op Factor Term'","",".","",".","",".",""},
78 {"","","","","","( Expr )","","","ID","NUM","",""},
79 {"","+","-","","","","","","","","",""},
80 {"","","","*","/","","","","","","",""}
81 };
82
83 char Product[23][50]={ //记录产生式出现的字符串
84 "Program", //0
85 "Stmt-List", //1
86 "Stmt-List'", //2
87 "Stmt", //3
88 "Assign-stmt", //4
89 "Expr", //5
90 "Expr'", //6
91 "Term", //7
92 "Term'", //8
93 "Factor", //9
94 "Add-Op", //10
95 "Multiple-Op", //11
96
97 "BEGIN", //12
98 "+", //13
99 "-", //14
100 "*", //15
101 "/", //16
102 "(", //17
103 ")", //18
104 "=", //19
105 "ID", //20
106 "NUM", //21
107 "END" //22
108 };
109
110
111 //语法树节点
112 struct Node{
113 Node(char na[]){ //构造函数
114 strcpy(name,na);
115 wp = 0;
116 brother = NULL;
117 next = NULL;
118 }
119 char name[50];
120 int wp; //终结符在token流中的位置
121 Node* brother; //指向下一个兄弟节点
122 Node* next; //指向当前节点的孩子节点
123 }*root,*now,*p;
124
125 void Init()
126 {
127 memset(src,0,sizeof(src)); //初始化源代码字符数组
128 memset(TokenList_kind,0,sizeof(TokenList_kind)); //初始化词法单元流
129 memset(TokenList_value,0,sizeof(TokenList_value)); //初始化词法单元流
130 memset(WordList,0,sizeof(WordList)); //初始化符号表
131 TokenListPoint = 1;
132 WordListPoint = 1;
133
134 WordsPoint = 1;
135
136 //初始化指针
137 root = NULL;
138 now = NULL;
139 p = NULL;
140 tmpcnt = 1;
141 }
142
143 //--------------- 词法分析 start ---------------
144 void AddToken(char kind[],char value[],int line) //将<类别,值>放入token流中
145 {
146 strcpy(TokenList_kind[TokenListPoint],kind);
147 TokenList_value[TokenListPoint++] = WordListPoint;
148
149 strcpy(WordList[WordListPoint],value);
150 LineList[WordListPoint++] = line;
151 }
152
153 void strsub(char str1[],int start,int len,char str2[]) //截取str1的子字符串给str2
154 {
155 int i=0,j;
156 for(j=0;j<len;j++){
157 str2[i++] = str1[start+j];
158 }
159 str2[i] = '\0';
160 }
161
162 void InputString() //从文件中读取源代码,同时过滤注释,一行只能放置一条语句
163 {
164 //文件读入
165 FILE* fs = fopen(".\\src.txt","rb"); //源代码
166 if(fs==NULL){
167 printf("源代码文件 src.txt 不存在\n");
168 return ;
169 }
170
171 char s[10010]={0};
172 //fscanf(fs,"%s",src);
173 while(fgets(s,10010,fs)){
174 if(sscanf(s,"%s",s)==-1){ //没有读到字符串,将s清空
175 s[0]='\0';
176 continue;
177 }
178 //过滤注释
179 if(s[0]=='/' && s[1]=='/')
180 continue;
181 int i;
182 for(i=0;s[i];i++)
183 if(s[i]=='/' && s[i+1]=='/')
184 break;
185 s[i]='\0';
186
187 strcat(src,s); //连接到源代码字符串后
188 strcat(src," "); //连接一个空白符
189 }
190
191 int len = strlen(src);
192 len--;
193 src[len] = '\0';
194 }
195
196 bool getBEGIN(int &i,int &line) //读取“BEGIN”
197 {
198 char tmp[6];
199 strsub(src,i,5,tmp);
200 if(strcmp(tmp,"BEGIN")==0){
201 i = i+5;
202 AddToken("BEGIN","BEGIN",line); //添加token,<类别,值>
203 return true;
204 }
205 else
206 return false;
207 }
208 bool getBLANK(int &i) //读取“空白符”==>' '
209 {
210 if(src[i]==' '){
211 i++;
212 return true;
213 }
214 else
215 return false;
216 }
217 bool getEND(int &i,int &line) //读取“END”
218 {
219 char tmp[4];
220 strsub(src,i,3,tmp);
221 if(strcmp(tmp,"END")==0){
222 i = i+3;
223 AddToken("END","END",line); //添加token,<类别,值>
224 return true;
225 }
226 else
227 return false;
228 }
229 bool getExp(int &i,int &line) //读取表达式,遇到' '结束
230 {
231 int status=0;
232 char tmp[10010]={0};
233 char t[2]={0};
234 int j=0;
235 stack <char> ss;
236 while(status!=8){
237 if(status==-1) //跳到错误的状态号,返回false
238 return false;
239 if(status==9) //跳到了错误状态,返回false
240 return false;
241
242 //根据src[i]确定下一个状态,直到抵达结束状态 8
243 if( ('a'<=src[i] && src[i]<='z') || ('A'<=src[i] && src[i]<='Z') ){
244 //读取到字母
245 status = ExpTable[status][0];
246 tmp[j++] = src[i++];
247 }
248 else if('0'<=src[i] && src[i]<='9'){
249 //读取到数字
250 status = ExpTable[status][1];
251 tmp[j++] = src[i++];
252 }
253 else{
254 switch(src[i]){
255 case ' ': //空白符
256 status = ExpTable[status][2];
257 if(tmp[0]!='\0'){
258 //如果是后来读到空白符,说明表达式该结束了
259 //将读取的最后一个单词放入token
260 if(j!=0){ //说明之前是一个单词或数字,否则是一个),)已经将最后一个单词放入token流中了,所以不需要处理它
261 if( ('a'<=tmp[0] && tmp[0]<='z') || ('A'<=tmp[0] && tmp[0]<='Z') )
262 AddToken("ID",tmp,line); //将这个字符代表的单词放入token流中
263 else if( '0'<=tmp[0] && tmp[0]<='9' )
264 AddToken("NUM",tmp,line); //将这个字符代表的单词放入token流中
265 j=0;
266 }
267 }
268 line++;
269 i++;
270 break;
271 case '=': // =
272 status = ExpTable[status][3];
273
274 tmp[j] = '\0';
275 AddToken("ID",tmp,line); //=前面一定是标识符,放入token流
276 j=0;
277 AddToken("=","=",line); //将当前的=也放入token流
278
279 i++;
280 break;
281 case '+': //OP
282 case '-':
283 case '*':
284 case '/':
285 status = ExpTable[status][4];
286
287 tmp[j] = '\0';
288 if( ('a'<=tmp[0] && tmp[0]<='z') || ('A'<=tmp[0] && tmp[0]<='Z') ) //如果运算符前是字母,则说明是标识符
289 AddToken("ID",tmp,line);
290 else if( '0'<=tmp[0] && tmp[0]<='9' )
291 AddToken("NUM",tmp,line);
292 j=0;
293 t[0] = src[i];
294 t[1] = '\0';
295 AddToken(t,t,line); //将运算符放入token流
296
297 i++;
298 break;
299 case '(': // (
300 status = ExpTable[status][5];
301
302 AddToken("(","(",line); //将(放入token流
303 ss.push('(');
304
305 i++;
306 break;
307 case ')': // )
308 status = ExpTable[status][6];
309
310 tmp[j] = '\0';
311 if( ('a'<=tmp[0] && tmp[0]<='z') || ('A'<=tmp[0] && tmp[0]<='Z') ) //如果)前是字母,则说明是标识符,即ID
312 AddToken("ID",tmp,line);
313 else if( '0'<=tmp[0] && tmp[0]<='9' )
314 AddToken("NUM",tmp,line);
315 j=0;
316
317 AddToken(")",")",line); //将(放入token流
318
319 if(ss.empty()) //括号不匹配
320 return false;
321 else
322 ss.pop();
323
324 i++;
325 break;
326 default: //其它
327 status = ExpTable[status][7];
328 i++;
329 break;
330 }
331 }
332 }
333
334 if(status==8){ //正确跳出
335 /*
336 if(ss.empty()) //括号匹配
337 return true;
338 else
339 return false;
340 */
341 return true;
342 }
343 else
344 return false;
345 }
346
347 bool Lex() //进行词法分析
348 {
349 printf("词法分析......\n");
350 int i=0;
351 int line = 1;
352 InputString();
353 try{
354 getBEGIN(i,line)?1:throw 1;
355 getBLANK(i)?line++:throw 2;
356 while(1){ //读取表达式
357 if(src[i]=='\0') //还没检测到END,程序就结束了
358 throw 3;
359 char tmp[4];
360 strsub(src,i,3,tmp); //截取字符串
361 if(strcmp(tmp,"END")==0){
362 //如果检测到END,跳出循环
363 break;
364 }
365
366 //读取表达式
367 getExp(i,line)?1:throw 4;
368 }
369 getEND(i,line)?1:throw 3;
370 if(src[i]!='\0') //如果END结束标志之后还有输入符号,说明出错误了
371 throw 5;
372 }
373 catch(int err){
374 printf("【词法错误】\n");
375 //计算行号
376 int errline = 1;
377 int j;
378 for(j=0;j<=i;j++)
379 if(src[j]==' ')
380 errline++;
381
382 switch(err){
383 case 1:
384 printf("ERROR 1 (第%d行) : 没有读取到开始标识 BEGIN!\n",errline);
385 printf("具体位置:\t%s%s\n",WordList[WordListPoint-2],WordList[WordListPoint-1]);
386 printf("\t\t");
387 for(j=0;j<strlen(WordList[WordListPoint-2]);j++)
388 printf(" ");
389 printf("^\n");
390 printf("\n");
391 return false;
392 case 2:
393 printf("ERROR 2 (第%d行) : 没有读取到空白符!\n",errline);
394 printf("具体位置:\t%s%s\n",WordList[WordListPoint-2],WordList[WordListPoint-1]);
395 printf("\t\t");
396 for(j=0;j<strlen(WordList[WordListPoint-2]);j++)
397 printf(" ");
398 printf("^\n");
399 printf("\n");
400 return false;
401 case 3:
402 printf("ERROR 3 (第%d行) : 没有读取到结束标识 END!\n",errline);
403 printf("具体位置:\t%s%s\n",WordList[WordListPoint-2],WordList[WordListPoint-1]);
404 printf("\t\t");
405 for(j=0;j<strlen(WordList[WordListPoint-2]);j++)
406 printf(" ");
407 printf("^\n");
408 printf("\n");
409 printf("\n");
410 return false;
411 case 4:
412 printf("ERROR 4 (第%d行) : 表达式错误。例如:标识符有误!\n",errline);
413 printf("具体位置:\t%s%s\n",WordList[WordListPoint-2],WordList[WordListPoint-1]);
414 printf("\t\t");
415 for(j=0;j<strlen(WordList[WordListPoint-2]);j++)
416 printf(" ");
417 printf("^\n");
418 printf("\n");
419 return false;
420 case 5:
421 printf("ERROR 5 (第%d行) : BEGIN...END 代码段格式错误!\n",errline);
422 printf("具体位置:\t%s%s\n",WordList[WordListPoint-2],WordList[WordListPoint-1]);
423 printf("\t\t");
424 for(j=0;j<strlen(WordList[WordListPoint-2]);j++)
425 printf(" ");
426 printf("^\n");
427 printf("\n");
428 return false;
429 default:break;
430 }
431 }
432 printf("没有词法错误\n");
433 printf("\n");
434 return true;
435 }
436
437 void printTokenList() //输出token流
438 {
439 int i=1;
440 printf("单词流:\n");
441 printf("<\t类别\t,值\t>\n");
442 for(;i<TokenListPoint;i++){
443 printf("<\t%s\t,%s\t>\n",TokenList_kind[i],WordList[TokenList_value[i]]);
444 }
445 printf("\n");
446 }
447 //--------------- 词法分析 end ---------------
448
449
450 //--------------- 语法分析 start ---------------
451 //生成语法分析树
452
453 void OutStack(stack <char*> z) //输出栈中内容的前两个
454 {
455 char t[200]={0};
456 int j=0;
457 while(!z.empty()){
458 if(j==2)
459 break;
460 if(j==1)
461 strcat(t,",");
462 strcat(t,z.top());
463 z.pop();
464 j++;
465 }
466 strcat(t,"$");
467 printf("%23s",t);
468 }
469
470 void OutRightStr() //输出当前token流中前两个
471 {
472 char t[200]={0};
473 int i,j=0;
474 for(i = WordsPoint;i<WordListPoint;i++){
475 if(j==2)
476 break;
477 char tt[200]={0};
478 sprintf(tt,"<%s,%s>",TokenList_kind[i],WordList[TokenList_value[i]]);
479 strcat(t,tt);
480 j++;
481 }
482 printf("%23s$",t);
483 }
484
485 void OutAction(char action[]) //输出动作
486 {
487 printf(" %s\n",action);
488 }
489
490 bool seltab(int row,char f[])
491 {
492 if(strcmp(TokenList_kind[WordsPoint],"BEGIN")==0){
493 strcpy(f,PreTab[row][0]);
494 }
495 else if(strcmp(TokenList_kind[WordsPoint],"+")==0){
496 strcpy(f,PreTab[row][1]);
497 }
498 else if(strcmp(TokenList_kind[WordsPoint],"-")==0){
499 strcpy(f,PreTab[row][2]);
500 }
501 else if(strcmp(TokenList_kind[WordsPoint],"*")==0){
502 strcpy(f,PreTab[row][3]);
503 }
504 else if(strcmp(TokenList_kind[WordsPoint],"/")==0){
505 strcpy(f,PreTab[row][4]);
506 }
507 else if(strcmp(TokenList_kind[WordsPoint],"(")==0){
508 strcpy(f,PreTab[row][5]);
509 }
510 else if(strcmp(TokenList_kind[WordsPoint],")")==0){
511 strcpy(f,PreTab[row][6]);
512 }
513 else if(strcmp(TokenList_kind[WordsPoint],"=")==0){
514 strcpy(f,PreTab[row][7]);
515 }
516 else if(strcmp(TokenList_kind[WordsPoint],"ID")==0){
517 strcpy(f,PreTab[row][8]);
518 }
519 else if(strcmp(TokenList_kind[WordsPoint],"NUM")==0){
520 strcpy(f,PreTab[row][9]);
521 }
522 else if(strcmp(TokenList_kind[WordsPoint],"END")==0){
523 strcpy(f,PreTab[row][10]);
524 }
525 else if(strcmp(TokenList_kind[WordsPoint],"$")==0){
526 strcpy(f,PreTab[row][11]);
527 }
528 else{
529 return false;
530 }
531 if(f[0]=='\0') //确定的表位置为空
532 return false;
533 return true;
534 }
535
536 bool Parse() //语法分析阶段。输入是token流,输出分析结果
537 {
538 stack <char*> z;
539 stack <Node*> nz;
540 z.push(*Product);
541
542 root = new Node("Program");
543 now = root;
544
545 printf("词法分析......\n");
546 printf("【分析流程】\n");
547 printf("%22s%24s%22s\n","栈","输入","动作");
548 char action[100]={0};
549 try{
550 while(!z.empty() || WordsPoint<WordListPoint){ //栈和输入串中只剩结束符号(栈空 or 指向'\0')时退出循环
551
552 //输出当前分析结果
553 OutStack(z); //输出栈中内容
554 OutRightStr(); //输出剩余输入字符串
555 OutAction(action); //输出动作
556
557 memset(action,0,sizeof(action));
558
559 //预处理。例:匹配e。预处理:将e出栈,输入指针后移。
560
561 //还没结束栈就空了
562 if(z.empty())
563 throw 1; //非法跳出
564
565 if(strcmp(z.top(),TokenList_kind[WordsPoint])==0){ //栈顶元素==指针指向字符,匹配成功
566 //语义动作 - 构造语法树
567 while(!now->brother){ //回到有下一个兄弟节点的节点为止
568 if(nz.empty()){
569 if(now==root) //如果回到了根节点
570 goto label;
571 else
572 throw 1;
573 }
574 now = nz.top();
575 nz.pop();
576 }
577 now = now->brother;
578
579 label:
580 //准备输出字符串 action
581 strcat(action,"匹配");
582 strcat(action,z.top());
583
584 //出栈、指针后移
585 if(!z.empty())
586 z.pop();
587 if(WordsPoint<WordListPoint)
588 WordsPoint++;
589 }
590 else{ //不相等,输出推导
591 //确定推导
592 char f[200]={0};
593 if(strcmp(z.top(),"Program")==0){
594 if(!seltab(0,f)) //从表中确定推导串
595 throw 2; //没有找到对应的推导
596 }
597 else if(strcmp(z.top(),"Stmt-List")==0){
598 if(!seltab(1,f)) //从表中确定推导串
599 throw 2; //没有找到对应的推导
600 }
601 else if(strcmp(z.top(),"Stmt-List'")==0){
602 if(!seltab(2,f)) //从表中确定推导串
603 throw 2; //没有找到对应的推导
604 }
605 else if(strcmp(z.top(),"Stmt")==0){
606 if(!seltab(3,f)) //从表中确定推导串
607 throw 2; //没有找到对应的推导
608 }
609 else if(strcmp(z.top(),"Assign-stmt")==0){
610 if(!seltab(4,f)) //从表中确定推导串
611 throw 2; //没有找到对应的推导
612 }
613 else if(strcmp(z.top(),"Expr")==0){
614 if(!seltab(5,f)) //从表中确定推导串
615 throw 2;
616 }
617 else if(strcmp(z.top(),"Expr'")==0){
618 if(!seltab(6,f)) //从表中确定推导串
619 throw 2;
620 }
621 else if(strcmp(z.top(),"Term")==0){
622 if(!seltab(7,f)) //从表中确定推导串
623 throw 2;
624 }
625 else if(strcmp(z.top(),"Term'")==0){
626 if(!seltab(8,f)) //从表中确定推导串
627 throw 2;
628 }
629 else if(strcmp(z.top(),"Factor")==0){
630 if(!seltab(9,f)) //从表中确定推导串
631 throw 2;
632 }
633 else if(strcmp(z.top(),"Add-Op")==0){
634 if(!seltab(10,f)) //从表中确定推导串
635 throw 2;
636 }
637 else if(strcmp(z.top(),"Multiple-Op")==0){
638 if(!seltab(11,f)) //从表中确定推导串
639 throw 2;
640 }
641 else{
642 throw 2;
643 }
644 //准备输出字符串 action
645 strcat(action,"输出");
646 strcat(action,z.top());
647 strcat(action,"->");
648 strcat(action,f);
649
650 //将栈顶字符串记录下来后用
651 char proleft[50];
652 //将栈顶元素出栈并将推导入栈
653 if(!z.empty()){
654 strcpy(proleft,z.top());
655 z.pop();
656 }
657 else
658 throw 1;
659
660 char tmp[100];
661
662 //如果推导出来的是空,即f->.,不作处理
663 if(f[0]=='.'){
664 nz.push(now);
665
666 now->next = new Node(".");
667 now = now->next; //now指向当前产生式右边的第一个字符串
668
669 while(!now->brother){ //回到有下一个兄弟节点的节点为止
670 if(nz.empty()){
671 if(now==root) //如果回到了根节点
672 goto label;
673 else
674 throw 1;
675 }
676 now = nz.top();
677 nz.pop();
678 }
679 now = now->brother;
680
681 continue;
682 }
683 stack <char*> tz; //临时的栈
684
685 //正向输入到临时栈中
686 while(sscanf(f,"%s",tmp)!=-1){
687 //语义动作 - 创建语法树
688 if(strcmp(proleft,now->name)==0){
689 nz.push(now); //将当前节点记录下来
690
691 now->next = new Node(tmp);
692 now = now->next; //now指向当前产生式右边的第一个字符串
693 p = now;
694 }
695 else{
696 p->brother = new Node(tmp);
697 p = p->brother;
698 }
699
700 char* pos = strstr(f,tmp);
701 strcpy(f,pos+strlen(tmp));
702 if(strcmp(tmp,"Program")==0){
703 tz.push(*(Product));
704 }
705 else if(strcmp(tmp,"Stmt-List")==0){
706 tz.push(*(Product+1));
707 }
708 else if(strcmp(tmp,"Stmt-List'")==0){
709 tz.push(*(Product+2));
710 }
711 else if(strcmp(tmp,"Stmt")==0){
712 tz.push(*(Product+3));
713 }
714 else if(strcmp(tmp,"Assign-stmt")==0){
715 tz.push(*(Product+4));
716 }
717 else if(strcmp(tmp,"Expr")==0){
718 tz.push(*(Product+5));
719 }
720 else if(strcmp(tmp,"Expr'")==0){
721 tz.push(*(Product+6));
722 }
723 else if(strcmp(tmp,"Term")==0){
724 tz.push(*(Product+7));
725 }
726 else if(strcmp(tmp,"Term'")==0){
727 tz.push(*(Product+8));
728 }
729 else if(strcmp(tmp,"Factor")==0){
730 tz.push(*(Product+9));
731 }
732 else if(strcmp(tmp,"Add-Op")==0){
733 tz.push(*(Product+10));
734 }
735 else if(strcmp(tmp,"Multiple-Op")==0){
736 tz.push(*(Product+11));
737 }
738 else if(strcmp(tmp,"BEGIN")==0){
739 tz.push(*(Product+12));
740 }
741 else if(strcmp(tmp,"+")==0){
742 tz.push(*(Product+13));
743 }
744 else if(strcmp(tmp,"-")==0){
745 tz.push(*(Product+14));
746 }
747 else if(strcmp(tmp,"*")==0){
748 tz.push(*(Product+15));
749 }
750 else if(strcmp(tmp,"/")==0){
751 tz.push(*(Product+16));
752 }
753 else if(strcmp(tmp,"(")==0){
754 tz.push(*(Product+17));
755 }
756 else if(strcmp(tmp,")")==0){
757 tz.push(*(Product+18));
758 }
759 else if(strcmp(tmp,"=")==0){
760 tz.push(*(Product+19));
761 }
762 else if(strcmp(tmp,"ID")==0){
763 tz.push(*(Product+20));
764 }
765 else if(strcmp(tmp,"NUM")==0){
766 tz.push(*(Product+21));
767 }
768 else if(strcmp(tmp,"END")==0){
769 tz.push(*(Product+22));
770 }
771 else{
772 throw 1;
773 }
774
775 }
776
777 //反向输出到真正的栈中
778 while(!tz.empty()){
779 if(strcmp(tz.top(),"Program")==0){
780 z.push(*(Product));
781 }
782 else if(strcmp(tz.top(),"Stmt-List")==0){
783 z.push(*(Product+1));
784 }
785 else if(strcmp(tz.top(),"Stmt-List'")==0){
786 z.push(*(Product+2));
787 }
788 else if(strcmp(tz.top(),"Stmt")==0){
789 z.push(*(Product+3));
790 }
791 else if(strcmp(tz.top(),"Assign-stmt")==0){
792 z.push(*(Product+4));
793 }
794 else if(strcmp(tz.top(),"Expr")==0){
795 z.push(*(Product+5));
796 }
797 else if(strcmp(tz.top(),"Expr'")==0){
798 z.push(*(Product+6));
799 }
800 else if(strcmp(tz.top(),"Term")==0){
801 z.push(*(Product+7));
802 }
803 else if(strcmp(tz.top(),"Term'")==0){
804 z.push(*(Product+8));
805 }
806 else if(strcmp(tz.top(),"Factor")==0){
807 z.push(*(Product+9));
808 }
809 else if(strcmp(tz.top(),"Add-Op")==0){
810 z.push(*(Product+10));
811 }
812 else if(strcmp(tz.top(),"Multiple-Op")==0){
813 z.push(*(Product+11));
814 }
815 else if(strcmp(tz.top(),"BEGIN")==0){
816 z.push(*(Product+12));
817 }
818 else if(strcmp(tz.top(),"+")==0){
819 z.push(*(Product+13));
820 }
821 else if(strcmp(tz.top(),"-")==0){
822 z.push(*(Product+14));
823 }
824 else if(strcmp(tz.top(),"*")==0){
825 z.push(*(Product+15));
826 }
827 else if(strcmp(tz.top(),"/")==0){
828 z.push(*(Product+16));
829 }
830 else if(strcmp(tz.top(),"(")==0){
831 z.push(*(Product+17));
832 }
833 else if(strcmp(tz.top(),")")==0){
834 z.push(*(Product+18));
835 }
836 else if(strcmp(tz.top(),"=")==0){
837 z.push(*(Product+19));
838 }
839 else if(strcmp(tz.top(),"ID")==0){
840 z.push(*(Product+20));
841 }
842 else if(strcmp(tz.top(),"NUM")==0){
843 z.push(*(Product+21));
844 }
845 else if(strcmp(tz.top(),"END")==0){
846 z.push(*(Product+22));
847 }
848 else{
849 throw 1;
850 }
851 tz.pop();
852 }
853 }
854
855 }
856 if(z.empty() && WordsPoint >= WordListPoint){ //正常退出循环
857 //输出最后一行分析结果
858 OutStack(z); //输出栈中内容
859 OutRightStr(); //输出剩余输入字符串
860 OutAction(action); //输出动作
861 }
862 else{ //非正常情况
863 throw 1;
864 }
865 }
866 catch(int err){
867 printf("\n");
868 printf("【语法错误】\n");
869
870 switch(err){
871 case 1:
872 printf("ERROR 1 (第%d行) : 非法跳出!\n",LineList[WordsPoint]);
873 printf("\n");
874 return false;
875 case 2:
876 printf("ERROR 2 (第%d行) : 没有找到 %s 对应的推导!\n",LineList[WordsPoint],z.top());
877 printf("\n");
878 return false;
879 default:
880 break;
881 }
882 }
883 printf("没有语法错误\n");
884 printf("\n");
885 return true;
886 }
887 //--------------- 语法分析 end ---------------
888
889 //--------------- 生成三地址代码 start ---------------
890 //对语法分析树进行后序遍历,执行语义规则,一遍扫描之后,树根的code即为三地址代码
891
892
893 void setWP(Node* cur) //设置每一个叶子节点的wp指针
894 {
895 if(!cur->next){
896 if(cur->name[0]=='.')
897 return ;
898 cur->wp = WordsPoint++;
899 return ;
900 }
901 Node* p = cur->next;
902 while(p){
903 setWP(p);
904 p = p->brother;
905 }
906 }
907
908 char* getNext(Node* cur,FILE* fo)
909 {
910 //递归出口
911 if(!cur->next){
912 if(cur->name[0]=='.'
913 || cur->name[0]=='('
914 || cur->name[0]==')'){ //忽略空. 和 ( 和 )
915 char* t = new char[2];
916 t[0]='\0';
917 return t;
918 }
919 return WordList[TokenList_value[cur->wp]];
920 }
921 if(strcmp(cur->name,"Program")==0){
922 fprintf(fo,"%s\r\n",getNext(cur->next,fo));
923 getNext(cur->next->brother,fo);
924 fprintf(fo,"%s\r\n",getNext(cur->next->brother->brother,fo));
925 char* tmp = new char[2];
926 tmp[0] = '\0';
927 return tmp;
928 }
929 else if(strcmp(cur->name,"Assign-stmt")==0){
930 char* tmp = new char[2];
931 tmp[0] = '\0';
932 fprintf(fo,"%s=%s\r\n",getNext(cur->next,fo),getNext(cur->next->brother->brother,fo));
933 return tmp;
934 }
935 else if(strcmp(cur->name,"Term")==0){
936 char* tmp = new char[150];
937 tmp = getNext(cur->next->brother,fo);
938 if(tmp[0]=='*' || tmp[0]=='/'){
939 fprintf(fo,"t%d=%s%s\r\n",tmpcnt,getNext(cur->next,fo),tmp);
940 sprintf(tmp,"t%d",tmpcnt++);
941 return tmp;
942 }
943 }
944 else if(strcmp(cur->name,"Expr")==0){
945 char* tmp = new char[150];
946 tmp = getNext(cur->next->brother,fo);
947 if(tmp[0]=='+' || tmp[0]=='-'){
948 fprintf(fo,"t%d=%s%s\r\n",tmpcnt,getNext(cur->next,fo),tmp);
949 sprintf(tmp,"t%d",tmpcnt++);
950 return tmp;
951 }
952 }
953 else if(strcmp(cur->name,"Term'")==0){
954 char* tmp = new char[150];
955 if(cur->next->brother!=NULL){
956 p = cur->next->brother->brother;
957 if(p->next->brother!=NULL){
958 tmp = getNext(cur->next->brother->brother,fo);
959 if(tmp[0]=='*' || tmp[0]=='/'){
960 if(*getNext(cur->next,fo)=='/'){ //如果最前面的是‘-’,后面的运算符应该是反的
961 if(tmp[0]=='/')
962 tmp[0]='*';
963 else
964 tmp[0]='/';
965 }
966 fprintf(fo,"t%d=%s%s\r\n",tmpcnt,getNext(cur->next->brother,fo),tmp);
967 sprintf(tmp,"%st%d",getNext(cur->next,fo),tmpcnt++);
968 return tmp;
969 }
970 }
971 }
972 }
973 else if(strcmp(cur->name,"Expr'")==0){
974 char* tmp = new char[150];
975 if(cur->next->brother!=NULL){
976 p = cur->next->brother->brother;
977 if(p->next->brother!=NULL){
978 tmp = getNext(cur->next->brother->brother,fo);
979 if(tmp[0]=='+' || tmp[0]=='-'){
980 if(*getNext(cur->next,fo)=='-'){ //如果最前面的是‘-’,后面的运算符应该是反的
981 if(tmp[0]=='-')
982 tmp[0]='+';
983 else
984 tmp[0]='-';
985 }
986 fprintf(fo,"t%d=%s%s\r\n",tmpcnt,getNext(cur->next->brother,fo),tmp);
987 sprintf(tmp,"%st%d",getNext(cur->next,fo),tmpcnt++);
988 return tmp;
989 }
990 }
991 }
992 }
993
994 char * s = new char[150]; //new一个字符串,存储这个节点的结果
995 memset(s,0,sizeof(s));
996
997 Node* p = cur->next;
998 while(p){
999 strcat(s,getNext(p,fo));
1000 p = p->brother;
1001 }
1002 return s;
1003 }
1004
1005 void get3AddrCode()
1006 {
1007 WordsPoint = 1;
1008 FILE* fo = fopen(".\\out.txt","wb");
1009 if(fo==NULL){
1010 printf("三地址代码生成文件 out.txt 打开失败!\n");
1011 return ;
1012 }
1013
1014 setWP(root);
1015 printf("生成三地址语句......\n");
1016 getNext(root,fo);
1017 }
1018 //--------------- 生成三地址代码 end ---------------
1019
1020 int main()
1021 {
1022 bool f=true;
1023 Init();
1024 if(!Lex()) //词法分析
1025 f=false;
1026 //printTokenList();
1027 if(!Parse()) //语法分析
1028 f=false;
1029 if(f) //都通过了才能生成三地址代码
1030 get3AddrCode(); //生成三地址代码
1031 return 0;
1032 }
Freecode : www.cnblogs.com/yym2013