编译原理PL0编译程序源代码.docx
《编译原理PL0编译程序源代码.docx》由会员分享,可在线阅读,更多相关《编译原理PL0编译程序源代码.docx(35页珍藏版)》请在冰豆网上搜索。
编译原理PL0编译程序源代码
/*PL/0编译程序(C语言版)
*编译和运行环境:
*VisualC++6.0
*WinXP/7
*使用方法:
*运行后输入PL/0源程序文件名
*回答是否将虚拟机代码写入文件
*回答是否将符号表写入文件
*执行成功会产生四个文件(词法分析结果.txt符号表.txt虚拟代码.txt源程序和地址.txt)
*/
#include
#include"pl0.h"
#include"string"
#definestacksize500//解释执行时使用的栈
intmain(){
boolnxtlev[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);
return0;
}
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'topenfile!
\n");
}
fclose(cifa);//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;ideclbegsys[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;
}//用数组实现集合的集合运算
intinset(inte,bool*s){
returns[e];
}
intaddset(bool*sr,bool*s1,bool*s2,intn){
inti;
for(i=0;isr[i]=s1[i]||s2[i];
return0;
}
voiderror(intn){//出错处理,打印出错位置和错误编码
charspace[81];
memset(space,32,81);
space[cc-1]=0;
printf("error(%d)",n);
fprintf(fa1,"error(%d)",n);
switch(n){
case1:
printf("\t\t常量说明中的“=”写成“:
=”\n");
fprintf(fa1,"\t\t常量说明中的“=”写成“:
=”\n");
break;
case2:
printf("\t\t常量说明中的=后应该是数字\n");
fprintf(fa1,"\t\t常量说明中的=后应该是数字\n");
break;
case3:
printf("\t\t常量说明符中的表示符应该是=\n");
fprintf(fa1,"\t\t常量说明符中的表示符应该是=\n");
break;
case4:
printf("\t\tconst,var,procedure后应为标识符\n");
fprintf(fa1,"\t\tconst,var,procedure后应为标识符\n");
break;
case5:
printf("\t\t漏掉了“,”或“;”\n");
fprintf(fa1,"\t\t漏掉了“,”或“;”\n");
break;
case6:
printf("\t\t过程说明后的符号不正确\n");
fprintf(fa1,"\t\t过程说明后的符号不正确\n");
break;
case7:
printf("\t\t应是语句开始符\n");
fprintf(fa1,"\t\t应是语句开始符\n");
break;
case8:
printf("\t\t程序体内语句部分的后跟符不正确\n");
fprintf(fa1,"\t\t程序体内语句部分的后跟符不正确\n");
break;
case9:
printf("\t\t程序结尾丢了句号“.”\n\n");
fprintf(fa1,"\t\t程序结尾丢了句号“.”\n");
break;
case10:
printf("\t\t语句之间漏了“;”\n");
fprintf(fa1,"\t\t语句之间漏了“;”\n");
break;
case11:
printf("\t\t标识符拼写错误或未说明\n");
fprintf(fa1,"\t\t标识符拼写错误或未说明\n");
break;
case12:
printf("\t\t赋值语句中,赋值号左部标识符属性应是变量\n");
fprintf(fa1,"\t\t赋值语句中,赋值号左部标识符属性应是变量\n");
break;
case13:
printf("\t\t赋值语句左部标识符后应是复制号“:
=”\n");
fprintf(fa1,"\t\t赋值语句左部标识符后应是复制号“:
=”\n");
break;
case14:
printf("\t\tcall后应为标识符\n");
fprintf(fa1,"\t\tcall后应为标识符\n");
break;
case15:
printf("\t\tcall后标识符属性应为过程\n");
fprintf(fa1,"\t\tcall后标识符属性应为过程\n");
break;
case16:
printf("\t\t条件语句中丢了then\n");
fprintf(fa1,"\t\t条件语句中丢了then\n");
break;
case17:
printf("\t\t丢了“end”或“;”\n");
fprintf(fa1,"\t\t丢了“end”或“;”\n");
break;
case18:
printf("\t\twhile型循环语句中丢了“do”\n");
fprintf(fa1,"\t\twhile型循环语句中丢了“do”\n");
break;
case19:
printf("\t\t语句后的符号不正确\n");
fprintf(fa1,"\t\t语句后的符号不正确\n");
break;
case20:
printf("\t\t应为关系运算符\n");
fprintf(fa1,"\t\t应为关系运算符\n");
break;
case21:
printf("\t\t表达式内标示符属性不能是过程\n");
fprintf(fa1,"\t\t表达式内标示符属性不能是过程\n");
break;
case22:
printf("\t\t表达式漏掉了右括号\n");
fprintf(fa1,"\t\t表达式漏掉了右括号\n");
break;
case23:
printf("\t\t因子后的非法符号\n");
fprintf(fa1,"\t\t因子后的非法符号\n");
break;
case24:
printf("\t\t表达式的开始符不能是此符号\n");
fprintf(fa1,"\t\t表达式的开始符不能是此符号\n");
break;
case25:
printf("\t\t标识符越界\n");
fprintf(fa1,"\t\t标识符越界\n");
break;
case26:
printf("\t\t非法字符\n");
fprintf(fa1,"\t\t非法字符\n");
break;
case31:
printf("\t\t数越界\n");
fprintf(fa1,"\t\t数越界\n");
break;
case32:
printf("\t\tread语句括号中的标识符不是变量\n");
fprintf(fa1,"\t\tread语句括号中的标识符不是变量\n");
break;
case33:
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调用
intgetch(){
if(cc==ll){
if(feof(fin)){
printf("programincomplete");
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++;
return0;
}
intgetsym(){//词法分析
inti,j,k,l;
while(ch==''||ch==10||ch==9)//忽略空格换行TAB
getchdo;
if(ch>='a'&&ch<='z'){//以字母开头的为保留字或者标识符
k=0,l=1;
do{
if(ka[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);
}else
fprintf(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");
}
}
}
}
}
}return0;
}
//生成目标代码//目标代码的功能码,层差和位移量
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;
}
//测试字符串
inttest(bool*s1,bool*s2,intn){
if(!
inset(sym,s1)){//测试sym是否属于s1,不属于则报错n
error(n);
while((!
inset(sym,s1))&&(!
inset(sym,s2))){//检测不通过时,不停获得符号,直到它属于需要或补救的集合
getsymdo;
}
}return0;
}
//编译程序主体
//lev:
当前分程序