编译器的代码生成._第1页
编译器的代码生成._第2页
编译器的代码生成._第3页
编译器的代码生成._第4页
编译器的代码生成._第5页
已阅读5页,还剩47页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、佛山科学技术学院 实 验 报 告课程名称 编译原理 实验项目 编译器的代码生成 专业班级 计算机1班 姓 名 学 号 指导教师 黄营 成 绩 日 期 2014/6/7 一、实验目的; 掌握PL语言编译器的中间代码生成的程序分析与实现方法,并能对错误进行分析与处理二、实验内容; 为了使我们的编译程序保持适当简单的水平,不致陷入与本课程无关的实际机器的特有性质的考虑中去,我们假想有台适合PL程序运行的计算机,我们称之为PL处理机。PL处理机顺序解释生成的目标代码。三、实验原理;PL处理机的指令集根据PL语言的要求而设计,它包括以下的指令:(1)LIT /* 将常数置于栈顶 */(2)LOD /*

2、将变量值置于栈顶 */(3)STO /* 将栈顶的值赋与某变量 */(4)CAL /* 用于过程调用的指令 */(5)INT /* 在数据栈中分配存贮空间 */(6)JMP, JPC /* 用于if, while语句的条件或无条件控制转移指令 */(7)OPR /* 一组算术或逻辑运算指令 */上述指令的格式由三部分组成:FLA其中,f, l, a的含义见下表:FLaINT常 量LIT常 量LOD层次差数据地址STO层次差数据地址CAL层次差程序地址JMP程序地址JPC程序地址OPR运算类别表1 PL 处理机指令四、实验步骤; PL的编译程序为每一条PL源程序的可执行语句生成后缀式目标代码。另

3、一方面,发现错误,并给出合适的诊断信息且继续编译下去从而发现更多的错误,对于编译程序而言是完全必要的。结合关键字规则、镇定规则,采用策略:先用一些明显的关键符号给它赋初值,然后随着分析子目标的层次深入,逐步补充别的合法符号。5、 程序代码PL0.h:/*PL/0 编译系统C版本头文件 pl0.h*/*typedef enumfalse,true,bool;*/# define norw 20 /*关键字个数*/# define txmax 100 /*名字表容量*/# define nmax 14 /*number的最大位数*/# define al 10 /*符号的最大长度*/# defin

4、e amax 2047 /*地址上界*/# define levmax 3 /*最大允许过程嵌套声明层数0,lexmax*/# define cxmax 200 /*最多的虚拟机代码数*/*符号*/enum symbolnul, ident, number, plus, minus,times, slash, oddsym, eql, neq,lss, leq, gtr, geq, lparen,rparen, comma, semicolon, period, becomes,beginsym,endsym, ifsym, thensym, whilesym,writesym,readsym

5、, dosym, callsym, constsym,varsym, procsym, elsesym, forsym, tosym,downtosym,returnsym,pluseql, minuseql,plusplus,minusminus,repeatsym,dowhilesym,;#define symnum 43/*-*/enum object constant, variable, procedur,;/*-*/enum fctlit, opr, lod, sto, cal, inte, jmp, jpc,;#define fctnum 8/*-*/struct instruc

6、tion enum fct f; int l; int a;FILE * fas;FILE * fa;FILE * fa1;FILE * fa2;bool tableswitch;bool listswitch;char ch;enum symbol sym;char idal+1;int num;int cc,ll;int cx;char line81;char aal+1;struct instruction codecxmax;char wordnorwal;enum symbol wsymnorw;enum symbol ssym256;char mnemonicfctnum5;boo

7、l declbegsyssymnum;bool statbegsyssymnum;bool facbegsyssymnum;/*-*/struct tablestruct char nameal; /*名字*/ enum object kind; /*类型:const,var,array or procedure*/ int val; /*数值,仅const使用*/ int level; /*所处层,仅const不使用*/ int adr; /*地址,仅const不使用*/ int size; /*需要分配的数据区空间,仅procedure使用*/;struct tablestruct tab

8、letxmax; /*名字表*/FILE * fin;FILE* fout;char fnameal;int err; /*错误计数器*/*当函数中会发生fatal error时,返回1告知调用它的函数,最终退出程序*/#define getsymdo if(-1=getsym()return -1#define getchdo if(-1=getch()return -1#define testdo(a,b,c) if(-1=test(a,b,c)return -1#define gendo(a,b,c) if(-1=gen(a,b,c)return -1#define expression

