编译原理pl0头文件源码

合集下载

PL0编译程序源程序

PL0编译程序源程序

procedure constdeclaration; (*常量定义的处理*) begin if sym = ident then begin getsym; if sym in [eql,becomes] then begin if sym = becomes then error(1); getsym; if sym = number then begin enter(constant); getsym; end else error(2) end else error(3) end else error(4); end; (*constdeclaration 结束*)
until kk = k; id:= a; i:= 1; (*二分法查保留字表*) j:= norw; repeat k:= (i+j) div 2; if id <= word[k] then j:= k-1; if id >= word[k] then i:= k+1 until i>j; if i-1 > j then sym:= wsym[k] else sym:= ident; end else if ch in ['0'..'9'] then begin (*number*) k:= 0; num:= 0; sym:= number; repeat num:= 10 * num+(ord(ch)-ord('0')); k:= k+1; getch until not (ch in ['0'..'9']); if k > nmax then error(30); end else if ch = ':' then begin getch; if ch = '=' then begin sym:= becomes; getch; end else sym:= nul; end else (*<=*)

编译原理(PL0编译程序源代码)

编译原理(PL0编译程序源代码)

/*PL/0编译程序(C语言版)*编译和运行环境:*Visual C++6.0*WinXP/7*使用方法:*运行后输入PL/0源程序文件名*回答是否将虚拟机代码写入文件*回答是否将符号表写入文件*执行成功会产生四个文件(词法分析结果.txt符号表.txt虚拟代码.txt源程序和地址.txt)*/#include <stdio.h>#include"pl0.h"#include"string"#define stacksize 500//解释执行时使用的栈int main(){bool nxtlev[symnum];printf("请输入源程序文件名:");scanf("%s",fname);fin=fopen(fname,"r");//以只读方式打开pl0源程序文件cifa=fopen("词法分析结果.txt","w");fa1=fopen("源程序和地址.txt","w");//输出源文件及各行对应的首地址fprintf(fa1,"输入pl0源程序文件名:");fprintf(fa1,"%s\n",fname);if(fin){printf("是否将虚拟机代码写入文件?(Y/N)");//是否输出虚拟机代码scanf("%s",fname);listswitch=(fname[0]=='y'||fname[0]=='Y');printf("是否将符号表写入文件?(Y/N)");//是否输出符号表scanf("%s",fname);tableswitch=(fname[0]=='y'||fname[0]=='Y');init();//初始化err=0;cc=cx=ll=0;ch=' ';if(-1!=getsym()){fa=fopen("虚拟代码.txt","w");fas=fopen("符号表.txt","w");addset(nxtlev,declbegsys,statbegsys,symnum);nxtlev[period]=true;if(-1==block(0,0,nxtlev)){//调用编译程序fclose(fa);fclose(fa1);fclose(fas);fclose(fin);return 0;}if(sym!=period){error(9);//结尾丢失了句号}if(err!=0){printf("pl0源程序出现错误,退出编译!!!请从第一个错误处开始修改.\n\n");fprintf(cifa,"源程序出现错误,请检查!!!");fprintf(fa1,"源程序出现错误,请检查!!!");fprintf(fa,"源程序出现错误,请检查!!!");fprintf(fas,"源程序出现错误,请检查!!!");}fclose(fa);fclose(fa1);fclose(fas);}fclose(fin);}else{printf("Can't open file!\n");}fclose(cifa);//printf("\n");return 0;}void init(){//初始化int i;for(i=0;i<=255;i++)ssym[i]=nul;//设置单字符符号ssym['+']=plus;ssym['-']=minus;ssym['*']=times;ssym['/']=slash;ssym['(']=lparen;ssym[')']=rparen;ssym['=']=eql;ssym[',']=comma;ssym['.']=period;ssym['#']=neq;ssym[';']=semicolon;strcpy(&(word[0][0]),"begin");//保留字设置,以字母顺序排列便于折半查找strcpy(&(word[1][0]),"call");strcpy(&(word[2][0]),"const");strcpy(&(word[3][0]),"do");strcpy(&(word[4][0]),"end");strcpy(&(word[5][0]),"if");strcpy(&(word[6][0]),"odd");strcpy(&(word[7][0]),"procedure");strcpy(&(word[8][0]),"read");strcpy(&(word[9][0]),"then");strcpy(&(word[10][0]),"var");strcpy(&(word[11][0]),"while");strcpy(&(word[12][0]),"write");wsym[0]=beginsym;//设置保留字类别一字即一类wsym[1]=callsym;wsym[2]=constsym;wsym[3]=dosym;wsym[4]=endsym;wsym[5]=ifsym;wsym[6]=oddsym;wsym[7]=procsym;wsym[8]=readsym;wsym[9]=thensym;wsym[10]=varsym;wsym[11]=whilesym;wsym[12]=writesym;strcpy(&(mnemonic[lit][0]),"lit");//设置指令名称strcpy(&(mnemonic[opr][0]),"opr");strcpy(&(mnemonic[lod][0]),"lod");strcpy(&(mnemonic[sto][0]),"sto");strcpy(&(mnemonic[cal][0]),"cal");strcpy(&(mnemonic[inte][0]),"int");strcpy(&(mnemonic[jmp][0]),"jmp");strcpy(&(mnemonic[jpc][0]),"jpc");for(i=0;i<symnum;i++){//设置符号集declbegsys[i]=false;statbegsys[i]=false;facbegsys[i]=false;}declbegsys[constsym]=true;//设置声明开始符号集declbegsys[varsym]=true;declbegsys[procsym]=true;statbegsys[beginsym]=true;//设置语句开始符号集statbegsys[callsym]=true;statbegsys[ifsym]=true;statbegsys[whilesym]=true;facbegsys[ident]=true;//设置因子开始符号集facbegsys[number]=true;facbegsys[lparen]=true;}//用数组实现集合的集合运算int inset(int e,bool* s){return s[e];}int addset(bool*sr,bool* s1,bool* s2,int n){int i;for(i=0;i<n;i++)sr[i]=s1[i]||s2[i];return 0;}void error(int n){//出错处理,打印出错位置和错误编码char space[81];memset(space, 32,81);space[cc-1]=0;printf("error(%d)",n);fprintf(fa1,"error(%d)",n);switch(n){case 1:printf("\t\t常量说明中的“=”写成“:=”\n");fprintf(fa1,"\t\t常量说明中的“=”写成“:=”\n");break;case 2:printf("\t\t常量说明中的=后应该是数字\n");fprintf(fa1,"\t\t常量说明中的=后应该是数字\n");break;case 3:printf("\t\t常量说明符中的表示符应该是=\n" );fprintf(fa1,"\t\t常量说明符中的表示符应该是=\n");break;case 4:printf("\t\tconst,var,procedure后应为标识符\n" );fprintf(fa1,"\t\tconst,var,procedure后应为标识符\n");break;case 5:printf("\t\t漏掉了“,”或“;”\n" );fprintf(fa1,"\t\t漏掉了“,”或“;”\n" );break;case 6:printf("\t\t过程说明后的符号不正确\n" );fprintf(fa1,"\t\t过程说明后的符号不正确\n");break;case 7:printf("\t\t应是语句开始符\n" );fprintf(fa1,"\t\t应是语句开始符\n" );break;case 8:printf("\t\t程序体内语句部分的后跟符不正确\n" );fprintf(fa1,"\t\t程序体内语句部分的后跟符不正确\n" );break;case 9:printf("\t\t程序结尾丢了句号“.”\n\n" );fprintf(fa1,"\t\t程序结尾丢了句号“.”\n");break;case 10:printf("\t\t语句之间漏了“;”\n" );fprintf(fa1,"\t\t语句之间漏了“;”\n");break;case 11:printf("\t\t标识符拼写错误或未说明\n" );fprintf(fa1,"\t\t标识符拼写错误或未说明\n");break;case 12:printf("\t\t赋值语句中,赋值号左部标识符属性应是变量\n" );fprintf(fa1,"\t\t赋值语句中,赋值号左部标识符属性应是变量\n");break;case 13:printf("\t\t赋值语句左部标识符后应是复制号“:=”\n" );fprintf(fa1,"\t\t赋值语句左部标识符后应是复制号“:=”\n");break;case 14:printf("\t\tcall后应为标识符\n" );fprintf(fa1,"\t\tcall后应为标识符\n");break;case 15:printf("\t\tcall后标识符属性应为过程\n" );fprintf(fa1,"\t\tcall后标识符属性应为过程\n");break;case 16:printf("\t\t条件语句中丢了then\n" );fprintf(fa1,"\t\t条件语句中丢了then\n");break;case 17:printf("\t\t丢了“end”或“;”\n" );fprintf(fa1,"\t\t丢了“end”或“;”\n");break;case 18:printf("\t\twhile型循环语句中丢了“do”\n" );fprintf(fa1,"\t\twhile型循环语句中丢了“do”\n");break;case 19:printf("\t\t语句后的符号不正确\n" );fprintf(fa1,"\t\t语句后的符号不正确\n" );break;case 20:printf("\t\t应为关系运算符\n" );fprintf(fa1,"\t\t应为关系运算符\n");break;case 21:printf("\t\t表达式内标示符属性不能是过程\n" );fprintf(fa1,"\t\t表达式内标示符属性不能是过程\n");break;case 22:printf("\t\t表达式漏掉了右括号\n" );fprintf(fa1,"\t\t表达式漏掉了右括号\n");break;case 23:printf("\t\t因子后的非法符号\n" );fprintf(fa1,"\t\t因子后的非法符号\n");break;case 24:printf("\t\t表达式的开始符不能是此符号\n" );fprintf(fa1,"\t\t表达式的开始符不能是此符号\n");break;case 25:printf("\t\t标识符越界\n" );fprintf(fa1,"\t\t标识符越界\n");break;case 26:printf("\t\t非法字符\n" );fprintf(fa1,"\t\t非法字符\n");break;case 31:printf("\t\t数越界\n");fprintf(fa1,"\t\t数越界\n");break;case 32:printf("\t\tread语句括号中的标识符不是变量\n" );fprintf(fa1,"\t\tread语句括号中的标识符不是变量\n");break;case 33:printf("\t\twrite()或read()中应为完整表达式\n" );fprintf(fa1,"\t\twrite()或read()中应为完整表达式\n");break;default:printf("\t\t出现未知错误\n" );fprintf(fa1,"\t\t出现未知错误\n");}err++;}//漏掉空格,读取一个字符,每次读一行,存入line缓冲区,line被getsym取空后再读一//行,被函数getsym调用int getch(){if(cc==ll){if(feof(fin)){printf("program incomplete");return-1;}ll=0;cc=0;printf("\n%d ",cx);fprintf(fa1,"\n%d ",cx);ch=' ';while(ch!=10){if(EOF==fscanf(fin,"%c",&ch)){line[ll]=0;break;}printf("%c",ch);fprintf(fa1,"%c",ch);line[ll]=ch;ll++;}fprintf(cifa,"\n");}ch=line[cc];cc++;return 0;}int getsym(){//词法分析int i,j,k,l;while(ch==' '||ch==10||ch==9)//忽略空格换行 TABgetchdo;if(ch>='a'&&ch<='z'){//以字母开头的为保留字或者标识符k=0,l=1;do{if(k<al){//al为标识符或保留字最大长度a[k]=ch;k++;}if(k==al&&l==1){error(25);l=0;}getchdo;}while(ch>='a'&&ch<='z'||ch>='0'&&ch<='9');a[k]=0;//末尾存零strcpy(id,a);i=0;j=norw-1;do{//开始折半查找k=(i+j)/2;if(strcmp(id,word[k])<=0){j=k-1;}if(strcmp(id,word[k])>=0){i=k+1;}}while(i<=j);if(i-1>j){//找到即为保留字sym=wsym[k];fprintf(cifa,"%s\t\t%ssym\n",id,id);//printf("%s\t\t%ssym\n",id,id);}else{//否则为标识符或数字sym=ident;fprintf(cifa,"%s\t\tident\n",id);//printf("%s\t\tident\n",id);}}else {if(ch>='0'&&ch<='9'){k=0;num=0;sym=number;do{num=10*num+ch-'0';//数字的数位处理k++;getchdo;}while(ch>='0'&&ch<='9');k--;if(k>nmax){//数字的长度限制fprintf(cifa,"0\t\tnumber\n");num=0;error(31);}elsefprintf(cifa,"%d\t\tnumber\n",num);//printf("%d\t\tnumber\n",num);}else{if(ch==':'){//检测赋值符号,:只能和=匹配,否则不能识别getchdo;if(ch=='='){sym=becomes;fprintf(cifa,":=\t\tbecomes\n");getchdo;}else{sym=nul;}}else{if(ch=='<'){getchdo;if(ch=='='){sym=leq;//小于等于fprintf(cifa,"<=\t\tleq\n");getchdo;}else{sym=lss;//小于fprintf(cifa,"<\t\tlss\n");}}else{if(ch=='>'){getchdo;if(ch=='='){sym=geq;//大于等于fprintf(cifa,">=\t\tgeq\n");getchdo;}else{sym=gtr;//大于fprintf(cifa,">\t\tgtr\n");}}else{sym=ssym[ch];//不满足上述条件时按单字//符处理switch(ch){case'+':fprintf(cifa,"%c\t\tplus\n",ch);break;case '-':fprintf(cifa,"%c\t\tminus\n",ch );break;case '*':fprintf(cifa,"%c\t\ttimes\n",ch);break;case '/':fprintf(cifa,"%c\t\tslash\n",ch);break;case '(':fprintf(cifa,"%c\t\tlparen\n",ch);break;case ')':fprintf(cifa,"%c\t\trparen\n",ch);break;case '=':fprintf(cifa,"%c\t\teql\n",ch);break;case ',':fprintf(cifa,"%c\t\tcomma\n",ch);break;case '#':fprintf(cifa,"%c\t\tneq\n",ch);break;case ';':fprintf(cifa,"%c\t\tsemicolon\n",ch);break;case '.':break;default :error(26);}if(sym!=period){//判断是否结束getchdo;}else{printf("\n");fprintf(cifa,".\t\tperiod\n");}}}}}}return 0;}//生成目标代码//目标代码的功能码,层差和位移量int gen(enum fct x,int y,int z){if(cx>=cxmax){//如果目标代码索引过大,报错printf("Program too long");return -1;}code[cx].f=x;code[cx].l=y;code[cx].a=z;cx++;return 0;}//测试字符串int test(bool* s1,bool* s2,int n){if(!inset(sym,s1)){//测试sym是否属于s1,不属于则报错nerror(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;//保留初始txint cx0;//保留初始cxbool nxtlev[symnum];dx=3;//相对地址从3开始,前3个单元即0、1、2单元分别为 SL:静态链;//DL:动态链;RA:返回地址tx0=tx;//记录本层的初始位置table[tx].adr=cx;gendo(jmp,0,0);if(lev>levmax){//层数超过3error(32);}do{if(sym==constsym){//收到常量声明printf("该语句为常量定义语句\n");getsymdo;do{constdeclarationdo(&tx,lev,&dx);//常量声明处理,dx 会改//变所以使用指针while(sym==comma){//处理一次多常量定义getsymdo;constdeclarationdo(&tx,lev,&dx);}if(sym==semicolon){//常量声明处理结束getsymdo;}else{error(5);//漏掉了逗号或者分号(一般是分号)}}while(sym==ident);}if(sym==varsym){//收到变量声明printf("该语句为变量声明语句\n");getsymdo;do{vardeclarationdo(&tx,lev,&dx);//变量声明处理while(sym==comma){//处理一次多变量定义getsymdo;vardeclarationdo(&tx,lev,&dx);}if(sym==semicolon){//变量声明处理结束getsymdo;}else{error(5);//漏掉逗号或者分号}}while(sym==ident);}while(sym==procsym){//收到过程声明printf("该语句为过程声明语句\n");getsymdo;if(sym==ident){enter(procedur,&tx,lev,&dx);//记录过程名getsymdo;}else{error(4);//过程声明后应为标识符}if(sym==semicolon){getsymdo;}else{error(5);//漏掉了分号}memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[semicolon]=true;if(-1==block(lev+1,tx,nxtlev)){return -1;}if(sym==semicolon){getsymdo;memcpy(nxtlev,statbegsys,sizeof(bool)*symnum);nxtlev[ident]=true;nxtlev[procsym]=true;testdo(nxtlev,fsys,6);}else{error(5);}}memcpy(nxtlev,statbegsys,sizeof(bool)*symnum);nxtlev[ident]=true;nxtlev[period]=true;testdo(nxtlev,declbegsys,7);}while(inset(sym,declbegsys));//直到没有声明符号code[table[tx0].adr].a=cx;//开始生成当前过程代码table[tx0].adr=cx;//当前过程代码地址table[tx0].size=dx;cx0=cx;gendo(inte,0,dx);//生成分配内存代码if(tableswitch){//输出符号表if(tx0+1<tx){fprintf(fas,"TABLE:\n");//printf("NULL\n");}for(i=tx0+1;i<=tx;i++){switch(table[i].kind){case constant:fprintf(fas,"%d const %s ",i,table[i].name);fprintf(fas,"val=%d\n",table[i].val);break;case variable:fprintf(fas,"%d var %s ",i,table[i].name);fprintf(fas,"lev=%daddr=%d\n",table[i].level,table[i].adr);break;case procedur:fprintf(fas,"%d proc %s ",i,table[i].name);fprintf(fas,"lev=%daddr=%dsize=%d\n", table[i].level,table[i].adr,table[i].size);break;}}}memcpy(nxtlev,fsys,sizeof(bool)*symnum);//每个后跟符号集和都包含上层后跟符//号集和,以便补救nxtlev[semicolon]=true;nxtlev[endsym]=true;statementdo(nxtlev,&tx,lev);gendo(opr,0,0);//每个过程出口都要使用的释放数据指令memset(nxtlev,0,sizeof(bool)*symnum);//分程序没有补救集合testdo(fsys,nxtlev,8);//检测后跟符号集的正确性listcode(cx0);//输出代码return 0;}//k:const var procedure//ptx:符号表尾的指针//pdx:dx为当前应分配变量的相对地址//lev:符号名字所在的层次//往符号表中添加void enter(enum object k,int* ptx,int lev,int* pdx){(* ptx)++;strcpy(table[(*ptx)].name,id);table[(* ptx)].kind=k;switch(k){case constant:if(num>amax){error(31);num=0;}table[(*ptx)].val=num;break;case variable:table[(*ptx)].level=lev;table[(*ptx)].adr=(*pdx);(*pdx)++;break;case procedur:table[(*ptx)].level=lev;break;}}//寻找符号在符号表中的地址int position(char*idt,int tx){int i;strcpy(table[0].name,idt);i=tx;//符号表尾while(strcmp(table[i].name,idt)!=0){i--;}return i;}//常量声明处理int constdeclaration(int* ptx,int lev,int* pdx){if(sym==ident){getsymdo;if(sym==eql||sym==becomes){if(sym==becomes){error(1);}getsymdo;if(sym==number){enter(constant,ptx,lev,pdx);getsymdo;}else{error(2);}}else{error(3);}}else{error(4);}return 0;}//变量声明处理int vardeclaration (int* ptx,int lev,int* pdx){if(sym==ident){enter(variable,ptx,lev,pdx);getsymdo;}else{error(4);}return 0;}//输出目标代码清单void listcode(int cx0){int i;if(listswitch){for(i=cx0;i<cx;i++){fprintf(fa,"%d %s %d %d\n",i,mnemonic[code[i].f],code[i].l,code[i],a);}}}//语句处理int statement(bool* fsys,int* ptx,int lev){int i,cx1,cx2;bool nxtlev[symnum];if(sym==ident){i=position(id,*ptx);if(i==0){error(11);}else{if(table[i].kind!=variable){error(12);i=0;}else{getsymdo;if(sym==becomes){getsymdo;printf("该语句为赋值语句。

