Dalam Linux, flex ialah alat analisis leksikal yang boleh mengenal pasti corak leksikal dalam teks, Flex membaca fail input yang diberikan, atau jika tiada nama fail diberikan, ia membaca daripada input standard, dengan itu Mendapat penerangan tentang; pengimbas yang akan dihasilkan.
Persekitaran pengendalian tutorial ini: sistem linux5.9.8, komputer Dell G3.
flex: Penganalisis leksikal
flex ialah penganalisis leksikal. Digunakan untuk menjana fail .l ke dalam fail program .c. Iaitu, penganalisis leksikal dihasilkan. Kemudian baca input, padankannya dengan ungkapan biasa, dan kemudian lakukan tindakan yang sepadan untuk merealisasikan fungsi program. Kita boleh mendapati bahawa flex melaksanakan fungsi menerima input di luar program.
Flex ialah alat yang menjana pengimbas yang mampu mengenal pasti corak leksikal dalam teks. Flex membaca fail input yang diberikan, atau input standard jika tiada nama fail diberikan, untuk mendapatkan penerangan pengimbas yang akan dijana. Penerangan ini dipanggil peraturan dan terdiri daripada pasangan ungkapan biasa dan kod C. Output Flex ialah fail kod C—lex.yy.c—di mana fungsi yylex() ditakrifkan. Menyusun fail output menghasilkan fail boleh laku. Apabila boleh laku dijalankan, ia menganalisis fail input, mencari padanan untuk setiap ungkapan biasa. Apabila padanan ditemui, ia melaksanakan kod C yang dikaitkan dengan ungkapan biasa ini. Flex bukan projek GNU, tetapi GNU telah menulis manual untuk Flex.
Penggunaan
Pasang flex
sudo apt-get install flex //或者下载相应版本的安装文件安装
Kemudian buat fail teks baharu dan masukkan kandungan berikut:
%% [0-9]+ printf("?"); # return 0; . ECHO; %% int main(int argc, char* argv[]) { yylex(); return 0; } int yywrap() { return 1; }
Simpan fail ini sebagai angka sembunyi . Ambil perhatian bahawa %% dalam fail ini mestilah pada permulaan baris ini (iaitu, tidak boleh ada sebarang ruang di hadapan %%). Selepas
, masukkan dalam terminal:
flex hide-digits.l
Di kali ini Terdapat fail "lex.yy.c" tambahan dalam direktori Susun dan jalankan fail C ini:
gcc -o hide-digits lex.yy.c ./hide-digits
Kemudian teruskan menaip mana-mana Tekan butang. kekunci dan tekan Enter Anda boleh mendapati bahawa dalam kandungan yang ditaip, semua aksara kecuali nombor adalah output sebagaimana adanya, dan setiap rentetan aksara angka digantikan dengan ?. Akhir sekali, taip # dan program keluar. Seperti berikut:
eruiewdkfj eruiewdkfj 1245 ? fdsaf4578 fdsaf? ... #
Apabila menjalankan flex pada baris arahan, parameter baris arahan kedua (hide-digits.l di sini) ialah fail mod segmentasi perkataan yang disediakan untuk flex , ini fail corak terutamanya mengandungi corak pemadanan pembahagian perkataan yang ditulis oleh pengguna dengan ungkapan biasa Gunakan flex untuk menterjemah ungkapan biasa ini ke dalam fungsi yylex dalam format kod C, dan mengeluarkannya ke fail lex.yy.c. Fungsi ini boleh dilihat dalam sebuah automaton keadaan terhingga.
Apabila menjalankan flex pada baris arahan, parameter baris arahan kedua (hide-digit.l di sini) ialah fail mod segmentasi perkataan yang disediakan untuk flex Dalam fail mod ini corak pemadanan pembahagian perkataan yang ditulis oleh pengguna dengan ungkapan biasa Flex akan menterjemahkan ungkapan biasa ini ke dalam fungsi yylex dalam format kod C dan mengeluarkannya ke fail lex.yy.c. Fungsi ini boleh dianggap sebagai mesin automatik keadaan terhingga.
Mari jelaskan kod dalam fail hide-digits.l secara terperinci Pertama sekali, perenggan pertama ialah:
%% [0-9]+ printf("?"); # return 0; . ECHO; %%
int main(int argc, char *argv[]) { yylex(); return 0; } int yywrap() { return 1; }
Contoh
pemecah kata.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; }
Kompil dan laksanakan
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 '"' */ 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视频教程》
Atas ialah kandungan terperinci apa itu linux flex. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!