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

📄 compiler.cpp

📁 PL0的一个编译器
💻 CPP
📖 第 1 页 / 共 4 页
字号:
void term(struct node *fsys)
{    
	 char mulop[10];
	 int m=0;
	 int n=0;
	 struct node *tp;
     char *tpset[]={"times","slash",NULL};
	 tp=(struct node *)malloc(sizeof(struct node));
	 
	 while(tpset[m]!=NULL)
		 tp->pa[m++]=tpset[n++];
	 tp->pa[m]=NULL;
	
	 factor(add(tp,fsys));		 	 //每一个项都应该由因子开始,因此调用factor子程序分析因子
     while(in(sym,tp)==1)			 //一个因子后应当最到乘号或除号
	 {
		 strcpy(mulop,sym);			 //保存当前运算符
         getsym();					 //获取下一个token
		 factor(add(tp,fsys));		 //运算符后应是一个因子,故调用factor子程序分析因子
		 if(strcmp(mulop,"times")==0)//如果刚才遇到乘号
			 gen(opr,0,4);			 //生成乘法指令
		 else						 
			 gen(opr,0,5);			 //不是乘号一定是除号,生成除法指令

	 }
}//term end

//算术表达式处理过程expression
void expression(struct node *fsys)
{
	 char addop[10];
	 int m=0,n=0;
	 struct node *tp;
	 char *tpset[]={"plus","minus",NULL};
	 tp=(struct node *)malloc(sizeof(struct node));
     
	 while(tpset[n]!=NULL)
		 tp->pa[m++]=tpset[n++];
	 tp->pa[m]=NULL;
     
	 if(in(sym,tp)==1)					//一个表达式可能会由加号或减号开始,表示正负号
	 {
		 strcpy(addop,sym);				//把当前的正号或负号保存起来,以便下面生成相应代码
		 getsym();						//获取一个token;
		 term(add(fsys,tp));			//正负号后面应该是一个项,调term子程序分析
		 if(strcmp(addop,"minus")==0)   //如果保存下来的是负号
		     gen(opr,0,1);				//生成一条1号操作指令:取反运算
										//如果不是负号就是正号,正号不需要生成相应的指令
	 }
	 else
		 term(add(fsys,tp));			//如果不是由正负号开头,就应是一个项开头,调用term子程序分析项
	 while(in(sym,tp)==1)				//项后应该是回法运算符+/-
	 {
		 strcpy(addop,sym);				//把运算符保存下来
		 getsym();						//获取下一个token
		 term(add(fsys,tp));			//调用term子程序分析项
		 if(strcmp(addop,"plus")==0)	//如果项与项之间的运算符是加号
			gen(opr,0,2);				//生成2号操作指令:加法
	     else
			gen(opr,0,3);				//生成3号操作指令:减法
	 }
}//expression end



//条件处理过程
void condition(struct node *fsys)
{
	char relop[10];					//用于临时记录token(这里一定是一个二元逻辑运算符的内容)
	int m=0,n=0;
	struct node *tp;
	char *tpset[]={"eql","neq","lss","leq","gtr","geq",NULL};
	tp=(struct node*)malloc(sizeof(struct node));

    while(tpset[n]!=NULL)
		tp->pa[m++]=tpset[n++];
	tp->pa[m]=NULL;

	if(strcmp(sym,"oddsym")==0)      //如果是odd运算符(一元)
	{
		getsym();					//获取下一个token
		expression(fsys);			//对odd的表达式进行处理计算
		gen(opr,0,6);				//生成6号操作指令:奇偶判断运算
	}
	else							//如果不是odd运算符(那就一定是二元逻辑运算符)
	{
		expression(add(tp,fsys));	//对表达式左部进行处理计算
		if(in(sym,tp)==0)			//如果token不是逻辑运算符中的一个
			error(20);				//抛出20号错误
		else
		{
			strcpy(relop,sym);		//记录下当前的逻辑运算符
			getsym();				//获取下一个token
			expression(fsys);		//对表达式右部进行处理计算
		
			//如果刚才的运算符是下面的一种
			if(strcmp(relop,"eql")==0)
				gen(opr,0,8);		//如果是等号,产生8号判等指令
			if(strcmp(relop,"neq")==0)
				gen(opr,0,9);		//如果是不等号,产生9号判不等指令
			if(strcmp(relop,"lss")==0)
				gen(opr,0,10);		//如果是小于号,产生10号判小指令
			if(strcmp(relop,"geq")==0)
				gen(opr,0,11);		//如果是大于等于号,产生11号判不小于指令
			if(strcmp(relop,"gtr")==0)
				gen(opr,0,12);		//如果是大于号,产生12号判大于指令
			if(strcmp(relop,"leq")==0)
				gen(opr,0,13);		//如果是小于等于号,产生13号判不大于指令
		}
	}
}//condition end


