学习使用的PL/0编译器增强版PL/0plusplusCompiler(二)加入支持命令行参数

本文主要是介绍学习使用的PL/0编译器增强版PL/0plusplusCompiler(二)加入支持命令行参数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

每次程序运行后输入源码文件名不是很好,于是做了支持命令行参数的改进。大体思路:在main函数入口加入命令行参数,进入main后判断文件名是否为空,为空就退出,否则就继续编译。
在main的括号中加入

int argc, char** argv

在main第一行加入

 /*如果没有在命令行中输入文件名会提示输入源码文件名*/if(argv[1]==NULL){printf("请输入源程序!\n");return;}

把这两行注释掉

//  printf("Input pl/0 file ?");
//  scanf("%s",fname); 

读取文件改成

fin=fopen(argv[1],"r");

效果:
这里写图片描述
PL0.c完整代码

/*编译和运行环境:
*1Visual C++6.0,VisualC++.NET and Visual C++.NET 2003
*WinNT, Win 200, WinXP and  Win2003 
*2 gcc version 3.3.2  20031022(Red Hat Linux 3.3.2-1)
*Redhat Fedora core 1
*Intel 32 platform
*使用方法:
*运行后输入PL/0 源程序文件名
*回答是否输出虚拟机代码
*回答是否输出名字表
*fa.txt 输出虚拟机代码
*fa1.txt  输出源文件及其各行对应的首地址
*fa2.txt  输出结果 
*fas.txt  输出名字表
*//*
改进:
*1.编译文件使用命令行参数
*
*
*/#include <stdio.h>
#include "PL0.h"
#include "string.h"
/*解释执行时使用的栈*/
#define stacksize 500
int main(int argc, char** argv)
{/*如果没有在命令行中输入文件名会提示输入源码文件名*/if(argv[1]==NULL){printf("请输入源程序!\n");return;}bool nxtlev[symnum];
//  printf("Input pl/0 file ?");
//  scanf("%s",fname); fin=fopen(argv[1],"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.txt","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.txt","w");fas=fopen("fas.txt","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.txt", "w");interpret();fclose(fa2);}else{printf("Errors in pl/0 program");}}fclose(fin);}else{printf("Can't open file! \n");}printf("\n");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]),"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<symnum;i++){declbegsys[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;
}
/*
*用数组实现集合的集合运算
*/
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-1printf("****%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{ sym=lss;}}else{if(ch=='>')          /*检测大于或大于等于符号*/{getchdo;if(ch=='='){sym=geq;getchdo;}else{sym=gtr;}}else{sym=ssym[ch];/* 当符号不满足上述条件时,全部按照单字符号处理*///getchdo;//richardif(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);}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;}}
/*
*查找名字的位置
*找到则返回在名字表中的位置,否则返回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;
}
/*
*输入目标代码清单
*/
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){error(12);i=0;}else{getsymdo;if(sym==becomes){getsymdo;}else{error(13);}memcpy(nxtlev,fsys,sizeof(bool)* symnum);expressiondo(nxtlev,ptx,lev);if(i!=0){gendo(sto,lev-table[i].level,table[i].adr);}}}}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{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;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[rparen]=true;nxtlev[comma]=true;        /* write的后跟符号为)or,*/expressiondo(nxtlev,ptx,lev);/* 调用表达式处理,此处与read不同,read为给变量赋值*/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后的语句*/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;}}getsymdo;}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];      /*栈*/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: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);
}
/*通过过程基址求上1层过程的基址*/
int base(int l,int * s,int b)
{int b1;b1=b;while(l>0){b1=s[b1];l--;}return b1;
}

这篇关于学习使用的PL/0编译器增强版PL/0plusplusCompiler(二)加入支持命令行参数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1101191

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

C++ Primer 多维数组的使用

《C++Primer多维数组的使用》本文主要介绍了多维数组在C++语言中的定义、初始化、下标引用以及使用范围for语句处理多维数组的方法,具有一定的参考价值,感兴趣的可以了解一下... 目录多维数组多维数组的初始化多维数组的下标引用使用范围for语句处理多维数组指针和多维数组多维数组严格来说,C++语言没

在 Spring Boot 中使用 @Autowired和 @Bean注解的示例详解

《在SpringBoot中使用@Autowired和@Bean注解的示例详解》本文通过一个示例演示了如何在SpringBoot中使用@Autowired和@Bean注解进行依赖注入和Bean... 目录在 Spring Boot 中使用 @Autowired 和 @Bean 注解示例背景1. 定义 Stud