编译原理程序设计实践(五) 语法分析的相关函数

语法分析采用递归子程序,基本上一条规则对应一个分析函数。

声明处理的相关代码

/* 常量声明处理过程constdeclaration */
void constdeclaration(const int& lev, int& tx,int &dx)
{
	if  (sym == ident)/* 常量声明过程开始遇到的第一个符号必然应为标识符 */
	{
		getsym( ); /* 获取下一个token */
		if  (in (sym, symset{eql,becomes})) /* 如果是等号或赋值号 */
		{
			if  (sym == becomes)/* 如果是赋值号(常量生明中应该是等号) */
				error(1); /* 抛出1号错误 */
			/* 这里其实自动进行了错误纠正使编译继续进行,把赋值号当作等号处理 */
			getsym( ); /* 获取下一个token,等号或赋值号后应接上数字 */
			if  (sym == number)/* 如果的确是数字 */ 
			{
				enter(constant,lev,tx,dx); /* 把这个常量登陆到符号表 */
				getsym( ); /* 获取下一个token,为后面作准备 */
			}
			else
				error(2); /* 如果等号后接的不是数字,抛出2号错误 */
		}
		else
			error(3); /* 如果常量标识符后接的不是等号或赋值号,抛出3号错误 */
	}
	else
		error(4); /* 如果常量声明过程遇到的第一个符号不为标识符,抛出4号错误 */
} /* constdeclaration */;
/* 变量声明过程vardeclaration */  
void vardeclaration(const int &lev,int& tx,int &dx)
{
	if  (sym == ident)/* 变量声明过程开始遇到的第一个符号必然应为标识符 */
	{
		enter(variable,lev,tx,dx); /* 将标识符登陆到符号表中 */
		getsym(); /* 获取下一个token,为后面作准备 */
	}
	else
		error(4); /* 如果变量声明过程遇到的第一个符号不是标识符,抛出4号错误 */
} /* vardeclaration */;


表达式的相关处理

