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

📄 编译大作业.cpp

📁 这是一个用c语言编写的编译大作业
💻 CPP
📖 第 1 页 / 共 2 页
字号:
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);			
		}
	}
}
//语句处理
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)
				{  //expression将执行一系列指令,但最终结果将会保存在栈顶,执行sto命令完成赋值
					gendo(sto,lev-table[i].level,table[i].adr);
				}
			}
		}
	}
	else if(sym==readsym) //准备按照read语句处理                            
	{
		getsymdo;
		if(sym!=lparen)
		{
			error(34); //格式错误,应是左括号
		}
		else
		{
			do{
				getsymdo;
				if(sym==ident)
				{
					i=position(id,*ptx); //查找要读的变量
				}
				else
				{
					i=0;
				}
				if(i==0)
				{
					error(35); //read()中应是声明过的变量名
				}
				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); //生成输出指令,输出栈顶的值
			gendo(opr,0,15);
			}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; //后跟符号为then		  
		conditiondo(nxtlev,ptx,lev); //调用条件处理(逻辑运算)函数
		if(sym==thensym)
		{
			getsymdo;
		}
		else
		{
			error(16); //缺少then
		}
		cx1=cx; //保存当前指令地址
		gendo(jpc,0,0); //生成条件跳转指令,跳转地址暂写0
		nxtlev[elsesym]=true; //后跟符号为else
		statementdo(fsys,ptx,lev); //处理then后的语句
		if(sym==elsesym)
		{	
			cx2=cx; //记录当前虚拟机代码指针位置
		    gendo(jmp,0,0); //为跳转到else语句后的语句准备,其跳转地址在后面填写
		 	getsymdo;
			memcpy(nxtlev,fsys,sizeof(bool)*symnum);
			nxtlev[elsesym]=true;
			statementdo(fsys,ptx,lev);
			code[cx1].a=cx2+1; //填写跳转至else部分的jpc语句的地址
			code[cx2].a=cx; //填写跳过else部分的jmp语句的地址
		}
		else
		{		
			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;
    else if(sym==repeatsym)
	{
GetSym(); CX1=CX;
STATEMENT(SymSetUnion(SymSetNew(SEMICOLON,
UNTILSYM,DOWHILESYM),FSYS),LEV,TX);
while(SymIn(SYM,SymSetAdd(SEMICOLON,STATBEGSYS)))
{ if(SYM==SEMICOLON) GetSym();
else Error(10);
STATEMENT(SymSetUnion(SymSetNew(SEMICOLON,
UNTILSYM,DOWHILESYM),FSYS),LEV,TX);
}
flag=SYM; GetSym();
CONDITION(FSYS,LEV,TX);
CX2=CX; GEN(JPC,0,0);
CX3=CX; GEN(JMP,0,0); //CX3是一个整型局部量
if(flag==UNTILSYM)
{ CODE[CX2].A=CX1; CODE[CX3].A=CX; }
else
{ CODE[CX2].A=CX; CODE[CX3].A=CX1; }
break;

    
}
//表达式处理
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)
{
	int i;
	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;
			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
			{
				error(25); //关系运算符后面应该是标识符
			}
			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 bl;
	bl=b;
	while(l>0)
	{
		bl=s[bl];
		l--;
	}
	return bl;
}

⌨️ 快捷键说明

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