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

📄 symtax.cpp

📁 PL/0编译器
💻 CPP
📖 第 1 页 / 共 2 页
字号:
{
	symbol addop;
	CSymset symset;
	symset += fsys;
	symset += plus;
	symset += minus;

	if ( sym==plus||sym==minus )			//一个表达式可能会由加号或减号开始,表示正负号
	{
		addop=sym;							//把当前的正号或负号保存起来,以便下面生成相应代码
		getsym();			
		term(symset);						//正负号后面应该是一个项,调term子程序分析
		if (addop==minus)
			pl->code->Gen(opr,0,1);			//如果保存下来的符号是负号,生成一条1号操作指令:取反运算
	}
	else
		term(symset);						//如果不是由正负号开头,就应是一个项开头

	while (sym==plus||sym==minus)			//项后应是加运算或减运算
	{
		addop=sym;
		getsym();							//获取下一个token,加减运算符后应跟的是一个项
		term(symset);
		if (addop==plus)
			pl->code->Gen(opr,0,2);			//生成2号操作指令:加法
		else
			pl->code->Gen(opr,0,3);			//生成3号操作指令:减法
	}
}

//条件处理过程condition
void CSymtax::condition(CSymset fsys)
{
	symbol relop;							//用于临时记录token(这里一定是一个二元逻辑运算符)的内容
	CSymset s1,s2;
	s1+=eql;
	s1+=neq;
	s1+=lss;
	s1+=leq;
	s1+=gtr;
	s1+=geq;

	if (sym==oddsym)						//如果是odd运算符(一元)
	{
		getsym();
		expression(fsys);					//对odd的表达式进行处理计算
		pl->code->Gen(opr,0,6);				//生成6号操作指令:奇偶判断运算
	}
	else
	{
		s2+=s1;
		expression(s2+=fsys);				//对表达式左部进行处理计算
		if (!s1.InSet(sym))
			pl->errors->Add(20);			//如果token不是逻辑运算符中的一个 
		else
		{
			relop=sym;
			getsym();
			expression(fsys);				//对表达式右部进行处理计算 
			switch (relop)
			{
			case eql:
				pl->code->Gen(opr,0,8);
				break;						//等号:产生8号判等指令
			case neq:
				pl->code->Gen(opr,0,9);
				break;						//不等号:产生9号判不等指令
			case lss:
				pl->code->Gen(opr,0,10);
				break;						//小于号:产生10号判小指令
			case geq:
				pl->code->Gen(opr,0,11);
				break;						//大于等号号:产生11号判不小于指令
			case gtr:
				pl->code->Gen(opr,0,12);
				break;						//大于号:产生12号判大于指令
			case leq:
				pl->code->Gen(opr,0,13);
				break;						//小于等于号:产生13号判不大于指令
			}
		}
	}
}

