symbol.cpp

来自「Win32 Console下C++实现的PL/0语言编译程序」· C++ 代码 · 共 280 行

CPP
280
字号
/*
FileName:		symbol.cpp
Author:			LiWen
Create:			2005-11-23
Last Modified:	2005-12-30
*/

#include "compiler.h"

///////////////////////////////////////////////////////////////////////////////
//词法分析采取自动机模式,根据的到的字符进入不同的分析,新的
//类型的开始或者间隔符号标志着上一个词的结束;但这会给打印带
//来问题,在判断出词型的同时,下一个词的第一个字符已经被读入
//故程序采取了预读入模式,当move的时候才会把字符放入结果
//

/*************相关的宏定义,检测字符类型*******************/
#define ischar(a) (((a)>='a'&&(a)<='z')||(a)>='A'&&(a)<='Z')
#define isnum(n) ((n)>='0'&&(n)<='9')

char ch;					//存放取得的字符
int num;					//存放数字结果
char word[IDENTMAX];		//存放标识符、关键字
char cursym[IDENTMAX];
char lastword[IDENTMAX];	//上一word,错误报告用
char line[BUFSIZE];			//读取文件缓冲区
char symtype[SYMNUM][20];	//词类型,用于词法分析结果输出
int cp,lp,row,entag;		//当前读取字符指针,缓冲区末尾指针,行数,换行标志

symbol sym;					//当前词类型
symbol chsym[256];			//存放单字符运算符类型,以进行识别
SYM keyws[KEYNUM];			//关键字

extern bool DisWSwitch;		//显示词法分析结果开关
extern char str[];			//临时字串,中间结果
extern char WResult[];		//存放词法分析结果
extern FILE* fin;			//输入文件