编译原理(PL0编译程序源代码)

编译原理(PL0编译程序源代码)

/*PL/0编译程序(C语言版)*编译和运行环境:*Visual C++6.0*WinXP/7*使用方法:*运行后输入PL/0源程序文件名*回答是否将虚拟机代码写入文件*回答是否将符号表写入文件*执行成功会产生四个文件(词法分析结果.txt符号表.txt虚拟代码.txt源程序和地址.txt)*/#include <stdio.h>#include"pl0.h"#include"string"#define stacksize 500//解释执行时使用的栈int main(){bool nxtlev[symnum];printf("请输入源程序文件名:");scanf("%s",fname);fin=fopen(fname,"r");//以只读方式打开pl0源程序文件cifa=fopen("词法分析结果.txt","w");fa1=fopen("源程序和地址.txt","w");//输出源文件及各行对应的首地址fprintf(fa1,"输入pl0源程序文件名:");fprintf(fa1,"%s\n",fname);if(fin){printf("是否将虚拟机代码写入文件?(Y/N)");//是否输出虚拟机代码scanf("%s",fname);listswitch=(fname[0]=='y'||fname[0]=='Y');printf("是否将符号表写入文件?(Y/N)");//是否输出符号表scanf("%s",fname);tableswitch=(fname[0]=='y'||fname[0]=='Y');init();//初始化err=0;cc=cx=ll=0;ch=' ';if(-1!=getsym()){fa=fopen("虚拟代码.txt","w");fas=fopen("符号表.txt","w");addset(nxtlev,declbegsys,statbegsys,symnum);nxtlev[period]=true;if(-1==block(0,0,nxtlev)){//调用编译程序fclose(fa);fclose(fa1);fclose(fas);fclose(fin);return 0;}if(sym!=period){error(9);//结尾丢失了句号}if(err!=0){printf("pl0源程序出现错误,退出编译!!!请从第一个错误处开始修改.\n\n");fprintf(cifa,"源程序出现错误,请检查!!!");fprintf(fa1,"源程序出现错误,请检查!!!");fprintf(fa,"源程序出现错误,请检查!!!");fprintf(fas,"源程序出现错误,请检查!!!");}fclose(fa);fclose(fa1);fclose(fas);}fclose(fin);}else{printf("Can't open file!\n");}fclose(cifa);//printf("\n");return 0;}void init(){//初始化int i;for(i=0;i<=255;i++)ssym[i]=nul;//设置单字符符号ssym['+']=plus;ssym['-']=minus;ssym['*']=times;ssym['/']=slash;ssym['(']=lparen;ssym[')']=rparen;ssym['=']=eql;ssym[',']=comma;ssym['.']=period;ssym['#']=neq;ssym[';']=semicolon;strcpy(&(word[0][0]),"begin");//保留字设置,以字母顺序排列便于折半查找strcpy(&(word[1][0]),"call");strcpy(&(word[2][0]),"const");strcpy(&(word[3][0]),"do");strcpy(&(word[4][0]),"end");strcpy(&(word[5][0]),"if");strcpy(&(word[6][0]),"odd");strcpy(&(word[7][0]),"procedure");strcpy(&(word[8][0]),"read");strcpy(&(word[9][0]),"then");strcpy(&(word[10][0]),"var");strcpy(&(word[11][0]),"while");strcpy(&(word[12][0]),"write");wsym[0]=beginsym;//设置保留字类别一字即一类wsym[1]=callsym;wsym[2]=constsym;wsym[3]=dosym;wsym[4]=endsym;wsym[5]=ifsym;wsym[6]=oddsym;wsym[7]=procsym;wsym[8]=readsym;wsym[9]=thensym;wsym[10]=varsym;wsym[11]=whilesym;wsym[12]=writesym;strcpy(&(mnemonic[lit][0]),"lit");//设置指令名称strcpy(&(mnemonic[opr][0]),"opr");strcpy(&(mnemonic[lod][0]),"lod");strcpy(&(mnemonic[sto][0]),"sto");strcpy(&(mnemonic[cal][0]),"cal");strcpy(&(mnemonic[inte][0]),"int");strcpy(&(mnemonic[jmp][0]),"jmp");strcpy(&(mnemonic[jpc][0]),"jpc");for(i=0;i<symnum;i++){//设置符号集declbegsys[i]=false;statbegsys[i]=false;facbegsys[i]=false;}declbegsys[constsym]=true;//设置声明开始符号集declbegsys[varsym]=true;declbegsys[procsym]=true;statbegsys[beginsym]=true;//设置语句开始符号集statbegsys[callsym]=true;statbegsys[ifsym]=true;statbegsys[whilesym]=true;facbegsys[ident]=true;//设置因子开始符号集facbegsys[number]=true;facbegsys[lparen]=true;}//用数组实现集合的集合运算int inset(int e,bool* s){return s[e];}int addset(bool*sr,bool* s1,bool* s2,int n){int i;for(i=0;i<n;i++)sr[i]=s1[i]||s2[i];return 0;}void error(int n){//出错处理,打印出错位置和错误编码char space[81];memset(space, 32,81);space[cc-1]=0;printf("error(%d)",n);fprintf(fa1,"error(%d)",n);switch(n){case 1:printf("\t\t常量说明中的“=”写成“:=”\n");fprintf(fa1,"\t\t常量说明中的“=”写成“:=”\n");break;case 2:printf("\t\t常量说明中的=后应该是数字\n");fprintf(fa1,"\t\t常量说明中的=后应该是数字\n");break;case 3:printf("\t\t常量说明符中的表示符应该是=\n" );fprintf(fa1,"\t\t常量说明符中的表示符应该是=\n");break;case 4:printf("\t\tconst,var,procedure后应为标识符\n" );fprintf(fa1,"\t\tconst,var,procedure后应为标识符\n");break;case 5:printf("\t\t漏掉了“,”或“;”\n" );fprintf(fa1,"\t\t漏掉了“,”或“;”\n" );break;case 6:printf("\t\t过程说明后的符号不正确\n" );fprintf(fa1,"\t\t过程说明后的符号不正确\n");break;case 7:printf("\t\t应是语句开始符\n" );fprintf(fa1,"\t\t应是语句开始符\n" );break;case 8:printf("\t\t程序体语句部分的后跟符不正确\n" );fprintf(fa1,"\t\t程序体语句部分的后跟符不正确\n" );break;case 9:printf("\t\t程序结尾丢了句号“.”\n\n" );fprintf(fa1,"\t\t程序结尾丢了句号“.”\n");break;case 10:printf("\t\t语句之间漏了“;”\n" );fprintf(fa1,"\t\t语句之间漏了“;”\n");break;case 11:printf("\t\t标识符拼写错误或未说明\n" );fprintf(fa1,"\t\t标识符拼写错误或未说明\n");break;case 12:printf("\t\t赋值语句中,赋值号左部标识符属性应是变量\n" );fprintf(fa1,"\t\t赋值语句中,赋值号左部标识符属性应是变量\n");break;case 13:printf("\t\t赋值语句左部标识符后应是复制号“:=”\n" );fprintf(fa1,"\t\t赋值语句左部标识符后应是复制号“:=”\n");break;case 14:printf("\t\tcall后应为标识符\n" );fprintf(fa1,"\t\tcall后应为标识符\n");break;case 15:printf("\t\tcall后标识符属性应为过程\n" );fprintf(fa1,"\t\tcall后标识符属性应为过程\n");break;case 16:printf("\t\t条件语句中丢了then\n" );fprintf(fa1,"\t\t条件语句中丢了then\n");break;case 17:printf("\t\t丢了“end”或“;”\n" );fprintf(fa1,"\t\t丢了“end”或“;”\n");break;case 18:printf("\t\twhile型循环语句中丢了“do”\n" );fprintf(fa1,"\t\twhile型循环语句中丢了“do”\n");break;case 19:printf("\t\t语句后的符号不正确\n" );fprintf(fa1,"\t\t语句后的符号不正确\n" );break;case 20:printf("\t\t应为关系运算符\n" );fprintf(fa1,"\t\t应为关系运算符\n");break;case 21:printf("\t\t表达式标示符属性不能是过程\n" );fprintf(fa1,"\t\t表达式标示符属性不能是过程\n");break;case 22:printf("\t\t表达式漏掉了右括号\n" );fprintf(fa1,"\t\t表达式漏掉了右括号\n");break;case 23:printf("\t\t因子后的非法符号\n" );fprintf(fa1,"\t\t因子后的非法符号\n");break;case 24:printf("\t\t表达式的开始符不能是此符号\n" );fprintf(fa1,"\t\t表达式的开始符不能是此符号\n");break;case 25:printf("\t\t标识符越界\n" );fprintf(fa1,"\t\t标识符越界\n");break;case 26:printf("\t\t非法字符\n" );fprintf(fa1,"\t\t非法字符\n");break;case 31:printf("\t\t数越界\n");fprintf(fa1,"\t\t数越界\n");break;case 32:printf("\t\tread语句括号中的标识符不是变量\n" );fprintf(fa1,"\t\tread语句括号中的标识符不是变量\n");break;case 33:printf("\t\twrite()或read()中应为完整表达式\n" );fprintf(fa1,"\t\twrite()或read()中应为完整表达式\n");break;default:printf("\t\t出现未知错误\n" );fprintf(fa1,"\t\t出现未知错误\n");}err++;}//漏掉空格,读取一个字符,每次读一行,存入line缓冲区,line被getsym取空后再读一//行,被函数getsym调用int getch(){if(cc==ll){if(feof(fin)){printf("program incomplete");return-1;}ll=0;cc=0;printf("\n%d ",cx);fprintf(fa1,"\n%d ",cx);ch=' ';while(ch!=10){if(EOF==fscanf(fin,"%c",&ch)){line[ll]=0;break;}printf("%c",ch);fprintf(fa1,"%c",ch);line[ll]=ch;ll++;}fprintf(cifa,"\n");}ch=line[cc];cc++;return 0;}int getsym(){//词法分析int i,j,k,l;while(ch==' '||ch==10||ch==9)//忽略空格换行 TABgetchdo;if(ch>='a'&&ch<='z'){//以字母开头的为保留字或者标识符k=0,l=1;do{if(k<al){//al为标识符或保留字最大长度a[k]=ch;k++;}if(k==al&&l==1){error(25);l=0;}getchdo;}while(ch>='a'&&ch<='z'||ch>='0'&&ch<='9');a[k]=0;//末尾存零strcpy(id,a);i=0;j=norw-1;do{//开始折半查找k=(i+j)/2;if(strcmp(id,word[k])<=0){j=k-1;}if(strcmp(id,word[k])>=0){i=k+1;}}while(i<=j);if(i-1>j){//找到即为保留字sym=wsym[k];fprintf(cifa,"%s\t\t%ssym\n",id,id);//printf("%s\t\t%ssym\n",id,id);}else{//否则为标识符或数字sym=ident;fprintf(cifa,"%s\t\tident\n",id);//printf("%s\t\tident\n",id);}}else {if(ch>='0'&&ch<='9'){k=0;num=0;sym=number;do{num=10*num+ch-'0';//数字的数位处理k++;getchdo;}while(ch>='0'&&ch<='9');k--;if(k>nmax){//数字的长度限制fprintf(cifa,"0\t\tnumber\n");num=0;error(31);}elsefprintf(cifa,"%d\t\tnumber\n",num);//printf("%d\t\tnumber\n",num);}else{if(ch==':'){//检测赋值符号,:只能和=匹配,否则不能识别getchdo;if(ch=='='){sym=becomes;fprintf(cifa,":=\t\tbecomes\n");getchdo;}else{sym=nul;}}else{if(ch=='<'){getchdo;if(ch=='='){sym=leq;//小于等于fprintf(cifa,"<=\t\tleq\n");getchdo;}else{sym=lss;//小于fprintf(cifa,"<\t\tlss\n");}}else{if(ch=='>'){getchdo;if(ch=='='){sym=geq;//大于等于fprintf(cifa,">=\t\tgeq\n");getchdo;}else{sym=gtr;//大于fprintf(cifa,">\t\tgtr\n");}}else{sym=ssym[ch];//不满足上述条件时按单字//符处理switch(ch){case'+':fprintf(cifa,"%c\t\tplus\n",ch);break;case '-':fprintf(cifa,"%c\t\tminus\n",ch );break;case '*':fprintf(cifa,"%c\t\ttimes\n",ch);break;case '/':fprintf(cifa,"%c\t\tslash\n",ch);break;case '(':fprintf(cifa,"%c\t\tlparen\n",ch);break;case ')':fprintf(cifa,"%c\t\trparen\n",ch);break;case '=':fprintf(cifa,"%c\t\teql\n",ch);break;case ',':fprintf(cifa,"%c\t\tcomma\n",ch);break;case '#':fprintf(cifa,"%c\t\tneq\n",ch);break;case ';':fprintf(cifa,"%c\t\tsemicolon\n",ch);break;case '.':break;default :error(26);}if(sym!=period){//判断是否结束getchdo;}else{printf("\n");fprintf(cifa,".\t\tperiod\n");}}}}}}return 0;}//生成目标代码//目标代码的功能码,层差和位移量int gen(enum fct x,int y,int z){if(cx>=cxmax){//如果目标代码索引过大,报错printf("Program too long");return -1;}code[cx].f=x;code[cx].l=y;code[cx].a=z;cx++;return 0;}//测试字符串int test(bool* s1,bool* s2,int n){if(!inset(sym,s1)){//测试sym是否属于s1,不属于则报错nerror(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;//保留初始txint cx0;//保留初始cxbool nxtlev[symnum];dx=3;//相对地址从3开始,前3个单元即0、1、2单元分别为 SL:静态链;//DL:动态链;RA:返回地址tx0=tx;//记录本层的初始位置table[tx].adr=cx;gendo(jmp,0,0);if(lev>levmax){//层数超过3error(32);}do{if(sym==constsym){//收到常量声明printf("该语句为常量定义语句\n");getsymdo;do{constdeclarationdo(&tx,lev,&dx);//常量声明处理,dx 会改//变所以使用指针while(sym==comma){//处理一次多常量定义getsymdo;constdeclarationdo(&tx,lev,&dx);}if(sym==semicolon){//常量声明处理结束getsymdo;}else{error(5);//漏掉了逗号或者分号(一般是分号)}}while(sym==ident);}if(sym==varsym){//收到变量声明printf("该语句为变量声明语句\n");getsymdo;do{vardeclarationdo(&tx,lev,&dx);//变量声明处理while(sym==comma){//处理一次多变量定义getsymdo;vardeclarationdo(&tx,lev,&dx);}if(sym==semicolon){//变量声明处理结束getsymdo;}else{error(5);//漏掉逗号或者分号}}while(sym==ident);}while(sym==procsym){//收到过程声明printf("该语句为过程声明语句\n");getsymdo;if(sym==ident){enter(procedur,&tx,lev,&dx);//记录过程名getsymdo;}else{error(4);//过程声明后应为标识符}if(sym==semicolon){getsymdo;}else{error(5);//漏掉了分号}memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[semicolon]=true;if(-1==block(lev+1,tx,nxtlev)){return -1;}if(sym==semicolon){getsymdo;memcpy(nxtlev,statbegsys,sizeof(bool)*symnum);nxtlev[ident]=true;nxtlev[procsym]=true;testdo(nxtlev,fsys,6);}else{error(5);}}memcpy(nxtlev,statbegsys,sizeof(bool)*symnum);nxtlev[ident]=true;nxtlev[period]=true;testdo(nxtlev,declbegsys,7);}while(inset(sym,declbegsys));//直到没有声明符号code[table[tx0].adr].a=cx;//开始生成当前过程代码table[tx0].adr=cx;//当前过程代码地址table[tx0].size=dx;cx0=cx;gendo(inte,0,dx);//生成分配存代码if(tableswitch){//输出符号表if(tx0+1<tx){fprintf(fas,"TABLE:\n");//printf("NULL\n");}for(i=tx0+1;i<=tx;i++){switch(table[i].kind){case constant:fprintf(fas,"%d const %s ",i,table[i].name);fprintf(fas,"val=%d\n",table[i].val);break;case variable:fprintf(fas,"%d var %s ",i,table[i].name);fprintf(fas,"lev=%daddr=%d\n",table[i].level,table[i].adr);break;case procedur:fprintf(fas,"%d proc %s ",i,table[i].name);fprintf(fas,"lev=%daddr=%dsize=%d\n", table[i].level,table[i].adr,table[i].size);break;}}}memcpy(nxtlev,fsys,sizeof(bool)*symnum);//每个后跟符号集和都包含上层后跟符//号集和,以便补救nxtlev[semicolon]=true;nxtlev[endsym]=true;statementdo(nxtlev,&tx,lev);gendo(opr,0,0);//每个过程出口都要使用的释放数据指令memset(nxtlev,0,sizeof(bool)*symnum);//分程序没有补救集合testdo(fsys,nxtlev,8);//检测后跟符号集的正确性listcode(cx0);//输出代码return 0;}//k:const var procedure//ptx:符号表尾的指针//pdx:dx为当前应分配变量的相对地址//lev:符号名字所在的层次//往符号表中添加void enter(enum object k,int* ptx,int lev,int* pdx){(* ptx)++;strcpy(table[(*ptx)].name,id);table[(* ptx)].kind=k;switch(k){case constant:if(num>amax){error(31);num=0;}table[(*ptx)].val=num;break;case variable:table[(*ptx)].level=lev;table[(*ptx)].adr=(*pdx);(*pdx)++;break;case procedur:table[(*ptx)].level=lev;break;}}//寻找符号在符号表中的地址int position(char*idt,int tx){int i;strcpy(table[0].name,idt);i=tx;//符号表尾while(strcmp(table[i].name,idt)!=0){i--;}return i;}//常量声明处理int constdeclaration(int* ptx,int lev,int* pdx){if(sym==ident){getsymdo;if(sym==eql||sym==becomes){if(sym==becomes){error(1);}getsymdo;if(sym==number){enter(constant,ptx,lev,pdx);getsymdo;}else{error(2);}}else{error(3);}}else{error(4);}return 0;}//变量声明处理int vardeclaration (int* ptx,int lev,int* pdx){if(sym==ident){enter(variable,ptx,lev,pdx);getsymdo;}else{error(4);}return 0;}//输出目标代码清单void listcode(int cx0){int i;if(listswitch){for(i=cx0;i<cx;i++){fprintf(fa,"%d %s %d %d\n",i,mnemonic[code[i].f],code[i].l,code[i],a);}}}//语句处理int statement(bool* fsys,int* ptx,int lev){int i,cx1,cx2;bool nxtlev[symnum];if(sym==ident){i=position(id,*ptx);if(i==0){error(11);}else{if(table[i].kind!=variable){error(12);i=0;}else{getsymdo;if(sym==becomes){getsymdo;printf("该语句为赋值语句。

