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

📄 pl0.c

📁 本程序实现编译原理中
💻 C
📖 第 1 页 / 共 3 页
字号:
					error(5);
				}
			}while(sym == ident);//indet表示用户定义的常量名,变量名,过程名
		}	
		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);//ident:标识符
		}
		while(sym == procsym)//过程
		{
			getsymdo;
			if(sym == ident)
			{
				enter(procedur,&tx,lev,&dx);//登记过程名
				getsymdo;
			}
			else
			{
				error(4);
			}
			if(sym == semicolon)//";"
			{
				getsymdo;
			}
			else
			{
				error(5);
			}
			memcpy(nxtlev,fsys,sizeof(bool)*symnum);//把方法block()获得参数fsys的值放入数组nxtlev中
			nxtlev[semicolon] = true;
			
			
			if(-1 == block(lev+1,tx,nxtlev))//<--------------递归调用(Warning:层次增一).
			{//变量的分层是在过程的基础上的,此操作是为了获取内层的信息。
			 //如:过程P的信息(P的内层过程Q以前的信息)已经采集完,层加1,采集Q的信息。
			 //一次递推,直到过程的信息被采集完。与过程同层的变量的信息也一样采集
				return -1;
			}
			if(sym == semicolon)//";"
			{
				getsymdo;    
				              //statbegsys:语句开始符号集
				memcpy(nxtlev,statbegsys,sizeof(bool)*symnum);//把语句开始符号的标记加到临时数组nxtlev中
				nxtlev[ident] = true;//标识符行赋true值
				nxtlev[procsym] = true;//过程行赋true值
				testdo(nxtlev,fsys,6);/*block调用返回后*/
			}
			else
			{
				error(5);
			}
		}
						//statbegsys:语句开始符号集
		memcpy(nxtlev,statbegsys,sizeof(bool)*symnum);//
		nxtlev[ident] = true;						  //
		nxtlev[period] = true;						  //准备按语句处理
		testdo(nxtlev,declbegsys,7);/*<><><><><><><><>*/
						//declbegsys:声明开始符号集
	}while(inset(sym,declbegsys));

	/*
	回填跳转指令的地址,跳转指令格式:(JMP 0 a)无条件跳转到地址a .
	由于该程序是先生成内部过程代码,然后生成外部过程代码,这时由程序
	格式决定的,也是由于递归调用决定的,因此一个一个内部嵌有子过程的过程
	在分析之初根本无法知道应该跳到那里去开始执行,那什么时候才知道呢?很明显
	只有把它内部嵌有的所有过程都分析完(产生代码),这时程序才会从递归中退回来
	开始真正(因为上面的分析只是一些声明的处理,只有将这些声明处理完后,才会开
	始分析语句)分析该过程,这时的第一句代码就是跳转指令应跳到的地址。
	*/

	code[table[tx0].adr].a = cx;//跳转指令的跳转地址,即过程代码的首地址。
	table[tx0].adr = cx;//过程代码的首地址
	table[ tx0].size = dx;/*
							过程数据区的大小,数据区只针对变量而言,
							数据区的大小不是说在table表中占有多少空间,
							它指的是在运行栈中的大小。常量被放置在栈中。
							因为常量是不允许修改的,因此将放在栈中操作即可。
							不需要将其放在数据区中。这也是为什么在登记常量时
							没有执行(*pdx)++;这条语句。
						  */

	//cx0 = cx;
	gendo(inte,0,dx);//加入虚拟代码

	if(tableswitch)
	{
		printf("\nHere is the lists of table:%d---%d",tx0,tx);
		printf("\n~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ \n");
		if(tx0+1 > tx)
		{
			printf("There is no symbol in the table!\n");
		}
		for(i = tx0+1;i<=tx;i++)
		{
			switch(table[i].kind)
			{
				case constant:
					printf("%d\tconst\t%s\t",i,table[i].name);
					printf("val=%d\n",table[i].val);
					fprintf(fas,"%d\tconst\t%s\t",i,table[i].name);//打印到文件上
					fprintf(fas,"val=%d\n",table[i].val);
					break;
				case variable:
					printf("%d\tvar\t%s\t",i,table[i].name);
					printf("lev=%d\taddr=%d\t\n",table[i].level,table[i].adr);
					fprintf(fas,"%d\tvar\t%s\t",i,table[i].name);
					fprintf(fas,"lev=%d\taddr=%d\t\n",table[i].level,table[i].adr);
					break;
				case procedur:
					printf("%d\tproce\t%s\t",i,table[i].name);
					printf("lev=%d\taddr=%d\tsize=%d\t\n",table[i].level,table[i].adr,table[i].size);
					fprintf(fas,"%d\tproce\t%s\t",i,table[i].name);
					fprintf(fas,"lev=%d\taddr=%d\tsize=%d\n",table[i].level,table[i].adr,table[i].size);
					break;
			}
		}
		printf("\n~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ \n");
	}


	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);/*<><><><><><><><>block将要退出时*/

	listcode(cx0);

	return 0;
}

