实验五-编译-用语法制导方式生成中间代码生成器(共13页).doc

上传人:飞****2 文档编号:7048985 上传时间:2022-02-17 格式:DOC 页数:13 大小:192.50KB
返回 下载 相关 举报
实验五-编译-用语法制导方式生成中间代码生成器(共13页).doc_第1页
第1页 / 共13页
实验五-编译-用语法制导方式生成中间代码生成器(共13页).doc_第2页
第2页 / 共13页
点击查看更多>>
资源描述

《实验五-编译-用语法制导方式生成中间代码生成器(共13页).doc》由会员分享,可在线阅读,更多相关《实验五-编译-用语法制导方式生成中间代码生成器(共13页).doc(13页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。

1、精选优质文档-倾情为你奉上实验5 用语法制导方式生成中间代码生成器一、实验目的掌握语法制导定义和翻译的原理和技术,在语法分析器的基础上,加上语义分析,构造一个中间代码生成器。二、实验内容在实验四生成的语法分析器基础上加入语义动作,将源程序翻译为对应的中间代码序列。三、实验要求1. 个人完成,提交实验报告。实验报告必须包括设计的思路,以及测试报告(输入测试例子,输出结果)。2. 实验报告中给出采用测试源代码片断,及其对应的三地址码形式(内部表示形式可以自行考虑)。例如,程序片断 对应的中间代码为:四、实验过程本次实验运用flex和bison工具进行中间代码的生成。并自动生成中间代码。1. 首先创

2、建一个example文件夹,该文件夹中包含有flex.exe2. 用文本编译器编辑相应的flex文件mylex.l,此次mylex.l可以在上次实验的l文件上做一些修改,再利用flex将l文件生成相应的lex.yy.c程序,mylex.l的代码如下所示: mylex.l%#include myyacc.tab.h%delim tnrwsdelim+letterA-Za-zdigit0-9idletter(letter|digit)*integerdigit+exponentE+-?integernumberintegerexponent?realinteger(.integer)?expone

3、nt?%option noyywrap%|=|!=|= filloperator(&yylval, yytext); return( REL); if return( IF ); else return( ELSE ); while return( WHILE ); do return( DO ); for return( FOR ); switch return( SWITCH ); case return( CASE ); default return( DEFAULT ); break return( BREAK ); true return( TRUE ); false return(

4、 FALSE ); int return( INT ); long return( LONG ); char return( CHAR ); bool return( BOOL ); float return( FLOAT ); double return( DOUBLE ); & return( AND ); | return( OR ); ! return( !); + return( INC ); - return( DEC ); + return( + ); - return( - ); * return( * ); / return( / ); = return( = ); retu

5、rn( ); return( ); return( ); return( ); ( return( ( ); ) return( ) ); ; return( ; ); ws id filllexeme(&yylval, yytext); return( ID ); number filllexeme(&yylval, yytext); return( NUMBER ); real filllexeme(&yylval, yytext); return( REAL ); %在代码中,先定义正则定义,即对letter,digit,专用符号, 空格进行声明;接着在转换规则中,定义一些识别规则的代码

6、。完成词法分析后,就可以将获取的每一个词素用于语法分析器使用。 将mylex.l与myyacc.y相结合的方法是在每获得一个词素,则用return语句返回,即如果获得的是if,则return(if),并且在头文件中加入#include myYacc.tab.h,则在myyacc中定义的类型在mylex中可利用,否则会出现返回的单元未定义的错误。3. 用文本编译器编辑相应的bison文件myyacc.y,myyacc.y文件中,在每个生成式后加上语法制导翻译,主要是依据truelist和falselist来实现回填功能。编写完后,在myyacc.y中以头文件的方式加入自己编写的myyacc.h文

7、件,编译即可。Myyacc.y的代码如下所示:Myyacc.y%#include myyacc.h#define YYSTYPE node#include myyacc.tab.hint yyerror();int yyerror(char* msg);extern int yylex();codelist* list;%token BASIC NUMBER REAL ID TRUE FALSE%token INT LONG CHAR BOOL FLOAT DOUBLE%token REL%token IF ELSE WHILE DO BREAK FOR SWITCH CASE DEFAULT

8、 %token OR AND%left OR%left AND%right !%left + -%left * /%right UMINUS%right INC DEC%program : block ;block : decls statementlist ;decls: decls decl | ;decl: type ID ; ;type: type NUMBER | BASIC ;statementlist: statementlist M statement backpatch(list, $1.nextlist, $2.instr); $.nextlist = $3.nextlis

9、t; | statement $.nextlist = $1.nextlist; ;Statement : IF ( boolean ) M statement ELSE N M statement backpatch(list, $3.truelist, $5.instr); backpatch(list, $3.falselist, $9.instr); $6.nextlist = merge($6.nextlist, $8.nextlist); $.nextlist = merge($6.nextlist, $10.nextlist); | IF ( boolean ) M statem

10、ent backpatch(list, $3.truelist, $5.instr); $.nextlist = merge($3.falselist, $6.nextlist); | WHILE M ( boolean ) M statement backpatch(list, $7.nextlist, $2.instr); backpatch(list, $4.truelist, $6.instr); $.nextlist = $4.falselist; gen_goto(list, $2.instr); | DO M statement M WHILE ( boolean ) M ; b

11、ackpatch(list, $3.nextlist, $4.instr); backpatch(list, $7.truelist, $9.instr); $.nextlist = $7.falselist; gen_goto(list, $2.instr); | FOR ( assignment ; M boolean ; M assignment ) N M statement backpatch(list, $6.truelist, $12.instr);backpatch(list, $11.nextlist, $5.instr);backpatch(list, $13.nextli

12、st, $8.instr);$.nextlist = $6.falselist;gen_goto(list, $8.instr); | BREAK ; | statementlist $.nextlist = $2.nextlist; | assignment ; $.nextlist = NULL; ;assignment: ID = boolean copyaddr(&$1, $1.lexeme); gen_assignment(list, $1, $3); ;loc : loc boolean | ID copyaddr(&$, $1.lexeme); ;boolean : boolea

13、n OR M boolean backpatch(list, $1.falselist, $3.instr); $.truelist = merge($1.truelist, $4.truelist); $.falselist = $4.falselist; | boolean AND M boolean backpatch(list, $1.truelist, $3.instr); $.truelist = $4.truelist; $.falselist = merge($1.falselist, $4.falselist); | ! boolean $.truelist = $1.fal

14、selist; $.falselist = $1.truelist; | ( boolean ) $.truelist = $1.truelist; $.falselist = $1.falselist; | expression REL expression $.truelist = new_instrlist(nextinstr(list); $.falselist = new_instrlist(nextinstr(list)+1); gen_if(list, $1, $2.oper, $3); gen_goto_blank(list); | TRUE copyaddr(&$, TRUE

15、); gen_goto_blank(list); | FALSE copyaddr(&$, FALSE); gen_goto_blank(list); | expression copyaddr_fromnode(&$, $1); ;M : $.instr = nextinstr(list); ;N : $.nextlist = new_instrlist(nextinstr(list); gen_goto_blank(list); ;expression : expression + expression new_temp(&$, get_temp_index(list); gen_3add

16、r(list, $, $1, +, $3); | expression - expression new_temp(&$, get_temp_index(list); gen_3addr(list, $, $1, -, $3); | expression * expression new_temp(&$, get_temp_index(list); gen_3addr(list, $, $1, *, $3); | expression / expression new_temp(&$, get_temp_index(list); gen_3addr(list, $, $1, /, $3); |

17、 - expression %prec UMINUS new_temp(&$, get_temp_index(list); gen_2addr(list, $, -, $2); | loc copyaddr_fromnode(&$, $1); | NUMBER copyaddr(&$, $1.lexeme); | REAL copyaddr(&$, $1.lexeme); ;%int yyerror(char* msg)printf(nERROR with message: %sn, msg);return 0;int main()list = newcodelist();freopen(te

18、xt.in, rt+, stdin);freopen(text.out, wt+, stdout);yyparse();print(list);fclose(stdin);fclose(stdout);return 0;在代码中,先定义一些头文件,extern int yylex(); extern int yyerror();这两个语句是必须的,引用全局变量是为了能够使用之前词法分析器所获取的词素。并且调用一个yyerror函数用来当发生错误时能够报告错误。接着定义一些终结符号,比如说%token NUM。yacc规定每个终结符都有一个唯一的编号(token number)。当我们用上面的方

19、式定义终结符时,终结符的编号由yacc内部决定,其编号规则是从257开始依次递增,每次加1。为了能够联合词法分析器和语法分析器,词法分析程序名字必须是yylex,调法分析程序向语法分析程序提供当前输入的单词符号。yylex提供给yyparse的不是终结符本身,而是终结符的编号,即token number,如果当前的终结符有语义值,yylex必须把它赋给yylval。 接着是翻译规则部分,这个翻译规则由一个文法产生式和一个相关联的语义动作组成,在这里在每个生成式后边加上语法制导翻译以实现回填的功能。4. 另外编写一个头文件myyacc.h将其加入到myyacc.y文件中去文件如下所示:Myyac

20、c.h#ifndef CP_H#define CP_H#include #include #include typedef struct listeleint instrno;struct listele *next;listele;listele* new_listele(int no)listele* p = (listele*)malloc(sizeof(listele);p-instrno = no;p-next = NULL;return p;typedef struct instrlistlistele *first,*last;instrlist;instrlist* new_i

21、nstrlist(int instrno)instrlist* p = (instrlist*)malloc(sizeof(instrlist);p-first = p-last = new_listele(instrno);return p;instrlist* merge(instrlist *list1, instrlist *list2)instrlist *p;if (list1 = NULL) p = list2;elseif (list2!=NULL)if (list1-last = NULL)list1-first = list2-first;list1-last =list2

22、-last;else list1-last-next = list2-first;list2-first = list2-last = NULL;free(list2);p = list1;return p;typedef struct node instrlist *truelist, *falselist, *nextlist;char addr256;char lexeme256;char oper3;int instr;node;int filloperator(node *dst, char *src)strcpy(dst-oper, src);return 0;int fillle

23、xeme(node *dst, char *yytext)strcpy(dst-lexeme, yytext);return 0;int copyaddr(node *dst, char *src)strcpy(dst-addr, src);return 0;int new_temp(node *dst, int index)sprintf(dst-addr, t%d, index);return 0;int copyaddr_fromnode(node *dst, node src)strcpy(dst-addr, src.addr);return 0;typedef struct code

24、list int linecnt, capacity;int temp_index;char *code;codelist; codelist* newcodelist()codelist* p = (codelist*)malloc(sizeof(codelist);p-linecnt = 0;p-capacity = 1024;p-temp_index = 0;p-code = (char*)malloc(sizeof(char*)*1024);return p;int get_temp_index(codelist* dst)return dst-temp_index+;int next

25、instr(codelist *dst) return dst-linecnt; int Gen(codelist *dst, char *str)if (dst-linecnt = dst-capacity)dst-capacity += 1024;dst-code = (char*)realloc(dst-code, sizeof(char*)*dst-capacity);if (dst-code = NULL)printf(short of memeoryn);return 0;dst-codedst-linecnt = (char*)malloc(strlen(str)+20);str

26、cpy(dst-codedst-linecnt, str);dst-linecnt+;return 0;char tmp1024;int gen_goto_blank(codelist *dst)sprintf(tmp, goto);Gen(dst, tmp);return 0;int gen_goto(codelist *dst, int instrno)sprintf(tmp, goto %d, instrno);Gen(dst, tmp);return 0;int gen_if(codelist *dst, node left, char* op, node right)sprintf(

27、tmp, if %s %s %s goto, left.addr, op, right.addr);Gen(dst, tmp);return 0;int gen_1addr(codelist *dst, node left, char* op)sprintf(tmp, %s %s, left.addr, op);Gen(dst, tmp);return 0;int gen_2addr(codelist *dst, node left, char* op, node right)sprintf(tmp, %s = %s %s, left.addr, op, right.addr);Gen(dst

28、, tmp);return 0;int gen_3addr(codelist *dst, node left, node op1, char* op, node op2)sprintf(tmp, %s = %s %s %s, left.addr, op1.addr, op, op2.addr);Gen(dst, tmp);return 0;int gen_assignment(codelist *dst, node left, node right)gen_2addr(dst, left, , right);return 0;int backpatch(codelist *dst, instr

29、list *list, int instrno)if (list!=NULL)listele *p=list-first;char tmp20;sprintf(tmp, %d, instrno);while (p!=NULL)if (p-instrnolinecnt)strcat(dst-codep-instrno, tmp);p=p-next;return 0;int print(codelist* dst)int i;for (i=0; i linecnt; i+)printf(%5d: %sn, i, dst-codei);return 0;#endif五、实验测试和实验结果在mayya

30、cc代码中用于打开test.in文件,即本次的测试文件,内容如下:当程序正在测试时,显示Compiling.!,当测试结束后,显示completed successfully!中间代码生成结果如下所示:六、实验心得 此次实验是编写一个用语法制导方式生成的中间代码,虽然上次实验是实现一个语法分析器,可以承接上次实验,但这次实验同上次差别还是比较大的。除了使用软件flex和bison实现生成两个c文件和一个h文件外,还需要自己编写一个h文件。此次实验还需要运用回填技术实现中间代码的生成,如何合理的使用这一技术更是成功输出结果的关键所在。由于刚学过该知识,没能很好地巩固,编写起来还是比较困难的。原因

31、是不知道该用什么语句将l文件和y文件结合起来,该在什么地方加上回填。后来经过对网上资料和书本知识的认真学习下发现,其实大部分知识都是课堂上曾经讲过的,只是加上了一些固定的格式函数。而要想联系这几个文件,可以增加一些头文件即可实现连接的功能。 总的来说,此次实验难度比之前几次都要难,不仅覆盖了之前实验的内容,而且还需要额外加入新的知识和编程技术。由于对书本知识掌握的不是很精通,以及对知识软件的掌握程度还不够,所以对理论知识有一定的了解,但要将它真正地运用到程序编写中还是有一定难度的。这几次实验,从词法分析器到语法分析器再到中间代码的生成,内容步步深入,程度逐渐加深,对程序编写是一个比较大的锻炼。专心-专注-专业

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 应用文书 > 教育教学

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知得利文库网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号-8 |  经营许可证:黑B2-20190332号 |   黑公网安备:91230400333293403D

© 2020-2023 www.deliwenku.com 得利文库. All Rights Reserved 黑龙江转换宝科技有限公司 

黑龙江省互联网违法和不良信息举报
举报电话:0468-3380021 邮箱:hgswwxb@163.com