PL0语言编译程序C++面向对象实现

PL0语言编译程序C++面向对象实现

PL0语言编译程序C++面向对象实现类关系:源码:头文件Lexa.h(词法分析)#ifndef LEXA_H#define LEXA_H#include <fstream>#include "sysdef.h"#include <iostream>using namespace std;// 词法符号struct Symbol{int kind;int value;char str[20];};// 词法分析const int BufferSize = 160; // 双缓冲,每一个大小为80 class Buffer{public:Buffer();void putback();bool Getch(char&);void init();private:ifstream in;char data[BufferSize];int curPos;bool last;// 是否是最后一次缓冲int lastIndex;friend class LexA;};class LexA{public:LexA(char* filename = NULL);bool Open(char* filename);bool GetSym();inline bool IsSpace(char);inline bool IsNumber(char);inline bool IsChar(char);inline bool IsOperator(char);inline bool IsSeparator(char);/*debuginline int GetType(){return V alue.kind;}inline int GetV alue(){return V alue.value;}*/private:Symbol V alue;Buffer buf;friend class SynA;};bool LexA::IsChar(char ch){return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); }bool LexA::IsNumber(char ch){return (ch >= '0' && ch <= '9');}bool LexA::IsOperator(char ch){return (ch =='+' || ch == '-' || ch == '*' || ch == '/'|| ch == '>' || ch == '<' || ch == '=' || ch == '#' || ch == ':'); }bool LexA::IsSeparator(char ch){return (ch == '.' || ch == ',' || ch == ';' || ch == '(' || ch == ')'); }bool LexA::IsSpace(char ch){return (ch == ' ' || ch == '\t' || ch == '\n');}#endifSyna.h(语法分析)#ifndef SYNA_H#define SYNA_H#include "sysdef.h"#include "lexa.h"// 错误处理类struct ErrorItem{int id;int hang;int lie;};const int MaxErrorNum = 100;class Error{public:Error(){ErrorNum = 0;}int Add(int id, int hang, int lie = 0){if(ErrorNum < MaxErrorNum){error[ErrorNum].id = id;error[ErrorNum].hang = hang;error[ErrorNum++].lie = lie;}else return -1;return 1;}void OutPut(){for(int i = 0; i <= ErrorNum-1; i++)cout << error[i].id << endl;}private:ErrorItem error[MaxErrorNum];int ErrorNum;// 语法分析需要处理错误,表项管理把错误编号返回friend class SynA;};const int MAXNAMELEN = 30;struct tableItem{char name[MAXNAMELEN];int kind;int value_lev;int adr;int size;};const int TableSize = 100;class Table{public:Table():tx(0), lev(0){}int enter(tableItem&);int find(Symbol& sym, int& result);int ChangeLev(int dir);void List(){cout << "变量名\t类型\t值或者层\t地址" << endl;for(int i = 0; i <= tx-1; i++){cout << data[i].name << '\t';if(data[i].kind == V ARIABLE){cout << "variable" << '\t' << data[i].value_lev << '\t' <<data[i].adr;}else if(data[i].kind == CONSTANT){cout << "constant" << '\t' << data[i].value_lev;}else{cout << "procedure" << '\t' << data[i].value_lev << '\t' << data[i].adr;}cout << endl;}}private:tableItem data[TableSize];// tx为即将填入的地方int tx, lev;friend class SynA;};// 语法分析struct Code{int fun;int lev;int a;};struct Buff{Buff(){full = false;};bool full;Symbol sym;};const char FUN[8][4] = {"LIT", "LOD", "STO", "CAL", "INT", "JMP", "JPC", "OPR"};class SynA{public:SynA(char* filename);bool GetSym(Symbol& sym);int block();int program(int& start);int constProcess();int varProcess();int procedureProcess();int Statement();int Condition();int Expression();int Item();int Factor();void ListCode(){for(int i = 0; i <= cx-1; i++){cout << i << '\t' << FUN[code[i].fun-60] << ' ' << code[i].lev << ' ' << code[i].a <<endl;}}void ListError(){err.OutPut();}void ListTable(){table.List();}private:LexA lex;int cx, dx; //当前代码行数Table table;tableItem tbItem;Code code[100];Error err;Buff buf;};#endifCpp文件lexa.cpp#include "lexa.h"// 关键字表const int KeyWordNum = 13;struct KeyWord{char name[10];int ID;};KeyWord KeyWordTable[KeyWordNum] = {{"const", CONST}, {"var", V AR}, {"procedure", PROCEDURE}, {"call", CALL}, {"begin", BEGIN}, {"end", END},{"if", IF}, {"then", THEN}, {"while", WHILE},{"do", DO}, {"read", READ}, {"write", WRITE},{"odd", ODD}};// 运算符表const int OperatorNum = 11;struct Operator{char name[3];int ID;};Operator OperatorTable[OperatorNum]= {{"+", PLUS}, {"-", MINUS}, {"*", TIME}, {"/", DEVIDE},{">", GREA TER}, {"<", SMALLER}, {"=", EQUAL}, {"#", UNEQUAL}, {">=", GE}, {"<=", SE}, {":=", EQUAL1}};//分隔符表const int SeparatorNum = 5;struct Separator{char name;int ID;};Separator SeparatorTable[SeparatorNum] = {{'.', PERIOD}, {',', COMMA}, {';', SEMICOLON},{'(', LPARENTHESIS}, {')', RPARENTHESIS}};Buffer::Buffer(){last = false;}// 遇到文件尾,返回falsebool Buffer::Getch(char& ch){if(last){if(curPos == lastIndex) return false;ch = data[curPos++];curPos %= BufferSize;return true;}if(BufferSize/2+1 == curPos && !last){if(!in.read(data, BufferSize/2)){lastIndex = in.gcount();last = true;}}if(curPos == 1 && !last){if(!in.read(data+BufferSize/2, BufferSize/2)){lastIndex = in.gcount()+BufferSize/2;last = true;}}ch = data[curPos++];curPos %= BufferSize;return true;}void Buffer::putback(){if(curPos == 0) curPos = BufferSize-1;else{curPos -= 1;curPos %= BufferSize;}}void Buffer::init(){if(!in.read(data, BufferSize/2)){last = true;lastIndex = in.gcount();}curPos = 0;}LexA::LexA(char* filename){if(filename){buf.in.open(filename);if(buf.in.fail()){cout << "Can't open file:" << filename << endl;return;}buf.init();}}bool LexA::Open(char* filename){buf.in.open(filename);if(buf.in.fail()){cout << "Can't open file:" << filename << endl;return false;}buf.init();return true;}bool LexA::GetSym(){char ch;do{if(!buf.Getch(ch)) return false;}while(IsSpace(ch));if(IsNumber(ch)){int temp = ch-'0';do{if(buf.Getch(ch)){if(IsNumber(ch)){temp *= 10;temp += ch-'0';}else{buf.putback();break;}}else break;}while(!IsSpace(ch));V alue.kind = NUMBER;V alue.value = temp;return true;}if(IsChar(ch)){int i = 0;V alue.str[i] = ch;do{i++;if(buf.Getch(ch)){if(IsChar(ch) || IsNumber(ch)){V alue.str[i] = ch;}else if(IsSpace(ch)) break;else{buf.putback();break;}}else{break;}}while(1);V alue.str[i] = 0;for(i = 0; i <= KeyWordNum-1; i++){if(strcmp(V alue.str, KeyWordTable[i].name) == 0){ V alue.kind = KEYWORD;V alue.value = KeyWordTable[i].ID;return true;}}V alue.kind = IDENTSYM;return true;}if(IsOperator(ch)){char temp[3];temp[0] = ch;temp[1] = 0;buf.Getch(ch);if(!IsOperator(ch)) buf.putback();else if(ch == '='){if(temp[0] == '<' || temp[0] == '>' || temp[0] == ':'){temp[1] = '=';temp[2] = 0;}}else buf.putback();for(int i = 0; i <= OperatorNum-1; i++){if(strcmp(temp, OperatorTable[i].name) == 0){V alue.kind = OPERA TORSYM;V alue.value = OperatorTable[i].ID;return true;}}}if(IsSeparator(ch)){for(int i = 0; i <= SeparatorNum-1; i++){if(ch == SeparatorTable[i].name){V alue.kind = SEPARA TORSYM;V alue.value = SeparatorTable[i].ID;return true;}}}return false;}Syna.cpp#include "lexa.h"#include "syna.h"// table成员函数的实现// 返回错误号,1表示成功int Table::enter(tableItem& item){if(tx+1 == TableSize){return UNKNOWERROR;}data[tx].adr = item.adr;data[tx].kind = item.kind;strcpy(data[tx].name, );data[tx].size = item.size;data[tx++].value_lev = item.value_lev;return 1;}// 找到sym后返回1,result为data中序号int Table::find(Symbol& sym, int& result){for(int i = tx-1; i >= 0; i--){if(sym.kind == NUMBER){if(sym.value == data[i].value_lev){result = i;return 1;}}else if(sym.kind == IDENTSYM){if(strcmp(sym.str, data[i].name) == 0){result = i;return 1;}}else{return UNKNOWERROR;}}return 1;}int Table::ChangeLev(int dir){if(dir == -1) lev --;else lev ++;if(lev < 0){return UNKNOWERROR;}if(lev > 3){return UNKNOWERROR;}return 1;}// 语法分析类的实现SynA::SynA(char* filename){if(!lex.Open(filename)) exit(1);cx = 1;dx = 3;}bool SynA::GetSym(Symbol& sym){if(buf.full){sym = buf.sym;buf.full = false;return true;}if(!lex.GetSym()){err.Add(UNKNOWERROR, 0, 0);return false;};sym = lex.V alue;return true;}int SynA::block(){Symbol sym;int start;if(program(start) != 1) return -1;if(!GetSym(sym)) return -1;if(sym.value != PERIOD) return -1;if(GetSym(sym)){// 不明文件尾err.Add(UNKNOWERROR, 0, 0);return -1;}return 1;}int SynA::program(int& start){Symbol sym;if(!GetSym(sym)) return -1;if(sym.value == CONST){if(constProcess() != 1) return -1;if(!GetSym(sym)) return -1;}if(lex.V alue.value == V AR){if(varProcess() != 1) return -1;if(!GetSym(sym)) return -1;}if(lex.V alue.value == PROCEDURE){ int temp = dx;dx = 3;table.ChangeLev(1);if(procedureProcess() != 1) return -1;table.ChangeLev(-1);dx = temp;}else{buf.full = true;buf.sym = sym;}if(table.lev == 0){code[0].fun = JMP;code[0].lev = 0;code[0].a = cx;}start = cx;int var_num = cx++;//int指令将要写入的位置int var_num_lev = table.lev;do{int tttemp = Statement();if(tttemp == 0) break;else if(tttemp != 1) return -1;else{}Symbol sym1;if(table.lev != 0){if(!GetSym(sym1)) return -1;if(sym1.value == SEMICOLON){break;}else{buf.full = true;buf.sym = sym1;}}}while(1);code[cx].fun = OPR;code[cx].lev = 0;code[cx++].a = 0;int temp_lev = table.data[table.tx-1].value_lev, num = 0; for(int i = table.tx-1; i >= 0; i--){if(temp_lev == table.data[i].value_lev) num ++;else break;}if(var_num_lev == table.lev){code[var_num].fun = INT;code[var_num].lev = 0;code[var_num].a = num;}return 1;}int SynA::constProcess(){Symbol sym;tbItem.kind = CONSTANT;do{if(!GetSym(sym)) return -1;if(sym.kind == IDENTSYM){strcpy(, sym.str);if(!GetSym(sym)) return -1;if(sym.value == EQUAL){if(!GetSym(sym)) return -1;if(sym.kind == NUMBER) tbItem.value_lev = sym.value;table.enter(tbItem);}else if(sym.value == EQUAL1){err.Add(UNKNOWERROR, 0, 0);return -1;}else{err.Add(UNKNOWERROR, 0, 0);return -1;}}else{err.Add(UNKNOWERROR, 0, 0);return -1;}if(!GetSym(sym)) return -1;}while(sym.value == COMMA);if(sym.value != SEMICOLON){err.Add(UNKNOWERROR, 0, 0);return -1;}return 1;}int SynA::varProcess(){Symbol sym;tbItem.kind = V ARIABLE;do{if(!GetSym(sym)) return -1;if(sym.kind == IDENTSYM){tbItem.adr = dx++;tbItem.value_lev = table.lev;strcpy(, sym.str);table.enter(tbItem);// 重名错误}else{err.Add(UNKNOWERROR, 0, 0);return -1;}if(!GetSym(sym)) return -1;}while(sym.value == COMMA);if(sym.value != SEMICOLON){err.Add(UNKNOWERROR, 0, 0);return -1;};return 1;}int SynA::procedureProcess(){Symbol sym;tbItem.kind = PROCEDURE;if(!GetSym(sym)) return -1;if(sym.kind == IDENTSYM){strcpy(, sym.str);tbItem.adr = cx;table.enter(tbItem);int temp = cx++;if(!GetSym(sym)) return -1;if(sym.value != SEMICOLON){err.Add(UNKNOWERROR, 0, 0);return -1;}int start;if(program(start) != 1) return -1;code[temp].fun = JMP;code[temp].lev = 0;code[temp].a = start;}else{err.Add(UNKNOWERROR, 0, 0);return -1;}return 1;}int SynA::Statement(){int result, temp, temp1;Symbol sym;if(!GetSym(sym)) return -1;if(sym.kind == IDENTSYM){if(!table.find(sym, result)) return false;if(table.data[result].kind != V ARIABLE) return -1;if(!GetSym(sym)) return -1;if(sym.value == EQUAL1){if(Expression() != 1) return -1;code[cx].fun = STO;code[cx].lev = table.lev-table.data[result].value_lev;code[cx++].a = table.data[result].adr;}else return -1;return 1;}switch(sym.value){case CALL:if(!GetSym(sym)) return -1;if(sym.kind == IDENTSYM){if(!table.find(sym, result)) return -1;if(table.data[result].kind != PROCEDURE) return -1;code[cx].fun = CAL;code[cx].lev = table.lev-table.data[result].value_lev;code[cx++].a = table.data[result].adr;}break;case BEGIN:do{int ttemp = Statement();if(ttemp != 1 && ttemp != 0){return -1;}if(!GetSym(sym)) return -1;if(sym.value == SEMICOLON){continue;}else if(sym.value == END)break;else return -1;}while(1);break;case IF:if(Condition() != 1) return -1;//判断条件是否成立code[cx].fun = JPC;code[cx].lev = 0;temp = cx;cx ++;if(!GetSym(sym)) return -1;if(sym.value != THEN) return -1;if(Statement() != 1) return -1;code[temp].a = cx;break;case WHILE:temp1 = cx;if(Condition() != 1) return -1;code[cx].fun = JPC;code[cx].lev = 0;temp = cx;cx ++;if(!GetSym(sym)) return -1;if(sym.value != DO) return -1;if(Statement() != 1) return -1;code[cx].fun = JMP;code[cx].lev = 0;code[cx++].a = temp1;code[temp].a = cx;break;case READ:if(!GetSym(sym)) return -1;if(sym.value !=LPARENTHESIS) return -1;do{if(!GetSym(sym)) return -1;if(sym.kind == IDENTSYM){if(!table.find(sym, result)) return -1;else{if(table.data[result].kind == V ARIABLE){code[cx].fun = OPR;code[cx].lev = 0;code[cx++].a = 16;code[cx].fun = STO;code[cx].lev = 0;code[cx++].a = table.data[result].adr;}else return -1;}}else return -1;if(!GetSym(sym)) return -1;if(sym.value != COMMA) break;}while(1);if(sym.value != RPARENTHESIS) return -1;break;case WRITE:if(!GetSym(sym)) return -1;if(sym.value !=LPARENTHESIS) return -1;do{if(Expression() != 1) return -1;code[cx].fun = OPR;code[cx].lev = 0;code[cx++].a = 15;if(!GetSym(sym)) return -1;if(sym.value != COMMA) break;}while(1);if(sym.value != RPARENTHESIS) return -1;break;default:// 空语句,返回0buf.full = true;buf.sym = sym;return 0;}return 1;}int SynA::Condition(){Symbol sym;Symbol temp_sym;if(!GetSym(sym)) return -1;if(sym.value == ODD){if(Expression() != 1) return -1;code[cx].fun = OPR;code[cx].lev = 0;code[cx++].a = 6;}else{buf.full = true;buf.sym = sym;if(Expression() != 1) return -1;if(!GetSym(temp_sym)) return -1;if(Expression() != 1) return -1;code[cx].fun = OPR;code[cx].lev = 0;switch(temp_sym.value){case EQUAL:code[cx].a = 8;break;case UNEQUAL:code[cx].a = 9;break;case SMALLER:code[cx].a = 10;break;case SE:code[cx].a = 11;break;case GREA TER:code[cx].a = 12;break;case GE:code[cx].a = 13;break;default:return -1;}cx ++;}return 1;}int SynA::Expression(){Symbol sym;bool Minus = false;if(!GetSym(sym)) return -1;if(sym.value == MINUS){//将-1放到栈顶,并乘法Minus = true;}else{buf.full = true;buf.sym = sym;}bool first = true;int value;do{if(Item() != 1) return -1;if(!first){// 生成加减法指令code[cx].fun = OPR;if(value == PLUS) code[cx].a = 2;else code[cx].a = 3;code[cx++].lev = 0;}first = false;if(!GetSym(sym)) return -1;if(sym.value == PLUS || sym.value == MINUS){ value = sym.value;}else{buf.full = true;buf.sym = sym;break;}}while(1);if(Minus){// 生成乘以-1的指令code[cx].fun = LIT;code[cx].a = -1;code[cx++].lev = 0;code[cx].fun = OPR;code[cx].a = 4;code[cx++].lev = 0;}return 1;}int SynA::Item(){Symbol sym;bool first = true;int value;do{if(Factor() != 1) return -1;if(!first){// 生成乘法或除法指令code[cx].fun = OPR;if(value == TIME) code[cx].a = 4;else code[cx].a = 5;code[cx++].lev = 0;}first = false;if(!GetSym(sym)) return -1;if(sym.value == TIME || sym.value == DEVIDE){value = sym.value;}else{buf.full = true;buf.sym = sym;return 1;}}while(1);}int SynA::Factor(){int result;Symbol sym;if(!GetSym(sym)) return -1;if(sym.kind == IDENTSYM){if(table.find(sym, result) == 1){//取变量到栈顶if(table.data[result].kind == V ARIABLE){code[cx].fun = LOD;code[cx].lev = table.lev-table.data[result].value_lev;code[cx++].a = table.data[result].adr;}else if(table.data[result].kind == CONSTANT){//取常量到栈顶code[cx].fun = LIT;code[cx].lev = 0;code[cx++].a = table.data[result].value_lev;}else{return -1;}}else return -1;}else if(sym.kind == NUMBER){//取数到栈顶code[cx].fun = LIT;code[cx].lev = 0;code[cx++].a = sym.value;}else if(sym.kind == LPARENTHESIS){if(Expression() != 1) return -1;if(!GetSym(sym)) return -1;if(sym.kind != RPARENTHESIS) return -1;}else{// buf.full = true;// buf.sym = sym;return -1; //并非程序错误,返回上一级继续判断}return 1;}T est.cpp#include "lexa.h"#include "syna.h"// 词法分析测试/*int main(){LexA lex("in4.txt");while(lex.GetSym()){}return 0;}*/int main(){SynA syn("in4.txt");if(syn.block() != 1){cout << "Have Error List:" << endl;syn.ListError();}cout << "Table:" << endl;syn.ListTable();cout << endl;cout << "Code:" << endl;syn.ListCode();return 0;}测试数据:const a=10;var b,c;procedure p;beginc:=b+aend;beginread(b);while b#0 dobegincall p;write(2*c);read(b) end;end.以上数据保存在in4.txt中结果:a)一个能正确运行的例子结果完全正确b)源代码存在错误的情况:结尾出现多余代码,输出Error提示指出了源代码有错误,但未明确指出错误位置和类型。

