首頁 > 運維 > linux運維 > linux flex是什麼

linux flex是什麼

青灯夜游
發布: 2022-03-03 16:27:51
原創
3556 人瀏覽過

在linux中,flex是一個詞法分析工具,能夠識別文本中的詞法模式;Flex讀入給定的輸入文件,如果沒有給定文件名的話,則從標準輸入讀取,從而取得一個關於需要產生的掃描器的描述。

linux flex是什麼

本教學操作環境:linux5.9.8系統、Dell G3電腦。

flex:詞法分析器

#flex是一個詞法分析器。用來將一個.l檔產生一個.c程式檔。即生成一個詞法分析器。然後讀取輸入,和正規表示式匹配,再執行對應的動作,實現了程式的功能。我們可以發現flex實作在程式外部就可以接受輸入的功能。

Flex是一個產生掃描器的工具,能夠辨識文本中的詞法模式。 Flex 讀入給定的輸入文件,如果沒有給定文件名的話,則從標準輸入讀取,從而獲得一個關於需要生成的掃描器的描述。此描述叫做規則,由正規表示式和 C代碼對組成。 Flex 的輸出是一個 C 程式碼檔案-lex.yy.c-其中定義了yylex() 函數。編譯輸出檔可以產生一個可執行檔。當執行可執行檔的時候,它會分析輸入文件,為每一個正規表示式尋找匹配。當發現一個符合時,它執行與此正規表示式相關的C代碼。 Flex 不是GNU工程,但是GNU為Flex 寫了手冊。

用法

  • #安裝flex

sudo apt-get install flex
//或者下载相应版本的安装文件安装
登入後複製
  • 然後新建一個文字文件,輸入以下內容:

%%
[0-9]+  printf("?");
#       return 0;
.       ECHO;
%%
int main(int argc, char* argv[]) {
    yylex();
    return 0;
}
int yywrap() { 
    return 1;
}
登入後複製

將此文件另存為hide-digits.l 。注意此文件中的 %% 必須在本行的最前面(即 %% 前面不能有任何空格)。

  • 之後,在終端機輸入:

flex hide-digits.l
登入後複製
  • ##此時目錄下多了一個「lex.yy.c」 文件,把這個C 檔案編譯並運行一遍:

  •  gcc -o hide-digits lex.yy.c
    ./hide-digits
    登入後複製
然後在終端機不停的敲入任意鍵並回車,可以發現,敲入的內容中,除數字外的字元都被原樣的輸出了,而每串數字字元都被替換成? 了。最後敲入 # 後程式退出了。如下:

eruiewdkfj
eruiewdkfj
1245
?
fdsaf4578
fdsaf?
...
#
登入後複製

  • 當在命令列中執行flex 時,第二個命令列參數(此處是hide-digits.l )是提供給flex 的分詞模式文件, 此模式檔案中主要是使用者用正規表示式寫的分詞匹配模式,用flex 會將這些正規表示式翻譯成C 程式碼格式的函數yylex ,並輸出到lex.yy.c 檔案中,該函數可以看成一個有限狀態自動機。

  • 當在命令列中執行flex 時,第二個命令列參數(此處是hide-digits.l )是提供給flex 的分詞模式文件, 此模式檔案中主要是使用者用正規表示式寫的分詞匹配模式,用flex 會將這些正規表示式翻譯成C 程式碼格式的函數yylex ,並輸出到lex.yy.c 檔案中,該函數可以看成一個有限狀態自動機。

  • 下面再來詳細解釋hide-digits.l 檔案中的程式碼,首先第一段是:

  • %%
    [0-9]+  printf("?");
    #       return 0;
    .       ECHO;
    %%
    登入後複製
  • flex 模式文件中,用%% 和%%做分割, 上面分割的內容被稱為規則(rules),本文件中每一行都是一條規則,每條規則由匹配模式(pattern) 和事件( action) 組成, 模式在前面,用正規表示式表示,事件在後面,也就是C 程式碼。每當一個模式被配對到時,後面的 C 程式碼就會執行。

  • flex 會將本段內容翻譯成一個名為yylex 的函數,該函數的作用就是掃描輸入檔案(預設為標準輸入),當掃描到一個完整的、最長的、可以和某條規則的正規表示式所符合的字串時,函數會執行此規則後面的C 程式碼。如果這些 C 程式碼中沒有 return 語句,則執行完這些 C 程式碼後, yylex 函數會繼續運行,開始下一輪的掃描和匹配。

  • 當有多條規則的模式被配對到時, yylex 會選擇符合長度最長的那條規則,如果有符合長度相等的規則,則選擇排在最前面的規則。

  • int main(int argc, char *argv[]) {
        yylex();
        return 0;
    }
    int yywrap() { return 1; }
    登入後複製
  • 第二段中的 main 函數是程式的入口,flex 會將這些程式碼原樣的複製到 lex.yy.c 檔案的最後面。最後一行的 yywrap 函數, flex 要求有這麼一個函數。

範例

#word-spliter.l

%{
#define T_WORD 1
int numChars = 0, numWords = 0, numLines = 0;
%}
WORD([^ \t\n\r\a]+)
%%
\n{ numLines++; numChars++; }
{WORD}{ numWords++; numChars += yyleng; return T_WORD; }
<<EOF>>{ return 0; }
.{ numChars++; }
%%
int main() {
int token_type;
while (token_type = yylex()) {
printf("WORD:\t%s\n", yytext);
}
printf("\nChars\tWords\tLines\n");
printf("%d\t%d\t%d\n", numChars, numWords, numLines);
return 0;
}
int yywrap() {
return 1;
}
登入後複製

