詞法分析的理論知識不少,包括了正規式、正規文法、它們之間的轉換以及確定的有窮自動機和不確定的有窮自動機等等。。。
要自己寫一個詞法分析器也不會很難,只要給出了最簡的有窮自動機,就能很方便實現了,用if、switch-case來寫一通所謂的狀態轉換就可以,我近期會寫一個簡單的詞法剖析器來作為例子。。。
現在已經有人發明了一個叫LEX的工具讓你去應用,那我們就省了不少力氣,畢竟沒到萬不得已的時候,我們都沒必要重新發明輪子,從另一個角度來說,使用工具是我們人類知識繼承的一種方法,也是我們比其他動物優勝的地方。所以這篇文章我們就來探討一下如何使用這個工具。。。
工具的準備:
我是用了VC6和flex.exe(這個程式可以在WINDOWS下使用,下面還帶了個BISON。exe的程式,可以上網找找看,下載下來,因為我都忘記在哪裡下的了。。。)
flex.exe的使用:
首先要寫個尾碼為 .l 的檔案,這個檔案分為了上中下三部分,三部分是用兩串的%%來隔開的。
開始部分是指你要準備的工作,例如定義一下要用到的變數阿之類的。。。
中間部分是指要識別的字串和識別到之後要進行的動作。。。
最後部分就是一些要拷貝到組建檔案裡的C代碼了,LEX基本原封不動的幫你拷貝過去。。。
下面就是我寫的 .l 檔案,看到兩個%%隔開的三部分了吧,如果用flex組建檔案的過程中出現什麼 "yywrap"的錯誤,就像我一樣在下面加上 %option noyywrap 這一句:
%{
int num_lines = 0, num_chars = 0;
%}
%option noyywrap
%%
[a-z] ECHO;
/n ++num_lines; ++num_chars;
. ++num_chars;
%%
int main(int argc, char* argv[])
{
yylex();
printf( "# of lines = %d, # of chars = %d/n", num_lines, num_chars );
}
主要還是中間部分比較重要,在LEX的參考文檔裡,是一種 pattern--action 的對應,識別出來,要幹嗎就由你來定了,這裡是:
1、[a-z] ECHO; 用ECHO來輸出一下 字母字串,
2、/n ++num_lines; ++num_chars;碰到/n分行符號就行數加一,這樣可以用來統計代碼的行數,
3、. ++num_chars; 這裡是碰到任何字元都字元數加一,這樣可以統計一下字元的個數。
然後就用flex.exe來"編譯"一下,如果沒有錯誤,就直接通過並產生一個"lex.yy.c" 檔案。。。
vc6和flex.exe的整合:
flex.exe給我們產生了個 .c 的檔案,我們要在vc6裡使用它,那首先就是建立一個console工程,把這個 C檔案包含進來。上面寫的.l 檔案也要和"lex.yy.c" 檔案放在一起。。。
然後直接編譯,OK,通過了,我們運行之,然後敲一些數字和一些字母斷行符號,我們就會發現,程式把字母顯示出來了(ECHO),數字沒有顯示,然後我們按 CTRL+break 來退出程式的時候,就會輸出有多少行和多少個字元。。。
上面我們的輸出和輸入都是標準的,就是螢幕,如果我們要讀入一個檔案來分析應該怎麼辦呢?
很簡單,我們就改寫一下"lex.yy.c" 檔案裡的main()函數,改成下面這樣就好了(開啟一個檔案,把輸入 yyin 指向檔案的控制代碼,yyin 和 yylex 都是lex產生的固定變數和函數,還有一些yyout什麼的,先自己看看哈):
int main(int argc, char* argv[])
{
FILE *f = fopen("main.txt", "r");
yyin = f;
yylex();
printf( "# of lines = %d, # of chars = %d/n", num_lines, num_chars );
}
好了,一個簡單的詞法剖析器就產生了,入了門,要做些別的事情就發揮你的想象力吧。。。
尚待解決的問題:
使用flex.exe和vc6的整合還是很不舒服,如果flex產生的是c++檔案,又會要求包含一些unix下的標頭檔,我還沒找到解決的辦法,知道的請告訴我一下,先謝過哈。