标准实验报告(PL0编译程序)

标准实验报告(PL0编译程序)

[标准实验报告]南昌航空大学实验报告年月日课程名称:编译原理实验名称:扩充的PL/0编译程序班级:姓名:同组人:指导教师评定:签名:一、实验目的进一步熟悉编译程序的整体框架,给出整个编译程序的流程结构,用C 或vc++语言编写程序;并将编制的编译程序进行调试、实现PL/0编译程序。

二、实验要求(1)根据所选的程序设计语言,修改并调试。

(2)举出例子程序,在程序中进行编译。

(3)用此编译程序对有关语句进行编译,并输出目标指令。

(4)书写出合格的实验报告。

三、实验步骤1.输入文件中变量的声明形如:var a,b,c; 以var保留字开始,不同变量以”,”分隔,最后以”;”结束。

2.read语句格式为read(a)或者read(a,b);3.write语句格式为write(a),括号里面没有字符串常量,注意与书后的形如write(‘a=’,a)是不相同的。

4.的声明形如:”procedure proname;”不含参数表。

5.一维数组形如:变量类型array 数组名[数组下标]。

6.条件语句形如:if <条件>then<语句> {;else,语句>}7.扩充的记录型数据类型形如:for 循环语句及带参数的过程。

四、参考源代码#include<stdio.h>/*#include"plo.h"*/#include"string.h"#define stacksize 500typedef enum{false,true}bool;enum object{procedur , constant ,variable};#define norw 13#define txmax 100#define nmax 14#define al 10#define levmax 3#define cxmax 200#define amax 2047#define symnum 32enum symbol{nul, 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, dosym, callsym, constsym,varsym, procsym,};enum fct {lit, opr, lod,sto, cal, inte,jmp, jpc,};#define fctnum 8struct instruction{enum fct f;int l;int a;};FILE* fas;FILE* fa;FILE* fal;FILE* fa2;bool listswitch;bool tableswitch;char ch;enum symbol sym;char id[al+1];int num;int cc,ll;int cx;char line[81];char a [al+1];int num ;int cc,ll;int cx;char line [81];char a [al+1];struct instruction code [cxmax]; char word [norw][al];struct instruction code [cxmax]; char word [norw][al];enum symbol wsym [norw]; enum symbol ssym [256]; char mnemonic [fctnum][5]; bool declbegsys [symnum]; bool statbegsys [symnum]; bool facbegsys [symnum]; bool facstatbegsys[symnum]; struct tablestruct{char name [al];enum object kind ;int val;int level;int adr;int size;};struct tablestruct table [txmax]; FILE * fin;FILE * fout;char fname [al];int err;#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 expressiondo(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==constdeclaration(a,b,c))return -1 #define vardeclarationdo(a,b,c) if(-1==vardeclaration(a,b,c))return -1 void error(int n);int getsym();int getch();void init();int gen(enum fct x,int y,int z);int test(bool *sl,bool *s2,int n);int inset (int e,bool *s);int addset (bool* sr,bool* sl,bool *s2,int n);int subset (bool* sr,bool* sl,bool *s2,int n);int mulset (bool* sr,bool* sl,bool *s2,int n);int block (int lev,int tx,bool* fsys);void interpret();int factor (bool* fays,int * ptx,int lev);int term (bool* fays,int * ptx,int lev);int condition (bool* fays,int * ptx,int lev);int expression (bool* fays,int * ptx,int lev);int statement (bool* fays,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);int main(){bool nxtlev[symnum];printf("input pl/o file?");scanf("%s",fname);fin=fopen(fname,"r");if(fin){printf("list objeck code? (Y/N)");scanf("%s",fname);/*listwitch=(fname[0]=='y'||fname[0]=='Y');*/ printf("list symbol table? (Y/N)");scanf("%s",fname);tableswitch=(fname[0]=='y'||fname[0]=='Y'); fal=fopen("fal.tmp","w");fprintf(fal,"input pl/o file?");fprintf(fal,"%s",fname);init();err=0;cc=cx=ll=0;ch='';if(-1 !=getsym()){ fa=fopen("fa.tmp","w");fas=fopen("fas.tmp","w");addset(nxtlev,declbegsys,statbegsys,symnum); nxtlev[period]=true;if(-1==block(0,0,nxtlev)){fclose(fa);fclose(fal);fclose(fas);fclose(fin);printf("\n");return 0;}fclose(fa);fclose(fal);fclose(fas);if(sym!=period){error(9);}if(err==0){fa2=fopen("fa2.tmp","w");interpret();fclose(fa2);}else{printf("error in pl/o program"); }}fclose(fin);}else{printf("can't open file! \n");}printf("\n");return 0;}/*chushihua*/void init(){ int i;for (i=0;i<=255;i++){ssym[i]=nul;}ssym['+']=plus;ssym['-']=minus;ssym['*']=times;ssym['/']=slash;ssym['(']=lparen;ssym[')']=rparen;ssym['=']=eql;ssym[',']=comma;ssym['.']=period;ssym['#']=neq;ssym[';']=semicolon;strcpy(&(word[0][0]),"begin"); strcpy(&(word[1][0]),"call"); strcpy(&(word[2][0]),"const"); strcpy(&(word[3][0]),"do");strcpy(&(word[4][0]),"end");strcpy(&(word[5][0]),"if");strcpy(&(word[6][0]),"odd"); strcpy(&(word[7][0]),"procedure"); strcpy(&(word[8][0]),"read"); strcpy(&(word[9][0]),"then"); strcpy(&(word[10][0]),"var"); strcpy(&(word[11][0]),"while"); strcpy(&(word[12][0]),"write");wsym[0]=beginsym;wsym[1]=callsym;wsym[2]=constsym;wsym[3]=dosym;wsym[4]=endsym;wsym[5]=ifsym;wsym[6]=oddsym;wsym[7]=procsym;wsym[8]=readsym;wsym[9]=thensym;wsym[10]=varsym;wsym[11]=whilesym;wsym[12]=writesym;strcpy(&(mnemonic[lit][0]),"lit"); strcpy(&(mnemonic[opr][0]),"opr"); strcpy(&(mnemonic[lod][0]),"lod"); strcpy(&(mnemonic[sto][0]),"sto"); strcpy(&(mnemonic[cal][0]),"cal"); strcpy(&(mnemonic[inte][0]),"inte"); strcpy(&(mnemonic[jmp][0]),"jmp"); strcpy(&(mnemonic[jpc][0]),"jpc");for(i=0;i<symnum;i++){declbegsys[i]=false;statbegsys[i]=false;facbegsys[i]=false;}declbegsys[constsym]=true;declbegsys[varsym]=true;declbegsys[procsym]=true;statbegsys[beginsym]=true;statbegsys[callsym]=true;statbegsys[ifsym]=true;statbegsys[whilesym]=true;facstatbegsys[ident]=true; facstatbegsys[number]=true; facstatbegsys[lparen]=true;}int inset(int e,bool*s){return s[e];}int addset(bool* sr,bool * s1,bool* s2,int n) {int i ;for(i=0;i<n;i++){sr[i]=s1[i]||s2[i];}return 0;}int subset(bool* sr,bool * s1,bool* s2,int n) {int i ;for(i=0;i<n;i++){sr[i]=s1[i]&&(!s2[i]);}return 0;}int mulset(bool* sr,bool * s1,bool* s2,int n) {int i ;for(i=0;i<n;i++){sr[i]=s1[i]&&(s2[i]);}return 0;}void error(int n){char space[81];memset(space,32,81);space[cc-1]=0;printf("*****%s!%d\n",space,n);fprintf(fal,"********%s!%d\n",space,n); err++;}int getch(){if(cc==ll){if(feof(fin)){printf("program,incomplete");return -1;}ll=0;cc=0;printf("%d",cx);fprintf(fal,"%d",cx);ch='';while(ch!=10){if(EOF==fscanf(fin,"%c",&ch)){line[ll]=0;break;}printf("%c",ch);fprintf(fal,"%c",ch);line[ll]=ch;++ll;}printf("\n");fprintf(fal,"\n");}ch=line[cc];cc++;return 0;}/*****************************8 */int getsym(){int i,j,k;while (ch==''||ch==10||ch==9){getchdo;}if(ch>='a'&& ch<='z'){k=0;do{if(k<al){a[k]=ch;k++;}getchdo;}while(ch>='a'&& ch<='z'||ch>='0'&& ch<='9');a[k]=0;strcpy(id,a);i=0;j=norw-1 ;do{k=(i+j)/2 ;if(strcmp(id,word[k])<=0) {j=k-1;}if(strcmp(id,word[k])>=0)i=k+1;}while(i<=j);if(i-1>j){sym=wsym[k];}else{sym=ident;}}else{if(ch>='0'&&ch<='9'){k=0;num=0;sym=number;do{num=10*num+ch-'0';k++;getchdo;}while (ch>='0'&&ch<='9');k--;if(k>nmax){error(30);}}else{if(ch==';'){getchdo;if(ch=='='){sym=becomes;getchdo;}else{sym=nul;}}else{if (ch=='<'){getchdo;if(ch=='='){sym=leq;getchdo;}else{sym=lss;}}else{if(ch=='>'){getchdo;if(ch=='='){sym=geq;getchdo;}else{sym=gtr;}}else{sym=ssym[ch];if(sym!=period){getchdo;}}}}}}return 0;}int gen(enum fct x,int y,int z){if(cx>=cxmax){printf("program too ling ");return -1;}code[cx].f=x;code[cx].l=y;code[cx].a=z;cx++;return 0;}int test(bool * s1,bool * s2,int n){if(! inset(sym,s1)){error(n);while((! inset(sym,s1))&&(! inset(sym,s2))) {getsymdo;}}return 0;}int block(int lev,int tx,bool* fsys){int i;int dx;int txo;int cxo;bool nxtlev[symnum];dx=3;txo=tx;table[tx].adr=cx;gendo(jmp,0,0);if(lev>levmax){error(32);}do{if(sym==constsym){getsymdo;do{constdeclarationdo(&tx,lev,&dx);while(sym==comma){getsymdo;constdeclarationdo(&tx,lev,&dx);}if (sym==semicolon) {getsymdo;}else{error(5);}}while(sym==ident);}if(sym==varsym) {getsymdo;do{vardeclarationdo(&tx,lev,&dx); while(sym==comma) {getsymdo; vardeclarationdo(&tx,lev,&dx); }if(sym==semicolon) {getsymdo;}else{error(5);}}while(sym==ident);}while(sym==procsym) {getsymdo;if(sym==ident){enter(procedur,&tx,lev,&dx); getsymdo;}else{error(4);}if(sym==semicolon) {getsymdo;}else{error(5);}memcpy(nxtlev,fsys,sizeof(bool)*symnum); nxtlev[semicolon]=true;if(-1==block(lev+1,tx,nxtlev)){return -1;}if(sym==semicolon){getsymdo;memcpy(nxtlev,statbegsys,sizeof(bool) * symnum); nxtlev[ident]=true;nxtlev[procsym]=true;testdo(nxtlev,fsys,6);}else{error(5);}}memcpy(nxtlev,statbegsys,sizeof(bool) * symnum); nxtlev[ident]=true;nxtlev[period]=true;testdo(nxtlev,declbegsys,7);}while(inset(sym,declbegsys));code[table[txo].adr].a=cx;table[txo].adr=cx;table[txo].size=dx;cxo=cx;gendo(inte,0,dx);if(tableswitch){printf("TABLE:\n");if(txo+1>tx){printf("NULL\n");}for(i=txo+1;i<=tx;i++){switch(table[i].kind){case constant:printf("%d const %s",i,table[i].name);printf("val=%d\n",table[i].val);fprintf(fas,"%d const %s",i,table[i].name);fprintf(fas,"val=%d\n",table[i].val);break;case variable:printf("%d var %s",i,table[i].name);printf("lev=%d addr=%d\n",table[i].level,table[i].adr);fprintf(fas,"%d var %s",i,table[i].name);fprintf(fas,"lev=%d addr=%d\n",table[i].level,table[i].adr);break;case procedur:printf("%d proc %s",i,table[i].name);printf("lev=%d addr=%d size=%d\n",table[i].level,table[i].adr,table[i].size); fprintf(fas,"%d proc %s",i,table[i].name);fprintf(fas,"lev=%d addr=%d size=%d\n",table[i].level,table[i].adr,table[i].size); break;}}printf("\n");}memcpy(nxtlev,fsys,sizeof(bool) * symnum);nxtlev[semicolon]=true;nxtlev[endsym]=true;statementdo(nxtlev,&tx,lev);gendo(opr,0,0);memset(nxtlev,0,sizeof(bool) * symnum);testdo(fsys,nxtlev,8);listcode(cxo);return 0;}void enter(enum object k , int * ptx , int lev , int * pdx){(*ptx)++;strcpy(table[(*ptx)].name,id);table[(*ptx)].kind=k;switch(k){case constant:if(num>amax){error(31);num=0;}table[(*ptx)].val=num;break;case variable:table[(*ptx)].level=lev;table[(*ptx)].adr=(*pdx);(*pdx)++;break;case procedur:table[(*ptx)].level=lev;break;}}int position(char*idt,int tx){int i;strcpy(table[0].name,idt);i=tx;while(strcmp(table[i].name,idt)!=0){i--;}return i;}int constdecalration(int *ptx,int lev,int *pdx) {if(sym==ident){getsymdo;if(sym==eql||sym==becomes){if(sym==becomes)error(1);getsymdo;if(sym==number){enter(constant,ptx,lev,pdx);getsymdo;}else{error(2);}}else{error(3);}}else{error(4);}return 0;}int constdeclaration(int * ptx,int lev,int * pdx){if (sym==ident){getsymdo;if (sym==eql||sym==becomes){if (sym==becomes){error(1);}getsymdo;if (sym ==number){enter(constant,ptx,lev,pdx);getsymdo;}else{error(2);}}else{error(3);}}else{error(4);}return 0;}int vardeclaration(int* ptx,int lev,int* pdx){if (sym==ident){enter(variable,ptx,lev,pdx);getsymdo;}else{error(4);}return 0;}void listcode(int cx0){int i;if (listswitch){for (i=cx0;i<cx;i++){printf("%d %d %d %d\n",i,mnemonic[code[i].f],code[i].l,code[i].a);fprintf(fa,"%d %s %d %d\n",i,mnemonic[code[i].f],code[i].l,code[i].a);}}}int statement(bool* fsys,int* ptx,int lev){int i,cxl,cx2;bool nxtlev[symnum];if (sym==ident){i=position(id,*ptx);if (i==0){error(11);}else{if(table[i].kind !=variable){error(12);i=0;}else{getsymdo;if(sym==becomes){getsymdo;}else{error(13);}memcpy(nxtlev,fsys,sizeof(bool)*symnum);expressiondo(nxtlev,ptx,lev);if(i!=0){gendo(sto,lev-table[i].level,table[i].adr);}}}/*if(i==0)*/}else{if(sym==readsym){getsymdo;if(sym!=lparen){error(34);}else{do{getsymdo;if(sym==ident){i=position(id,*ptx);}else{i=0;}if(i==0){error(35);}else{gendo(opr,0,16);gendo(sto,lev-table[i].level,table[i].adr) ;}getsymdo;}while(sym==comma);}if(sym!=rparen){error(33);while(! inset(sym,fsys)){getsymdo;}}else{getsymdo;}}else{if(sym==writesym){getsymdo;if(sym==lparen){do{getsymdo; memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[rparen]=true;nxtlev[comma]=true;expressiondo(nxtlev,ptx,lev);gendo(opr,0,14);}while(sym==comma);if(sym!=rparen){error(33);}else{getsymdo;}}gendo(opr,0,15);}else{if(sym==callsym){getsymdo;if(sym!=ident){error(14);}else{i=position(id,*ptx);if(i==0){error(11);}else{if(table[i].kind==procedur){gendo(cal,lev-table[i].level,table[i].adr);}else{error(15);}}getsymdo;}}else{if(sym==ifsym){getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[thensym]=true;nxtlev[dosym]=true;conditiondo(nxtlev,ptx,lev);if(sym==thensym){getsymdo;}else{error(16);}cxl=cx;gendo(jpc,0,0);statementdo(fsys,ptx,lev);code[cxl].a=cx;}else{if(sym==beginsym){getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[semicolon]=true;nxtlev[endsym]=true;statementdo(nxtlev,ptx,lev);while(inset(sym,statbegsys)||sym==semicolon){if(sym==semicolon){getsymdo;}else{error(10);}statementdo(nxtlev,ptx,lev);}if(sym==endsym){getsymdo;}else{error(17);}}else{if(sym==whilesym){cxl=cx;getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[dosym]=true;conditiondo(nxtlev,ptx,lev);cx2=cx;gendo(jpc,0,0);if(sym==dosym){getsymdo;}else{error(18);}statementdo(fsys,ptx,lev);gendo(jmp,0,cxl);code[cx2].a=cx;}else{testdo(fsys,nxtlev,19);}}}}}}}return 0;}int expression(bool * fsys,int * ptx,int lev){enum symbol addop;bool nxtlev[symnum];if(sym==plus||sym==minus){addop=sym;getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[plus]=true;nxtlev[minus]=true;termdo(nxtlev,ptx,lev);if(addop==minus){gendo(opr,0,1);}}else{memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[plus]=true;nxtlev[minus]=true;termdo(nxtlev,ptx,lev);}while(sym==plus||sym==minus){addop=sym;getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[plus]=true;nxtlev[minus]=true;termdo(nxtlev,ptx,lev);if(addop==plus){gendo(opr,0,2);}else{gendo(opr,0,3);}}return 0;}int term(bool*fsys,int*ptx,int lev){enum symbol mulop;bool nxtlev[symnum];memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[times]=true;nxtlev[slash]=true;factordo(nxtlev,ptx,lev);while(sym==times||sym==slash){mulop=sym;getsymdo;factordo(nxtlev,ptx,lev);if(mulop==times){gendo(opr,0,4);}else{gendo(opr,0,5);}}return 0;}int factor(bool*fsys,int*ptx,int lev){int i;bool nxtlev[symnum];testdo(facbegsys,fsys,24);while(inset(sym,facbegsys)){if(sym==ident){i=position(id,*ptx);if(i==0){error(11);}else{switch(table[i].kind){case constant:gendo(lit,0,table[i].val);break;case variable:gendo(lod,lev-table[i].level,table[i].adr);break;case procedur:error(21);break;}}getsymdo;}else{if(sym==number){if(num>amax){error(31);num=0;}gendo(lit,0,num);getsymdo;}else{if(sym==lparen){getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[rparen]=true;expressiondo(nxtlev,ptx,lev);if(sym==rparen){getsymdo;}else{error(22);}}testdo(fsys,facbegsys,23);}}}return 0;}int condition(bool*fsys,int*ptx,int lev){enum symbol relop;bool nxtlev[symnum];if(sym==oddsym){getsymdo;expressiondo(fsys,ptx,lev);gendo(opr,0,6);}else{memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[eql]=true;nxtlev[neq]=true;nxtlev[lss]=true;nxtlev[leq]=true;nxtlev[gtr]=true;nxtlev[geq]=true;expressiondo(nxtlev,ptx,lev);if(sym!=eql&&sym!=neq&&sym!=lss&&sym!=leq&&sym!=gtr&&s ym!=geq){error(20);}else{relop=sym;getsymdo;expressiondo(fsys,ptx,lev);switch(relop){case eql:gendo(opr,0,8);break;case neq:gendo(opr,0,9);break;case lss:gendo(opr,0,10);break;case geq:gendo(opr,0,11);break;case gtr:gendo(opr,0,12);break;case leq:gendo(opr,0,13);break;}}}return 0;}void interpret(){int p,b,t;struct instruction i;int s[stacksize];printf("start pl0\n");t=0;b=0;p=0;s[0]=s[1]=s[2]=0;do{i=code[p];p++;switch(i.f){case lit:s[t]=i.a;t++;break;case opr:switch(i.a){case 0:t=b;p=s[t+2];b=s[t+1]; break;case 1:s[t-1]=-s[t-1]; break;case 2:t--;s[t-1]=s[t-1]+s[t]; break;case 3:t--;s[t-1]=s[t-1]-s[t]; break;case 4:t--;s[t-1]=s[t-1]*s[t]; break;case 5:t--;s[t-1]=s[t-1]/s[t]; break;case 6:t--;s[t-1]=s[t-1]%2; break;case 8:t--;s[t-1]=(s[t-1]==s[t]); break;case 9:t--;s[t-1]=(s[t-1]!=s[t]); break;case 10:t--;s[t-1]=(s[t-1]<s[t]); break;case 11:t--;s[t-1]=(s[t-1]>=s[t]); break;case 12:t--;s[t-1]=(s[t-1]>s[t]); break;case 13:t--;s[t-1]=(s[t-1]<=s[t]); break;case 14:printf("%d",s[t-1]); fprintf(fa2,"%d",s[t-1]); t--;break;case 15:printf("\n");fprintf(fa2,"\n"); break;case 16:printf("?");fprintf(fa2,"?");scanf("%d",&(s[t])); fprintf(fa2,"%d\n",s[t]);t++;break;}break;case lod:s[t]=s[base(i.l,s,b)+i.a];t++;break;case sto:t--;s[t]=s[base(i.l,s,b)+i.a]=s[t]; break;case cal:s[t]=base(i.l,s,b);s[t+1]=b;s[t+2]=p;b=t;p=i.a;break;case inte:t+=i.a;break;case jmp:p=i.a;break;case jpc:t--;if(s[t]==0)p=i.a;break;}}while(p!=0);}int base(int l,int *s,int b) {int b1;b1=b;while(l>0){b1=s[b1];l--;}return b1;}五、实验结果1.输入PL/0源程序const a=10;var b,c;procedure pbeginc:=b+aend;beginread (b);while b#0 dobegincall p;write(2*c);read(b)endend.2. 输入分别输入b值的结果当b=2;输出结果为24当b=3;输出结果为26当b=1;出结果为22当b=0;结束程序六、实验体会通过该实验,本人学会了应用C语言调试和扩充PL/0编译程序的能力,此实验完成了PL/0词法分析、语法分析、语义分析、代码生成和代码优化等功能,并在此基础上实现了PL/0语言的扩充能力,从实际的应用中深刻领悟了编译程序的原理,更加深刻的学习了理论知识。

