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 + -
显示快捷键?