//语句处理过程
void statement(struct node *fsys,int plev)
{
	int m=0,n=0;
	int i,cx1,cx2;
	char *tempset1[]={"rparen","comma",NULL};
	char *tempset2[]={"thensym","dosym",NULL};
	char *tempset3[]={"semicolon","endsym",NULL};
	char *tempset4[]={"semicolon",NULL};
	char *tempset5[]={"dosym",NULL};
	char *tempset6[]={NULL};

	struct node *temp1,*temp2,*temp3,*temp4,*temp5,*temp6;
	temp1=(struct node *)malloc(sizeof(struct node));
	temp2=(struct node *)malloc(sizeof(struct node));
	temp3=(struct node *)malloc(sizeof(struct node));
	temp4=(struct node *)malloc(sizeof(struct node));
	temp5=(struct node *)malloc(sizeof(struct node));
	temp6=(struct node *)malloc(sizeof(struct node));

	while(tempset1[n]!=NULL)
		temp1->pa[m++]=tempset1[n++];
	temp1->pa[m]=NULL;

	m=0;
	n=0;
	while(tempset2[n]!=NULL)
		temp2->pa[m++]=tempset2[n++];
	temp2->pa[m]=NULL;

	m=0;
	n=0;
	while(tempset3[n]!=NULL)
		temp3->pa[m++]=tempset3[n++];
	temp3->pa[m]=NULL;

	m=0;
	n=0;
	while(tempset4[n]!=NULL)
		temp4->pa[m++]=tempset4[n++];
	temp4->pa[m]=NULL;

	m=0;
	n=0;
	while(tempset5[n]!=NULL)
		temp5->pa[m++]=tempset5[n++];
	temp5->pa[m]=NULL;

	m=0;
	n=0;
	while(tempset6[n]!=NULL)
		temp6->pa[m++]=tempset6[n++];
	temp6->pa[m]=NULL;

	m=0;
	n=0;

	if(strcmp(sym,"ident")==0)			 //所谓语句可能是赋值语句,以标识符开头
	{
		i=position(id);					 //在符号表中查到该符号所在位置
		if(i==0)
			error(11);					 //如果没有找到,抛出11号错误
		else
		{
			if(table1[i].kind!=variable) //如果在符号表中找到该标识符,但该标识符不是变量名
			{	
				error(12);				 //
				i=0;
			}
		}
		getsym();						//获取下一个token,正常应为赋值符号
		if(strcmp(sym,"becomes")==0)	//如果的确为赋值符号
			getsym();					//获取下一个token,正常应为一个表达式
		else
			error(13);					//如果不是赋值号,抛出13号错误
		expression(fsys);				//处理表达式
		if(i!=0)						//如果不曾出错,i将不为0,i所指为当前语句左部标识符在符号表中的位置
			gen(sto,plev-table1[i].level,table1[i].adr);//产生一行指把表达式值写往指定内存的sto目标代码
	}
	
	else if(strcmp(sym,"readsym")==0)	//如果不是赋值语句,而是遇到了read语句
	{
		getsym();						//获取下一个token,正常情况下应为左括号
		if(strcmp(sym,"lparen")!=0)
			error(24);					//如果read后跟的不是左括号,抛出34错误
		else
		{
			do//循环不断生成代码直到read语句的参数表中的变量遍历完为止,这里最到不是逗号,应为右括号
			{
				getsym();				//token,正常应是一个变量名
				if(strcmp(sym,"ident")==0)//如果确为一个标识符
					i=position(id);		//查符号表,找到它所在位置给i,找不到i会为0
				else
					i=0;
				if(i==0)
					error(35);
				else
				{
					gen(opr,0,16);
					gen(sto,plev-table1[i].level,table1[i].adr);
				}
				getsym();
			}while(strcmp(sym,"comma")==0);
		}
			
		if(strcmp(sym,"rparen")!=0)
		{
			error(22);
			while(in(sym,fsys)==0)
				getsym();
		}
		else
			getsym();	//如果read语句正常结束,得到下一个token,一般为分号,或end

	}

	else if(strcmp(sym,"writesym")==0)		//如果最到了write语句
	{
		getsym();							//获取下一个token,应为左括号
		if(strcmp(sym,"lparen")==0)			//如果确为左括号
		{
			do	//循环直到遇到的不再是逗号,这时应是右括号
			{
				getsym();					//获取下一个token,这里应是一个标识符
				expression(add(temp1,fsys));	//调用expression过程分析表达式,用于出错恢复的集合中加上右括号和逗号
				gen(opr,0,14);				//生成14号指令,向屏幕输出
			}while(strcmp(sym,"comma")==0);
			
			if(strcmp(sym,"rparen")!=0)		//如果不是右括号
				error(33);					//抛出33号错误
			else
				getsym();
		}
		gen(opr,0,15);						//生成一个15号操作的目标代码,功能是输出一个换行
	}

	else if(strcmp(sym,"callsym")==0)		//如果是call语句
	{
		getsym();							//获取token,应是过程名标识符
		if(strcmp(sym,"ident")!=0)			//如果call后面跟的不是标识符
			error(14);						//抛出14号错误
		else
		{
			i=position(id);					//从符号表中找出相应的标识符
			if(i==0)							//如果没找到
				error(11);					//抛出11号错误
			else							//如果找到标识符位于符号表第i位置
			{
				if(table1[i].kind==procedur)//如果这个标识符为一个过程名
					gen(cal,plev-table1[i].level,table1[i].adr);//生cal目标代码,呼叫这个过程
				else
					error(15);				//如果call后面跟的不是过程名,抛出15号错误
			}
			getsym();						//获取下一个token
		}
	}

	else if(strcmp(sym,"ifsym")==0)			//如果是if语句
	{
		getsym();							//获取下一个token,应是一个逻辑表达式
		condition(add(temp2,fsys));			//对逻辑表达式进行分析计算,出错恢复集中加入then和do语句
		if(strcmp(sym,"thensym")==0)		//表达式后应最到then语句
			getsym();						//获取then后的token,应是一语句
		else
			error(16);						//如果if后没有then,抛出16号错误
		cx1=cx;								//记下当前代码分配指针位置
		gen(jpc,0,0);						//生成条件跳转指令,跳转位置暂时填0,分析完语句后再填写
		statement(fsys,plev);				//分析then后的语句
		code[cx1].a=cx;						//上一行指令(cx1所指的)的跳转位置应为当前cx所指位置
	}

	else if(strcmp(sym,"beginsym")==0)		//如果遇到begin
	{
		getsym();							//获取下一个token
		statement(add(temp3,fsys),plev);	//对begin与end之间的语句进行分析处理
		
		while(in(sym,add(temp4,statbegsys))==1)//如果分析完一句后遇到分号或语句开始循环分析下一句语句
		{
			if(strcmp(sym,"semicolon")==0)	//如果语句是分号(可能是空语句)
				getsym();					//获取下一个token继续分析
			else
				error(10);					//如果语句与语句间没有分号,出10号错
			statement(add(temp3,fsys),plev);//分析一个语句
		}
		
		if(strcmp(sym,"endsym")==0)			//如果语句全分析完了,应该遇到end
			getsym();						//的确是end ,读下一个token
		else
			error(17);						//如果不是end,抛出17号错误
	}

	else if(strcmp(sym,"whilesym")==0)		//如果遇到while语句
	{
		cx1=cx;							//记下当前代码分配位置,这是while循环的开始位置
		getsym();						//获取下一个token,应为一逻辑表达式
		condition(add(temp5,fsys));		//对这个逻辑表达式进行分析计算
		cx2=cx;							//记下当前代码分配位置,这是while的do中的语句的开始位置			gen(jpc,0,0);					//生成条件跳转指令,跳转位置暂时填0
		gen(jpc,0,0);					//生成条件跳转指令,跳转位置暂置0
		if(strcmp(sym,"dosym")==0)		//逻辑表达式后应为do语句
			getsym();					//获取下一个token		
		else
			error(18);					//while后少do,抛出18号错误码
		statement(fsys,plev);			//分析do后的语句块
		gen(jmp,0,cx1);					//循环跳转到cx1位置,即再次进行逻辑判断
		code[cx2].a=cx;					//把刚才填0的跳转位置改成当前位置,完成while语句的处理
		
	}
	
	
	test(fsys,temp6,19);					//到此一个语句处理完成,一定会遇到fsys集中的符号,如果没有遇到,就抛19号错误
}