/*
参数:enum object k ---- 登录到名字表的标识符的类型(常量、变量、过程)。
	  int* ptx ---- 名字表索引的指针。
	  int lev ---- 将要登录的符号所在层。
	  int* pdx ---- 若将要登录的是一个变量,则(*pdx)代表该变量在数据区中的相对位置????
*/
void enter(enum object k,int* ptx,int lev,int* pdx)
{
	(*ptx)++;


	strcpy(table[(*ptx)].name,id);
	table[(*ptx)].kind = k;
	switch(k)
	{
		/*
		假如在变量声明的之前有常量声明,那么变量的相对地址与没有常量声明一样吗?
		例: const a,b;
			var c,d,e,f;
		*/
		
		case constant://常量
			if(numlen > MAX_NUM_LENGTH)
			{
				error(31);//数字串太长
				num = 0;
			}
			table[(*ptx)].val = num;
			break;
		case variable://变量
			table[(*ptx)].level = lev;
			table[(*ptx)].adr = (*ptx);
			(*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;
}
/*
constdeclaration 函数功能:将常量登记到名字表中,不产生任何代码。
*/
int constdeclaration(int* ptx,int lev,int* pdx)
{

	//<常量说明> ::= const <常量定义>{,<常量定义>};
	//<常量定义> ::= <标识符> = <无符号整数>
	if(sym == ident)
	{
		getsymdo;
		if(sym == eql || sym == becomes)
		{
			if(sym == becomes)//becomes is ':=' 
			{
				error(1);
			}
			getsymdo;
			if(sym == number)
			{
				enter(constant,ptx,lev,pdx);
				getsymdo;
			}
			else
			{
				error(2);
			}
		}
		else
		{
			error(3);
		}
	}
	else
	{
		error(4);
	}
	return 0;
}

/*
vardeclaration 函数功能:将变量登记到名字表中,不产生任何代码。
*/
int vardeclaration(int* ptx,int lev,int* pdx)
{
	//printf("I come into the function vardeclaration!\n");

	if(sym == ident)
	{
		enter(variable,ptx,lev,pdx);
		getsymdo;
	}
	else
	{
		error(4);
	}
	return 0;
}

void listcode(int cx0)
{
	int i;
	
	//printf("I come into the function listcode!\n");

	if(listswitch)
	{
		printf("\n* * * * * * * * * * * * * * * * * * * * * * * * * *\n");
		printf("\tF\tL\tA\n");
		fprintf(fa,"\tF\tL\tA\n");
		for(i=cx0;i<cx;i++)
		{
			//输出格式:指令地址 指令名称 指令所在层 a
			printf("%d\t%s\t%d\t%d\n",i,mnemonic[code[i].f],code[i].l,code[i].a);
			fprintf(fa,"%d\t%s\t%d\t%d\n",i,mnemonic[code[i].f],code[i].l,code[i].a);
		}	
		printf("* * * * * * * * * * * * * * * * * * * * * * * * * *\n");
	}
}

/*
<语句> ::= <赋值语句>|<条件语句>|<当型循环语句>|<过程调用语句>|<读语句>|<写语句>|<复合语句>|<空>
根据sym的值来确定按照某种语句来处理,若是ident调用赋值语句;若是ifsym则调用条件语句;若是whilesym
则调用当型循环语句,依次类推....
<分程序> ::= [<常量说明部分>][<变量说明部分>][<过程说明部分>]<语句>
block()函数负责常量、变量、过程声明的处理,当声明处理完后就只剩下语句了。
由于block是递归调用,所以内层tx>=外层tx,也就是说内部过程可以调用外部过程声明的变量,但反之不可。
*/
int statement(bool* fsys,int* ptx,int lev)
{
	int i,cx1,cx2;
	bool nxtlev[symnum];


	/*
	准备按照赋值语句处理
	<赋值语句> ::= <标识符> := <表达式>
	*/
	if(sym == ident)						
	{
		i = position(id,*ptx);//tx指向表尾
		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);//lev-table[i].level标识符引用层减去标识符定义层
				}
			}
		}
	}
	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);
					}
					else
					{
						gendo(opr,0,16);
						gendo(sto,lev-table[i].level,table[i].adr);
					}
					getsymdo;
				}while(sym == comma);//","
			}
			if(sym != rparen)
			{
				error(33);
				while(!inset(sym,fsys))
				{
					getsymdo;
				}
			}
			else
			{
				getsymdo;
			}
		}
		else
		{
			if(sym == writesym)
			{
				getsymdo;
				if(sym == lparen)
				{
					do
					{
						getsymdo;
						memcpy(nxtlev,fsys,sizeof(bool)*symnum);
						nxtlev[rparen] = true;
						nxtlev[comma] = true;
						expressiondo(nxtlev,ptx,lev);

						gendo(opr,0,14);
					}while(sym == comma);
					if(sym != rparen)
					{
						error(33);
					}
					else
					{
						getsymdo;
					}
				}
				gendo(opr,0,15);
			}
			else
			{
				if(sym == callsym)
				{
					getsymdo;
					if(sym != ident)
					{
						error(14);
					}
					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);
								/*
								产生过程调用指令lev是当前过程的层次,
																			
								*/
							}
							else
							{
								error(15);
							}
						}
						getsymdo;
					}
				}
				else
				{
					if(sym == ifsym)
					{
						getsymdo;
						memcpy(nxtlev,fsys,sizeof(bool)*symnum);
						nxtlev[thensym] = true;
						nxtlev[dosym] = true;
						conditiondo(nxtlev,ptx,lev);
						if(sym == thensym)
						{
							getsymdo;
						}
						else
						{
							error(16);
						}
						cx1  = cx;
						gendo(jpc,0,0);
						statementdo(fsys,ptx,lev);
						code[cx1].a = cx;
					}
					else
					{
						if(sym == beginsym)
						{
							getsymdo;
							memcpy(nxtlev,fsys,sizeof(bool)*symnum);
							nxtlev[semicolon] = true;
							nxtlev[endsym] = true;

							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);
							}
						}
						else

⌨️ 快捷键说明

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