ホームページ  >  記事  >  運用・保守  >  Linuxフレックスとは何ですか

Linuxフレックスとは何ですか

青灯夜游
青灯夜游オリジナル
2022-03-03 16:27:513483ブラウズ

Linux では、flex はテキスト内の字句パターンを識別できる字句解析ツールです。Flex は指定された入力ファイルを読み取るか、ファイル名が指定されていない場合は標準入力から読み取り、その結果、ファイルの説明を取得します。生成されるスキャナー。

Linuxフレックスとは何ですか

#このチュートリアルの動作環境: linux5.9.8 システム、Dell G3 コンピューター。

flex: 字句アナライザー

flex は字句アナライザーです。 .l ファイルを .c プログラム ファイルに生成するために使用されます。つまり、字句解析器が生成される。次に、入力を読み取り、正規表現と照合し、対応するアクションを実行してプログラムの機能を実現します。 flex はプログラム外部からの入力を受け付ける機能を実装していることがわかります。

Flex は、テキスト内の語彙パターンを識別できるスキャナーを生成するツールです。 Flex は、指定された入力ファイル、またはファイル名が指定されていない場合は標準入力を読み取り、生成されるスキャナーの説明を取得します。この記述はルールと呼ばれ、正規表現と C コードのペアで構成されます。 Flex の出力は、yylex() 関数が定義されている C コード ファイル lex.yy.c です。出力ファイルをコンパイルすると、実行可能ファイルが生成されます。実行可能ファイルが実行されると、入力ファイルが分析され、各正規表現との一致が検索されます。一致が見つかると、この正規表現に関連付けられた C コードが実行されます。 Flex は GNU プロジェクトではありませんが、GNU は 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
  • At thisディレクトリ内の時間 追加の「lex.yy.c」ファイルがあります。この C ファイルをコンパイルして実行します:

 gcc -o hide-digits lex.yy.c
./hide-digits

次に、ターミナルに任意のキーを入力し続けて、 を押します。と入力すると、入力した内容は数字以外の文字がそのまま出力され、数字の文字列がそれぞれ?に置き換えられていることがわかります。最後に # を入力するとプログラムが終了します。次のように:

eruiewdkfj
eruiewdkfj
1245
?
fdsaf4578
fdsaf?
...
#
  • コマンド ラインで flex を実行する場合、2 番目のコマンド ライン パラメータ (ここでは Hide-digits.l) は、flex に提供される単語セグメンテーション モード ファイルです。ファイルには主に、正規表現を使用してユーザーが記述した単語分割一致パターンが含まれています。flex を使用して、これらの正規表現を C コード形式の関数 yylex に変換し、lex.yy.c ファイルに出力します。この関数は有限状態として見ることができますオートマトン。

  • コマンド ラインで flex を実行する場合、2 番目のコマンド ライン パラメータ (ここでは Hide-digits.l) は、flex に提供される単語セグメンテーション モード ファイルです。このモード ファイルでは主にユーザーが正規表現を使用して記述した単語の分割一致パターン。Flex はこれらの正規表現を C コード形式の関数 yylex に変換し、lex.yy.c ファイルに出力します。この関数は有限状態自動マシンとみなすことができます。

  • # Hide-digits.l ファイルのコードを詳しく説明します。まず、最初の段落は次のとおりです。

  • #
    %%
    [0-9]+  printf("?");
    #       return 0;
    .       ECHO;
    %%
  • flex パターン ファイルは %% と %% で分割されています。上で分割された内容をルールと呼びます。このファイルの各行がルールです。各ルールは、一致するパターン (パターン) とイベント (アクション) で構成され、パターンは正規表現で表現された前部にあり、イベントは後部にあり、C コードです。パターンが一致するたびに、次の C コードが実行されます。

  • flex は、この段落を yylex という名前の関数に変換します。この関数の機能は、入力ファイル (デフォルトでは標準入力) をスキャンすることです。完全な の場合、可能な最長の文字列が返されます。ルールの正規表現に一致すると、この関数はこのルールの背後で C コードを実行します。これらの C コードに return ステートメントがない場合、これらの C コードの実行後、yylex 関数は実行を継続し、次のラウンドのスキャンとマッチングを開始します。

  • 複数のルールのパターンが一致した場合、yylex は一致する長さが最も長いルールを選択します。一致する長さが等しいルールが存在する場合は、それが先頭から選択されます。のルール。

  • int main(int argc, char *argv[]) {
        yylex();
        return 0;
    }
    int yywrap() { return 1; }
  • 2 番目の段落の 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 によって提供される 2 つのグローバル変数 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フレックスとは何ですか

相关推荐:《Linux视频教程

以上がLinuxフレックスとは何ですかの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。