9、do(a,b,c) if(-1=expression(a,b,c)return -1#define factordo(a,b,c) if(-1=factor(a,b,c)return -1#define termdo(a,b,c) if(-1=term(a,b,c)return -1#define conditiondo(a,b,c) if(-1=condition(a,b,c)return -1#define statementdo(a,b,c) if(-1=statement(a,b,c)return -1#define constdeclarationdo(a,b,c) if(-1=co

10、nstdeclaration(a,b,c)return -1#define vardeclarationdo(a,b,c) if(-1=vardeclaration(a,b,c)return -1void error(int n);int getsym();int getch();void init();int gen(enum fct x,int y,int z);int test(bool*s1,bool*s2,int n);int inset(int e,bool*s);int addset(bool*sr,bool*s1,bool*s2,int n);int subset(bool*s

11、r,bool*s1,bool*s2,int n);int mulset(bool*sr,bool*s1,bool*s2,int n);int block(int lev,int tx,bool* fsys);void interpret();int factor(bool* fsys,int* ptx,int lev);int term(bool*fsys,int*ptx,int lev);int condition(bool*fsys,int*ptx,int lev);int expression(bool*fsys,int*ptx,int lev);int statement(bool*f

12、sys,int*ptx,int lev);void listcode(int cx0);int vardeclaration(int* ptx,int lev, int* pdx);int constdeclaration(int* ptx,int lev, int* pdx);int position(char* idt,int tx);void enter(enum object k,int* ptx,int lev,int* pdx);int base(int l,int* s,int b);PL0.cpp:/*使用方法:*运行后输入PL/0 源程序文件名*回答是否输出虚拟机代码*回答是

13、否输出名字表*fa.tmp 输出虚拟机代码*fa1.tmp 输出源文件及其各行对应的首地址*fa2.tmp 输出结果 *fas.tmp 输出名字表*/#include<stdio.h>#include"pl0.h"#include"string.h"#include <cstdio>/*解释执行时使用的栈*/#define stacksize 500int main()int c;bool nxtlevsymnum;printf("Input pl/0 file ?");scanf("%s"

