詞法分析器flex的簡單用法

安裝flex

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

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個單詞,<=可以匹配兩個單詞,那麼選擇匹配元素多的<=;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章