?? scanner.cpp
字號(hào):
/****************************************************/
/* 文件 scanner.cpp */
/* 說明 TINY編譯器的詞法掃描器實(shí)現(xiàn) */
/* 主題 編譯器結(jié)構(gòu):原理和實(shí)例 */
/****************************************************/
/************ 該代碼文件所包含的頭文件 **************/
#include "globals.h" /* 該頭文件globals.h定義了全局類與變量 */
#include "string.h"
#include "ctype.h" /* 用到了該庫中的isalnum,isalpha,isdigit函數(shù) */
#include "util.h" /* 該頭文件util.h定義了相關(guān)功能函數(shù) */
#include "math.h" /* 用到了這個(gè)庫里的取模運(yùn)算 */
/*****************詞法分析器確定性有限自動(dòng)機(jī)DFA的狀態(tài)類型*************/
/* START 開始狀態(tài); INASSIGN 賦值狀態(tài); INRANGE 下標(biāo)范圍狀態(tài); */
/* INNUM 數(shù)字狀態(tài); INID 標(biāo)識(shí)符狀態(tài); DONE 完成狀態(tài); */
/* INCHAR 字符狀態(tài);INCOMMENT 注釋狀態(tài); */
typedef enum
{ START,INASSIGN,INRANGE,INCOMMENT,INNUM,INID,INCHAR,DONE }
StateType;
/* tokenString用于保存標(biāo)識(shí)符和保留字單詞的詞元,長度41 */
char tokenString[MAXTOKENLEN+1];
/* BUFLEN源代碼行的輸入緩沖區(qū)長度為256 */
#define BUFLEN 256
/* lineBuf為當(dāng)前輸入代碼行緩沖區(qū) */
static char lineBuf[BUFLEN];
/* linepos為在代碼緩沖區(qū)LineBuf中的當(dāng)前字符位置,初始為0 */
static int linepos = 0;
/* bufsize為當(dāng)前緩沖器中所存字串大小 */
static int bufsize = 0;
/* EOF_flag當(dāng)為文件尾時(shí),改變函數(shù)ungetNextChar功能 */
static int EOF_flag = FALSE;
/*******************************************************************/
/* 函數(shù)名 getNextChar */
/* 功 能 取得下一非空字符函數(shù) */
/* 說 明 該函數(shù)從輸入緩沖區(qū)lineBuf中取得下一個(gè)非空字符 */
/* 如果lineBuf中的字串已經(jīng)讀完,則從源代碼文件中讀入一新行 */
/*******************************************************************/
static int getNextChar(void)
{
/* 當(dāng)前代碼輸入行緩沖器lineBuf已經(jīng)耗盡 */
if (!(linepos < bufsize))
{
/* 源代碼行號(hào)lineno加1 */
lineno++;
/* 從源文件source中讀入BUFLEN-2(254)個(gè)字符到行緩沖區(qū)lineBuf中 *
* fgets在的lineBuf末尾保留換行符.并在末尾加了一個(gè)NULL字符表示結(jié)束 */
if (fgets(lineBuf,BUFLEN-1,source))
{
/* 如果源文件追蹤標(biāo)志EchoSource為TRUE *
* 將源程序行號(hào)lineno及行內(nèi)容lineBuf在詞法掃描時(shí)寫入列表文件listing */
if (EchoSource) fprintf(listing,"%4d: %s",lineno,lineBuf);
/* 取得當(dāng)前輸入源代碼行的實(shí)際長度,送給變量bufsize */
bufsize = strlen(lineBuf);
/* 輸入行緩沖區(qū)lineBuf中當(dāng)前字符位置linepos指向lineBuf開始位置 */
linepos = 0;
/* 取得輸入行緩沖區(qū)lineBuf中下一字符 */
return lineBuf[linepos++];
}
else
{
/* 未能成功讀入新的代碼行,fget函數(shù)返回值為NULL *
* 已經(jīng)到源代碼文件末尾,設(shè)置EOF_flag標(biāo)志為TRUE */
EOF_flag = TRUE;
/* 函數(shù)返回EOF */
return EOF;
}
}
/* 行輸入緩沖區(qū)lineBuf中字符還未讀完,直接取其中下一字符,函數(shù)返回所取字符 */
else return lineBuf[linepos++];
}
/********************************************************/
/* 函數(shù)名 ungetNextChar */
/* 功 能 字符回退函數(shù) */
/* 說 明 該過程在行輸入緩沖區(qū)lineBuf中回退一個(gè)字符 */
/* 用于超前讀字符后不匹配時(shí)候的回退 */
/********************************************************/
static void ungetNextChar(void)
{
/* 如果EOF_flag標(biāo)志為FALSE,不是處于源文件末尾 *
* 輸入行緩沖區(qū)lineBuf中當(dāng)前字符位置linepos減1 */
if (!EOF_flag) linepos-- ;
}
/******************* 保留字查找表 ********************/
static struct
{ char* str;
LexType tok;
} reservedWords[MAXRESERVED]
= { {"program",PROGRAM},{"type",TYPE},{"var",VAR},{"procedure",PROCEDURE}
,{"begin",BEGIN},{"end",END},{"array",ARRAY},{"of",OF},{"record",RECORD}
,{"if",IF},{"then",THEN},{"else",ELSE},{"fi",FI},{"while",WHILE}
,{"do",DO},{"endwh",ENDWH},{"read",READ},{"write",WRITE},{"return",RETURN}
,{"integer",INTEGER},{"char",CHAR} };
/**************************************************************/
/* 函數(shù)名 reservedLookup */
/* 功 能 保留字查找函數(shù) */
/* 說 明 使用線性查找,查看一個(gè)標(biāo)識(shí)符是否是保留字 */
/* 標(biāo)識(shí)符如果在保留字表中則返回相應(yīng)單詞,否則返回單詞ID */
/**************************************************************/
static LexType reservedLookup (char * s)
{
int i;
/* 在保留字表中查找,MAXRESERVED已經(jīng)定義為8,為保留字?jǐn)?shù) */
for (i=0;i<MAXRESERVED;i++)
/* 線性查保留字表,察看函數(shù)參數(shù)s指定標(biāo)識(shí)符是否在表中 *
* 當(dāng)兩字符串匹配的時(shí)候,函數(shù)strcmp返回值為0(FALSE) */
if (!strcmp(s,reservedWords[i].str))
/* 字符串s與保留字表中某一表項(xiàng)匹配,函數(shù)返回對(duì)應(yīng)保留字單詞 */
return reservedWords[i].tok;
/* 字符串s未在保留字表中找到,函數(shù)返回標(biāo)識(shí)符單詞ID */
return ID;
}
/****************************************
********* 詞法掃描器基本函數(shù) **********
****************************************/
/************************************************************/
/* 函數(shù)名 getTokenlist */
/* 功 能 取得單詞函數(shù) */
/* 說 明 函數(shù)從源文件字符串序列中獲取所有Token序列 */
/* 使用確定性有限自動(dòng)機(jī)DFA,采用直接轉(zhuǎn)向法 */
/* 超前讀字符,對(duì)保留字采用查表方式識(shí)別 */
/* 產(chǎn)生詞法錯(cuò)誤時(shí)候,僅僅略過產(chǎn)生錯(cuò)誤的字符,不加改正 */
/************************************************************/
void getTokenlist(void)
{
ChainNodeType *chainHead; /*鏈表的表頭指針*/
ChainNodeType *currentNode; /*指向處理當(dāng)前Token的當(dāng)前結(jié)點(diǎn)*/
ChainNodeType *preNode; /*指向當(dāng)前結(jié)點(diǎn)的前驅(qū)結(jié)點(diǎn)*/
ChainNodeType *tempNode; /*臨時(shí)指針,用于釋放鏈表部分*/
TokenType currentToken; /*存放當(dāng)前的Token*/
/*產(chǎn)生鏈表的第一個(gè)結(jié)點(diǎn)*/
chainHead=preNode=currentNode=(ChainNodeType *)malloc(CHAINNODELEN);
/*初始化當(dāng)前結(jié)點(diǎn)中,指向下一個(gè)結(jié)點(diǎn)的指針為空*/
(*currentNode).nextToken=NULL;
do
{ /* tokenStringIndex用于記錄當(dāng)前正在識(shí)別單詞的詞元存儲(chǔ)區(qū) *
* tokenString中的當(dāng)前正在識(shí)別字符位置,初始為0 */
int tokenStringIndex = 0;
/* 當(dāng)前狀態(tài)標(biāo)志state,始終都是以START作為開始 */
StateType state = START;
/* tokenString的存儲(chǔ)標(biāo)志save,整數(shù)類型 *
* 決定當(dāng)前識(shí)別字符是否存入當(dāng)前識(shí)別單詞詞元存儲(chǔ)區(qū)tokenString */
int save;
/* 當(dāng)前確定性有限自動(dòng)機(jī)DFA狀態(tài)state不是完成狀態(tài)DONE */
while (state != DONE)
{
/* 從源代碼文件中獲取下一個(gè)字符,送入變量c作為當(dāng)前字符 */
int c = getNextChar();
/* 當(dāng)前正識(shí)別字符的存儲(chǔ)標(biāo)志save初始為TRUE */
save = TRUE;
switch (state)
{
/* 當(dāng)前DFA狀態(tài)state為開始狀態(tài)START,DFA處于當(dāng)前單詞開始位置 */
case START:
/* 當(dāng)前字符c為數(shù)字,當(dāng)前DFA狀態(tài)state設(shè)置為數(shù)字狀態(tài)INNUM *
* 確定性有限自動(dòng)機(jī)DFA處于數(shù)字類型單詞中 */
if (isdigit(c))
state = INNUM;
/* 當(dāng)前字符c為字母,當(dāng)前DFA狀態(tài)state設(shè)置為標(biāo)識(shí)符狀態(tài)INID *
* 確定性有限自動(dòng)機(jī)DFA處于標(biāo)識(shí)符類型單詞中 */
else if (isalpha(c))
state = INID;
/* 當(dāng)前字符c為冒號(hào),當(dāng)前DFA狀態(tài)state設(shè)置為賦值狀態(tài)INASSIGN *
* 確定性有限自動(dòng)機(jī)DFA處于賦值類型單詞中 */
else if (c == ':')
state = INASSIGN;
/* 當(dāng)前字符c為.,當(dāng)前DFA狀態(tài)state設(shè)置為數(shù)組下標(biāo)界限狀態(tài)*/
/* INRANGE,確定性有限自動(dòng)機(jī)DFA處于數(shù)組下標(biāo)界限類型單詞中*/
else if (c == '.')
state = INRANGE;
/* 當(dāng)前字符c為',當(dāng)前DFA狀態(tài)state設(shè)置為字符標(biāo)志狀態(tài)*/
/* INCHAR,確定性有限自動(dòng)機(jī)DFA處于字符標(biāo)志類型單詞中*/
else if (c == '\'')
{
save = FALSE;
state = INCHAR;
}
/* 當(dāng)前字符c為空白(空格,制表符,換行符),字符存儲(chǔ)標(biāo)志save設(shè)置為FALSE *
* 當(dāng)前字符為分隔符,不需要產(chǎn)生單詞,無須存儲(chǔ) */
else if ((c == ' ') || (c == '\t') || (c == '\n'))
save = FALSE;
/* 當(dāng)前字符c為左括號(hào),字符存儲(chǔ)標(biāo)志save設(shè)置為FALSE *
* 當(dāng)前DFA狀態(tài)state設(shè)置為注釋狀態(tài)INCOMMENT *
* 確定性有限自動(dòng)機(jī)DFA處于注釋中,不生成單詞,無需存儲(chǔ) */
else if (c == '{')
{
save = FALSE;
state = INCOMMENT;
}
/* 當(dāng)前字符c為其它字符,當(dāng)前DFA狀態(tài)state設(shè)置為完成狀態(tài)DONE *
* 確定性有限自動(dòng)機(jī)DFA處于單詞的結(jié)束位置,需進(jìn)一步分類處理 */
else
{
state = DONE;
switch (c)
{
/* 當(dāng)前字符c為EOF,字符存儲(chǔ)標(biāo)志save設(shè)置為FALSE,無需存儲(chǔ) *
* 當(dāng)前識(shí)別單詞返回值currentToken設(shè)置為文件結(jié)束單詞ENDFILE */
case EOF:
save = FALSE;
currentToken.Lex = ENDFILE;
break;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -