为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

pl0源代码

2011-03-22 29页 doc 202KB 31阅读

用户头像

is_591471

暂无简介

举报
pl0源代码程序功能: 源代码 pl0c.h /* 关键字个数 */ #define norw 13 /* 名字表容量 */ #define txmax 100 /* 所有的add1用于定义数组 */ #define txmaxadd1 101 /* number的最大位数 */ #define nmax 14 /* 符号的最大长度 */ #define al 10 /* 地址上界 */ #define amax 2047 /* 最大允许过程嵌套声明层数 */ #define levmax 3 /* 最多的虚拟机代码数 */ #defin...
pl0源代码
程序功能: 源代码 pl0c.h /* 关键字个数 */ #define norw 13 /* 名字表容量 */ #define txmax 100 /* 所有的add1用于定义数组 */ #define txmaxadd1 101 /* number的最大位数 */ #define nmax 14 /* 符号的最大长度 */ #define al 10 /* 地址上界 */ #define amax 2047 /* 最大允许过程嵌套声明层数 */ #define levmax 3 /* 最多的虚拟机代码数 */ #define cxmax 200 #define cxmaxadd1 201 /* 当函数中会发生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 typedef enum {false,true} bool; /* 符号 */ 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}; #define symnum 32 /* 名字表中的类型 */ enum object {constant,variable,procedur}; /* 虚拟机代码 */ enum fct {lit,opr,lod,sto,cal,inte,jmp,jpc}; #define fctnum 8 /* 虚拟机代码结构 */ 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]; /* 当前ident */ int num; /* 当前number */ int cc,ll,kk; /* getch使用的计数器,cc表示当前字符(ch)的位置 */ int cx; /* 虚拟机代码指针 */ char line[81]; /* 读取行缓冲区 */ char a[al]; /* 临时符号 */ struct instruction code[cxmaxadd1]; /* 存放虚拟机代码的数组 */ 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 or procedure */ int val; /* 数值,仅const使用 */ int level; /* 所处层,仅const不使用 */ int adr; /* 地址,仅const不使用 */ int size; /* 需要分配的数据区空间,仅procedure使用 */ }; struct tablestruct table[txmaxadd1]; /* 名字表 */ FILE* fin; FILE* fout; char fname[al]; int err; /* 错误计数器 */ void 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 postion(char* idt,int tx); void enter(enum object k,int* ptx,int lev,int* pdx); int base(int l,int* s,int b); pl0c.c /* Windows 下c语言PL/0编译程序 在Visual C++ 6.0和Visual C.NET上运行通过 使用方法: 运行后输入PL/0源程序文件名 回答是否输出虚拟机代码 回答是否输出名字表 fa.tmp输出虚拟机代码 fa1.tmp输出源文件及其各行对应的首地址 fa2.tmp输出结果 fas.tmp输出名字表 */ #include #include "pl0c.h" #include "string.h" /* 解释执行时使用的栈 */ #define stacksize 500 int main() { bool nxtlev[symnum]; init(); /* 初始化 */ fas=fopen("fas.tmp","w"); fa1=fopen("fa1.tmp","w"); printf("Input file? "); fprintf(fa1,"Input file? "); scanf("%s",fname); /* 输入文件名 */ fin=fopen(fname,"r"); if(fin) { fprintf(fa1,"%s\n",fname); 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'); err=0; cc=cx=ll=0; ch=' '; kk=al-1; if(-1!=getsym()) { fa=fopen("fa.tmp","w"); fa2=fopen("fa2.tmp","w"); addset(nxtlev,declbegsys,statbegsys,symnum); nxtlev[period]=true; if(-1==block(0,0,nxtlev)) /* 调用编译程序 */ { fclose(fa); fclose(fa1); fclose(fin); printf("\n"); return 0; } fclose(fa); fclose(fa1); if(sym!=period)error(9); if(err==0)interpret(); /* 调用解释执行程序 */ else { printf("Errors in pl/0 program"); } } fclose(fin); } else { printf("Can't open file!\n"); fprintf(fa1,"Can't open file!\n"); fclose(fa1); } fclose(fas); printf("\n"); return 0; } /* 在适当的位置显示错误 */ void error(int n) { char space[81]; memset(space,32,81); space[cc-1]=0; /* 出错时当前符号已经读完,所以cc-1 */ printf("****%s!%d\n",space,n); fprintf(fa1,"****%s!%d\n",space,n); err++; } /* 词法分析,获取一个符号 */ int getsym() { int i,j,k; while(ch==' '||ch==10||ch==9) /* 忽略空格、换行和TAB */ { getchdo; } if(ch>='a'&&ch<='z') { /* 名字或保留字以a..z开头 */ k=0; do { if(k='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') { /* 检测是否为数字:以0..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]; /* 当符号不满足上述条件时,全部按照单字符符号处理 */ getchdo; } } } } } return 0; } /* 生成虚拟机代码 */ int gen(enum fct x, /* f */ int y, /* l */ int z /* a */ ) { 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负责这项监测,并且负责当监测不通过时的补救,程序在需要检测时指定当前需要的符 号集合和补救用的集合(如之前未完成部分的后跟符号),以及检测不通过时的错误号 */ 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 tx0; /* 保留初始tx */ int cx0; /* 保留初始cx */ bool nxtlev[symnum]; /* 在下级函数的参数中,符号集合均为值参,但由于使用数租实现, 传递进来的是指针,为防止下级函数改变上级函数的集合,开辟新的空间 传递给下级函数,之后所有的nxtlev都是这样 */ 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); } 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; 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 addr=%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); /*分程序没有补救集合 */ testdo(fsys,nxtlev,8); /* 检测后跟符号正确性 */ listcode(cx0); /* 输出代码 */ 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: /* 将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 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: /* 取相对当前过程的数据基地址为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); fclose(fa2); } /* 初始化 */ 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;iamax) { 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; } } /* 查找名字的位置 */ /* 找到则返回在名字表中的位置,否则返回0 */ int postion(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); /* var后应是标识 */ return 0; } /* 输出代码 */ void listcode(int cx0) { int i; if(listswitch) { for(i=cx0;i
/
本文档为【pl0源代码】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索