1、pl0cpp/* 编译和运行环境 * Visual C+6.0,Visual C+.net and Visual C+.net 2003 * WinNT,Win2000,WinXP and Win2003 * 2gcc version 3.3.2 20031022(Red Hat Linux 3.3.2-1) * Redhat Fedora core 1 * intel 32 platform * 使用方法: * 运行后输入pl/0源程序文件名称 * 回答是否输出虚拟机代码 * 回答是否输出名字表 * fa.tmp输出虚拟机代码 * fa1.tmp输出源文件及其各行对应的首地址 * fa2.t
2、mp输出结果 * fas.tmp输出名字表 */#include#includepl0.h#includestring.h/解释执行时使用的栈#define stacksize 500int main() bool nxtlevsymnum; printf(Input pl/0 file?); scanf(%s,fname); /输入文件名 fin=fopen(fname,r); if(fin) printf(List object code ?(N/Y); /是否输出虚拟机代码 scanf(%s,fname); listswitch=(fname0=y | fname0=Y); printf
3、( List symbol table ? (Y/N); /是否输出名字表 scanf(%s,fname); tableswitch=(fname0=y | fname0=Y); fa1=fopen(fa1.tmp,w); fprintf(fa1,Input pl/0 file?); fprintf(fa1,%sn,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
4、, 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 print
5、f (Errors in pl/0 program); fclose (fin); else printf (Cant open file! n); printf (n); return 0; /初始化void init () int i; /设置单字符符号 for (i=0; i=255; i+) ssymi = nul; ssym+ = plus; ssym- = minus; ssym* = times; ssym/ = slash; ssym( = lparen; ssym) = rparen; ssym= = eql; ssym, = comma; ssym. = period; s
6、sym# = neq; ssym; = semicolon; /设置保留字名字,按照字母顺序,便于折半查找 strcpy (&(word 00), begin); strcpy (&(word 10), call); strcpy (&(word 20), const); strcpy (&(word 30), do); strcpy (&(word 40), end); strcpy (&(word 50), if); strcpy (&(word 60), odd); strcpy (&(word 70), procedure); strcpy (&(word 80), read); st
7、rcpy (&(word 90), then); strcpy (&(word 100), var); strcpy (&(word 110), while); strcpy (&(word 120), 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
8、10 = varsym; wsym 11 = whilesym; wsym 12 = writesym; /设置指令名称 strcpy(&(mnemoniclit0),lit); strcpy(&(mnemonicopr0),opr); strcpy(&(mnemoniclod0),lod); strcpy(&(mnemonicsto0),sto); strcpy(&(mnemoniccal0),cal); strcpy(&(mnemonicinte0),int); strcpy(&(mnemonicjmp0),jmp); strcpy(&(mnemonicjpc0),jpc); /设置符号集
9、 for (i=0; isymnum; i+) declbegsys i = false; statbegsys i = false; facbegsys i = false; /*PL/0 C-代码432-434页-LAN */ /*设置声明开始符号集*/ declbegsysconstsym=true; declbegsysvarsym=true; declbegsysprocsym=true; /*设置语句开始符号集*/ statbegsysbeginsym=true; statbegsyscallsym=true; statbegsysifsym=true; statbegsyswhi
10、lesym=true; /*设置因子开始符号集*/ facbegsysident=true; facbegsysnumber=true; facbegsyslparen=true;/*用数组实现集合的集合运算*/int inset(int e,bool* s) return se;int addset(bool* sr,bool* s1,bool* s2,int n) int i; for(i=0;in;i+) sri=s1i|s2i; return 0;int subset(bool* sr,bool* s1,bool* s2,int n) int i; for(i=0;in;i+) sri
11、=s1i&(! s2i); return 0;int mulset(bool* sr,bool* s1,bool* s2,int n) int i; for(i=0;i=a&ch=z) /*名字或保留字以a.z开头*/ k=0; do if(k=a & ch=0 & ch=9); ak=0; strcpy(id,a); i=0; j=norw-1; do /*都多当前符号是否为保留字*/ k=(i+j)/2; if(strcmp(id,wordk)=0) i=k+1; while(ij) sym=wsymk; else /*搜索失败,则是名字或数字*/ sym=ident; else if(c
12、h=0&ch=0 & chnmax) error(30); else if(ch=:) /检测赋值符号 getchdo; if(ch=) sym=becomes; getchdo; else sym=nul; /不能识别的符号 else if(ch=) /检测大于或大于等于符号 getchdo; if(ch=) sym=geq; getchdo; else sym=gtr; else sym=ssymch; /当符号不满足上述条件时,全部按照单符号字符处理 /getchdo; /richard if(sym!=period) getchdo; /end richard return 0;/*
13、* 生成虚拟机代码 * * 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; codecx.f=x; codecx.l=y; codecx.a=z; cx+; return 0; /* * 测试当前符号是否合法 * * 在某一部分(如一条语句,一个表达式)将要结束时我们希望下一个符号属于某个集合 * (该部分的后跟符号),test负责这项检测,并且负责当检
14、测不通过时的补救措施 * 程序在需要检测时指定当前需要的符号集合和补救用的集合(如之前未完成部分的后跟 * 符号),以及检测不通过时的错误信号 * * 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; /* * 编译程序主体 * * le
15、v:当前分程序所在层 * tx:名字表当前尾指针 * fsys:当前模块后跟符号集合 */ int block(int lev,int tx,bool * fsys) int i; int dx; /名字分配到的相对地址 int tx0; /保留初始tx int cx0; /保留初始cx bool nxtlevsymnum; /* 在下级函数的参数中,符号集合均为值参,但由于使用数组 实现,传递进来的指针为防止下级函数改变上级函数的 集合,开辟新的空间传递给下级函数 */ dx=3; tx0=tx; /记录本层名字的初始位置 tabletx.adr=cx; gendo(jmp,0,0); if
16、(levlevmax) error(32); do if(sym=constsym) /收到常量声明符号,开始处理常量声明 getsymdo; do constdeclarationdo(&tx,lev,&dx); while(sym=comma) getsymdo; constdeclarationdo(&tx,lev,&dx); /dx的值会被constdeclaration改变, /使用指针 if(sym=semicolon) getsymdo; /437 /* 438页 */ else error(5); /*漏掉了逗号或者分号*/ while(sym = ident); if(sym
17、 = 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);
18、/*记录过程名字*/ getsymdo; else error(4); /*procedure后应为标志符*/ if(sym = semicolon) getsymdo; else error(5); /*漏掉了分号*/ memcpy(nxtlev,fsys,sizeof(bool)*symnum); nxtlevsemicolon = true; if(-1 = block(lev+1,tx,nxtlev) return -1; /*递归调用*/ if(sym = semicolon) getsymdo; memcpy(nxtlev,statbegsys,sizeof(bool)*symnu
19、m); nxtlevident = true; nxtlevprocsym = true; testdo(nxtlev,fsys,6); else error(5); /*漏掉了分号*/ memcpy(nxtlev,statbegsys,sizeof(bool)*symnum); nxtlevident = true; nxtlevperiod = true; testdo(nxtlev,declbegsys,7); while( inset(sym,declbegsys); /*直到没有声明符号*/ codetabletx0.adr.a = cx; /*开始生成当前过程代码*/ tablet
20、x0.adr =cx; /*当前过程代码地址*/ tabletx0.size = dx; /*声明部分中每增加一条声明都会给dx增加1,声明 部分已经结束,dx就是当前过程数据的size*/ cx0 = cx; gendo(inte,0,dx); /*生成分配内存代码*/ if(tableswitch) /*输出名字表*/ printf(TABLE:n); if(tx0 + 1 tx) printf(NULLn); for(i =tx0+1;i = tx;i+) switch(tablei.kind) case constant: printf(%d const %s,i,tablei.name); printf(val = %dn,tablei.val); fprintf(fas,%d const %s,i,tablei.name); fprintf(fas,val = %dn,tablei.val); break; case variable: printf(%d var %s,i,tablei.name); printf(lev=%d addr=%dn,tablei.level,tablei.adr); fprint
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1