void block(int plev,struct node *fsys)
{
	int m=0,n=0;
	int dx=3;					//地址指示器给出每层局部量当前已分配到的相应位置
								//置初始值为3的原因是:每一层最开始的位置有三个空间用于存放静态链SL,动态链DL和返回地址RA
	int tx0=tx;					//初始符号表指针指向当前层的符号在符号表中的开始位置
	lev=plev;
	static int cx0=0;			//起始代码下标
	table1[tx].adr=cx;			//符号表当前位置记下层代码的开始位置

	
	char *tempset1[]={"semicolon","endsym",NULL};
	char *tempset2[]={"ident","procsym",NULL};
	char *tempset3[]={"semicolon",NULL};
	char *tempset4[]={"ident",NULL};
	char *tempset5[]={NULL};

	struct node *temp1,*temp2,*temp3,*temp4,*temp5;
	temp1=(struct node *)malloc(sizeof(struct node));
	temp2=(struct node *)malloc(sizeof(struct node));
	temp3=(struct node *)malloc(sizeof(struct node));
	temp4=(struct node *)malloc(sizeof(struct node));
	temp5=(struct node *)malloc(sizeof(struct node));
//	temp6=(struct node *)malloc(sizeof(struct node));

	while(tempset1[n]!=NULL)
		temp1->pa[m++]=tempset1[n++];
	temp1->pa[m]=NULL;

	m=0;
	n=0;
	while(tempset2[n]!=NULL)
		temp2->pa[m++]=tempset2[n++];
	temp2->pa[m]=NULL;

	m=0;
	n=0;
	while(tempset3[n]!=NULL)
		temp3->pa[m++]=tempset3[n++];
	temp3->pa[m]=NULL;

	m=0;
	n=0;
	while(tempset4[n]!=NULL)
		temp4->pa[m++]=tempset4[n++];
	temp4->pa[m]=NULL;

	m=0;
	n=0;
	while(tempset5[n]!=NULL)
		temp5->pa[m++]=tempset5[n++];
	temp5->pa[m]=NULL;

	m=0;
	n=0;

	gen(jmp,0,1);				//产生一行跳转指令,跳转达位置暂时未知填0
	
	if(plev>LEVMAX)				//如果当前过程嵌套层数大于最大允许的套层数
		error(32);				//抛出32号错误

	do
	{
		if(strcmp(sym,"constsym")==0)
		{
			getsym();

	
			do
			{
				constdeclaration();				//声明以当前token为标识符的常量
				while(strcmp(sym,"comma")==0)	//如果最到了逗号则反复声明下一个常量

⌨️ 快捷键说明

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