编译原理(PL0编译程序源代码)

编译原理(PL0编译程序源代码)

/*PL/0编译程序(C语言版)*编译和运行环境:*Visual C++*WinXP/7*利用方式:*运行后输入PL/0源程序文件名*回答是不是将虚拟机代码写入文件*回答是不是将符号表写入文件*执行成功会产生四个文件(词法分析结果.txt符号表.txt虚拟代码.txt源程序和地址.txt)*/#include <>#include""#include"string"#define stacksize 500xt","w");fa1=fopen("源程序和地址.txt","w");xt","w");fas=fopen("符号表.txt","w");addset(nxtlev,declbegsys,statbegsys,symnum);nxtlev[period]=true;if(-1==block(0,0,nxtlev)){n\n");fprintf(cifa,"源程序显现错误,请检查!!!");fprintf(fa1,"源程序显现错误,请检查!!!");fprintf(fa,"源程序显现错误,请检查!!!");fprintf(fas,"源程序显现错误,请检查!!!");}fclose(fa);fclose(fa1);fclose(fas);}fclose(fin);}else{printf("Can't open file!\n");}fclose(cifa);]=period;ssym['#']=neq;ssym[';']=semicolon;strcpy(&(word[0][0]),"begin");\n\n" );fprintf(fa1,"\t\t程序结尾丢了句号“.”\n");break;case 10:printf("\t\t语句之间漏了“;”\n" );fprintf(fa1,"\t\t语句之间漏了“;”\n");break;case 11:printf("\t\t标识符拼写错误或未说明\n" );fprintf(fa1,"\t\t标识符拼写错误或未说明\n");break;case 12:printf("\t\t赋值语句中,赋值号左部标识符属性应是变量\n" );fprintf(fa1,"\t\t赋值语句中,赋值号左部标识符属性应是变量\n");break;case 13:printf("\t\t赋值语句左部标识符后应是复制号“:=”\n" );fprintf(fa1,"\t\t赋值语句左部标识符后应是复制号“:=”\n");break;case 14:printf("\t\tcall后应为标识符\n" );fprintf(fa1,"\t\tcall后应为标识符\n");break;case 15:printf("\t\tcall后标识符属性应为进程\n" );fprintf(fa1,"\t\tcall后标识符属性应为进程\n");break;case 16:printf("\t\t条件语句中丢了then\n" );fprintf(fa1,"\t\t条件语句中丢了then\n");break;case 17:printf("\t\t丢了“end”或“;”\n" );fprintf(fa1,"\t\t丢了“end”或“;”\n");break;case 18:printf("\t\twhile型循环语句中丢了“do”\n" ); fprintf(fa1,"\t\twhile型循环语句中丢了“do”\n");break;case 19:printf("\t\t语句后的符号不正确\n" );fprintf(fa1,"\t\t语句后的符号不正确\n" );break;case 20:printf("\t\t应为关系运算符\n" );fprintf(fa1,"\t\t应为关系运算符\n");break;case 21:printf("\t\t表达式内标示符属性不能是进程\n" ); fprintf(fa1,"\t\t表达式内标示符属性不能是进程\n");break;case 22:printf("\t\t表达式漏掉了右括号\n" );fprintf(fa1,"\t\t表达式漏掉了右括号\n");break;case 23:printf("\t\t因子后的非法符号\n" );fprintf(fa1,"\t\t因子后的非法符号\n");break;case 24:printf("\t\t表达式的开始符不能是此符号\n" );fprintf(fa1,"\t\t表达式的开始符不能是此符号\n");break;case 25:printf("\t\t标识符越界\n" );fprintf(fa1,"\t\t标识符越界\n");break;case 26:printf("\t\t非法字符\n" );fprintf(fa1,"\t\t非法字符\n");break;case 31:printf("\t\t数越界\n");fprintf(fa1,"\t\t数越界\n");break;case 32:printf("\t\tread语句括号中的标识符不是变量\n" );fprintf(fa1,"\t\tread语句括号中的标识符不是变量\n");break;case 33:printf("\t\twrite()或read()中应为完整表达式\n" );fprintf(fa1,"\t\twrite()或read()中应为完整表达式\n");break;default:printf("\t\t显现未知错误\n" );fprintf(fa1,"\t\t显现未知错误\n");}err++;}:break;default :error(26);}if(sym!=period){t\tperiod\n");}}}}}}return 0;}=x;code[cx].l=y;code[cx].a=z;cx++;return 0;}dr=cx;gendo(jmp,0,0);if(lev>levmax){dr].a=cx;dr=cx;ize=dx;cx0=cx;gendo(inte,0,dx);ind){case constant:fprintf(fas,"%d const %s ",i,table[i].name);fprintf(fas,"val=%d\n",table[i].val);break;case variable:fprintf(fas,"%d var %s ",i,table[i].name);fprintf(fas,"lev=%daddr=%d\n",table[i].level,table[i].adr);break;case procedur:fprintf(fas,"%d proc %s ",i,table[i].name);fprintf(fas,"lev=%daddr=%dsize=%d\n", table[i].level,table[i].adr,table[i].size);break;}}}memcpy(nxtlev,fsys,sizeof(bool)*symnum);ame,id);table[(* ptx)].kind=k;switch(k){case constant:if(num>amax){error(31);num=0;}table[(*ptx)].val=num;break;case variable:table[(*ptx)].level=lev;table[(*ptx)].adr=(*pdx);(*pdx)++;break;case procedur:table[(*ptx)].level=lev;break;}}ame,idt);i=tx;ame,idt)!=0){i--;}return i;}],code[i].l,code[i],a);}}}ind!=variable){error(12);i=0;}else{getsymdo;if(sym==becomes){getsymdo;printf("该语句为赋值语句。