/*=======================================================
函数:judge
参数:被识别为标识符的字串
描述:二分法查找,用于字串核对,检测是否为关键字
返回:是关键字,返回关键字类型,否则,返回标识符
========================================================*/
symbol judge(char* word){
	int begin, end, mid;
	begin = 0;
	end = KEYNUM - 1;
	word = strlwr(word);
	while(begin<=end){
		mid = (begin+end)/2;
		if(strcmp(word,keyws[mid].word) == 0){
			return keyws[mid].sym;
		}else if(strcmp(word,keyws[mid].word) < 0){
			end = mid-1;
		}else{
			begin = mid+1;
		}
	}
	return ident;
}
/*=======================================================
函数:preread
参数:无
描述:从缓冲区中预读取一个字符,赋给全局量ch
返回:正常0,文件末尾TMNT
========================================================*/
int preread(){
	/*如果缓冲区空*/
	if(cp == lp){
		cp = 0;
		ch = ' ';
		for(lp=0;lp<BUFSIZE;lp++){
			/*如果读到文件末尾*/
			if(fscanf(fin,"%c",&line[lp])==EOF){
				if(lp!=0)		//如果不是缓冲区首,不算错误
					break;
				/*report error*/
				PRT_REPORT(UNEXPECTED_FILE_END);
				return TMNT;
			}
		}
	}
	ch = line[cp];
	return 0;
}
/*=========================================================
函数:move
参数:无
描述:移动缓冲区内一个指针,记录换行
返回:无
==========================================================*/
void move(){
	if(entag == 1){		//换行
		row ++;
		entag = 0;
	}
	if(ch == 10)		//如果到了换行,置换行标志
		entag = 1;
	if(!(ch==' '||ch=='\t'||ch=='\n')){
		sprintf(str,"%c",ch);
		strcat(WResult,str);
		if(strlen(cursym)<IDENTMAX-1){
			strcat(cursym,str);
		}
	}
	cp ++;
	return;
}
/*=========================================================
函数:getsym
参数:无
描述:调用preread和move获取字符,并根据字符组成判断其类型
	  放到全局量sym内
返回:正常0,Fetal Error TMNT
==========================================================*/
int getsym(){
	int i;
	PRT_PREREAD();
	memset(cursym,0,IDENTMAX);
	if(strcmp(lastword,word) !=0){
		strcpy(lastword,word);
	}
	while(ch == ' '||ch == '\t'||ch == '\n'){		//为空格、Tab、换行
		move();
		PRT_PREREAD();
	}
	if(ischar(ch)){									//是字符,理解为标识符
		for(i=0; (ischar(ch)||isnum(ch)); i++){
			if(i>=IDENTMAX){						//超长部分不予处理
				move();
				PRT_PREREAD();
				continue;
			}
			word[i] = ch;
			move();
			PRT_PREREAD();
		}
		if(i>=IDENTMAX){							//报告标示符过长
			PRT_REPORT(IDENT_TOO_LONG);
			sym = ident;
			return 0;
		}
		word[i] = 0;
		sym = judge(word);							//判断标识符是否关键字
	}else if(isnum(ch)){							//是数字,理解为数字
		num = 0;
		for(i=0;isnum(ch);i++){
			num = num*10+(ch-'0');
			move();
			PRT_PREREAD();
		}
		if(i>NUMDMAX){								//数字位数过大
			PRT_REPORT(NUM_TOO_BIG);
			num = 0;
		}
		sym = number;
	}else if(ch == ':'){		//是:,按:=处理
		move();
		PRT_PREREAD();
		if(ch == '='){
			move();
			sym = becomes;
		}else{
			sym = nul;
		}
	}else if(ch == '>'){		//> or >=
		sym = gtr;
		move();
		PRT_PREREAD();
		if(ch == '='){
			move();
			sym = geq;
		}
	}else if(ch == '<'){		//< or <=
		sym = lss;
		move();
		PRT_PREREAD();
		if(ch == '='){
			move();
			sym = leq;
		}
	}else{						//按单字符处理
		sym = chsym[ch];
		move();
		if(sym == period){
			return 0;
		}
		else if(sym == nul)		//都不是,报告不可识别
			PRT_REPORT(UNKNOWN_SYMBOL);
		PRT_PREREAD();
	}
	return 0;
}
/*=========================================================
函数:symbolinit
参数:无
描述:进行词法分析前的变量初始化
返回:无
==========================================================*/
void symbolinit(){
	int i; 
	row = 0;
	entag = 1;
	lp = cp = 0;
	ch = ' ';
	/* 设置单字符符号 */
	for(i=0;i<=255;i++)chsym[i]=nul;
	chsym['+']=plus;
	chsym['-']=minus;
	chsym['*']=times;
	chsym['/']=slash;
	chsym['(']=lparen;
	chsym[')']=rparen;
	chsym['=']=eql;
	chsym[',']=comma;
	chsym['.']=period;
	chsym['#']=neq;
	chsym[';']=semicolon;
	/*设置关键字*/
	keyws[0].sym = beginsym;
	keyws[1].sym = callsym;
	keyws[2].sym = constsym;
	keyws[3].sym = dosym;
	keyws[4].sym = endsym;
	keyws[5].sym = ifsym;
	keyws[6].sym = oddsym;
	keyws[7].sym = procsym;
	keyws[8].sym = readsym;
	keyws[9].sym = thensym;
	keyws[10].sym = varsym;
	keyws[11].sym = whilesym;
	keyws[12].sym = writesym;
	strcpy(keyws[0].word,"begin");
	strcpy(keyws[1].word,"call");
	strcpy(keyws[2].word,"const");
	strcpy(keyws[3].word,"do");
	strcpy(keyws[4].word,"end");
	strcpy(keyws[5].word,"if");
	strcpy(keyws[6].word,"odd");
	strcpy(keyws[7].word,"procedure");
	strcpy(keyws[8].word,"read");
	strcpy(keyws[9].word,"then");
	strcpy(keyws[10].word,"var");
	strcpy(keyws[11].word,"while");
	strcpy(keyws[12].word,"write");
	/*设置类型对应的字串,用于打印*/
	strcpy(symtype[nul],"nul");
	strcpy(symtype[ident],"ident");
	strcpy(symtype[number],"number");
	strcpy(symtype[plus],"plus");
	strcpy(symtype[minus],"minus");
	strcpy(symtype[times],"times");
	strcpy(symtype[slash],"slash");
	strcpy(symtype[oddsym],"oddsym");
	strcpy(symtype[eql],"eql");
	strcpy(symtype[neq],"neq");
	strcpy(symtype[lss],"lss");
	strcpy(symtype[leq],"leq");
	strcpy(symtype[gtr],"gtr");
	strcpy(symtype[geq],"geq");
	strcpy(symtype[lparen],"lparen");
	strcpy(symtype[rparen],"rparen");
	strcpy(symtype[comma],"comma");
	strcpy(symtype[semicolon],"semicolon");
	strcpy(symtype[period],"period");
	strcpy(symtype[becomes],"becomes");
	strcpy(symtype[beginsym],"beginsym");
	strcpy(symtype[endsym],"endsym");
	strcpy(symtype[ifsym],"ifsym");
	strcpy(symtype[thensym],"thensym");
	strcpy(symtype[whilesym],"whilesym");
	strcpy(symtype[writesym],"writesym");
	strcpy(symtype[readsym],"readsym");
	strcpy(symtype[dosym],"dosym");
	strcpy(symtype[callsym],"callsym");
	strcpy(symtype[constsym],"constsym");
	strcpy(symtype[varsym],"varsym");
	strcpy(symtype[procsym],"procsym");
}

⌨️ 快捷键说明

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