?? 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 + -