编译原理pL0实验报告

编译原理pL0实验报告

一.课程设计要求基本内容:(1)扩充赋值运算:*= 和/=(2)扩充语句(Pascal的FOR语句):①FOR <变量>:=<表达式> TO <表达式> DO <语句>②FOR <变量>:=<表达式> DOWNTO <表达式> DO <语句>其中,语句①的循环变量的步长为2,语句②的循环变量的步长为-2。

二.设计思路在课内实验的基础上,额外增加*=和/=运算符和关键字的语义动作,以下是设计思路:1. 扩充单词在头文件pl0.h中的enum symbol中增加关键字forsym, tosym, downtosym, timeseqlsym,slasheqlsym,并修改关键字数#define symnum 46。

/*初始化*/// ssym['*=']=timeseql;// ssym['/=']=slasheql;/*设置保留字名字,按照字母顺序,便于折半查找*/strcpy(&(word[14][0]),"to"); /*增加后需要按序排列*/strcpy(&(word[7][0]),"for");strcpy(&(word[4][0]),"downto");strcpy(&(word[3][0]),"do");/*设置保留字符号*/wsym[7]=forsym;wsym[14]=tosym;/*语法分析,获取一个符号*/在getsym()部分添加:else if(ch=='*'){ /** “*=” **/getchdo;if(ch=='='){sym=timeseql;getchdo;printf("check *= success!");}else sym=times;}else if(ch=='/'){ /* “/=” */getchdo;if(ch=='='){sym=slasheql;getchdo;printf("check /= success!");}else sym=slash;}/*其中printf部分均为识别成功后用作返回的信息而设*/2.扩充赋值运算符:*=和/=,关键字For①EBNF范式的书写:<变量>*=|/=<表达式><for 语句>::=for<变量>:=<表达式> to <表达式> do <语句> <for 语句>::=for<变量>:=<表达式> downto <表达式> do <语句>②语法描述图:a.*=和/=:③递归下降子程序a.增加+=,/=;找到statement部分的becomes部分作为修改:/以下为连接become语句后的修改部分*/else if(sym==timeseql){getsymdo;memcpy(nxtlev,fsys,sizeof(bool)* symnum);expressiondo(nxtlev,ptx,lev);gendo(lod,lev-table[i].level,table[i].adr);gendo(opr,0,4);gendo(sto,lev-table[i].level,table[i].adr);}else if(sym==slasheql){getsymdo;memcpy(nxtlev,fsys,sizeof(bool)* symnum);gendo(lod,lev-table[i].level,table[i].adr);expressiondo(nxtlev,ptx,lev);gendo(opr,0,5);gendo(sto,lev-table[i].level,table[i].adr);}}}}b.增加for:找到statement部分的calsym部分后作为增加:/以下为连接callsym语句后的增加部分*/elseif(sym==forsym){getsymdo;if(sym==ident).{i=position(id,*ptx);if(i==0){error(11);}else{if(table[i].kind!=variable) {error(12);i=0;}else{getsymdo;if(sym==becomes){getsymdo;}else{error(13);}memcpy(nxtlev,fsys,sizeof(bool)* symnum);expressiondo(nxtlev,ptx,lev);if(i!=0){gendo(sto,lev-table[i].level,table[i].adr);}}}}if(sym==tosym){getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[dosym]=true;/*后跟符号为do*/cx1=cx; /*保存判断条件超作的位置*/gendo(lod,lev-table[i].level,table[i].adr);expressiondo(nxtlev,ptx,lev);gendo(opr,0,13);cx2=cx; /*保存循环体的结束的下一个位置*/ gendo(jpc,0,0);/*生成条件跳转,但跳出循环的地址未知*/if(sym==dosym){getsymdo;}else{error(18); /*缺少do*/}statementdo(fsys,ptx,lev); /*循环体*/gendo(lod,lev-table[i].level,table[i].adr);gendo(lit,lev-table[i].level,2);gendo(opr,0,2);gendo(sto,lev-table[i].level,table[i].adr);gendo(jmp,0,cx1);/*回头重新判断条件*/code[cx2].a=cx; /*反填跳出循环的地址,与if类似*/}else{if(sym==downtosym) {getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[dosym]=true;/*后跟符号为do*/cx1=cx; /*保存判断条件超作的位置*/gendo(lod,lev-table[i].level,table[i].adr);expressiondo(nxtlev,ptx,lev);gendo(opr,0,11);cx2=cx; /*保存循环体的结束的下一个位置*/gendo(jpc,0,0);/*生成条件跳转,但跳出循环的地址未知*/if(sym==dosym) {getsymdo;statementdo(fsys,ptx,lev); /*循环体*/}else{error(18); /*缺少do*/}gendo(lod,lev-table[i].level,table[i].adr);gendo(lit,lev-table[i].level,2);gendo(opr,0,3);gendo(sto,lev-table[i].level,table[i].adr);gendo(jmp,0,cx1);/*回头重新判断条件*/code[cx2].a=cx; /*反填跳出循环的地址,与if类似*/}c. 生成的pcode代码:1 int 0 82 lit 0 53 sto 0 34 lit 0 55 sto 0 46 lit 0 17 sto 0 78 lod 0 79 lit 0 1010 opr 0 13.11 jpc 0 2112 lod 0 313 lit 0 114 opr 0 215 sto 0 316 lod 0 717 lit 0 218 opr 0 219 sto 0 720 jmp 0 821 lod 0 322 opr 0 1423 opr 0 1524 lit 0 1825 sto 0 726 lod 0 727 lit 0 128 opr 0 1129 jpc 0 3930 lod 0 431 lit 0 132 opr 0 234 lod 0 735 lit 0 236 opr 0 337 sto 0 738 jmp 0 2639 lod 0 440 opr 0 1441 opr 0 1542 opr 0 0start pl03.测试用例的编写和运行结果:本次测试使用了三个测试用例,其中E02.PL0为检测是否能正确识别所增加的关键字和运算符,E04.PL0就是检测*=和/=是否能正确符合运算规则并求出得数,E05.PL0是for语句的检测。