14、,fname); /*输入文件名*/fin=fopen(fname,"r");if(fin)printf("List object code ?(Y/N)"); /*是否输出虚拟机代码*/scanf("%s",fname);listswitch=(fname0='y'|fname0='Y');printf("List symbol table ? (Y/N)"); /*是否输出名字表*/scanf("%s",fname);tableswitch=(fname0=&

15、#39;y'|fname0='Y');fa1=fopen("fa1.txt","w");fprintf(fa1,"Iput pl/0 file ?");fprintf(fa1,"%sn", fname);init(); /*初始化*/err=0;cc=cx=ll=0;ch=' ' if(-1!=getsym() fa=fopen("fa.txt","w");fas=fopen("fas.txt","w&qu

16、ot;);addset(nxtlev,declbegsys,statbegsys,symnum);nxtlevperiod=true;if(-1=block(0,0,nxtlev) /*调用编译程序*/ fclose(fa);fclose(fa1);fclose(fas);fclose(fin);printf("n");return 0;fclose(fa);fclose(fa1);fclose(fas);if(sym!=period)error(9);fclose(fin);elseprintf("Can't open file! n");pr

17、intf("n");while ( (c = getchar() != 'n' && c != EOF ) ; / 清空输入流clearerr(stdin); / 清除流的错误标记getchar(); / 等待用户输入回车return 0;/*初始化*/void init()int i;for(i=0;i<=255;i+)ssymi=nul;ssym'+'=plus;ssym'-'=minus;ssym'*'=times;ssym'/'=slash;ssym'(&#

18、39;=lparen;ssym')'=rparen;ssym'='=eql;ssym','=comma;ssym'.'=period;/ssym'#'=neq; / 注释掉不等号ssym''=semicolon;/*设置保留字名字,按照字母顺序,便于折半查找*/strcpy(&(word00),"begin");strcpy(&(word10),"call");strcpy(&(word20),"const");st

19、rcpy(&(word30),"do");strcpy(&(word40),"dowhile");/增加dowhile strcpy(&(word50),"downto"); /*增加downto*/ strcpy(&(word60),"else"); /*增加else*/ strcpy(&(word70),"end"); strcpy(&(word80),"for"); /*增加for*/ strcpy(&(word9

20、0),"if");strcpy(&(word100),"odd");strcpy(&(word110),"procedure");strcpy(&(word120),"read");strcpy(&(word130),"repeat");/增加repeat strcpy(&(word140),"return"); /*增加return*/strcpy(&(word150),"then"); strcpy(&a

21、mp;(word160),"to"); /*增加to*/ strcpy(&(word170),"var");strcpy(&(word180),"while");strcpy(&(word190),"write"); /*设置保留字符号*/wsym0=beginsym;wsym1=callsym;wsym2=constsym; wsym3=dosym;wsym4=dowhilesym;/*增加dowhilesym*/wsym5=downtosym; /*增加downtosym*/wsym6=

22、elsesym; /*增加elsesym*/wsym7=endsym;wsym8=forsym; /*增加forsym*/wsym9=ifsym;wsym10=oddsym;wsym11=procsym;wsym12=readsym;wsym13=repeatsym;/增加repeatsymwsym14=returnsym; /*增加returnsym*/ wsym15=thensym;wsym16=tosym; /*增加tosym*/wsym17=varsym;wsym18=whilesym;wsym19=writesym;/*设置指令名称*/strcpy(&(mnemoniclit

23、0),"lit");strcpy(&(mnemonicopr0),"opr");strcpy(&(mnemoniclod0),"lod");strcpy(&(mnemonicsto0),"sto");strcpy(&(mnemoniccal0),"cal");strcpy(&(mnemonicinte0),"int");strcpy(&(mnemonicjmp0),"jmp");strcpy(&(mn

24、emonicjpc0),"jpc");/*设置符号集*/for(i=0;i<symnum;i+)declbegsysi=false;statbegsysi=false;facbegsysi=false;/*设置声明开始符号集*/declbegsysconstsym=true;declbegsysvarsym=true;declbegsysprocsym=true;/*设置语句开始符号集*/statbegsysbeginsym=true;statbegsyscallsym=true;statbegsysifsym=true;statbegsyswhilesym=true

25、;statbegsysrepeatsym=true;/增加repeat为语句开始符号/*设置因子开始符号集*/facbegsysident=true;facbegsysnumber=true;facbegsyslparen=true; /* *用数组实现集合的集合运算 */int inset(int e,bool* s) return se;int addset(bool* sr,bool* s1,bool* s2,int n) int i; for(i=0;i<n;i+) sri=s1i|s2i; return 0;int subset(bool* sr,bool* s1,bool*

26、s2,int n) int i; for(i=0;i<n;i+) sri=s1i&&(!s2i); return 0; int mulset(bool* sr,bool* s1,bool* s2,int n) int i; for(i=0;i<n;i+) sri=s1i&&s2i; return 0;/* *出错处理,打印出错位置和错误编码 */void error(int n) char space81;memset(space,32,81); printf("-%cn",ch);spacecc-1=0;/出错时当前符号已经读完

27、,所以cc-1printf("*%s!%dn",space,n);err+;/* * 漏掉空格,读取一个字符 * * 每次读一行,存入line缓冲区,line被getsym取空后再读一行 * * 被函数getsym调用 */int getch()if(cc=ll) if(feof(fin)printf("program incomplete");return -1;ll=0;cc=0;printf("%d ",cx );fprintf(fa1,"%d ",cx);ch=' 'while(ch!=10

28、)/fscanf(fin,"%c",&ch) if(EOF=fscanf(fin,"%c",&ch)linell=0;break;printf("%c",ch);fprintf(fa1,"%c",ch);linell=ch;ll+;printf("n");fprintf(fa1,"n");ch=linecc;cc+;return 0; /*词法分析,获取一个符号 */int getsym()int i,j,k;while( ch=' '|ch=

29、10|ch=9)getchdo;if(ch>='a'&&ch<='z') k=0;doif(k<al) ak=ch;k+;getchdo; while(ch>='a'&&ch<='z'|ch>='0'&&ch<='9');ak=0;strcpy(id,a);i=0;j=norw-1;dok=(i+j)/2;if(strcmp(id,wordk)<=0)j=k-1;if(strcmp(id,wordk)&g

30、t;=0)i=k+1;while(i<=j);if(i-1>j)sym=wsymk;elsesym=ident;elseif(ch>='0'&&ch<='9')k=0;num=0;sym=number;donum=10*num+ch-'0'k+;getchdo;while(ch>='0'&&ch<='9'); /*获取数字的值*/k-;if(k>nmax)error(30);elseif(ch=':') /*检测赋值符号*/g

31、etchdo;if(ch='=')sym=becomes;getchdo;elsesym=nul; /*不能识别的符号*/elseif(ch='<') /*检测小于或小于等于符号*/getchdo;if(ch='=')sym=leq;getchdo;elseif(ch='>') /*将“#”变成"<>" */sym=neq;getchdo;else sym=lss;elseif(ch='>') /*检测大于或大于等于符号*/getchdo;if(ch='=&

32、#39;)sym=geq;getchdo;else sym=gtr; if(ch='+') /*增加检测"+="或"+" */ getchdo; if(ch='=') sym=pluseql; getchdo; else if(ch='+') sym=plusplus; getchdo; else sym=plus; else if(ch='-') /*增加检测"-="或"-" */ getchdo; if(ch='=') sym=mi

33、nuseql; getchdo; else if(ch='-') sym=minusminus; getchdo; else sym=minus; else sym=ssymch;/* 当符号不满足上述条件时,全部按照单字符号处理*/getchdo;/richardif(sym!=period)getchdo;/end richard return 0;/*生成虚拟机代码*x:instruction.f;*y:instruction.l;*z:instruction.a;*/int gen(enum fct x,int y,int z)if(cx>=cxmax)print

34、f("Program too long"); /*程序过长*/return -1;codecx.f=x;codecx.l=y;codecx.a=z;cx+;return 0;/*测试当前符号是否合法*在某一部分(如一条语句,一个表达式)将要结束时时我们希望下一个符号属于某集合*(该部分的后跟符号) test 负责这项检测,并且负责当检测不通过时的补救措施*程序在需要检测时指定当前需要的符号集合和补救用的集合(如之前未完成部分的后跟*符号),以及不通过时的错误号*S1:我们需要的符号*s2:如果不是我们需要的,则需要一个补救用的集合*n:错误号*/int test(bool*

35、 s1,bool* s2,int n) if(! inset(sym,s1) error(n);/*当检测不通过时,不停获取符号,直到它属于需要的集合或补救的集合*/while(! inset(sym,s1)&&(! inset(sym,s2)getsymdo; return 0;/* *编译程序主体 * *lev:当前分程序所在层 *tx:名字表当前尾指针 *fsys:当前模块后跟符号集合 */int block(int lev,int tx,bool* fsys) int i; int dx; /*名字分配到的相对地址*/ int tx0; /*保留初始tx*/ int c

36、x0; /*保留初始cx*/ bool nxtlevsymnum; /*在下级函数的参数中,符号集合均为值参,但由于使用数组 实现,传递进来的是指针,为防止下级函数改变上级函数的 集合,开辟新的空间传递给下级函数*/ dx=3; tx0=tx; /*记录本层名字的初始位置*/ tabletx.adr=cx; gendo(jmp,0,0); if(lev > levmax) error(32); do/各种声明语句处理 if(sym=constsym) /*收到常量声明符号,开始处理常量声明*/ getsymdo;do constdeclarationdo(&tx,lev,&

37、;dx); /*dx的值会被constdeclaration改变,使用 指针*/ while(sym=comma) getsymdo; constdeclarationdo(&tx,lev,&dx); if(sym=semicolon) getsymdo;elseerror(5); /*漏掉了逗号或者分号*/while(sym=ident);/end constif(sym=varsym)/*收到变量声名符号,开始处理变量声名*/getsymdo;dovardeclarationdo(&tx,lev,&dx);while(sym=comma)getsymdo;v

38、ardeclarationdo(&tx,lev,&dx);if(sym=semicolon)getsymdo;elseerror(5);while(sym=ident);/end varwhile(sym=procsym)/*收到过程声名符号,开始处理过程声名*/getsymdo;if(sym=ident)enter(procedur,&tx,lev,&dx);/*记录过程名字*/getsymdo;elseerror(4);/*procedure后应为标识符*/if(sym=semicolon)getsymdo;elseerror(5);/*漏掉了分号*/mem

39、cpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlevsemicolon=true;if(-1=block(lev+1,tx,nxtlev)return -1;/*递归调用*/ if(sym=semicolon) getsymdo; memcpy(nxtlev,statbegsys,sizeof(bool)*symnum); nxtlevident=true; nxtlevprocsym=true; testdo(nxtlev,fsys,6); else error(5); /*漏掉了分号*/ /end procsym while(inset(sym,declb

40、egsys); /*直到没有声明符号*/ memcpy(nxtlev,statbegsys,sizeof(bool)*symnum); nxtlevident=true; nxtlevperiod=true; testdo(nxtlev,declbegsys,7); codetabletx0.adr.a=cx; /*开始生成当前过程代码*/ tabletx0.adr=cx; /*当前过程代码地址*/ tabletx0.size=dx; /*声明部分中每增加一条声明都会给dx增加1,声明部分已经结束,dx就是当前过程数据的size*/ cx0=cx; gendo(inte,0,dx); /*生成

41、分配内存代码*/ if(tableswitch) /*输出名字表*/ printf("TABLE:n"); if(tx0+1>tx) printf("NULLn"); for(i=tx0+1;i<=tx;i+) switch(tablei.kind) case constant:printf("%d const %s ",i,);printf("val=%dn",tablei.val);fprintf(fas,"%d const %s ",i,tablei.na

42、me);fprintf(fas,"val=%dn",tablei.val); break; case variable: printf("%d var %s ",i,); printf("lev=%d addr=%dn",tablei.level,tablei.adr); fprintf(fas,"%d var %s ",i,); fprintf(fas,"lev=%d addr=%dn",tablei.level,tablei.adr); break; case procedur: printf("%d proc %s ",i,); printf("lev=%d addr=%d size=%dn",tablei.level,tablei

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论