学习使用的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

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

Andrej Karpathy最新采访:认知核心模型10亿参数就够了,AI会打破教育不公的僵局

夕小瑶科技说 原创  作者 | 海野 AI圈子的红人,AI大神Andrej Karpathy,曾是OpenAI联合创始人之一,特斯拉AI总监。上一次的动态是官宣创办一家名为 Eureka Labs 的人工智能+教育公司 ,宣布将长期致力于AI原生教育。 近日,Andrej Karpathy接受了No Priors(投资博客)的采访,与硅谷知名投资人 Sara Guo 和 Elad G