编译原理实验报告-简单 PL0编译程序及其扩展

编译原理实验报告-简单 PL0编译程序及其扩展

一、题目:简单PL0编译程序及其扩展表示多行表达式的<表达式序列>文法如下:<表达式序列>-> <表达式> ↙<表达式序列> |<表达式>↙↙<表达式> -> [<变量>=] [+|-]<项>{(+|-)<项>}<项> -> <因子>{(* | /)<因子>}<因子> -> <无符号实数>|<变量>|<标准函数>‘(’<表达式>‘)’|‘(’ <表达式>‘)’<标准函数> -> sin | cos | tan | exp其中的变量无需定义且其作用域为第一次赋值处至最后。

递归下降方式设计其编译程序,生成PL/0栈式指令代码,然后解释执行。

二、编译技术,主要数据结构及算法Class:MyPL0int getch();void error(int n);int gen(string function,int lev,string a);int factor();int term();int expression();void listcode();void interpret();void GetFile();void start();void Check(int i);void run(string str);Class:Code主要数据结构:数组,栈,链表三、测试本程序的测试源程序在test.txt中:a=1+2*3-4/(2*3) //检测是否实现基本文法b=sin2+cos6+tan10 //检测是否扩展标准函数(本组没能实现exp)c=9*(3+ //检测出错纠察—缺少右括号d=x+3 //检测变量无定义e=48*+33 //检测表达式非法用于测试的源代码用户也可以自己定义四、遗留问题及思考没有解决exp的识别和计算,有待考究追加通过对书后标准程序的改造和学习,本小组加深了PL0编译程序的执行过程,了解到栈式目标代码的具体生成过程,。

PL0编译器源程序分析

PL0编译器源程序分析

PL/0编译器源程序分析PL/0语言是Pascal语言的一个子集,我们这里分析的PL/0的编译程序包括了对PL/0语言源程序进行分析处理、编译生成类PCODE代码,并在虚拟机上解释运行生成的类PCODE代码的功能。

PL/0语言编译程序采用以语法分析为核心、一遍扫描的编译方法。

词法分析和代码生成作为独立的子程序供语法分析程序调用。

语法分析的同时,提供了出错报告和出错恢复的功能。

在源程序没有错误编译通过的情况下,调用类PCODE解释程序解释执行生成的类PCODE代码。

词法分析子程序分析:词法分析子程序名为getsym,功能是从源程序中读出一个单词符号(token),把它的信息放入全局变量sym、id和num中,语法分析器需要单词时,直接从这三个变量中获得。

(注意!语法分析器每次用完这三个变量的值就立即调用getsym子程序获取新的单词供下一次使用。

而不是在需要新单词时才调用getsym过程。

)getsym过程通过反复调用getch子过程从源程序过获取字符,并把它们拼成单词。

getch过程中使用了行缓冲区技术以提高程序运行效率。

词法分析器的分析过程:调用getsym时,它通过getch过程从源程序中获得一个字符。

如果这个字符是字母,则继续获取字符或数字,最终可以拼成一个单词,查保留字表,如果查到为保留字,则把sym变量赋成相应的保留字类型值;如果没有查到,则这个单词应是一个用户自定义的标识符(可能是变量名、常量名或是过程的名字),把sym置为ident,把这个单词存入id变量。

查保留字表时使用了二分法查找以提高效率。

如果getch获得的字符是数字,则继续用getch获取数字,并把它们拼成一个整数,然后把sym置为number,并把拼成的数值放入num变量。

如果识别出其它合法的符号(比如:赋值号、大于号、小于等于号等),则把sym则成相应的类型。

如果遇到不合法的字符,把sym置成nul。

语法分析子程序分析:语法分析子程序采用了自顶向下的递归子程序法,语法分析同时也根据程序的语意生成相应的代码,并提供了出错处理的机制。

PL0语言涉及的头文件

PL0语言涉及的头文件

涉及的头文件有<stdio.h>,”pl0.h”,”string.h”<Stdio.h> :stdio就是指“standard input & output"(标准输入输出)/** stdio.h* This file has no copyright assigned and is placed in the Public Domain.* This file is a part of the mingw-runtime package.* No warranty is given; refer to the file DISCLAIMER within the package.* Definitions of types and prototypes of functions for standard input and output. * NOTE: The file manipulation functions provided by Microsoft seem to* work with either slash (/) or backslash (\) as the directory separator.*/stdio.h所包含的函数:文件访问Fopen //打开文件Freopen //将已存在的流指针和新文件连接Fflush //刷新缓存区Fclose //关闭文件二进制输入/输出Fread //直接流读操作Fwrite //直接流写操作非格式化输入/输出fgetc/getc //输入一个字符/ 字符输入(控制台)fputc/putc //字符输出/ 字符输出(控制台)ungetc //把一个字符退回到输入流中fgets //字符串输入fputs //字符串输出格式化输入/输出scanf/fscanf/sscanf //格式输入printf/fprintf/sprint //格式输出文件定位Ftell //得到文件位置fseek //文件位置移动fgetpos //得到文件位置fsetpos//文件位置设置rewind //文件位置复零位错误处理Feof //文件结尾判断Ferror //文件错误检测perror //得到错误提示字符串文件操作Remove //删除文件Rename //修改文件名称Tmpfile //生成临时文件名称“string.h” :是关于字符数组的函数定义的头文件字符串拷贝,块拷贝(目的和源存储区不可重叠) memcpy 块拷贝(目的和源存储区可重叠) memmove串拷贝strcpy按长度的串拷贝strncpy字符串连接函数串连接strcat按长度连接字符串strncat串比较函数块比较memcmp字符串比较strcmp字符串比较(用于非英文字符) strcoll按长度对字符串比较strncmp字符串转换strxfrm字符与字符串查找字符查找memchr字符查找strchr字符串查找strcspn字符串查找strpbrk字符串查找strspn字符串查找strstr字符串分解strtok杂类函数字符串设置memset错误字符串映射strerror求字符串长度strlen“pl0.h”:Pl/0编译系统C版本头文件,描述Pl/0语言名字表中的类型、虚拟代码,虚拟代码结构及各种宏定义等。

PL0编译器源程序分析

PL0编译器源程序分析

PL/0编译器源程序分析PL/0语言是Pascal语言的一个子集,我们这里分析的PL/0的编译程序包括了对PL/0语言源程序进行分析处理、编译生成类PCODE代码,并在虚拟机上解释运行生成的类PCODE代码的功能。

PL/0语言编译程序采用以语法分析为核心、一遍扫描的编译方法。

词法分析和代码生成作为独立的子程序供语法分析程序调用。

语法分析的同时,提供了出错报告和出错恢复的功能。

在源程序没有错误编译通过的情况下,调用类PCODE解释程序解释执行生成的类PCODE代码。

词法分析子程序分析: 词法分析子程序名为getsym,功能是从源程序中读出一个单词符号(token),把它的信息放入全局变量sym、id和num中,语法分析器需要单词时,直接从这三个变量中获得。

(注意!语法分析器每次用完这三个变量的值就立即调用getsym子程序获取新的单词供下一次使用。

而不是在需要新单词时才调用getsym过程。

)getsym过程通过反复调用getch 子过程从源程序过获取字符,并把它们拼成单词。

getch过程中使用了行缓冲区技术以提高程序运行效率。

词法分析器的分析过程:调用getsym时,它通过getch过程从源程序中获得一个字符。

如果这个字符是字母,则继续获取字符或数字,最终可以拼成一个单词,查保留字表,如果查到为保留字,则把sym变量赋成相应的保留字类型值;如果没有查到,则这个单词应是一个用户自定义的标识符(可能是变量名、常量名或是过程的名字),把sym置为ident,把这个单词存入id变量。

查保留字表时使用了二分法查找以提高效率。

如果getch获得的字符是数字,则继续用getch获取数字,并把它们拼成一个整数,然后把sym置为number,并把拼成的数值放入num变量。

如果识别出其它合法的符号(比如:赋值号、大于号、小于等于号等),则把sym则成相应的类型。

如果遇到不合法的字符,把sym置成nul。

语法分析子程序分析: 语法分析子程序采用了自顶向下的递归子程序法,语法分析同时也根据程序的语意生成相应的代码,并提供了出错处理的机制。

编译原理修改后地PL0报告材料

编译原理修改后地PL0报告材料

一、上机实践要求“编译原理与技术〞的上机实验要求你对PL/0语言与其编译器进展扩大和修改。

每个扩大或修改方式可得到不同的分数,总分为为100分。

完成上机作业后,必须提交如下文档:(1)修改后的PL/0语言文本。

包含词法分析〔正规式〕,语法分析〔BNF〕。

(2)有关修改后的PL/0编译/解释器的说明。

详细说明你的编译器是如何编译新的PL/0语言程序的。

指出你的程序中最精彩的局部,以与你为什么这样做,你是如何控制和恢复语义错误的。

(3)给出你所改动后的编译器源程序清单,并标记出你所修改的局部。

比拟你的编译器和原来的编译器之间的差异。

(4)说明你的编译器中可能存在的错误。

(5)总结经验与教训,如果重做一遍,你会有哪些新的改良?对现存的PL/0编译程序可做如下修改或扩大,其中〔1〕、〔2〕、〔11〕和〔12〕必须完成,剩余的均可任意选择,但总分必须超过70分。

(1)注释〔5分〕注释由(*和*)包含,不允许嵌套。