void expression(const symset& fsys,const int &lev ,int &tx);
/* 因子处理过程factor */
/* 参数说明:fsys: 如果出错可用来恢复语法分析的符号集合 */
void factor(const symset& fsys,const int& lev,int &tx)
{
	int i;
	test(facbegsys, fsys, 24); /* 开始因子处理前,先检查当前token是否在facbegsys集合中。 */
	/* 如果不是合法的token,抛24号错误,并通过fsys集恢复使语法处理可以继续进行 */         
	while (in(sym, facbegsys)) /* 循环处理因子 */
	{
		if  (sym == ident)/* 如果遇到的是标识符 */
		{
			i = position(id, tx) ; /* 查符号表,找到当前标识符在符号表中的位置 */
			if  (i == 0)/* 如果查符号表返回为0,表示没有找到标识符 */
				error(11); /* 抛出11号错误 */
			else
				switch(table[i].kind)
				{
				case constant: 
					gen(lit, 0, table[i].val); /* 如果这个标识符对应的是常量,值为val,生成lit指令,把val放到栈顶 */
					break;
				case variable: 
					gen(lod, lev - table[i].level, table[i].adr); /* 如果标识符是变量名,生成lod指令, */
					/* 把位于距离当前层level的层的偏移地址为adr的变量放到栈顶 */
					break;
				case procedure: 
					error(21); /* 如果在因子处理中遇到的标识符是过程名,出错了,抛21号错 */
					break;
			}
			getsym( ); /* 获取下一token,继续循环处理 */
		}
		else if  (sym == number)/* 如果因子处理时遇到数字 */
		{
			if  (num > amax) /* 如果数字的大小超过允许最大值amax */
			{
				error(31); /* 抛出31号错 */
				num = 0; /* 把数字按0值处理 */
			}
			gen(lit, 0, num); /* 生成lit指令,把这个数值字面常量放到栈顶 */
			getsym( ); /* 获取下一token */
		}
		else if  (sym == lparen)/* 如果遇到的是左括号 */
		{
			getsym( ); /* 获取一个token */
			expression( symset{rparen} + fsys,lev,tx); /* 递归调用expression子程序分析一个子表达式 */
			if  (sym == rparen)/* 子表达式分析完后,应遇到右括号 */
				getsym( ); /* 如果的确遇到右括号,读取下一个token */
			else
				error(22); /* 否则抛出22号错误 */
		}
		test(fsys, facbegsys, 23); /* 一个因子处理完毕,遇到的token应在fsys集合中 */
						/* 如果不是,抛23号错,并找到下一个因子的开始,使语法分析可以继续运行下去 */
	}
} /* factor */;
/* 项处理过程term */
/* 参数说明:fsys: 如果出错可用来恢复语法分析的符号集合 */
void term(const symset& fsys ,const int & lev ,int &tx)
{ /* term */
	symbol mulop;
	factor(symset{times, slash} + fsys, lev ,tx); /* 每一个项都应该由因子开始,因此调用factor子程序分析因子 */
	while( in(sym, symset{times, slash}) ) /* 一个因子后应当遇到乘号或除号 */
	{
		mulop = sym ; /* 保存当前运算符 */
		getsym( ); /* 获取下一个token */
		factor(fsys + symset{times, slash},lev , tx); /* 运算符后应是一个因子,故调factor子程序分析因子 */
		if  (mulop == times)/* 如果刚才遇到乘号 */
			gen(opr, 0, 4); /* 生成乘法指令 */
		else
			gen(opr, 0, 5); /* 不是乘号一定是除号,生成除法指令 */
	}
}  /* term */;
void expression(const symset& fsys  ,const int & lev ,int &tx)
{ 
	symbol addop;
	/* expression */
	if  (in(sym, symset{plus, minus}) ) /* 一个表达式可能会由加号或减号开始,表示正负号 */
	{
		addop = sym ; /* 把当前的正号或负号保存起来,以便下面生成相应代码 */
		getsym( ); /* 获取一个token */
		term(fsys + symset{plus, minus} ,lev ,tx); /* 正负号后面应该是一个项,调term子程序分析 */
		if  (addop == minus)/* 如果保存下来的符号是负号 */
			gen(opr, 0, 1); /* 生成一条1号操作指令:取反运算 */
			/* 如果不是负号就是正号,不需生成相应的指令 */
	}
	else /* 如果不是由正负号开头,就应是一个项开头 */
		term(fsys + symset{plus, minus},lev, tx); /* 调用term子程序分析项 */ 
	while(in(sym, symset{plus, minus})) /* 项后应是加运算或减运算 */
	{
		addop = sym ; /* 把运算符保存下来 */
		getsym( ); /* 获取下一个token,加减运算符后应跟的是一个项 */
		term(fsys + symset{plus, minus} ,lev ,tx); /* 调term子程序分析项 */
		if  (addop == plus)/* 如果项与项之间的运算符是加号 */
			gen(opr, 0, 2); /* 生成2号操作指令:加法 */
		else /* 否则是减法 */
			gen(opr, 0, 3); /* 生成3号操作指令:减法 */
	}
}  /* expression */;
/* 条件处理过程condition */
/* 参数说明:fsys: 如果出错可用来恢复语法分析的符号集合 */
void condition(const symset& fsys,const int & lev ,int &tx)
{
	symbol relop; /* 用于临时记录token(这里一定是一个二元逻辑运算符)的内容 */
	if  (sym == oddsym)/* 如果是odd运算符(一元) */
	{
		getsym( ); /* 获取下一个token */
		expression(fsys, lev , tx); /* 对odd的表达式进行处理计算 */
		gen(opr, 0, 6); /* 生成6号操作指令:奇偶判断运算 */
	}
	else /* 如果不是odd运算符(那就一定是二元逻辑运算符) */
	{
		expression(symset{eql, neq, lss, leq, gtr, geq} + fsys,lev ,tx); /* 对表达式左部进行处理计算 */
		if  (!(in(sym ,symset{eql, neq, lss, leq, gtr, geq}))) /* 如果token不是逻辑运算符中的一个 */
			error(20); /* 抛出20号错误 */
		else
		{
			relop = sym ; /* 记录下当前的逻辑运算符 */
			getsym( ); /* 获取下一个token */
			expression(fsys ,lev ,tx); /* 对表达式右部进行处理计算 */
			switch (relop)  /* 如果刚才的运算符是下面的一种 */
			{		
			case eql: 
				gen(opr, 0, 8); /* 等号:产生8号判等指令 */
				break;
			case neq: 
				gen(opr, 0, 9); /* 不等号:产生9号判不等指令 */
				break;
			case lss: 
				gen(opr, 0, 10); /* 小于号:产生10号判小指令 */
				break;
			case geq: 
				gen(opr, 0, 11); /* 大于等号号:产生11号判不小于指令 */
				break;
			case gtr: 
				gen(opr, 0, 12); /* 大于号:产生12号判大于指令 */
				break;
			case leq: 
				gen(opr, 0, 13); /* 小于等于号:产生13号判不大于指令 */
				break;
			default:
				break;
			}
		}
	}
}  /* condition */


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值