📄 scan.cpp
字号:
/******************************************************************
** 文件名: scan.cpp
** 描 述: 这是一个完整的扫描器,实现C-语言的完整扫描功能。具体见
** 程序中的注释。
******************************************************************/
#include "globals.h"
#include "scan.h"
#include "ExternGla"
/**********************类CStates**************************************/
/***********************************
**拷贝构造函数,建立状态链表的一个结点。
************************************/
CStates::CStates(StateType pa_EnStates,
void (*paStates)(),CStates *pa_pNextState){
m_EnStates=pa_EnStates;
fnState=paStates;
m_pNextState=pa_pNextState;
}
/**********************类CScaner***************************************/
/**************************************
**静态数据成员进行初始化
**************************************/
CSymbols CScaner::m_ArraySymbols[10]=
{{'+',PLUS}, {'-', MINUS}, {'*', TIMES},{',',COMMA},{':', COLON}, {'(', LLPAREN},
{')', RLPAREN}, {'{', LGPAREN}, {'}', RGPAREN}, {';', SEMI}};
CReserved CScaner::m_ReservedWords[MAXRESERVED]=
{{"if",IF},{"else",ELSE},{"while",WHILE}, {"for",FOR},
{"goto",GOTO},{"break",BREAK},{"continue",CONTINUE},{"return",RETURN},
{"void",VOID},{"int",INT},{"char",CHAR},
{"float",FLOAT},{"writeb",WRITEB},{"writed",WRITED}};
CStates *CScaner::m_pFirstState=NULL;
StateType CScaner::m_Enstate=START;
TokenType CScaner::currentToken=VOID;
char CScaner::m_chGetchar='\0';
int CScaner::m_isave=TRUE;
int CScaner::m_iLinepos=0;
int CScaner::m_iBufsize=0;
char CScaner::m_pLineBuf[BUFLEN]=" ";
/**************************************************
**扫描器构造函数主要完成关于DFA链表的创建
**************************************************/
CScaner::CScaner(){
AllGlobals.lineno=0; //起初扫描行初始化为零。
try{
OnStates(); //完成链表的创建。
}
catch (bad_alloc){ //处理堆分配异常。
cout<<"Can't be allocated in heap, the programme must be terminated."<<endl;
exit(1);}
catch (...){ //处理其他类型的异常。
cout<<"Comething error."<<endl;
exit(1);}
};
CScaner::~CScaner(){
m_pMobileStates=m_pFirstState->m_pNextState;
m_pFirstState->m_pNextState=NULL;
m_pFirstState=m_pMobileStates; //把环型链表的环打断,以利于顺序销毁。
while(m_pFirstState!=NULL){
m_pMobileStates=m_pFirstState->m_pNextState;
delete m_pFirstState;
m_pFirstState=m_pMobileStates;
}
}
/***************************************************************************
**执行扫描的主函数
**功能简单描述:该函数在状态链表上匹配相应状态,并进行
**相应的函数进行扫描处理。
**举列如下:如扫描<=:
** 初始状态:字符数组m_tokenString为空,状态m_Enstate为START,
** 进行循环,匹配到STRAT相应的处理函数为OnStart,进行该函数,
** 该函数读取一个'<'返回状态m_Enstate为INNGT(小于等于,即'<'
** 号有可能后面还跟有'=', 保存'<',再进入INNGT的处理函数OnIngt进行
** 处理,读取到'=', 确定currentToken=NGT(不大于),最后状态m_Enstate
** 为DONE,m_tokenString="<=",扫描结束。
***************************************************************************/
TokenType CScaner::getToken(void){
int tokenStringIndex = 0;
m_Enstate=START;
m_tokenString[0]='\0'; //扫描开始前,所有相关变量初始化。
m_pMobileStates=m_pFirstState;
while(m_Enstate != DONE){ //一个循环完成一个记号扫描。
m_isave=TRUE;
try{
while(m_pMobileStates && m_Enstate != m_pMobileStates->m_EnStates)
m_pMobileStates=m_pMobileStates->m_pNextState;
if(m_pMobileStates) m_pMobileStates->fnState(); //执行匹配状态的相应处理函数。
else throw CInvalid_pointer();
}
catch(CInvalid_pointer& pa_pointer){
pa_pointer.Bad_pointer();
}
if((m_isave) && (tokenStringIndex <= MAXTOKENLEN))
m_tokenString[tokenStringIndex++] =m_chGetchar;//保存读到的字符。
if(m_Enstate==DONE){
m_tokenString[tokenStringIndex]='\0';
if(currentToken == ID)
currentToken = reservedLookup(m_tokenString); //对于ID类型,可能为保留字。
}
}
if(AllFlags.m_iTraceScan==1){ //输出扫描信息。
cout<<AllGlobals.lineno<<" ";
printToken(currentToken, m_tokenString);
}
return currentToken;
}
/**************建立状态链表的函数*****************/
void CScaner::OnStates(void){
CStates *pMobileStates;
AddStates(DONE, OnDone);
CStates *tempState=pMobileStates;
AddStates(INCOMMENT, OnIncomment);
AddStates(INNEQ, OnInneq);
AddStates(INAND, OnInand);
AddStates(INOR, OnInor);
AddStates(INNGT, OnInngt);
AddStates(INNLT, OnInnlt);
AddStates(INASSIGN, OnInassigh);
AddStates(INCHAR,OnInchar);
AddStates(INNUM, OnInnum);
AddStates(INID, OnInid);
AddStates(START, OnStart);
tempState->m_pNextState=m_pFirstState;
return;
}
/*******************************************************
**从文件缓冲区中读入一个字符,若读完,则从文件中读入一行。
*******************************************************/
char CScaner::getNextChar(void){
if(!(m_iLinepos<m_iBufsize)){ //注意,他们的初始状态都为零,所以文件被读取。
if(AllFlags.m_iTraceScan==1) cout<<endl;
if(AllGlobals.source.getline(m_pLineBuf,BUFLEN)){
AllGlobals.lineno++; //读入一行,文件行数加一。
if(AllFlags.m_iTraceScan==1)
cout<<AllGlobals.lineno<<":"<<m_pLineBuf<<endl;
m_iBufsize=strlen(m_pLineBuf);
m_iLinepos=0; //缓冲区位置指针归零。
return m_pLineBuf[m_iLinepos++];
}
else return EOF;
}
else return m_pLineBuf[m_iLinepos++];
};
void CScaner::ungetNextChar(void){
m_iLinepos--;
}
/*************************************************
** 每个记号扫描的起始状态从这里开始,记号被分成三种,
** "- * , ( ) { } ; + :"共十个为无二义性的单字符
** 记号,被保存在静态数组m_ArraySymbols[]中; 字符,
** 数字, 空格,换行,tab为第二类,单独处理。
** 第三类如'<'跟'<="等,第一个字符相同,需另加状态加于
** 处理。
****************************************************/
void CScaner::OnStart(void){
m_chGetchar=getNextChar();
int i=0;
while(i<=9 && m_ArraySymbols[i].m_chSymbols!=m_chGetchar) i++;
if(i<10){
currentToken=m_ArraySymbols[i].m_EnSymbols;
m_Enstate=DONE;
return;
} //处理第一类记号。
if(isdigit(m_chGetchar)) m_Enstate=INNUM;
else if (isalpha(m_chGetchar)) m_Enstate=INID;
else if((m_chGetchar==' ') || (m_chGetchar=='\t')
|| (m_chGetchar=='\n') || (m_chGetchar==NULL))
m_isave=FALSE; //处理第二类记号。
else{
switch(m_chGetchar){
case EOF:
m_isave=FALSE;
m_Enstate=DONE;
currentToken = ENDFILE;
break;
case '=':
m_Enstate=INASSIGN;
break;
case '<':
m_Enstate=INNGT;
break;
case '>':
m_Enstate=INNLT;
break;
case '!':
m_Enstate=INNEQ;
break;
case '&':
m_Enstate=INAND;
break;
case '|':
m_Enstate=INOR;
break;
case '\'':
m_isave=FALSE;
m_Enstate=INCHAR;
break;
case '/':
m_isave=FALSE;
m_Enstate=INCOMMENT;
break;
default:
m_Enstate=DONE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -