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

📄 pl0.cpp

📁 用C实现的PL0的编译器的原代码,弄链表实现了关键字的补充
💻 CPP
📖 第 1 页 / 共 4 页
字号:
			}while (sym == SYM_IDENTIFIER);  //如果遇到非标识符,则变量声明结束
			block_dx = dx;	
		}
		while (sym == SYM_PROCEDURE)  //循环声明各子过程
		{ 
			getsym();  //获取下一个token,此处正常应为作为过程名的标识符 
			if (sym == SYM_IDENTIFIER)  //如果token确为标识符
			{
				enter(ID_PROCEDURE);  //把这个过程登录到名字表中
				getsym();  //获取下一个token,正常情况应为分号
			}
			else
				error(4);
			if (sym == SYM_SEMICOLON) //如果当前token为分号
				getsym();  // 获取下一个token,准备进行语法分析的递归调用 
			else
				error(5); 
			level++;
			savedTx = tx;
			set1 = createset(SYM_SEMICOLON, SYM_NULL);
			set = uniteset(set1, fsys);
			block(set); //递归调用语法分析过程,当前层次加一,同时传递表头索引、合法单词符
			destroyset(set1);
			destroyset(set);
			tx = savedTx;
			level--;
			if (sym == SYM_SEMICOLON)  //递归返回后当前token应为递归调用时的最后一个end后的分号
			{
				getsym();  //获取下一个token 
				set1 = createset(SYM_IDENTIFIER, SYM_PROCEDURE, SYM_NULL);
				set = uniteset(statbegsys, set1);
				test(set, fsys, 6);  //检查当前token是否合法,不合法则用fsys恢复语法分析同时报出6号错误 
				destroyset(set1);
				destroyset(set);
			}
			else
				error(5); //如果过程声明后的符号不是分号,报出出5号错误
		}
		set1 = createset(SYM_IDENTIFIER, SYM_NULL);
		set = uniteset(statbegsys, set1);
		test(set, declbegsys, 7);  //检查当前状态是否合法,不合法则用声明开始符罕ǔ鲎鞒龃砘指础报出?号错 
		destroyset(set1);
		destroyset(set);
	}while (inset(sym, declbegsys));  //直到声明性的源程序分析完毕,继续向下执行,分析主程序
	code[mk->address].a = cx;  //把前面生成的跳转语句的跳转位置改成当前位置
	mk->address = cx;  //地址为当前代码分配地址
	cx0 = cx;  //记下当前代码分配位置
	gen(INT, 0, block_dx);  //生成分配空间指令,分配dx个空间
	set1 = createset(SYM_SEMICOLON, SYM_END, SYM_NULL);
	set = uniteset(set1, fsys);
	statement(set);  //处理当前遇到的语句或语句块 
	destroyset(set1);
	destroyset(set);
	gen(OPR, 0, 0); //生成从子程序返回操作指令
	test(fsys, phi, 8); // 用fsys检查当前状态是否合法,不合法则报出8号错
	listcode(cx0, cx);  //列出本层的类PCODE代码
} 


/*************************************************************************/
void constdeclaration() //常量声明处理过程
{
	if (sym == SYM_IDENTIFIER)  //常量声明过程开始遇到的第一个符号必然应为标识符
	{
		getsym();   //获取下一个token 
		if (sym == SYM_EQU || sym == SYM_BECOMES) //如果是等号或赋值号
		{
			if (sym == SYM_BECOMES)//如果是赋值号(常量生明中应该是等号)
				error(1);  //这里其实自动进行了错误纠正使编译继续进行,把赋值号当作等号处理 
			getsym(); //获取下一个token,等号或赋值号后应接上数字
			if (sym == SYM_NUMBER)  //如果的确是数字
			{
				enter(ID_CONSTANT);  //把这个常量登陆到符号表
				getsym();    //获取下一个token,为后面作准备
			}
			else
				error(2); // 如果等号后接的不是数字,报出出2号错误
		}
		else
			error(3); // 如果常量标识符后接的不是等号或赋值号,报出出3号错误
	}
	else		
		error(4); // 如果常量声明过程遇到的第一个符号不为标识符,报出出4号错误 
} 


/*************************************************************************/
void vardeclaration(void)   //变量说明处理
{
	if (sym == SYM_IDENTIFIER)//变量声明过程开始遇到的第一个符号必然应为标识符
	{
		enter(ID_VARIABLE);  //将标识符登陆到符号表中
		getsym();//获取下一个token,为后面作准备
	}
	else
		error(4); // 如果变量声明过程遇到的第一个符号不是标识符,报出4号错误
} 


