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

📄 pl0.cpp

📁 用C实现的PL0的编译器的原代码,弄链表实现了关键字的补充
💻 CPP
📖 第 1 页 / 共 4 页
字号:
											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号操作指令:减法
	} 
	destroyset(set);
} 

/*************************************************************************/
void term(symset fsys)    //项分析处理,fsys如果出错可用来恢复语法分析的符号集合
{
	int mulop;
	symset set;	
	set = uniteset(fsys, createset(SYM_TIMES, SYM_SLASH, SYM_NULL));
	factor(set);  //每一个项都应该由因子开始,因此调用factor子程序分析因子
	while (sym == SYM_TIMES || sym == SYM_SLASH) //一个因子后应当遇到乘号或除号
	{
		mulop = sym;  //保存当前运算符
		getsym();  //获取下一个token 
		factor(set);  //运算符后应是一个因子,故调factor子程序分析因子
		if (mulop == SYM_TIMES) //如果刚才遇到乘号
			gen(OPR, 0, 4);  //生成乘法指令
		else
			gen(OPR, 0, 5);//不是乘号一定是除号,生成除法指令
	} 
	destroyset(set);
} 

/*************************************************************************/
void factor(symset fsys)    //因子分析处理,fsys如果出错可用来恢复语法分析的符号集合
{
	void expression();
	int i;
	symset set;	
	test(facbegsys, fsys, 24); // 开始因子处理前,先检查当前token是否在facbegsys集合中
   //如果不是合法的token,报出24号错误
	while (inset(sym, facbegsys))  //循环处理因子 
	{
		if (sym == SYM_IDENTIFIER)  //如果遇到的是标识符
		{//查符号表,找到当前标识符在符号表中的位置
			if ((i = position(id)) == 0)   //如果查符号表返回为0,表示没有找到标识符
				error(11); // Undeclared identifier.
			else
			{
				switch (table[i].kind)  //如果在符号表中找到了当前标识符的位置,开始生成相应代码
				{
					mask* mk;
				case ID_CONSTANT:
					gen(LIT, 0, table[i].value);  //如果这个标识符对应的是常量,值为val,生成lit指令,把val放到栈顶
					break;
				case ID_VARIABLE:
					mk = (mask*) &table[i];
					gen(LOD, level - mk->level, mk->address);//如果标识符是变量名,生成lod指令
					break;//把位于距离当前层level的层的偏移地址为adr的变量放到栈顶
				case ID_PROCEDURE:
					error(21); //如果在因子处理中遇到的标识符是过程名,出错了,报出21号错
					break;
				} 
			}
			getsym();//获取下一token,继续循环处理
		}
		else 
			if (sym == SYM_NUMBER)  //如果因子处理时遇到数字
			{
				if (num > MAXADDRESS)//如果数字的大小超过允许最大值amax
				{
					error(30); 
					num = 0;//把数字按0值处理
				}
				gen(LIT, 0, num);  //生成lit指令,把这个数值字面常量放到栈顶
				getsym();  //获取下一token 
			}
			else 
				if (sym == SYM_LPAREN)  // 如果遇到的是左括号
				{
					getsym();  //获取一个token 
					set = uniteset(createset(SYM_RPAREN, SYM_NULL), fsys);
				//	expression(set); //递归调用expression子程序分析一个子表达式
					destroyset(set);
					if (sym == SYM_RPAREN)//子表达式分析完后,应遇到右括号
						getsym();  //如果的确遇到右括号,读取下一个token
					else
						error(22); 
				}
				else
					test(fsys, createset(SYM_LPAREN, SYM_NULL), 23); //一个因子处理完毕,遇到的token应在fsys集合中
		//如果不是,报出23号错,并找到下一个因子的开始,使语法分析可以继续运行下去
	} 
} 