本例中使用到了flex 提供的兩個全域變數yytext 和yyleng,分別用來表示剛剛符合的字串以及它的長度

編譯執行

flex word-spliter.l
gcc -o word-spliter lex.yy.c
./word-spliter < word-spliter.l
输出:
WORD:       %{
WORD:       #define
...
WORD:       }
Chars       Words   Lines
470 70      27
登入後複製

可见此程序其实就是一个原始的分词器,它将输入文件分割成一个个的 WORD 再输出到终端,同时统计输入文件中的字符数、单词数和行数。此处的 WORD 指一串连续的非空格字符。

扩展

(1) 列出所需的所有类型的 token;

(2) 为每种类型的 token 分配一个唯一的编号,同时写出此 token 的正则表达式;

(3) 写出每种 token 的 rule (相应的 pattern 和 action )。

第 1 类为单字符运算符,一共 15 种:

+ * - / % = , ; ! < > ( ) { }
登入後複製

第 2 类为双字符运算符和关键字,一共 16 种:

<=, >=, ==, !=, &&, ||
void, int, while, if, else, return, break, continue, print, readint
登入後複製

第 3 类为整数常量、字符串常量和标识符(变量名和函数名),一共 3 种。

拓展后

%{
#include "token.h"
int cur_line_num = 1;
void init_scanner();
void lex_error(char* msg, int line);
%}
/* Definitions, note: \042 is &#39;"&#39; */
INTEGER             ([0-9]+)
UNTERM_STRING       (\042[^\042\n]*)
STRING              (\042[^\042\n]*\042)
IDENTIFIER          ([_a-zA-Z][_a-zA-Z0-9]*)
OPERATOR            ([+*-/%=,;!<>(){}])
SINGLE_COMMENT1     ("//"[^\n]*)
SINGLE_COMMENT2     ("#"[^\n]*)
%%
[\n]                { cur_line_num++;                       }
[ \t\r\a]+          { /* ignore all spaces */               }
{SINGLE_COMMENT1}   { /* skip for single line comment */    }
{SINGLE_COMMENT2}   { /* skip for single line commnet */    }
{OPERATOR}          { return yytext[0];         }   
"<="                { return T_Le;              }
">="                { return T_Ge;              }
"=="                { return T_Eq;              }
"!="                { return T_Ne;              }
"&&"                { return T_And;             }
"||"                { return T_Or;              }
"void"              { return T_Void;            }
"int"               { return T_Int;             }
"while"             { return T_While;           }
"if"                { return T_If;              }
"else"              { return T_Else;            }
"return"            { return T_Return;          }
"break"             { return T_Break;           }
"continue"          { return T_Continue;        }
"print"             { return T_Print;           }
"readint"           { return T_ReadInt;         }
{INTEGER}           { return T_IntConstant;     }
{STRING}            { return T_StringConstant;  }
{IDENTIFIER}        { return T_Identifier;      }
<<EOF>>             { return 0; }
{UNTERM_STRING}     { lex_error("Unterminated string constant", cur_line_num);  }
.                   { lex_error("Unrecognized character", cur_line_num);        }
%%
int main(int argc, char* argv[]) {
    int token;
    init_scanner();
    while (token = yylex()) {
        print_token(token);
        puts(yytext);
    }
    return 0;
}
void init_scanner() {
    printf("%-20s%s\n", "TOKEN-TYPE", "TOKEN-VALUE");
    printf("-------------------------------------------------\n");
}
void lex_error(char* msg, int line) {
    printf("\nError at line %-3d: %s\n\n", line, msg);
}
int yywrap(void) {
    return 1;
}
登入後複製

上面这个文件中,需要注意的是,正则表达式中,用双引号括起来的字符串就是原始字符串,里面的特殊字符是不需要转义的,而双引号本身必须转义(必须用 \” 或 \042 ),这是 flex 中不同于常规的正则表达式的一个特性。

除单字符运算符外的 token 的编号则在下面这个 token.h 文件,该文件中同时提供了一个 print_token 函数,可以根据 token 的编号打印其名称。

#ifndef TOKEN_H
#define TOKEN_H
typedef enum {
    T_Le = 256, T_Ge, T_Eq, T_Ne, T_And, T_Or, T_IntConstant,
    T_StringConstant, T_Identifier, T_Void, T_Int, T_While,
    T_If, T_Else, T_Return, T_Break, T_Continue, T_Print,
    T_ReadInt
} TokenType;
static void print_token(int token) {
    static char* token_strs[] = {
        "T_Le", "T_Ge", "T_Eq", "T_Ne", "T_And", "T_Or", "T_IntConstant",
        "T_StringConstant", "T_Identifier", "T_Void", "T_Int", "T_While",
        "T_If", "T_Else", "T_Return", "T_Break", "T_Continue", "T_Print",
        "T_ReadInt"
    };
    if (token < 256) {
        printf("%-20c", token);
    } else {
        printf("%-20s", token_strs[token-256]);
    }
}
#endif
登入後複製

makefile

out: scanner
scanner: lex.yy.c token.h
gcc -o $@ $<
lex.yy.c: scanner.l
flex $<
登入後複製

linux flex是什麼

相关推荐:《Linux视频教程

以上是linux flex是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板