最近我們在做乙個有關snl語言的編譯器,下面寫了一下大概流程
詞法分析器是編譯過程的第一階段,功能是
1.對以字串形式輸入的源程式(這裡是把源程式從檔案讀出,也可以在控制台輸入)按順序進行掃瞄,根據snl語言的詞法規則識別具有獨立意義的單詞(符號)序列,
如保留字(由語言系統自身定義的,通常是由字母組成的字串),
識別符號(一般是由字母開頭,字母、數字,或其它符號的任意組合構成的,這裡snl是由字母開頭,後面加字母或數字組成的,分析起來較簡單),
常量(包括整數常數、 實數常數、字串常量等),
特殊符號(運算子和界限,運算子表示程 序中算術運算、邏輯運算、字元運算、賦值運算的確定的字元或字串)等,
並輸出與其等價的token序列(這裡將token序列儲存在了檔案中)。
2.報告詞法錯誤!
詞法錯誤:語言字母表以外的非法字元
(用確定有限自動機可以容易識別)
**幾個問題和處理方法**
1.保留字的識別
把保留字當作一般識別符號識別,然後查詢保留字表,就是這裡的lex表,如果有,把它當作保留字處理,如果沒有按一般識別符號處理。
2.復合單詞的識別
有一類單詞是由兩個或者兩個以上符號組成的,有時字首部分也可以是乙個獨立的單詞
3.數的轉換
詞法分析應把字串轉換成數,「123」看成123
4.向前看幾個字元的處理
為了識別出乙個單詞需要向前看好幾個單詞
5.控制字元的處理
1)無用的空格符和製表符刪掉(這裡是自動忽略)
2)字串內的空格不能刪
3)換行符不能直接刪除,用於錯誤定位
4)注釋
源程式中的注釋沒有任何語法和語義上的意義,在進行詞法分析時可以直接將注釋忽略,不必生成token
5)直接在語義資訊部分儲存
語義資訊的長度有限制時,直接將識別符號或常量本身儲存於token中的語義(語義資訊是為了 後面進行的語義分析和**生成提供資訊)
構造詞法分析器的步驟:
1.確定詞法分析器的介面,即確定詞法分析器是作為語法分析的乙個子程式還是作為獨立一遍
2.確定單次分類和token結構
3.確定每一類單詞的描述正規表示式->nfa->dfa
4.設計演算法實現dfa 單詞的內部表示:
token token通常包含兩部分:token-type,attribute-value token-type: 說明單詞的類別,為語法分析提供資訊 attribute-value:單詞的屬性,為語義分析和**生成提供資訊 (這裡 token包含4部分:在源程式中的行數,lex表中的詞法資訊編碼,語法資訊,語義資訊 這裡用確定有限自動機dfa識別符號串)
輸入:以eof作為結束符的符號串行 輸出:token序列
資料結構:
struct token45
*/6 #include "
scanner.h"7
char* lexstr =;
15char* word=;
33 tokennode::tokennode(int linenum,int code,const
char *lexinfor,const
char*semaninfor)
39 list::~list()45}
4647
bool list::outtofile(const
char *filename)
4860
fclose(file);
61return1;
62}63bool
list::outtoscreen()
6473
return1;
74}7576
bool list::insertnode(tokennode*p)
83else
89return
true;90
}9192 list* scanner::scanner(const
char* sourcefile,const
char*tokenfile)
100int linenum=1; //
從第一行開始
101bool flag=true
;102 tokennode*ptr;
103 list *list=new list;//
新建乙個tokenlist,用以儲存分析得到的token序列
104while
(flag)
148}
149150
fclose(fp);
151if(list->start()!=0
)152 tokenlist=list;
153if(!list->outtofile(tokenfile))
154 cerr<<"
error:cannot open the lexfile!
"<155if(!list->outtoscreen())
156 cerr<<"
error:cannot write on screen!
"<157return
list;
158159
}160 state scanner::thestate(char
ch)else
if(isdigit(ch))else
if(issymbol(ch))else
if(ch=='
else
if(ch=='
'||ch=='\t'
)else
if(ch=='
\n'||ch=='
\r')else
if(ch==eof)else
177return
s8;178
}179
bool scanner::isletter(char
ch)184
bool scanner::isdigit(char
ch)189
bool scanner::issymbol(char
ch)196
int scanner::getcode(const
char*ch)
201}
202return -1
;203
}204
int scanner::isreservedword(const
char*ch)
209}
210return -1
;211
}212
void scanner::inserttokenlist(list* list,tokennode*ptr)
213217
void scanner::isletterstr(file*fp,int linenum,list*list)
225if(ch!=eof)
226ungetnextchar(fp);
227int lex=isreservedword(str1.c_str());
228if(lex!=-1)//
c_str() 以 char* 形式傳回 str 內含字串
229else
236}
237238
void scanner::isnumstr(file*fp,int linenum,list*list)
246if(ch!=eof)
247ungetnextchar(fp);
248 tokennode *ptr;
249 ptr=new tokennode(linenum,intc,"
intc
",str2.c_str());
250inserttokenlist(list,ptr);
251}
252void scanner::issignstr(file*fp,int linenum,list*list)
265else
266ungetnextchar(fp);
267return
;268
}269
if(ch=='.'
) 270
278if(ch1!=eof)
279ungetnextchar(fp);
280 ptr=new tokennode(linenum,getcode("
."),"
dot","
程式結束符,無語義資訊");
281inserttokenlist(list,ptr);
282return
;283
}284
string
str;
285 str+=ch;
286 ptr=new tokennode(linenum,getcode(str.c_str()),word[getcode(str.c_str())],"
單分隔符,無語義資訊");
287inserttokenlist(list,ptr);
288}
289void scanner:: iscommentstr(file*fp,int
linenum) ')
295304 ch=getnextchar(fp);
305}
306307
}308
int scanner:: getlex(const
char *ch)
309315
return -1
;316 }
手工打造編譯器之詞法分析器3
逆波蘭表示式,可以去除括號 建立適合計算機處理的表示式,該表示式有正確的運算優先順序。正常的表示式 逆波蘭表示式 a b a,b,a b c a,b,c,a b c d a,b,c,d,a d b c a,d,b,c,a 1 3 a 1,3 運算的時候,遇到可以歸併的就歸併計算。如 5 4 3 2 ...
編譯器 詞法分析
總結 詞法分析 字串流 mov sum,x 執行加法運算 單詞流 mov sum,x 屬性字流 token type instr token type ident token type comma token type ident語法分析token currtoken getnexttoken 從屬...
編譯原理之詞法分析器(C C)
從乙個檔案中讀取原始碼,執行後可以直接看到結果,也可在指定檔案中檢視結果。這個詞法分析器只實現了部分關鍵字 字元等的識別,可在key陣列自行新增,種別碼的判別與新增用case更加方便,可寫下試試。include include include include include using namesp...