pl0cpp.docx

上传人:b****6 文档编号:7417153 上传时间:2023-01-23 格式:DOCX 页数:43 大小:25.91KB
下载 相关 举报
pl0cpp.docx_第1页
第1页 / 共43页
pl0cpp.docx_第2页
第2页 / 共43页
pl0cpp.docx_第3页
第3页 / 共43页
pl0cpp.docx_第4页
第4页 / 共43页
pl0cpp.docx_第5页
第5页 / 共43页
点击查看更多>>
下载资源
资源描述

pl0cpp.docx

《pl0cpp.docx》由会员分享,可在线阅读,更多相关《pl0cpp.docx(43页珍藏版)》请在冰豆网上搜索。

pl0cpp.docx

pl0cpp

/*编译和运行环境

*VisualC++6.0,VisualC++.netandVisualC++.net2003

*WinNT,Win2000,WinXPandWin2003

*2gccversion3.3.220031022(RedHatLinux3.3.2-1)

*RedhatFedoracore1

*intel32platform

*使用方法:

*运行后输入pl/0源程序文件名称

*回答是否输出虚拟机代码

*回答是否输出名字表

*fa.tmp输出虚拟机代码

*fa1.tmp输出源文件及其各行对应的首地址

*fa2.tmp输出结果

*fas.tmp输出名字表

*/

#include

#include"pl0.h"

#include"string.h"

//解释执行时使用的栈

#definestacksize500

intmain()

{

boolnxtlev[symnum];

printf("Inputpl/0file?

");

scanf("%s",fname);//输入文件名

fin=fopen(fname,"r");

if(fin)

{

printf("Listobjectcode?

(N/Y)");//是否输出虚拟机代码

scanf("%s",fname);

listswitch=(fname[0]=='y'||fname[0]=='Y');

printf("Listsymboltable?

(Y/N)");//是否输出名字表

scanf("%s",fname);

tableswitch=(fname[0]=='y'||fname[0]=='Y');

fa1=fopen("fa1.tmp","w");

fprintf(fa1,"Inputpl/0file?

");

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");

return0;

}

fclose(fa);

fclose(fa1);

fclose(fas);

if(sym!

=period)

{

error(9);

}

if(err==0)

{

fa2=fopen("fa2.tmp","w");

interpret();//调用解释执行程序

fclose(fa2);

}

else

{

printf("Errorsinpl/0program");

}

}

fclose(fin);

}

else

{

printf("Can'topenfile!

\n");

}

printf("\n");

return0;

}

//初始化

voidinit()

{

inti;

//设置单字符符号

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

{

declbegsys[i]=false;

statbegsys[i]=false;

facbegsys[i]=false;

}

/*PL/0C-代码432-434页--LAN*/

/*设置声明开始符号集*/

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;

}

/*

*用数组实现集合的集合运算

*/

intinset(inte,bool*s)

{

returns[e];

}

intaddset(bool*sr,bool*s1,bool*s2,intn)

{

inti;

for(i=0;i

{

sr[i]=s1[i]||s2[i];

}

return0;

}

intsubset(bool*sr,bool*s1,bool*s2,intn)

{

inti;

for(i=0;i

{

sr[i]=s1[i]&&(!

s2[i]);

}

return0;

}

intmulset(bool*sr,bool*s1,bool*s2,intn)

{

inti;

for(i=0;i

{

sr[i]=s1[i]&&s2[i];

}

return0;

}

/*

*出错处理,打印错误位置和错误编码

*/

voiderror(intn)

{

charspace[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++;

}

/*

*漏掉空格,读取一格字符

*

*每次读一行,存入line环从区,line被getsym取空后再读一行

*

*被函数getsym调用

*/

intgetch()

{

if(cc==ll)

{

if(feof(fin))

{

printf("programincomplete");

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++;

return0;

}

/*

*词法分析,获取一个符号

*/

intgetsym()

{

inti,j,k;

while(ch==''||ch==10||ch==9)/*忽略空格,换行和TAB*/

{

getchdo;

}

if(ch>='a'&&ch<='z')/*名字或保留字以a..z开头*/

{

k=0;

do{

if(k

{

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')/*检测是否为数字,以0..9开头*/

{

k=0;

num=0;

sym=number;

do{

//435

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=='<')//检测小于或小于等于符号

{

getch();

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;

//richard

if(sym!

=period)

{

getchdo;

}

//endrichard

}

}

}

}

}

return0;

}

/*

*生成虚拟机代码

*

*x:

instruction.f;

*y:

instruction.l;

*z:

instruction.a;

*/

intgen(enumfctx,inty,intz)

{

if(cx>=cxmax)

{

printf("Programtoolong");//程序过长

return-1;

}

code[cx].f=x;

code[cx].l=y;

code[cx].a=z;

cx++;

return0;

}

/*

*测试当前符号是否合法

*

*在某一部分(如一条语句,一个表达式)将要结束时我们希望下一个符号属于某个集合

*(该部分的后跟符号),test负责这项检测,并且负责当检测不通过时的补救措施

*程序在需要检测时指定当前需要的符号集合和补救用的集合(如之前未完成部分的后跟

*符号),以及检测不通过时的错误信号

*

*s1:

我们需要的符号

*s2:

如果不是我们需要的,则需要一个补救集合

*n:

错误号

*/

inttest(bool*s1,bool*s2,intn)

{

if(!

inset(sym,s1))

{

error(n);

//当检测不通过时,不停获取符号,直到它属于需要的集合后补救的集合

while((!

inset(sym,s1))&&(!

inset(sym,s2)))

{

getsymdo;

}

}

return0;

}

/*

*编译程序主体

*

*lev:

当前分程序所在层

*tx:

名字表当前尾指针

*fsys:

当前模块后跟符号集合

*/

intblock(intlev,inttx,bool*fsys)

{

inti;

intdx;//名字分配到的相对地址

inttx0;//保留初始tx

intcx0;//保留初始cx

boolnxtlev[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);

while(sym==comma)

{

getsymdo;

constdeclarationdo(&tx,lev,&dx);//dx的值会被constdeclaration改变,

}//使用指针

if(sym==semicolon)

{

getsymdo;

//437

/*438页*/

}

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;

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)

{

caseconstant:

printf("%dconst%s",i,table[i].name);

printf("val=%d\n",table[i].val);

fprintf(fas,"%dconst%s",i,table[i].name);

fprintf(fas,"val=%d\n",table[i].val);

break;

casevariable:

printf("%dvar%s",i,table[i].name);

printf("lev=%daddr=%d\n",table[i].level,table[i].adr);

fprint

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 小学教育 > 语文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1