/*************************************************************************/
void condition(symset fsys)   //条件分析处理,fsys如果出错可用来恢复语法分析的符号集合
{
	int relop;  //用于临时记录token的内容
	symset set;
	if (sym == SYM_ODD)  //如果是odd运算符
	{
		getsym();  //获取下一个token 
		expression(fsys);  //对odd的表达式进行处理计算
		gen(OPR, 0, 6);  //生成6号操作指令:奇偶判断运算
	}
	else  //如果不是odd运算符
	{
		set = uniteset(relset, fsys);
		expression(set);  //对表达式左部进行处理计算
		destroyset(set);
		if (! inset(sym, relset))  // 如果token不是逻辑运算符中的一个
			error(20);
		else
		{
			relop = sym;  //记录下当前的逻辑运算符
			getsym();  //获取下一个token 
			expression(fsys);  //对表达式右部进行处理计算 
			switch (relop)  //如果刚才的运算符是下面的一种
			{
			case SYM_EQU:  //等号:产生8号判等指令
				gen(OPR, 0, 8);
				break;
			case SYM_NEQ:  //不等号:产生9号判不等指令
				gen(OPR, 0, 9);
				break;
			case SYM_LSS: //小于号:产生10号判小指令
				gen(OPR, 0, 10);
				break;
			case SYM_GEQ: //大于等号号:产生11号判不小于指令 
				gen(OPR, 0, 11);
				break;
			case SYM_GTR:  //大于号:产生12号判大于指令
				gen(OPR, 0, 12);
				break;
			case SYM_LEQ:  //小于等于号:产生13号判不大于指令
				gen(OPR, 0, 13);
				break;
			} 
		} 
	} 
} 
 
/***************************************
*通过静态链求出数据区基地址的函数
****************************************/
int base(int stack[], int currentLevel, int levelDiff)  //levelDiff要求的数据区所在层与当前层的层差
{
	int b = currentLevel;	
	while (levelDiff>0)
	{
		b = stack[b];
		levelDiff--;
	}
	return b;//把找到的要求的数据区基址返回
} 