(2)布尔类型的数据〔10分〕布尔类型的BNF为:var_option →ε| var var_decl_listvar_decl_list → var_decl | var_decl_list var_declvar_decl → ident_list : data_typedata_type →integer | boolean这种修改包括:(i)区别整型与布尔型变量、常量和表达式。

(ii)增加按严格计算的布尔类型运算符and、or和not。

这些算符以与己有的运算符的优先级与Pascal语言一样。

(iii)能够使用布尔常量true和false。

(iv)把PL/0语言中的“条件〞概念一般化为Pascal语言那样。

(v)布尔表达式可以比拟大小:false < true(3)布尔表达式的短路计算〔5分〕增加布尔类型〔见〔2〕,除〔2〕的〔ii〕外〕,但对and和or采取短路计算。

(4)数组〔10分〕增加由任何数据类型构造的一维数组。

编译原理实验 (词法语法分析报告 附源代码

编译原理实验 (词法语法分析报告 附源代码

编译原理实验报告******************************************************************************* ******************************************************************************* PL0语言功能简单、结构清晰、可读性强,而又具备了一般高级程序设计语言的必须部分,因而PL0语言的编译程序能充分体现一个高级语言编译程序实现的基本方法和技术。

PL/0语言文法的EBNF表示如下:<程序>::=<分程序>.<分程序> ::=[<常量说明>][<变量说明>][<过程说明>]<语句><常量说明> ::=CONST<常量定义>{,<常量定义>};<常量定义> ::=<标识符>=<无符号整数><无符号整数> ::= <数字>{<数字>}<变量说明> ::=VAR <标识符>{, <标识符>};<标识符> ::=<字母>{<字母>|<数字>}<过程说明> ::=<过程首部><分程序>{; <过程说明> };<过程首部> ::=PROCEDURE <标识符>;<语句> ::=<赋值语句>|<条件语句>|<当循环语句>|<过程调用语句>|<复合语句>|<读语句><写语句>|<空><赋值语句> ::=<标识符>:=<表达式><复合语句> ::=BEGIN <语句> {;<语句> }END<条件语句> ::= <表达式> <关系运算符> <表达式> |ODD<表达式><表达式> ::= [+|-]<项>{<加法运算符> <项>}<项> ::= <因子>{<乘法运算符> <因子>}<因子> ::= <标识符>|<无符号整数>| ‘(’<表达式>‘)’<加法运算符> ::= +|-<乘法运算符> ::= *|/<关系运算符> ::= =|#|<|<=|>|>=<条件语句> ::= IF <条件> THEN <语句><过程调用语句> ::= CALL 标识符<当循环语句> ::= WHILE <条件> DO <语句><读语句> ::= READ‘(’<标识符>{,<标识符>}‘)’<写语句> ::= WRITE‘(’<表达式>{,<表达式>}‘)’<字母> ::= a|b|…|X|Y|Z<数字> ::= 0|1|…|8|9【预处理】对于一个pl0文法首先应该进行一定的预处理,提取左公因式,消除左递归(直接或间接),接着就可以根据所得的文法进行编写代码。

(完整word版)PL0源程序-编译原理实验代码

(完整word版)PL0源程序-编译原理实验代码

附件1 小组成员:程序清单Main.c#include<stdio.h>#include<stdlib.h>#include<string.h>void error(int n);void getsym();//void enter(enum object k,int *ptx,int lev,int *pdx);int position(char*idt,int tx);int constdeclaration(int *ptx,int lev,int *pdx);int vardeclaration(int *ptx,int lev,int *pdx);int factor(int*ptx,int lev);int term(int *ptx,int lev);int expression(int *ptx,int lev);int statement(int *ptx,int lev);int block();enum object{constant,variable,procedure};struct tab{char name[14];enum object kind;int val;int level;int adr;int size;}table[100];enum symbol{nul,ident,number,plus,minus,times,slash,oddsym,eql,neq,lss,leq,gtr,geq,lparen,r paren,comma,semicolon,period,becomes,beginsym,endsym,ifsym,thensym,whilesym,writesym,readsym,dosym,ca llsym,constsym,varsym,procsym,progsym,};enum symbol sym=nul;enum symbol mulop;enum symbol wsym[14];enum symbol ssym[256];char ch=' ';char *str;charword[14][10]={"begin","call","const","do","end","if","odd","procedure","program ","read","then","var","while","write"};//设置保留字名字int num;int lev=0;int tx=0;int k;int *mm;//=(int *)malloc(sizeof(int));char *id,sign[14];char a[14];FILE *fp1,*fp2,*fp3;void error(int n){switch(n){case 1:printf("常数说明中的\"=\"写成了\":=\"。

编译原理PL0报告(附源码教程)

编译原理PL0报告(附源码教程)

编译原理课程设计学院计算机学院专业计算机科学与技术班级学号姓名指导教师20 年月日一、课程设计要求基本内容(成绩范围:“中”、“及格”或“不及格”)(1)扩充赋值运算:*= 和/=扩充语句(Pascal的FOR语句):①FOR <变量>:=<表达式> TO <表达式> DO <语句>②FOR <变量>:=<表达式> DOWNTO <表达式> DO <语句>其中,语句①的循环变量的步长为2,语句②的循环变量的步长为-2。

(3)增加运算:++ 和--。

选做内容(成绩评定范围扩大到:“优”和“良”)(1)增加类型:①字符类型;②实数类型。

(2)扩充函数:①有返回值和返回语句;②有参数函数。

(3)增加一维数组类型(可增加指令)。

(4)其他典型语言设施。

二、概述目标:实现PL0某些特定语句实现语言:C语言实现工具平台:VS201运行平台:WIN7三、结构设计说明与功能块描述PL/0编译程序的结构图PL/0编译程序的总体流程图四、主要成分描述1、符号表编译程序里用了一个枚举类型enum symbol,然后定义了enum symbol sym来存放当前的符号,前面讲过,主程序定义了一个以字符为元素的一维数组word,称保留字表,这个保留字表也存放在符号表里,为了识别当前的符号是属于哪些保留字;还有标识符,拼数,拼符合词等的符号名都存放在符号表里,当sym存放当前的符号时,我们可以判断它是属于哪类的符号,然后加以处理。

在运行的过程中,主程序中又定义了一个名字表,也就是符号表,来专门存放变量、常量和过程名的各个属性,里面的属性包括name,kind,val/level,adr,size,我们来举一个PL/0语言过程说明部分的片段:Const a=35,b=49;Var c,d,e;Procedure p;Var g;当遇到标识符的引用时就调用position函数,根据当前sym的符号类型来查table表,看是否有过正确的定义,若已有,则从表中取相应的有关信息,供代码的生成用。

实验一PL0编译程序

实验一PL0编译程序

实验一PL0编译程序编译原理上机实验一1.软件准备(1)、pl/0编译程序:pl0 .exe(2)、pl/0编译程序源代码程序(PASCAL程序):pl0.pas(或pl0pl0.pas)(3)、pl/0程序实例(文本文件):text.pl0, text1.pl0, test2.pl0, … text9.pl0共10个例子2.实验要求:(1)阅读pl/0源程序实例(text.pl0,test1.pl0,………text9.pl0共10个例子)理解每个PL0程序的功能;熟悉并掌握pl/0语言相关规则。

(2)用pl/0编译程序,对提供的10个例子逐一进行编译并运行。

熟悉pl/0编译程序使用操作方法。

通过理解每个实例程序的功能,编程思想,进一步理解PL/0语言的语法及其语义;提高阅读程序的能力,应用程序设计语言的编程能力;增强程序语言语法、语义意识。

(3)用pl/0语言编写以下程序,进一步熟悉PL/0语言:a、由三角形的三条边长计算三角形面积。

b、编写一个PL0过程,计算以a为直径的圆的面积。

用主程序确定圆的直径,输出计算结果。

c、编写递归程序,计算n!。

d、计算1000之内的所有素数,并输出结果。

求出1000之内所有素数之和。

(要求编写3个以上的pl/0过程实现)3.文件(软件)使用说明(1)、打开文件目录“PL0编译…”,运行PL/0编译程序(pl0.exe),按提示要求输入PL0源程序文件名(如test1.pl0),┉(2)、打开Fa2.txt文件,可看到当前经过编译并运行后的pl/0程序的目标代码及其执行结果。

(3)、打开out1.txt或out2.txt、┉或out9.txt文件,可看到各个pl/0程序实例的编译、运行、操作过程结果。

4.提交实验报告及要求(1)、简述test4.pl0 …test7.pl0各程序语法含义,执行结果。

(2)、提交实验要求编写的4个PL/0源程序及其执行结果。

(3)、简写本次实验的收获与体会。

理解PL0编译程序原理

理解PL0编译程序原理

课程: 编译原理理解PL/0编译程序原理实验报告系专业班级姓名学号指导教师1.实验目的1. 学习使用教学辅助软件THPL0CAI2. 掌握PL/0源程序的编译和解释过程2.实验平台Windows + THPL0CAI3.实验内容目录:pl0演示1.运行THPL0CAI 程序1) 选择0 - Static Link 方式进入2) 选择Open/Create a source file 打开一个PL/0源程序, 如Test2.pl0 const a=10;var b,c;procedure p;var k;beginc:=b+10;end;beginread(b);while b#0 dobegincall p;write(2*c);read(b)endend.2.按F9键开始单步编译Test2.pl0 程序1) 观察符号表的构造过程Table.dat 窗口2) 观察目标代码的构造过程Code.dat 窗口3. 按F9键开始单步执行编译Test2.pl0 生成的代码1) 观察运行栈的变化过程Stack.dat 窗口2) 观察数据的输入输出Result.dat 窗口4.实验报告给出编译过程中符号表的建立过程,1.选定编译内容test22.按空格键进行编译3.得出的符号表table.dat给出运行过程中运行栈的变化过程,只给出部分说明即可。

1.F9开始运行栈2.输入2,给变量赋值3.输入3,给变量赋值,得出结果4.输入0,结束运行栈5.思考题1) 理解编译和解释的含义,目标代码是按何种方式执行的?PL/0编译程序所产生的目标代码是一个假想栈式计算机的汇编语言,可称为类PCODE指令代码,它不依赖任何具体计算机,其指令集极为简单,指令格式也很单纯,其格式如下:f l a其中f代表功能码,l表示层次差,也就是变量或过程被引用的分程序与说明该变量或过程的分程序之间的层次差。

a的含意对不同的指令有所区别,对存取指令表示位移量,而对其它的指令则分别有不同的含义,见下面对每条指令的解释说明。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
char word[norw][al]; /* 保留字 */
enum symbol wsym[norw]; /* 保留字对应的符号值 */
enum symbol ssym[256]; /* 单字符的符号值 */
char mnemonic[fctnum][5]; /* 虚拟机代码指令名称 */
{
char name[al]; /* 名字 */
enum object kind; /* 类型:const,var or procedure */
int val; /* 数值,仅const使用 */
int level; /* 所处层,仅const不使用 */
int adr; /* 地址,仅const不使用 */
#define statementdo(a,b,c) if(-1==statement(a,b,c))return -1
#define constdeclarationdo(a,b,c) if(-1==constdeclaration(a,b,c))return -1
#define vardeclarationdo(a,b,c) if(-1==vardeclaration(a,b,c))return -1
int postion(char* idt,int tx);
void enter(enum object k,int* ptx,int lev,int* pdx);
int base(int l,int* s,int b);
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);
void error(int n); etch();
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);
/* 最多的虚拟机代码数 */
#define cxmax 200
//#define cxmaxadd1 201
/* 当函数中会发生fatal error时,返回-1告知调用它的函数,最终退出程序 */
/* 符号 */
enum symbol
{nul,ident,number,plus,minus,times,slash,oddsym,eql,neq,lss,leq,
#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 txmaxadd1 101
/* number的最大位数 */
#define nmax 14
/* 符号的最大长度 */
#define al 10
/* 地址上界 */
#define amax 2047
/* 最大允许过程嵌套声明层数 */
#define levmax 3
#define symnum 32
/* 名字表中的类型 */
enum object {constant,variable,procedur};
/* 虚拟机代码 */
enum fct {lit,opr,lod,sto,cal,inte,jmp,jpc};
#define fctnum 8
/* 虚拟机代码结构 */
int addset(bool* sr,bool* s1,bool* s2,int n);
int subset(bool* sr,bool* s1,bool* s2,int n);
int mulset(bool* sr,bool* s1,bool* s2,int n);
int block(int lev,int tx,bool* fsys);
bool declbegsys[symnum]; /* 表示声明开始的符号集合 */
bool statbegsys[symnum]; /* 表示语句开始的符号集合 */
bool facbegsys[symnum]; /* 表示因子开始的符号集合 */
/* 名字表结构 */
struct tablestruct
int size; /* 需要分配的数据区空间,仅procedure使用 */
};
struct tablestruct table[txmax]; /* 名字表 */
FILE* fin;
FILE* fout;
char fname[al];
int err; /* 错误计数器 */
#define getsymdo if(-1==getsym())return -1
struct instruction
{
enum fct f; /* 虚拟机代码指令 */
int l; /* 引用层与声明层的层次差 */
int a; /* 根据f的不同而不同 */
};
FILE* fas; /* 输出名字表 */
FILE* fa; /* 输出虚拟机代码 */
FILE* fa1; /* 输出源文件及其各行对应的首地址 */
FILE* fa2; /* 输出结果 */
bool listswitch; /* 显示虚拟机代码与否 */
bool tableswitch; /* 显示名字表与否 */
char ch; /* 获取字符的缓冲区,getch 使用 */
enum symbol sym; /* 当前的符号 */
char id[al+1]; /* 当前ident */
int statement(bool* fsys,int* ptx,int lev);
void listcode(int cx0);
int vardeclaration(int* ptx,int lev,int* pdx);
int constdeclaration(int* ptx,int lev,int* pdx);
#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 expressiondo(a,b,c) if(-1==expression(a,b,c))return -1
int num; /* 当前number */
int cc,ll; /* getch使用的计数器,cc表示当前字符(ch)的位置 */
int cx; /* 虚拟机代码指针 */
char line[81]; /* 读取行缓冲区 */
char a[al+1]; /* 临时符号 */
struct instruction code[cxmax]; /* 存放虚拟机代码的数组 */
#include <stdio.h>
#include <string.h>
typedef enum
{
False,
True
}Bool;
/* 关键字个数 */
#define norw 13
/* 名字表容量 */
#define txmax 100
/* 所有的add1用于定义数组 */
gtr,geq,lparen,rparen,comma,semicolon,period,becomes,beginsym,
endsym,ifsym,thensym,whilesym,writesym,readsym,dosym,callsym,
constsym,varsym,procsym};
相关文档
最新文档