/*************************************************************************/
void statement(symset fsys)  //语句部分分析处理,fsys如果出错可用来恢复语法分析的符号集合 
{
	int i, cx1, cx2, q;
	char ida[MAXIDLEN + 1];
	symset set1, set;
    mask* mk;
	if (sym == SYM_IDENTIFIER)
	{ 		
		if (! (i = position(id)))  //在符号表中没有查到该标识符所在位置
			error(11);
		else 
			if (table[i].kind != ID_VARIABLE)  //如果在符号表中找到该标识符,但该标识符不是变量名
			{
				error(12); 
				i = 0;  //i置0作为错误标志
			}
			getsym();  //获得下一个token,正常应为赋值号
			if (sym == SYM_BECOMES)  //如果的确为赋值号
				getsym();  //获取下一个token,正常应为一个表达式
			else
				error(13); 
			expression(fsys);  //处理表达式
			mk = (mask*) &table[i];
			if (i)  //如果不曾出错,i将不为0,i所指为当前语名左部标识符在符号表中的位置
				gen(STO, level - mk->level, mk->address);//产生一行把表达式值写往指定内存的sto目标代码
	}
	else 
		if (sym == SYM_CALL)  //如果是call语句
		{ 
			getsym(); //获取token,应是过程名型标识符
			if (sym != SYM_IDENTIFIER)  //如果call后跟的不是标识符
				error(14); 
			else//从符号表中找出相应的标识符
			{
				if (! (i = position(id)))  
					error(11); 
				else //如果找到标识符位于符号表第i位置
					if (table[i].kind == ID_PROCEDURE)   //如果这个标识符为一个过程名
					{
						mk = (mask*) &table[i];
						gen(CAL, level - mk->level, mk->address);  //生成cal目标代码,呼叫这个过程
					}
					else
						error(15); // 如果call后跟的不是过程名,报出出15号错误
					getsym(); //获取下一token,为后面作准备
			} 
		} 
		else 
			if (sym == SYM_IF)  //如果是if语句
			{ 
				getsym();  //获取一token应是一个逻辑表达式
				set1 = createset(SYM_THEN, SYM_DO, SYM_NULL);  //对逻辑表达式进行分析计算,出错恢复集中加入then和do语句
				set = uniteset(set1, fsys);
				condition(set);
				destroyset(set1);
				destroyset(set);
				if (sym == SYM_THEN)  //表达式后应遇到then语句
					getsym();  //获取then后的token,应是一语句
				else
					error(16); // 如果if后没有then,报出出16号错误
				cx1 = cx;  //记下当前代码分配指针位置,这是then的开始位置
				gen(JPC, 0, 0);  //生成条件跳转指令,跳转位置暂时填0,分析完语句后再填写
				set1 = createset(SYM_ELSE, SYM_NULL);
				set = uniteset(set1, fsys);
				statement(set);
				destroyset(set1);
				destroyset(set);
				if (sym != SYM_ELSE) //表达式后遇到不是else语句
					code[cx1].a = cx;//把then填0的跳转位置改成当前位置,完成if语句的处理
				else
				{//表达式后遇到else语句
					getsym();
					cx2=cx;//记下当前代码分配位置,这是else的开始位置
					gen(JMP,0,0);//产生一行跳转指令,跳转位置暂时未知填0
					statement(fsys);
					code[cx1].a = cx2 + 1;//把then语句填0的跳转位置改成当前位置,完成if语句的处理
					code[cx2].a = cx;//把else填0的跳转位置改成当前位置,完成else语句的处理
				}			
			}
			else 
				if (sym == SYM_BEGIN)  //如果遇到begin
				{ 
					getsym();  //获取下一个token 
					set1 = createset(SYM_SEMICOLON, SYM_END, SYM_NULL);
					set = uniteset(set1, fsys);
					statement(set);  //对begin与end之间的语句进行分析处理
					while (sym == SYM_SEMICOLON || inset(sym, statbegsys))
					{ //如果分析完一句后遇到分号或语句开始符循环分析下一句语句
						if (sym == SYM_SEMICOLON)  //如果语句是分号(可能是空语句)
							getsym();  //获取下一token继续分析
						else 
							error(10);  //如果语句与语句间没有分号,出10号错
						statement(set);  //分析一个语句
					} 
					destroyset(set1);
					destroyset(set);
					if (sym == SYM_END)//如果语句全分析完了,应该遇到end 
						getsym();  // 的确是end,读下一token 
					else
						error(17); 
				}
				else 
					if (sym == SYM_WHILE)//如果遇到while语句 
					{ 
						cx1 = cx;  //记下当前代码分配位置,这是while循环的开始位置
						getsym(); //获取下一token,应为一逻辑表达式
						set1 = createset(SYM_DO, SYM_NULL);
						set = uniteset(set1, fsys);
						condition(set); //对这个逻辑表达式进行分析计算
						destroyset(set1);
						destroyset(set);
						cx2 = cx;  //记下当前代码分配位置,这是while的do中的语句的开始位置
						gen(JPC, 0, 0);  // 生成条件跳转指令,跳转位置暂时填0
						if (sym == SYM_DO)  //逻辑表达式后应为do语句
							getsym();  //获取下一token
						else
							error(18);   //if后缺少then,报出出18号错误
						statement(fsys);  //分析do后的语句块
						gen(JMP, 0, cx1);  //循环跳转到cx1位置,即再次进行逻辑判断
						code[cx2].a = cx;  //把刚才填0的跳转位置改成当前位置,完成while语句的处理
					}
					else
						if(sym == SYM_READ) // 如果不是赋值语句,而是遇到了read语句
						{
                            getsym();//获得下一token,正常情况下应为左括号
							if(sym != SYM_LPAREN)  //如果read语句后跟的不是左括号
                                error(40);  
							else  //循环得到read语句括号中的参数表,依次产生相应的“从键盘读入”目标代码
							{
								do
								{
									getsym();	//获得一个token,正常应是一个变量名									
									if (sym == SYM_IDENTIFIER)  //如果确为一个标识符
									{
										if (! (i = position(id))) //查符号表,找到它所在位置给i,找不到时i会为0	
											error(11);
										else
											if( table[i].kind!=ID_VARIABLE)	//判别类型是否为标识符
											{
												error(12);
												i=0;
											}
											else
											{
												mk = (mask*) &table[i];
												gen(RED, level - mk->level, mk->address);  //生成red指令,把读入的值存入指定变量所在的空间											
											}
									}
									else
										error(4);
									getsym();
								}while(sym==SYM_COMMA);//不断生成代码直到read语句的参数表中的变量遍历完为止
								if(sym!=SYM_RPAREN)
									error(22);
								getsym(); //如果read语句正常结束,得到下一个token,一般为分号或end 
							}
						}
						else
							if(sym == SYM_WRITE)// 如果不是赋值语句,而是遇到了write语句
							{
								getsym();  //获取下一token,应为左括号
								if(sym != SYM_LPAREN)//如果write语句后跟的不是左括号
									error(40);
								else
								{	
									do
									{ //依次获取括号中的每一个值,进行输出 
										getsym();
										set1 =createset(SYM_RPAREN, SYM_COMMA, SYM_NULL);
										set=uniteset(set1,fsys);
										expression(set);										
										gen(WRT,0,0);//生成wrt指令,把读入的值存入指定变量所在的空间																	
									}while(sym==SYM_COMMA);
									if(sym!=SYM_RPAREN)//如果不是右括号
										error(22);
									getsym();//正常情况下要获取下一个token,为后面准备好
								}   								
							}
							else
								if(sym == SYM_FOR)//for循环语句
								{
									getsym();
									if(sym != SYM_IDENTIFIER)
										error(25);
									strcpy(ida, id); //用另一个ida记录当前读到的IDENTIFIER
									set1 = createset(SYM_TO, SYM_DOWNTO, SYM_NULL);
									set = uniteset(set1, fsys);
									statement(set);
									destroyset(set1);
									destroyset(set);
									if((sym != SYM_TO) && (sym != SYM_DOWNTO))
										error(26);
									q=sym; //记录下当前所读到的字符
									cx1=cx;//记下当前代码分配位置,这是to/downto语句的开始位置
									gen(JMP,0,0);//产生一行跳转指令,跳转位置暂时未知填0
									getsym();
									set1 =createset(SYM_DO,SYM_BY,SYM_NULL);
									set=uniteset(set1,fsys);
									expression(set);
									if((sym != SYM_DO) && (sym != SYM_BY))
										error(27);
									strcpy(id, ida);//将ida记录下的IDENTIFIER拷贝给id
									i=position(id);
									if(i==0)
										error(11);
									else
										if( table[i].kind!=ID_VARIABLE)//判别类型是否为变量
										{
											error(12);
											i=0;
										}
										else
										{
											mk = (mask*) &table[i];
											gen(LOD, level - mk->level, mk->address);//生成lod指令,把读入的值存入指定变量所在的空间 
											if(sym == SYM_BY)
											{ //对by后的表达式进行判断
												getsym();
												//如果前一个字符为downto,则by后的sym应为SYM_MINUS,否则出错
                                                //如果前一个字符为to,则by后的sym应为SYM_PLUS,否则出错
												if(( sym==SYM_MINUS) || ( sym == SYM_PLUS))
												{
													set1 =createset(SYM_DO, SYM_NULL);
													set=uniteset(set1,fsys);
													expression(set);
													if(sym != SYM_DO)
														error(28);
												}
												else
												{
													if(q==SYM_DOWNTO)
														error(35);
													else
														if(q==SYM_TO)
															error(36);
												}
											}
											else //当没有by时,执行默认处理指令
											{
												gen(LIT,0,1);
												//downto默认执行1号操作
												if(q==SYM_DOWNTO)
													gen(OPR,0,1);
											}
											gen(OPR,0,2);
											mk = (mask*) &table[i];
											gen(STO,level - mk->level, mk->address);//生成sto指令,把读入的值存入指定变量所在的空间
											gen(LOD,level - mk->level, mk->address);//生成lod指令,把读入的值存入指定变量所在的空间

⌨️ 快捷键说明

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