/*************************************************************************/
void interpret()    //PL/0编译器产生的类PCODE目标代码解释运行过程
{
	int pc;        // pc为程序指令指针,指向下一条要运行的代码
	int stack[STACKSIZE];  //stack为栈式计算机的数据内存区
	int top;       //top为栈顶寄存器,类PCODE是在一种假想的栈式计算上运行的,这个变量记录这个计算机的当前栈顶位置
	int b;         // b为基址指针,指向每个过程被调用时数据区中分配给它的局部变量数据段基址
	instruction i; // i变量中存放当前在运行的指令
	printf("\n开始执行PL/0程序:\n");
	fprintf(outfile, "\n开始执行PL/0程序:\n");
	pc = 0;  //从0号代码开始执行程序
	b = 1; // 数据段基址为1
	top = 0;  //程序开始运行时栈顶寄存器置0 
	stack[1] = stack[2] = stack[3] = 0;  //数据内存中为SL,DL,RA三个单元均为0,标识为主程序
	do
	{  //开始依次运行程序目标代码
		i = code[pc];//获取一行目标代码,指令指针加一,指向下一条代码
		pc=pc+1;
		switch (i.f) //如果i的f,即指令助记符是下面的某种情况,执行不同的功能
		{
		case LIT:  //如果是lit指令
			stack[++top] = i.a; //该单元的内容存放i指令的a操作数,即实现了把常量值放到运行栈栈顶
			break;
		case OPR:  //如果是opr指令
			switch (i.a) // 根据a操作数不同,执行不同的操作
			{
			case 0: // 0号操作为从子过程返回操作
				top = b - 1;  //释放这段子过程占用的数据内存空间
				pc = stack[top + 3];  //把指令指针取到RA的值,指向的是返回地址
				b = stack[top + 2];  //把数据段基址取到DL的值,指向调用前子过程的数据段基址
				break;
			case 1:  //1号操作为栈顶数据取反操作 
				stack[top] = -stack[top];  //对栈顶数据进行取反
				break;
			case 2:  //2号操作为栈顶两个数据加法操作
				top--;  //栈顶指针下移
				stack[top] =stack[top] + stack[top + 1];  //把两单元数据相加存入栈顶
				break;
			case 3:  //3号操作为栈顶两个数据减法操作
				top--;  //栈顶指针下移
				stack[top] =stack[top] - stack[top + 1];  //把两单元数据相减存入栈顶
				break;
			case 4:  //4号操作为栈顶两个数据乘法操作
				top--;  //栈顶指针下移
				stack[top]=stack[top] * stack[top + 1];  //把两单元数据相乘存入栈顶
				break;
			case 5:  //5号操作为栈顶两个数据除法操作
				top--;  //栈顶指针下移
				if (stack[top + 1] == 0)
				{
					fprintf(stderr, "\n运行错误:被零除!\n");
					break;
				}
				stack[top]=stack[top] / stack[top + 1]; //把两单元数据相整除存入栈顶
				break;
			case 6:  //6号操作为判奇操作
				stack[top] =(stack[top] % 2);  //数据栈顶的值是奇数则把栈顶值置1,否则置0
				break;
			case 8:  //8号操作为栈顶两个数据判等操作
				top--;  //栈顶指针下移 
				stack[top] = (stack[top] == stack[top + 1]);  //判等,相等栈顶置1,不等置0
				break;
			case 9:  //9号操作为栈顶两个数据判不等操作 
				top--;  //栈顶指针下移
				stack[top] = (stack[top] != stack[top + 1]);  //判不等,不等栈顶置1,相等置0
				break;
			case 10:  //10号操作为栈顶两个数据判小于操作
				top--;  //栈顶指针下移
				stack[top] = (stack[top] < stack[top + 1]);  //判小于,如果下面的值小于上面的值,栈顶置1,否则置0
				break;
			case 11:  //11号操作为栈顶两个数据判大于等于操作
				top--;  //栈顶指针下移
				stack[top] = (stack[top] >= stack[top + 1]);  //判大于等于,如果下面的值大于等于上面的值,栈顶置1,否则置0
				break;
			case 12:  //12号操作为栈顶两个数据判大于操作
				top--;  //栈顶指针下移
				stack[top] = (stack[top] > stack[top + 1]);  //判大于,如果下面的值大于上面的值,栈顶置1,否则置0
				break;
			case 13:  //13号操作为栈顶两个数据判小于等于操作
				top--;  //栈顶指针下移
				stack[top] = (stack[top] <= stack[top + 1]);//判小于等于,如果下面的值小于等于上面的值,栈顶置1,否则置0
				break;
			} 
			break;
		case LOD:  // 如果是lod指令:将变量放到栈顶
			stack[++top] = stack[base(stack, b, i.l) + i.a]; 
            //栈顶上移,开辟空间,通过数据区层差l和偏移地址a找到变量的数据,存入上面开辟的新空间(即栈顶)
			break;
		case STO:  //如果是sto指令
			stack[base(stack, b, i.l) + i.a] = stack[top];  //把栈顶的值存入位置在数据区层差l偏移地址a的变量内存
			//printf("%d\n", stack[top]);
			fprintf(outfile, "%d\n", stack[top]);
			top--;  //栈项下移,释放空间
			break;
		case CAL:  //如果是cal指令
			stack[top + 1] = base(stack, b, i.l);  //在栈顶压入静态链SL 
			stack[top + 2] = b;  //然后压入当前数据区基址,作为动态链DL 
			stack[top + 3] = pc;  //最后压入当前的断点,作为返回地址RA 
			b = top + 1;  //把当前数据区基址指向SL所在位置 
			pc = i.a;  //从a所指位置开始继续执行指令,即实现了程序执行的跳转
			break;
		case INT:  //如果是int指令
			top += i.a;  //栈顶上移a个空间,即开辟a个新的内存单元 
			break;
		case JMP:  //如果是jmp指令
			pc = i.a;  //把jmp指令操作数a的值作为下一次要执行的指令地址,实现无条件跳转
			break;
		case JPC:  //如果是jpc指令
			if (stack[top] == 0)//判断栈顶值
				pc = i.a;  //如果是0就跳转,否则不跳转
			top--;  //释放栈顶空间
			break;
		case RED://如果是red指令
			//把栈顶的值存入位置在数据区层差l偏移地址a的变量内存
			printf("输入:\n");
			scanf("%d",&stack[base(stack, b, i.l) + i.a]);
			break;
		case WRT://如果是wrt指令
			printf("输出:%d\n", stack[top]);
			fprintf(outfile, "输出:%d\n", stack[top]);
			top++;//栈顶上移,开辟空间
			break;
		} 
	}while (pc!=0);
	printf("PL/0程序运行结束!\n\n");
	fprintf(outfile, "PL/0程序运行结束!\n");
}

⌨️ 快捷键说明

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