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

📄 symtax.cpp

📁 PL/0编译器
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include "StdAfx.h"
#include ".\symtax.h"
#include <string.h>
#include "pl0.h"
#include "errors.h"
#include "wording.h"
#include "form.h"
#include "code.h"

CSymtax::CSymtax(CPl0 *p)
{
	pl=p;

	//确立声明开始、表达式开始和项开始符号集合	
	declbegsys+=constsym;
	declbegsys+=varsym;
	declbegsys+=procsym;

	statbegsys+=beginsym;
	statbegsys+=callsym;
	statbegsys+=ifsym;
	statbegsys+=whilesym;
	statbegsys+=repeatsym;

	facbegsys+=ident;
	facbegsys+=number;
	facbegsys+=lparen;
}

void CSymtax::Analysis()
{
	getsym();							//首次调用词法分析子程序,获取源程序的第一个词(token)
	lev=-1;
	CSymset s;
	s = declbegsys;
	s += statbegsys;
	s += period;
	block(s);
}

void CSymtax::test(CSymset s1,CSymset s2,int n)
{
	/*参数:s1:当语法分析进入或退出某一语法单元时当前单词符合应属于的集合 
			s2:在某一出错状态下,可恢复语法分析正常工作的补充单词集合 
			n:出错信息编号,当当前符号不属于合法的s1集合时发出的出错信息 */

	if (!s1.InSet(sym))                 //如果当前符号不在应属于的集合中
	{
		pl->errors->Add(n);				//发出n号错误
		s1+=s2;							//把s2集合补充进s1集合
		while (!s1.InSet(sym)) 
			getsym();					//通过循环找到下一个合法的符号,以恢复语法分析工作
	}
}

void CSymtax::block(CSymset fsys)
{
	lev++;

	int tx0,cx0;						//tx0:记录本层开始时符号表位置;cx0:记录本层开始时代码段分配位置
	CSymset s;
	CErrors *err = pl->errors;
	CCode *cd = pl->code;				//dm
	CForm *fm = pl->form;				//bg

	dx[lev]=3;							//地址指示器给出每层局部量当前已分配到的相对位置。
										//每一层最开始的位置有三个空间用于存放静态链SL、动态链DL和返回地址RA
	tx0 = fm->TableIndex();				//初始符号表指针指向当前层的符号在符号表中的开始位置
	fm->table[tx0].adr = cd->cx;		//符号表当前位置记下当前层代码的开始位置
	cd->Gen(jmp,0,0);					//产生一行跳转指令,跳转位置暂时未知填0
	if (lev>MAX_LEVEL) 
		err->Add(32);					//如果当前过程嵌套层数大于最大允许的套层数,发送32号错误
	do{
		if (sym==constsym)				//如果当前token是const保留字,开始进行常量声明 
		{
			getsym();					//获取下一个token,正常应为用作常量名的标识符
			do{
				constdeclaration();
				while (sym==comma)		//如果遇到了逗号则反复声明下一个常量
				{
					getsym();			//获取下一个token,这里正好应该是标识符 
					constdeclaration();
				}
				if (sym==semicolon)		//如果常量声明结束,应遇到分号
					getsym(); 
				else 
					err->Add(5);		//如果常量声明语句结束后没有遇到分号则发出5号错误
			}while (sym==ident);		//反复进行常量声明,如果遇到非标识符,则常量声明结束
		}
		if (sym==varsym)
		{								//如果当前token是var保留字,开始进行变量声明,与常量声明类似
			getsym();
			do{
				vardeclaration();
				while (sym==comma)
				{
					getsym();
					vardeclaration();
				}
				if (sym==semicolon) 
					getsym(); 
				else 
					err->Add(5);
			}while (sym==ident);
		}
		while (sym==procsym)			//循环声明各子过程
		{
			getsym();					//获取下一个token,此处正常应为作为过程名的标识符
			if (sym==ident)
			{
				fm->Enter(procedure);	//把这个过程登录到名字表中
				getsym();
			}
			else 
				err->Add(4);
			if (sym==semicolon)			//如果当前token为分号
				getsym(); 
			else 
				err->Add(5);
			s = fsys;
			s += semicolon;
			block(s);					//递归调用语法分析过程,当前层次加一,同时传递表头索引、合法单词符 
			if (sym==semicolon)
			{							//递归返回后当前token应为递归调用时的最后一个end后的分号
				getsym();
				s=statbegsys;
				s+=ident;
				s+=procsym;
				test(s,fsys,6);			//检查当前token是否合法,不合法则用fsys恢复语法分析同时抛6号错
			}
			else
				err->Add(5);			//如果过程声明后的符号不是分号,抛出5号错误 
		}
		s = statbegsys;
		s += ident;
		test(s,declbegsys,7);			//查当前状态是否合法,不合法则用声明开始符号作出错恢复、抛7号错
	}while (declbegsys.InSet(sym));		//直到声明性的源程序分析完毕,继续向下执行,分析主程序

	cd->code[fm->table[tx0].adr].a = cd->cx; //把前面生成的跳转语句的跳转位置改成当前位置
	fm->table[tx0].adr = cd->cx;		//地址为当前代码分配地址
	fm->table[tx0].size = dx[lev];		//长度为当前数据代分配位置
	cx0 = cd->cx;						//记下当前代码分配位置 
	cd->Gen(tint,0,dx[lev]);			//生成分配空间指令,分配dx个空间

	s=fsys;
	s+=semicolon;
	s+=endsym;
	statement(s);						//处理当前遇到的语句或语句块

	cd->Gen(opr,0,0);					//生成从子程序返回操作指令
	test(fsys,CSymset(),8);				//用fsys检查当前状态是否合法,不合法则抛8号错

	lev--;
}

