1. 程式人生 > >編譯原理flex自動構造詞法分析基本瞭解

編譯原理flex自動構造詞法分析基本瞭解

安裝flex 在Ubuntu下安裝flex非常簡單,只需要在終端中輸入

  1. sudo apt-get install flex

即可;

如果說找不到flex,可能你需要更新系統的源,百度一下“Ubuntu更新源”,應該可以解決;

flex 什麼是flex? flex是指 fast lexical analyzer generator,快速詞法分析器生成器,也就是說,flex用於產生詞法分析器;

flex的輸入是檔案或輸入裝置,這些輸入中的資訊以正則表示式和C程式碼的形式組成,這些形式被稱為規則(rule); flex的預設輸出是C語言的原始碼檔案:lex.yy.c,也可以重新命名;該檔案通過編譯生成可執行的檔案; 當可執行檔案被執行時,其分析輸入中可能存在的符合規則的內容,當找到任何一個正則表示式相匹配內容時,相應的C程式碼將被執行;

flex的輸入檔案由3段組成,用一行中只有%%來分隔;

定義:definition
%%
規則:rules
%%
使用者程式碼:code

定義部分 其中定義有變數宣告,正則表示式宣告; 變數宣告有兩種: 例1:

%{
int a;
int b;
%}

例2:

 int a;
    int b;

需要有tab鍵縮排;

正則表示式宣告方式: 表示式名稱 表示式

在使用時需要將表示式名稱用{}括起來;

規則部分 一個規則一行,每行有兩部分構成: 正則表示式 {動作函式} 動作函式可以呼叫在使用者程式碼中定義的函式;

例子1 編碼過程 編寫一個名為t1.lex的檔案:

/*t1.lex*/
%option main /*生成main函式*/
%{
int fun();
%}

%%
/*第一個%%之後是規則部分*/
apple {fun();}

%%
int fun(){
    printf("banana");
    return 0;
}

這個檔案的規則為如果遇到“apple”,執行程式碼“printf(“banana”)”,及將輸入中的apple替換為banana; 通過:flex t1.lex生成lex.yy.c檔案; 通過編譯該c語言檔案:gcc lex.yy.c 生成一個可執行檔案a.out

實驗過程 在終端輸入:echo 123apple123 | a.out 輸出為:123banana123 在這裡插入圖片描述 例子2 編寫一個簡單的對c語言能夠解析的lex檔案,程式碼t2.lex如下所示:

/*t2.lex*/
%option main
%{
    int line=1;
%}
DIGIT [0-9]
OINTEGER [1-9]{DIGIT}*
INTEGER ("+"|"-")?{OINTEGER}
DECIMAL {INTEGER}(.{OINTEGER})?
LETTER [a-zA-Z]
ID ({LETTER}|_)({LETTER}|_|{DIGIT})*
OPT ("+="|"-="|"*="|"/="|"+"|"-"|"*"|"/"|"<="|">="|"=="|"=")
%%
\n {++line;}
(int|float|double|short) {printf("line%d:(type,%s)\n",line,yytext);}
for {printf("line%d:(for,)\n",line);}
{INTEGER} {printf("line%d:(integer,%s)\n",line,yytext);}
{DECIMAL} {printf("line%d:(decimal,%s)\n",line,yytext);}
{ID} {printf("line%d:(identify,%s)\n",line,yytext);}
("("|")"|"{"|"}"|"["|"]") {printf("line%d:(bracket,\"%s\")\n",line,yytext);}
"\"" {printf("line%d:(QUOTE,)\n",line);}
{OPT} {printf("line%d:(OPT,%s)\n",line,yytext);}

. {}
%%
/*輔助過程部分*/

程式碼說明: 3~5行:全域性變數的說明,需要用“%{”和“%}”括起來; 6行:類似於C語言中的巨集定義,翻譯規則中的{DIGIT}將被“[0-9]”所替換;”[0-9]”是一個正則表示式,表示字元’0’、’1’、…、’8’、’9’中的任意一個; 8行:+號需要用引號括起來,因為正則表示式也有+號;同理,-號也需要括起來; 21行:引號需要有反斜槓進行轉義; 實驗過程 建立一個test檔案:

int main(){
    int a = 10;
    double b = -20.9;
    if(a<=b)
        a+=b;
    return a;
}

在終端中分別輸入: flex -o t2.c t2.lex gcc t2.c -o ./a.out ./a.out < test 實驗結果如下: 在這裡插入圖片描述 輸出格式為: 元素所在行:{ID號,屬性}

注意點:

正規定義中[xy]等價於(x|y) 定義部分一些在翻譯規則中使用的變數的宣告,需要由%{和%}包圍起來,這部分宣告將被直接抄寫在lex.yy.c中,不作為正規定義和翻譯規則的一部分; 如果變數的宣告不在%{和%}之間,那麼需要在宣告部分進行縮排(使用tab縮排); 輔助過程是一些函式,能夠被抄入到生成的c檔案中,在規則後面的動作中可以呼叫; 規則後面的動作可以通過return返回詞法單元的記號;在動作、輔助過程中可以使用變數yylval、yytext、yyleng,這些變數為全域性變數,通過yylval傳送記號屬性給語法分析器,yytext為解析出的詞法單元字串的指標,yyleng為詞法單元字串長度; 若兩個表示式同時匹配一個詞法單元,如表示式if和[a-z]+同時匹配if\s,(注意\s表示空格),那麼按照兩個表示式在翻譯規則中的順序選擇動作;而表示式<和<=匹配<=\s時,<可以匹配1個單詞,<=可以匹配兩個單詞,那麼選擇匹配元素多的<=;