编译原理课程设计-PL/0编译器的扩充(C语言完整版)
来源:互联网 发布:java 个性签名演示 编辑:程序博客网 时间:2024/06/07 03:58
看到网上有很多pl0的源码,但是很多都是不完整的,这里上传一份完整版,按要求扩展了几个功能,希望对大家的理解有所帮助。
注:转载请声明转自:http://blog.csdn.net/ahoob/article/details/44519687
课程设计要求:
1、基本内容(成绩范围:“中”、“及格”或“不及格”)
(1)扩充赋值运算:*= 和 /=
(2)扩充语句(Pascal的FOR语句):
①FOR <变量>:=<表达式> TO <表达式> DO <语句>
②FOR <变量>:=<表达式> DOWNTO <表达式> DO <语句>
其中,语句①的循环变量的步长为1,
语句②的循环变量的步长为-1。
2、选做内容(成绩评定范围扩大到:“优”和“良”,完成2项以上才可为优,若两项以上的人少,则降低为两项才可以为优)
(1)增加类型:① 字符类型; ② 实数类型。
(2) 增加 注释; 注释由/和/包含;
(3)扩充函数:① 有返回值和返回语句;② 有参数函数。
(4)增加一维数组类型(可增加指令)。
(5)增加运算:++ 和 –。
(6)其他典型语言设施。
3、本人在课程设计中已实现的功能
(1)扩充赋值运算:*= 和 /=
(2)扩充语句(Pascal的FOR语句):
①FOR <变量>:=<表达式> TO <表达式> DO <语句>
②FOR <变量>:=<表达式> DOWNTO <表达式> DO <语句>
其中,语句①的循环变量的步长为1,
语句②的循环变量的步长为-1。
(3)增加类型:① 字符类型;
(4) 增加 注释; 注释由/和/包含;
(5)增加运算:++ 和 - -。
扩展了的pl0编译器,直接上代码
pl0.h
/*PL/0 编译系统C版本头文件 pl0.h*/# define norw 19 /*关键字个数*/ //关键字个数数由初始值13增加至19# define txmax 100 /*名字表容量*/# define nmax 14 /*number的最大位数*/# define al 10 /*符号的最大长度*/# define amax 2047 /*地址上界*/# define levmax 3 /*最大允许过程嵌套声明层数[0,lexmax]*/# define cxmax 200 /*最多的虚拟机代码数*//*符号*///增加单词:保留字 ELSE,FOR,TO,DOWNTO,RETURN//运算符 *=,/=,++,--enum 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, elsesym, forsym, tosym, downtosym, returnsym , timeseql, slasheql, plusplus, minusminus,charsym,};#define symnum 42 //符号数初始值由32增加至42/*-------------*/enum object{ constant, variable, procedur, charcon,//字符型 realcon,//实型};/*--------------*/enum fct{lit, opr, lod, sto, cal, inte, jmp, jpc,};#define fctnum 8/*--------------*/struct instruction{ enum fct f; int l; int a; //double a;//实型字符型修改};FILE * fas;FILE * fa;FILE * fa1;FILE * fa2;bool tableswitch;bool listswitch;char ch;enum symbol sym;char id[al+1];int num;int cc,ll;int cx;char line[81];char a[al+1];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];/*------------------------------*/struct tablestruct{ char name[al]; /*名字*/ enum object kind; /*类型:const,var,array or procedure*/ int val; /*数值,仅const使用*/ int level; /*所处层,仅const不使用*/ int adr; /*地址,仅const不使用*/ int size; /*需要分配的数据区空间,仅procedure使用*/};struct tablestruct table[txmax]; /*名字表*/FILE * fin;FILE* fout;char fname[al];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 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#define chardeclarationdo(a,b,c) if(-1==chardeclaration(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*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);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*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);int chardeclaration(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
有点长。。。耐心看
//A.2 C 版 本/**使用方法:*运行后输入PL/0 源程序文件名*回答是否输出虚拟机代码*回答是否输出名字表*fa.tmp 输出虚拟机代码*fa1.tmp 输出源文件及其各行对应的首地址*fa2.tmp 输出结果 *fas.tmp 输出名字表* @author:zzh*/#include<stdio.h>#include"pl0.h"#include"string.h"/*解释执行时使用的栈*/#define stacksize 500int main(){ bool nxtlev[symnum]; printf("Input pl/0 file ?"); scanf("%s",fname); /*输入文件名*/ fin=fopen(fname,"r"); if(fin) { printf("List object code ?(Y/N)"); /*是否输出虚拟机代码*/ scanf("%s",fname); listswitch=(fname[0]=='y'||fname[0]=='Y'); printf("List symbol table ? (Y/N)"); /*是否输出名字表*/ scanf("%s",fname); tableswitch=(fname[0]=='y'||fname[0]=='Y'); fa1=fopen("fa1.tmp","w"); fprintf(fa1,"Iput pl/0 file ?"); fprintf(fa1,"%s\n", 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(fa1); fclose(fas); fclose(fin); printf("\n"); return 0; } fclose(fa); fclose(fa1); fclose(fas); if(sym!=period) { error(9); } if(err==0) { fa2=fopen("fa2.tmp", "w"); interpret(); fclose(fa2); } else { printf("Errors in pl/0 program"); } } fclose(fin); } else { printf("Can't open file! \n"); } printf("\n"); getchar(); getchar(); 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]),"char");/*增加保留字char*/ strcpy(&(word[3][0]),"const"); strcpy(&(word[4][0]),"do"); strcpy(&(word[5][0]),"downto");/*增加保留字downto*/ strcpy(&(word[6][0]),"else");/*增加保留字else*/ strcpy(&(word[7][0]),"end"); strcpy(&(word[8][0]),"for");/**增加保留字for*/ strcpy(&(word[9][0]),"if"); strcpy(&(word[10][0]),"odd"); strcpy(&(word[11][0]),"procedure"); strcpy(&(word[12][0]),"read"); strcpy(&(word[13][0]),"return");/*增加保留字return*/ strcpy(&(word[14][0]),"then"); strcpy(&(word[15][0]),"to");/*增加保留字to*/ strcpy(&(word[16][0]),"var"); strcpy(&(word[17][0]),"while"); strcpy(&(word[18][0]),"write"); /*设置保留字符号*/ wsym[0]=beginsym; wsym[1]=callsym; wsym[2]=charsym;/*增加保留字符号charsym*/ wsym[3]=constsym; wsym[4]=dosym; wsym[5]=downtosym;/*增加保留字符号downtosym*/ wsym[6]=elsesym;/*增加保留字符号elsesym*/ wsym[7]=endsym; wsym[8]=forsym;/*增加保留字符号forsym*/ wsym[9]=ifsym; wsym[10]=oddsym; wsym[11]=procsym; wsym[12]=readsym; wsym[13]=returnsym;/*增加保留字符号returnsym*/ wsym[14]=thensym; wsym[15]=tosym;/*增加保留字符号tosym*/ wsym[16]=varsym; wsym[17]=whilesym; wsym[18]=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; declbegsys[charsym]=true;//增加声明开始符号charsym /*设置语句开始符号集*/ statbegsys[beginsym]=true; statbegsys[callsym]=true; statbegsys[ifsym]=true; statbegsys[whilesym]=true; /*设置因子开始符号集*/ facbegsys[ident]=true; facbegsys[number]=true; facbegsys[lparen]=true; facbegsys[plusplus]=true;//增加开始因子plusplus facbegsys[minusminus]=true;//增加开始因子minusminus facbegsys[charsym]=true;//增加开始因子charsym} /* *用数组实现集合的集合运算 */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); printf("-------%c\n",ch); space[cc-1]=0;//出错时当前符号已经读完,所以cc-1 printf("****%s!%d\n",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) { //fscanf(fin,"%c",&ch) if(EOF==fscanf(fin,"%c",&ch)) { line[ll]=0; break; } printf("%c",ch); fprintf(fa1,"%c",ch); line[ll]=ch; ll++; } printf("\n"); fprintf(fa1,"\n"); } ch=line[cc]; cc++; return 0;} /*词法分析,获取一个符号 */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 if(ch=='>')//小于号后面跟着大于号 { sym=neq;//构成不等号<> printf("识别出<>号"); getchdo; } else { sym=lss; } } else { if(ch=='>') /*检测大于或大于等于符号*/ { getchdo; if(ch=='=') { sym=geq; getchdo; } else { sym=gtr; } } else if(ch=='*') { getchdo; if(ch=='=') { sym=timeseql;//构成*=号 printf("识别出*=号\n"); getchdo; } else { sym=times; } } else if(ch=='/') { getchdo; if(ch=='=') { sym=slasheql;//构成/=号 printf("识别出/=号\n"); getchdo; } else if(ch=='*')//增加注释功能 { int end=1; char a=0,b=0; getchdo; printf("识别出注释/*%c",ch); while(end) { if(b!=0) {b=a;} else b=ch; getchdo; a=ch; printf("%c",a); if(b=='*'&&a=='/') { printf("注释到此结束\n"); end=0; break; } } getchdo; } else { sym=slash; } } else if(ch=='+') { getchdo; if(ch=='+') { sym=plusplus;//构成++号 printf("识别出++号\n"); getchdo; }else { sym=plus; } } else if(ch=='-') { getchdo; if(ch=='-') { sym=minusminus;//构成--号 printf("识别出--号\n"); getchdo; }else { sym=minus; } } else if(ch=='\'')//增加字符型 { getchdo; if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')) { num=(int)ch; getchdo; if(ch=='\'') sym=charsym; else { num=0; sym=nul; error(39); //类型错误 } } else error(39); //类型不匹配 getchdo; } else { sym=ssym[ch];/* 当符号不满足上述条件时,全部按照单字符号处理*/ //getchdo; //richard if(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) { printf("Program too long"); /*程序过长*/ return -1; } code[cx].f=x; code[cx].l=y; code[cx].a=z; cx++; return 0;}/**测试当前符号是否合法**在某一部分(如一条语句,一个表达式)将要结束时时我们希望下一个符号属于某集合*(该部分的后跟符号) test 负责这项检测,并且负责当检测不通过时的补救措施*程序在需要检测时指定当前需要的符号集合和补救用的集合(如之前未完成部分的后跟*符号),以及不通过时的错误号**S1:我们需要的符号*s2:如果不是我们需要的,则需要一个补救用的集合*n:错误号*/int test(bool* 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 cx0; /*保留初始cx*/ bool nxtlev[symnum]; /*在下级函数的参数中,符号集合均为值参,但由于使用数组 实现,传递进来的是指针,为防止下级函数改变上级函数的 集合,开辟新的空间传递给下级函数*/ dx=3; tx0=tx; /*记录本层名字的初始位置*/ table[tx].adr=cx; gendo(jmp,0,0); if(lev > levmax) { error(32); } do{ if(sym==constsym) /*收到常量声明符号,开始处理常量声明*/ { getsymdo; do{ constdeclarationdo(&tx,lev,&dx); /*dx的值会被constdeclaration改变,使用 指针*/ 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); } if(sym==charsym)/*收到符号型声名符号,开始处理符号型声名*/ { getsymdo; do{ chardeclarationdo(&tx,lev,&dx); while(sym==comma) { getsymdo; chardeclarationdo(&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);/*procedure后应为标识符*/ } 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; /*声明部分中每增加一条声明都会给dx增加1,声明部分已经结束,dx就是当前过程数据的size*/ cx0=cx; gendo(inte,0,dx); /*生成分配内存代码*/ if(tableswitch) /*输出名字表*/ { printf("TABLE:\n"); if(tx0+1>tx) { printf("NULL\n"); } for(i=tx0+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 adr=%d size=%d \n",table[i].level,table[i].adr,table[i].size); break; } } printf("\n"); } /*语句后跟符号为分号或end*/ 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); /*分程序没有补救集合*/ test(fsys,nxtlev,8); /*检测后跟符号正确性*/ listcode(cx0); /*输出代码*/ return 0;}/**在名字表中加入一项**k:名字种类const,var or procedure*ptx:名字表尾指针的指针,为了可以改变名字表尾指针的数值*lev:名字所在的层次,以后所有的lev都是这样*pdx:为当前应分配的变量的相对地址,分配后要增加1*/void enter (enum object k,int *ptx,int lev, int *pdx){ (*ptx)++; strcpy(table[(*ptx)].name,id); /*全局变量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; case charcon: /*字符型名字*/ table[(*ptx)].level=lev; table[(*ptx)].adr=(*pdx); (*pdx)++; break; }}/* *查找名字的位置 *找到则返回在名字表中的位置,否则返回0 * *idt: 要查找的名字 *tx::当前名字表尾指针 */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); /*const后应是标识*/ } return 0;}/* * */int vardeclaration(int * ptx,int lev,int * pdx){ if(sym==ident) { enter(variable,ptx,lev,pdx);//填写名字表 getsymdo; } else { error(4); } return 0;}/* *字符型声明 */int chardeclaration(int * ptx,int lev,int * pdx){ if(sym==ident) { enter(charcon,ptx,lev,pdx);//填写名字表 getsymdo; } else { error(4); } return 0;}/* *实型声明 *//*int realdeclaration(int * ptx,int lev,int * pdx){ if(sym==ident) { enter(realcon,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 %s %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,cx1,cx2; bool nxtlev[symnum]; if(sym==ident) { i=position(id,*ptx);//在符号表中查到该标识符所在位置 if(i==0) { error(11); } else { if((table[i].kind!=variable)&&(table[i].kind!=charcon)) { error(12); i=0; } else if(table[i].kind==charcon) { getsymdo; if(sym!=becomes) error(13); else { getsymdo; if(sym!=charsym) error(32); else { gendo(lit,0,num); gendo(sto,lev-table[i].level,table[i].adr); } } getsymdo;//坑:分号 } else { getsymdo; if(sym==becomes) { getsymdo; memcpy(nxtlev,fsys,sizeof(bool)* symnum); expressiondo(nxtlev,ptx,lev); if(i!=0)//如果不曾出错,i将不为0,i所指为当前语句 //左部标识符在符号表中的位置 { gendo(sto,lev-table[i].level,table[i].adr); } } else if(sym==timeseql) // *=运算 { getsymdo; memcpy(nxtlev,fsys,sizeof(bool)* symnum); gendo(lod,lev-table[i].level,table[i].adr); expressiondo(nxtlev,ptx,lev); if(i!=0) { 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); if(i!=0) { gendo(opr,0,5); gendo(sto,lev-table[i].level,table[i].adr); } } else if(sym==plusplus) // 后++运算 { getsymdo; gendo(lod,lev-table[i].level,table[i].adr);//找到变量地址,将其值入栈 gendo(lit,0,1);//将常数1取到栈顶 if(i!=0) { gendo(opr,0,2); //执行加操作 gendo(sto,lev-table[i].level,table[i].adr); } } else if(sym==minusminus) // 后--运算 { getsymdo; gendo(lod,lev-table[i].level,table[i].adr);//找到变量地址,将其值入栈 gendo(lit,0,1);//将常数1取到栈顶 if(i!=0) { gendo(opr,0,3); //执行减操作 gendo(sto,lev-table[i].level,table[i].adr); } } else { error(13); } } } } else if(sym==plusplus) // 前++运算 { 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; gendo(lod,lev-table[i].level,table[i].adr);//找到变量地址,将其值入栈 gendo(lit,0,1);//将常数1取到栈顶 if(i!=0) { gendo(opr,0,2); //执行加操作 gendo(sto,lev-table[i].level,table[i].adr); } } } } else { error(19); } } else if(sym==minusminus) // 前--运算 { 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; gendo(lod,lev-table[i].level,table[i].adr);//找到变量地址,将其值入栈 gendo(lit,0,1);//将常数1取到栈顶 if(i!=0) { gendo(opr,0,3); //执行减操作 gendo(sto,lev-table[i].level,table[i].adr); } } } } else { error(19); } } else if(sym==forsym) //检测到for语句 { 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) error(13); //赋值语句左部标识符后应是赋值号:= else getsymdo; memcpy(nxtlev,fsys,sizeof(bool)*symnum); nxtlev[tosym]=true; //后跟符to和downto nxtlev[downtosym]=true; expressiondo(nxtlev,ptx,lev); //处理赋值语句右部的表达式E1 gendo(sto,lev-table[i].level,table[i].adr); //保存初值 switch(sym) { case tosym: //步长为的向上增加 getsymdo; cx1=cx; //保存循环开始点 //将循环判断变量取出放到栈顶 gendo(lod,lev-table[i].level,table[i].adr); memcpy(nxtlev,fsys,sizeof(bool)*symnum); //处理表达式E2 nxtlev[dosym]=true; //后跟符do expressiondo(nxtlev,ptx,lev); /*判断循环变量条件,比如for i:=E1 to E2 do S中,判断i是否小于E2,如小于等于,继续循环,大于的话,跳出循环*/ gendo(opr,0,13); //生成比较指令,i是否小于等于E2的值 cx2=cx; //保存循环结束点 //生成条件跳转指令,跳出循环,跳出的地址未知 gendo(jpc,0,0); if(sym==dosym) //处理循环体S { getsymdo; statement(fsys,ptx,lev); //循环体处理 //增加循环变量步长为 //将循环变量取出放在栈顶 gendo(lod,lev-table[i].level,table[i].adr); gendo(lit,0,1); //将步长取到栈顶 gendo(opr,0,2); //循环变量加步长 //将栈顶的值存入循环变量 gendo(sto,lev-table[i].level,table[i].adr); gendo(jmp,0,cx1); //无条件跳转到循环开始点 /*回填循环结束点的地址,cx为else后语句执行完的位置,它正是前面未定的跳转地址*/ code[cx2].a=cx; } else { error(29); //for语句中少了do } break; case downtosym: //步长为的向下减少 getsymdo; cx1=cx; //保存循环开始点 //将循环判断变量取出放到栈顶 gendo(lod,lev-table[i].level,table[i].adr); memcpy(nxtlev,fsys,sizeof(bool)*symnum); //处理表达式E2 nxtlev[dosym]=true; //后跟符do expressiondo(nxtlev,ptx,lev); /*判断循环变量条件,比如for i:=E1 downto E2 do S中,判断i是否大于等于E2,如大于等于,继续循环, 小于的话,跳出循环*/ gendo(opr,0,11); //生成比较指令,i是否大于等于E2的值 cx2=cx; //保存循环结束点 //生成条件跳转指令,跳出循环,跳出的地址未知 gendo(jpc,0,0); if(sym==dosym) //处理循环体S { getsymdo; statement(fsys,ptx,lev); //循环体处理 //增加循环变量步长为 //将循环变量取出放在栈顶 gendo(lod,lev-table[i].level,table[i].adr); gendo(lit,0,1); //将步长取到栈顶 gendo(opr,0,3); //循环变量加步长 //将栈顶的值存入循环变量 gendo(sto,lev-table[i].level,table[i].adr); gendo(jmp,0,cx1); //无条件跳转到循环开始点 /*回填循环结束点的地址,cx为else后语句执行完的位置,它正是前面未定的跳转地址*/ code[cx2].a=cx; } else { error(29);//for语句中少了do } break; } } } } else { error(19); //for语句后跟赋值语句,赋值语句左部是变量,缺少变量 } } 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 if(table[i].kind==charcon)//字符型数输入 { gendo(opr,0,19); gendo(sto,lev-table[i].level,table[i].adr); } else { gendo(opr,0,16); gendo(sto,lev-table[i].level,table[i].adr); /* 储存到变量*/ } getsymdo; }while (sym==comma); /*一条read语句可读多个变量 */ } if(sym!=rparen) { error(33); /* 格式错误,应是右括号*/ while(!inset(sym,fsys))/* 出错补救,直到收到上层函数的后跟符号*/ { getsymdo; } } else { getsymdo; } } else { if(sym==writesym) /* 准备按照write语句处理,与read类似*/ { getsymdo; if(sym==lparen) { do{ getsymdo; if(sym==ident) { i=position(id,*ptx); if(i==0) { error(11); /*过程未找到*/ } } memcpy(nxtlev,fsys,sizeof(bool)*symnum); nxtlev[rparen]=true; nxtlev[comma]=true; /* write的后跟符号为)or,*/ expressiondo(nxtlev,ptx,lev);/* 调用表达式处理,此处与read不同,read为给变量赋值*/ if(table[i].kind==charcon) //字符型输出 { gendo(opr,0,17); } else gendo(opr,0,14);/* 生成输出指令,输出栈顶的值*/ }while(sym==comma); if(sym!=rparen) { error(33);/* write()应为完整表达式*/ } else { getsymdo; } } gendo(opr,0,15); /* 输出换行*/ } else { if(sym==callsym) /* 准备按照call语句处理*/ { getsymdo; if(sym!=ident) { error(14); /*call后应为标识符*/ } 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); /*生成call指令*/ } else { error(15); /*call后标识符应为过程*/ } } getsymdo; } } else { if(sym==ifsym) /*准备按照if语句处理*/ { getsymdo; memcpy(nxtlev,fsys,sizeof(bool)*symnum); nxtlev[thensym]=true; nxtlev[dosym]=true; /*后跟符号为then或do*/ conditiondo(nxtlev,ptx,lev); /*调用条件处理(逻辑运算)函数*/ if(sym==thensym) { getsymdo; } else { error(16); /*缺少then*/ } cx1=cx; /*保存当前指令地址*/ gendo(jpc,0,0); /*生成条件跳转指令,跳转地址暂写0*/ statementdo(fsys,ptx,lev); /*处理then后的语句*/ //if(sym==semicolon) //{ // getsymdo; //} if(sym==elsesym)/*than语句后面发现else*/ { getsymdo; cx2=cx; code[cx1].a=cx+1;/*cx为当前的指令地址, cx+1即为then语句执行后的else语句的位置,回填地址*/ gendo(jmp,0,0); statementdo(fsys,ptx,lev); code[cx2].a=cx; /*经statement处理后,cx为else后语句执行 完的位置,它正是前面未定的跳转地址,回填地址*/ } else { code[cx1].a=cx; /*经statement处理后,cx为then后语句执行 完的位置,它正是前面未定的跳转地址*/ } } else { if(sym==beginsym) /*准备按照复合语句处理*/ { getsymdo; memcpy(nxtlev,fsys,sizeof(bool)*symnum); nxtlev[semicolon]=true; nxtlev[endsym]=true;/*后跟符号为分号或end*/ /*循环调用语句处理函数,直到下一个符号不是语句开始符号或收到end*/ 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); /*缺少end或分号*/ } } else { if(sym==whilesym)/*准备按照while语句处理*/ { cx1=cx; /*保存判断条件超作的位置*/ getsymdo; memcpy(nxtlev,fsys,sizeof(bool)*symnum); nxtlev[dosym]=true;/*后跟符号为do*/ conditiondo(nxtlev,ptx,lev); /*调用条件处理*/ cx2=cx; /*保存循环体的结束的下一个位置*/ gendo(jpc,0,0);/*生成条件跳转,但跳出循环的地址未知*/ if(sym==dosym) { getsymdo; } else { error(18); /*缺少do*/ } statementdo(fsys,ptx,lev); /*循环体*/ gendo(jmp,0,cx1);/*回头重新判断条件*/ code[cx2].a=cx; /*反填跳出循环的地址,与if类似*/ } else { memset(nxtlev,0,sizeof(bool)*symnum);/*语句结束无补救集合*/ 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; case charcon: /*名字为字符型*/ gendo(lod,lev-table[i].level,table[i].adr); /*找到字符型地址并将其值入栈*/ break; } } getsymdo; if(sym==plusplus) { gendo(lit,lev-table[i].level,1);//将值为入栈 gendo(opr,lev-table[i].level,2);//+1,栈顶加次栈顶 gendo(sto,lev-table[i].level,table[i].adr);//出栈取值到内存 gendo(lod,lev-table[i].level,table[i].adr);//取值到栈顶 gendo(lit,0,1); gendo(opr,0,3);//栈顶值减 getsymdo; } else if(sym==minusminus) { gendo(lit,lev-table[i].level,1);//将值为入栈 gendo(opr,lev-table[i].level,3);//-1,栈顶加次栈顶 gendo(sto,lev-table[i].level,table[i].adr);//出栈取值到内存 gendo(lod,lev-table[i].level,table[i].adr);//取值到栈顶 gendo(lit,0,1); gendo(opr,0,2);//栈顶值加 getsymdo; } } else if(sym==plusplus) { getsymdo; if(sym==ident) { getsymdo; i=position(id,*ptx); if(i==0) error(11); else { if(table[i].kind==variable) { gendo(lod,lev-table[i].level,table[i].adr);//找到变量地址,将其值入栈 gendo(lit,0,1);//将常数1取到栈顶 gendo(opr,0,2); //执行加操作 gendo(sto,lev-table[i].level,table[i].adr);//出栈取值到内存 gendo(lod,lev-table[i].level,table[i].adr);//取值到栈顶 } } } } else if(sym==minusminus) { getsymdo; if(sym==ident) { getsymdo; i=position(id,*ptx); if(i==0) error(11); else { if(table[i].kind==variable) { gendo(lod,lev-table[i].level,table[i].adr);//找到变量地址,将其值入栈 gendo(lit,0,1);//将常数1取到栈顶 gendo(opr,0,3); //执行减操作 gendo(sto,lev-table[i].level,table[i].adr);//出栈取值到内存 gendo(lod,lev-table[i].level,table[i].adr);//取值到栈顶 } } } } 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) /*准备按照odd运算处理*/ { getsymdo; expressiondo(fsys,ptx,lev); gendo(opr,0,6); /*生成odd指令*/ } 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&&sym!=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]; /*栈*/ //double s[stacksize]; //改成doubule型栈 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: /*将a的值取到栈顶*/ 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: 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://14号操作为输出栈顶值操作 printf("%d",s[t-1]);//未修改成实型字符型型前 fprintf(fa2,"%d",s[t-1]); //printf("%d",(int)s[t-1]);//输出栈顶值,强制转换类型 //fprintf(fa2,"%lf\n",s[t-1]);//同时打印到文件 t--;//栈顶下移 break; case 15://15号操作为输出换行操作 printf("\n"); fprintf(fa2,"\n"); break; case 16: printf("?"); fprintf(fa2,"?"); scanf("%d",&(s[t])); fprintf(fa2,"%d\n",s[t]); //printf("输入整型数:"); //fprintf(fa2,"输入整型数:"); //scanf("%lf",&(s[t])); //fprintf(fa2,"%lf\n",s[t]); t++; break; case 17://17号操作为输出栈顶值操作 printf("输出字符:"); printf("%c\n",s[t-1]);//输出栈顶值 fprintf(fa2,"%c\n",s[t-1]);//同时打印到文件 t--;//栈顶下移 break; /*case 18://18号操作为输出栈顶值操作 printf("%lf",s[t-1]);//输出栈顶值 fprintf(fa2,"%lf\n",s[t-1]);//同时打印到文件 t--;//栈顶下移? break;*/ case 19://19号操作是接受键盘值输入到栈顶 printf("输入单字符:");//屏显问号 fprintf(fa2,"输入单字符:");//同时输出到文件 getchar();//消除输入的enter scanf("%c",&(s[t])); //scanf("%s",sta); //s[t]=sta[0];//获得输入 fprintf(fa2,"%c\n",s[t]);//把用户输入值打印到文件 t++;//栈顶上移,分配空间 break; /*case 20://20号操作是接受键盘值输入到栈顶 printf("输入双精度型数:");//屏显问号 fprintf(fa2,"输入双精度型数:");//同时输出到文件 scanf("%lf",&(s[t]));//获得输入 fprintf(fa2,"%lf\n",s[t]);//把用户输入值打印到文件 t++;//栈顶上移,分配空间 break;*/ } break; case lod: /*取相对当前过程的数据基地址为a的内存的值到栈顶*/ s[t]=s[base(i.l,s,b)+i.a]; t++; break; case sto: /*栈顶的值存到相对当前过程的数据基地址为a的内存*/ 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; /*将本过程基地址入栈,此两项用于base函数*/ 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);}/*通过过程基址求上1层过程的基址*/int base(int l,int * s,int b){ int b1; b1=b; while(l>0) { b1=s[b1]; l--; } return b1;}
- 编译原理课程设计-PL/0编译器的扩充(C语言完整版)
- 编译原理Pl/0语言 简单编译器思路
- 编译原理 编译器的实现(C语言实现)
- (编译原理)TINY扩充语言的语法分析
- PL/0语言编译器扩展 编译原理课程实践(1)
- 编译原理实验:写一个PL/0的编译器
- PL/0编译器---扩充IF-THEN-ELSE条件语句;
- 《C编译原理》自己写C语言编译器
- C语言的负数扩充
- C语言的编译器及编译过程
- 编译原理课程设计---用java写的SNLCompiler(简单嵌套语言SNL的编译程序)
- 小白说编译原理-9-最简单minus-c语言编译器
- 编译原理实验一:简单PL/0词法分析器C语言代码
- 编译原理课程设计_C--编译器_语法分析&代码生成
- 编译原理课程设计_C--编译器_语法分析&代码生成 - Justin
- C++语言对C语言的扩充
- 我的C语言课程设计
- 编译原理 实验1 PL/0语言词法分析
- #296 (div.2) C.Glass Carving
- android仿多看阅读三屏滚动效果 -- 更改OnPageChangeListener
- Unity4.6.3编译android版本报错,Creating directory failed
- 栋栋晓02:jQuery基础知识(转)
- 作业P51-11
- 编译原理课程设计-PL/0编译器的扩充(C语言完整版)
- 关于cocos2dx3.2返回键问题以及ansi转utf8的问题
- Lucene的IndexModifier方法
- linux 散知识点
- Java误区之长整除
- nyoj19 擅长排列的小明
- ViewPager实现导航页
- 为Git设置代理(zt)
- [LeetCode 160]Intersection of Two Linked Lists