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

📄 pl0.c

📁 pl0
💻 C
📖 第 1 页 / 共 4 页
字号:
				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指令,把读入的值存入指定变量所在的空间
											if(q==SYM_TO)//to默认执行11号操作
												gen(OPR,0,11);
											else
												gen(OPR,0,13);
											cx2=cx;//记下当前代码分配位置
											gen(JPC,0,0);//生成条件跳转指令,跳转位置暂时填0,分析完语句后再填写
											code[cx1].a=cx;//把刚才填0的跳转位置改成当前位置
											getsym();
											statement(fsys);
											gen(JMP,0,cx1+1);//循环跳转到cx1+1位置,即再次进行逻辑判断
											code[cx2].a=cx;//把刚才填0的跳转位置改成当前位置
										}
								}	
								else
									if(sym ==SYM_REPEAT) //重复语句
									{
										cx1 = cx;  //记下当前代码分配位置,这是repeat语句的开始位置
										getsym(); 
										set1 = createset(SYM_SEMICOLON, SYM_UNTIL, SYM_NULL);
										set = uniteset(set1, fsys);
										statement(set); 
                                        while (sym == SYM_SEMICOLON || inset(sym, statbegsys))
										{ 
											if (sym == SYM_SEMICOLON) //判别是否为‘;’ 
												getsym();  
											else 
												error(10);  
											statement(set); 
										} 
										destroyset(set1);
										destroyset(set);
										if (sym == SYM_UNTIL)
										{
											getsym();  
											condition(fsys);
											gen(JPC, 0, cx1);//生成条件跳转指令,跳转位置填cx1
										}
										else
											error(29);										  
									}
									else
										test(fsys, phi, 19);  //至此一个语句处理完成,一定会遇到fsys集中的符号,如果没有遇到,就抛19号错
} 


///////////////////////////////////////////////////////////////////////////////////////////
//表达式分析处理
void expression(symset fsys)
{
	int addop;
	symset set;
	set = uniteset(fsys, createset(SYM_PLUS, SYM_MINUS, SYM_NULL));
	if (sym == SYM_PLUS || sym == SYM_MINUS)//一个表达式可能会由加号或减号开始,表示正负号
	{
		addop = sym;//把当前的正号或负号保存起来,以便下面生成相应代码
		getsym();// 获取一个token 
		term(set);  //正负号后面应该是一个项,调term子程序分析
		if (addop == SYM_MINUS)   //如果保存下来的符号是负号
			gen(OPR, 0, 1);  //生成一条1号操作指令:取反运算
		//如果不是负号就是正号,不需生成相应的指令
	}
	else //如果不是由正负号开头,就应是一个项开头
		term(set);//调用term子程序分析项
	while (sym == SYM_PLUS || sym == SYM_MINUS)  //项后应是加运算或减运算
	{
		addop = sym;  //把运算符保存下来
		getsym();  //获取下一个token,加减运算符后应跟的是一个项
		term(set);  //调term子程序分析项 
		if (addop == SYM_PLUS)  //如果项与项之间的运算符是加号
			gen(OPR, 0, 2);   //生成2号操作指令:加法
		else //否则是减法
			gen(OPR, 0, 3);  //生成3号操作指令:减法
	} 

⌨️ 快捷键说明

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