리눅스 플렉스가 뭐야?

青灯夜游
青灯夜游원래의
2022-03-03 16:27:513554검색

Linux에서 flex는 텍스트의 어휘 패턴을 식별할 수 있는 어휘 분석 도구입니다. Flex는 지정된 입력 파일을 읽고, 파일 이름이 지정되지 않은 경우 표준 입력에서 읽어서 필요한 정보를 얻습니다. 생성된 스캐너의

리눅스 플렉스가 뭐야?

이 튜토리얼의 운영 환경: linux5.9.8 시스템, Dell G3 컴퓨터.

flex: 어휘 분석기

flex는 어휘 분석기입니다. .l 파일을 .c 프로그램 파일로 생성하는 데 사용됩니다. 즉, 어휘 분석기가 생성됩니다. 그런 다음 입력을 읽고 정규식과 일치시킨 다음 해당 작업을 수행하여 프로그램의 기능을 실현합니다. 우리는 flex가 프로그램 외부에서 입력을 받아들이는 기능을 구현한다는 것을 알 수 있습니다.

Flex는 텍스트의 어휘 패턴을 식별할 수 있는 스캐너를 생성하는 도구입니다. Flex는 생성할 스캐너에 대한 설명을 얻기 위해 지정된 입력 파일을 읽거나, 파일 이름이 지정되지 않은 경우 표준 입력을 읽습니다. 이 설명을 규칙이라고 하며 정규식과 C 코드의 쌍으로 구성됩니다. Flex의 출력은 yylex() 함수가 정의된 C 코드 파일(lex.yy.c)입니다. 출력 파일을 컴파일하면 실행 파일이 생성됩니다. 실행 파일이 실행되면 입력 파일을 분석하여 각 정규식과 일치하는 항목을 찾습니다. 일치하는 항목이 발견되면 이 정규식과 관련된 C 코드를 실행합니다. Flex는 GNU 프로젝트는 아니지만 GNU는 Flex용 매뉴얼을 작성했습니다. flex hide-digits.l을 설치합니다. 이 파일의 %%는 이 줄의 시작 부분에 있어야 합니다(즉, %% 앞에 공백이 있어서는 안 됩니다).

그런 다음 터미널에 다음을 입력하세요.

  • sudo apt-get install flex
    //或者下载相应版本的安装文件安装

    이때 디렉터리에 추가 "lex.yy.c" 파일이 있습니다.
  • %%
    [0-9]+  printf("?");
    #       return 0;
    .       ECHO;
    %%
    int main(int argc, char* argv[]) {
        yylex();
        return 0;
    }
    int yywrap() { 
        return 1;
    }

    그런 다음 터미널에 아무 키나 계속 입력하고 Enter를 누르면 입력된 내용에서 숫자를 제외한 모든 문자가 그대로 출력되고 각 숫자 문자열이 ?로 대체되는 것을 확인할 수 있습니다. 마지막으로 #을 입력하면 프로그램이 종료됩니다.

    flex hide-digits.l

  • 명령줄에서 flex를 실행할 때 두 번째 명령줄 매개변수(여기서 hide-digits.l)는 flex에 제공되는 단어 분할 패턴 파일입니다. 이 패턴 파일에는 주로 flex에서 사용하는 일반 규칙이 포함되어 있습니다. user. 표현식에 작성된 단어 분할 일치 패턴은 flex를 사용하여 C 코드 형식의 yylex 함수로 변환되고 lex.yy.c 파일로 출력됩니다. 이 함수는 유한 상태 자동 장치로 간주될 수 있습니다.

    명령줄에서 flex를 실행할 때 두 번째 명령줄 매개변수(여기서 hide-digits.l)는 flex에 제공되는 단어 분할 패턴 파일입니다. 이 패턴 파일은 주로 사용자가 정규식을 사용하여 작성합니다. 분할 일치 패턴을 사용하여 이러한 정규식을 C 코드 형식의 yylex 함수로 변환하고 lex.yy.c 파일에 출력합니다. 이 함수는 유한 상태 자동 장치로 간주될 수 있습니다.
  • hide-digits.l 파일의 코드를 자세히 설명해 보겠습니다. 우선 첫 번째 단락은 다음과 같습니다.

 gcc -o hide-digits lex.yy.c
./hide-digits
  • flex 모드 파일, %% 및 %%를 사용하여 내용을 분할합니다. 위의 분할 규칙 중 이 파일의 각 줄은 규칙입니다. 각 규칙은 일치하는 패턴과 이벤트로 구성됩니다. 패턴은 정규식으로 표시되고 이벤트는 뒤에 있습니다. C 코드. 패턴이 일치할 때마다 다음 C 코드가 실행됩니다.

  • flex는 이 단락을 yylex라는 함수로 변환합니다. 이 함수의 기능은 입력 파일(기본적으로 표준 입력)을 검색하는 것입니다. 이 함수는 규칙을 따르는 C 코드를 실행합니다. 이러한 C 코드에 return 문이 없으면 이러한 C 코드를 실행한 후 yylex 함수가 계속 실행되어 다음 스캔 및 일치 라운드를 시작합니다.

    여러 규칙의 패턴이 일치하는 경우 yylex는 일치하는 길이가 가장 긴 규칙을 선택합니다. 일치하는 길이가 동일한 규칙이 있는 경우 순위가 가장 높은 규칙이 선택됩니다.
  • eruiewdkfj
    eruiewdkfj
    1245
    ?
    fdsaf4578
    fdsaf?
    ...
    #
  • 두 번째 단락의 주요 기능은 프로그램의 진입점입니다. Flex는 이러한 코드를 그대로 lex.yy.c 파일 끝에 복사합니다. 마지막 줄의 yywrap 함수인 flex에는 이러한 함수가 필요합니다.

  • Example
  • word-spliter.l
  • %%
    [0-9]+  printf("?");
    #       return 0;
    .       ECHO;
    %%

    이 예에서는 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视频教程

위 내용은 리눅스 플렉스가 뭐야?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.