void CSymtax::statement(CSymset fsys)
{
	int i,cx1,cx2;
	table_type *table = pl->form->table;
	CErrors *err = pl->errors;
	CCode *cd = pl->code;
	CSymset s,s2;

	switch (sym)
	{
	case ident:											//所谓"语句"可能是赋值语句,以标识符开头
		i = pl->form->Position(pl->wording->id);		//在符号表中查到该标识符所在位置
		if (i==0)
			err->Add(11);								//没有找到
		else if (table[i].kind!=variable)
		{
			err->Add(12);								//如果在符号表中找到该标识符,但该标识符不是变量名
			i=0;
		}
		getsym();
		if (sym==becomes)								//获得下一个token,正常应为赋值号
			getsym();
		else
			err->Add(13);								//处理表达式
		expression(fsys);
		if (i>0)
			cd->Gen(sto,lev-table[i].level,table[i].adr); //产生一行把表达式值写往指定内存的sto目标代码
		break;
	case readsym:										//遇到了read语句
		getsym();
		if (sym!=lparen)								//获得下一token,正常情况下应为左括号
			err->Add(34);
		else
			do{
				getsym();								//获得一个token,正常应是一个变量名
				i = (sym==ident) ? pl->form->Position(pl->wording->id) : 0;
				if (i==0)
					err->Add(35);
				else
				{
					cd->Gen(opr,0,16);					//生成16号操作指令:从键盘读入数字
					cd->Gen(sto,lev-table[i].level,table[i].adr); //生成sto指令,把读入的值存入指定变量所在的空间
				}
				getsym();
			}while (sym==comma);						//获取下一个token,如果是逗号,则read语还没完,否则应当是右括号

		if (sym!=rparen)
		{
			err->Add(33);
			while (fsys.InSet(sym)) 
				getsym();
		}
		else getsym();									//如果read语句正常结束,得到下一个token,一般为分号或end
		break;

	case writesym:										//如果遇到了write语句
		s=fsys;
		s+=rparen;
		s+=comma;
		getsym();										//获取下一token,应为左括号
		if (sym==lparen)
		{
			do{
				getsym();
				expression(s);							//调用expression过程分析表达式,用于出错恢复的集合中加上右括号和逗号
				pl->code->Gen(opr,0,14);				//生成14号指令:向屏幕输出
			}while (sym==comma);
			if (sym!=rparen)
				err->Add(33);
			else
				getsym();
		}
		cd->Gen(opr,0,15);								//生成一个15号操作的目标代码,功能是输出一个换行
		break;

	case callsym:										//如果是call语句
		getsym();
		if (sym!=ident)									//获取token,应是过程名型标识符
			err->Add(14);
		else
		{
			i = pl->form->Position(pl->wording->id);
			if (i==0) err->Add(11);
			else if (table[i].kind==procedure)
				cd->Gen(cal,lev-table[i].level,table[i].adr); //生成cal目标代码,呼叫这个过程
			else
				err->Add(15);
			getsym();
		}
		break;

	case ifsym:											//如果是if语句
		s=fsys;
		s+=thensym;
		s+=dosym;
		getsym();
		condition(s);									//对逻辑表达式进行分析计算,出错恢复集中加入then和do语句

		if (sym==thensym) 
			getsym();									//获取then后的token,应是一语句
		else 
			err->Add(16);

		cx1 = cd->cx;									//记下当前代码分配指针位置
		cd->Gen(jpc,0,0);								//生成条件跳转指令,跳转位置暂时填0,分析完语句后再填写
		s = fsys;
		s += elsesym;
		statement(s);									//分析then后的语句
		if (sym==elsesym)								//如果后面是else语句
		{
			getsym();
			cx2=cd->cx;									//记下当前代码分配指针位置
			cd->Gen(jmp,0,0);
			statement(fsys);
			cd->code[cx1].a = cx2+1;
			cd->code[cx2].a = cd->cx;
		}
		else
			cd->code[cx1].a = cd->cx;					//上一行指令(cx1所指的)的跳转位置应为当前cx所指位置
		break;

	case beginsym:										//如果遇到begin
		s=fsys;
		s+=semicolon;
		s+=endsym;
		s2=statbegsys;
		s2+=semicolon;

		getsym();
		statement(s);									//对begin与end之间的语句进行分析处理
		
		while (s2.InSet(sym))							//如果分析完一句后遇到分号或语句开始符循环分析下一句语句
		{
			if (sym==semicolon)							//如果语句是分号(可能是空语句)
				getsym();
			else 
				err->Add(10);
			statement(s);
		}

		if (sym==endsym) 
			getsym(); 
		else 
			err->Add(17);
		break;

	case whilesym:										//如果遇到while语句
		cx1=cd->cx;										//记下当前代码分配位置,这是while循环的开始位置
		getsym();
		s=fsys;
		s+=dosym;
		condition(s);									//对这个逻辑表达式进行分析计算
		cx2=cd->cx;										//记下当前代码分配位置,这是while的do中的语句的开始位置
		cd->Gen(jpc,0,0);								//生成条件跳转指令,跳转位置暂时填0

		if (sym==dosym)									//逻辑表达式后应为do语句
			getsym(); 
		else 
			err->Add(18);
		statement(fsys);								//分析do后的语句块

		cd->Gen(jmp,0,cx1);								//循环跳转到cx1位置,即再次进行逻辑判断
		cd->code[cx2].a = cd->cx;						//把刚才填0的跳转位置改成当前位置,完成while语句的处理
		break;

	case repeatsym:
		getsym();
		s=fsys;
		s+=semicolon;
		s+=untilsym;
		cx1=cd->cx;										//记下当前代码分配位置,这是while循环的开始位置
		statement(s);									//分析repeat后的语句块
		s2=statbegsys;
		s2+=semicolon;

		while (s2.InSet(sym))							//如果分析完一句后遇到分号或语句开始符循环分析下一句语句
		{
			if (sym==semicolon) 
				getsym();
			else 
				err->Add(10);
			statement(s);
		}

		if (sym==untilsym)
		{
			getsym();
			condition(fsys);							//对这个逻辑表达式进行分析计算
			cd->Gen(jpc,0,cx1);							//生成条件跳转指令,跳转位置为循环位置之前
		}
		else
			err->Add(25);
		break;
	}
	test(fsys,CSymset(),19);							//至此一个语句处理完成,一定会遇到fsys集中的符号,如果没有遇到,就抛19号错
}

CSymtax::~CSymtax(void)
{
}

⌨️ 快捷键说明

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