//常量声明处理过程constdeclaration
void CSymtax::constdeclaration()
{
	CErrors *err = pl->errors;
	CForm *fm = pl->form;

	if ( sym == ident )						//常量声明过程开始遇到的第一个符号必然应为标识符
	{
		getsym();
		if (sym==eql || sym==becomes)		//如果是等号或赋值号
		{
			if (sym==becomes)				//如果是赋值号(常量生明中应该是等号)
				err->Add(1);
			getsym();
			if (sym==number)				//如果的确是数字
			{
				fm->Enter(constant);		//把这个常量登陆到符号表
				getsym();
			}
			else
				err->Add(2);				//如果等号后接的不是数字,抛出2号错误
		}
		else
			err->Add(3);					// 如果常量标识符后接的不是等号或赋值号,抛出3号错误
	}
	else
		err->Add(4);						//如果常量声明过程遇到的第一个符号不为标识符,抛出4号错误
}

//变量声明过程vardeclaration 
void CSymtax::vardeclaration()
{
	CErrors *err = pl->errors;
	CCode *cd = pl->code;
	CForm *fm = pl->form;

	if (sym==ident)							//变量声明过程开始遇到的第一个符号必然应为标识符
	{
		fm->Enter(variable);
		dx[lev]++;
		getsym();
	}
	else
		err->Add(4);						//如果变量声明过程遇到的第一个符号不是标识符,抛出4号错误
}

//因子处理过程factor
//参数说明:fsys: 如果出错可用来恢复语法分析的符号集合 
void CSymtax::factor(CSymset fsys)
{
	int i;
	CErrors *err = pl->errors;
	table_type *table = pl->form->table;
	CCode *cd = pl->code;

	test(facbegsys,fsys,24);				//开始因子处理前,先检查当前token是否在facbegsys集合中。 
											//如果不是合法的token,抛24号错误,并通过fsys集恢复使语法处理可以继续进行
	while (facbegsys.InSet(sym))			//循环处理因子
	{
		switch (sym)
		{
		case ident:							//如果遇到的是标识符
			i = pl->form->Position(pl->wording->id); //查符号表,找到当前标识符在符号表中的位置
			if (i==0)
				err->Add(11);				//如果查符号表返回为0,表示没有找到标识符
			else
			{
				switch (table[i].kind)
				{
				case constant:				//如果这个标识符对应的是常量,值为val,生成lit指令,把val放到栈顶
					cd->Gen(lit,0,table[i].val);
					break;
				case variable:				//如果标识符是变量名,生成lod指令
					cd->Gen(lod,lev-table[i].level,table[i].adr);
					//把位于距离当前层level的层的偏移地址为adr的变量放到栈顶
					break;
				case procedure:
					err->Add(21);			//如果在因子处理中遇到的标识符是过程名,出错了,抛21号错
					break;
				}
			}
			getsym();
			break;
		case number:						//如果因子处理时遇到数字
			if ( pl->wording->num > MAX_NUMBER )
			{
				err->Add(31);				//数字超界
				pl->wording->num = 0;
			}
			cd->Gen(lit,0,pl->wording->num);//生成lit指令,把这个数值字面常量放到栈顶
			getsym();
			break;
		case lparen:						//如果遇到的是左括号
			getsym();
			expression( fsys += rparen );	//递归调用expression子程序分析一个子表达式
			if (sym == rparen)
				getsym();					//子表达式分析完后,应遇到右括号
			else
				err->Add(22);
			break;
		}
		test(fsys,facbegsys,23);			//一个因子处理完毕,遇到的token应在fsys集合中
											//如果不是,抛23号错,并找到下一个因子的开始,使语法分析可以继续运行下去
	}
}

//项处理过程term
void CSymtax::term(CSymset fsys)
{
	symbol mulop;
	CSymset symset;
	symset+=fsys;
	symset+=times;
	symset+=slash;

	factor(symset);							//每一个项都应该由因子开始,因此调用factor子程序分析因子
	while ( sym==times||sym==slash )		//一个因子后应当遇到乘号或除号
	{
		mulop = sym;
		getsym();
		factor(symset);						//运算符后应是一个因子,故调factor子程序分析因子
		if (mulop == times)
			pl->code->Gen(opr,0,4);			//生成乘法指令
		else
			pl->code->Gen(opr,0,5);			//不是乘号一定是除号,生成除法指令
	}
}

//表达式处理过程expression
void CSymtax::expression(CSymset fsys)

⌨️ 快捷键说明

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