⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pl0.cpp

📁 pl0的编译程序
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*使用方法:
运行后输入PL/0源程序文件名
回答是否输出虚拟机代码
回答是否输出名字表
fa.tmp 输出虚拟机代码
fa1.tmp 输出源文件及其各行对应的首地址
fa2.tmp 输出结果
fas.tmp 输出名字表
*/

#include<stdio.h>
#include"pl0.h"
#include"string.h"                  

#define stacksize 500                //解释执行时使用的栈                                                                                           */

//////////////////////////////////////////////////////////////////////////////////////////////////
int main()                           //主函数
{
	bool nxtlev[symnum]={0};

//	printf("Input pl/0 file?");      //输入文件名    
//	scanf("%s",fname);  
	fin=fopen("pl0.txt","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.tmp","w");
		fprintf(fa1,"Input pl/0 file?");
		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");
				return 0;
			}
			fclose(fa);
			fclose(fa1);
			fclose(fas);

			if(sym!=period)
			{
				error(9);
			}
			else
			{
				if(err==0)
				{
					fa2=fopen("fa2.tmp","w");
					interpret();                               //调用解释执行程序
					fclose(fa2);
				}
				else
				{
					printf("\nErrors in pl/0 program\n");
				}
			}
		}
		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);
	space[cc-1]=0;
	printf("****%s!%d\n",space,n);
	fprintf(fa1,"****%s!%d\n",space,n);
	err++;
}

//////////////////////////////////////////////////////////////////////////////////////////////////
//漏掉空格,读取一个字符,每次读一行,存入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)                                  //每次读取一行
		{
			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)           //忽略空格,换行,Tab
	{
		getchdo;
	}

	if(ch>='a'&&ch<='z')                     //名字或保留字以a...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')                              //检测是否为数字:以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];                     //当符号不满足上述条件时,全部按照单字符符号处理
						if(sym!=period)
						{
							getchdo;
						} 
					}
				}
			}
		} 
	}
    return 0;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int gen(enum fct x,int y,int z)                  //生成虚拟机代码x:instruction.f; y:instruction.l; z:instruction.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;
} 

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

	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("\n%d const: %s",i,table[i].name);
				printf("\tval=%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("\n%d var: %s",i,table[i].name);
				printf("\tlev=%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("\n%d proc: %s",i,table[i].name);
				printf("\tlev=%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 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;
		}
}

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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -