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
hide-digits.l 파일의 코드를 자세히 설명해 보겠습니다. 우선 첫 번째 단락은 다음과 같습니다.
gcc -o hide-digits lex.yy.c ./hide-digits
flex 모드 파일, %% 및 %%를 사용하여 내용을 분할합니다. 위의 분할 규칙 중 이 파일의 각 줄은 규칙입니다. 각 규칙은 일치하는 패턴과 이벤트로 구성됩니다. 패턴은 정규식으로 표시되고 이벤트는 뒤에 있습니다. C 코드. 패턴이 일치할 때마다 다음 C 코드가 실행됩니다.
eruiewdkfj eruiewdkfj 1245 ? fdsaf4578 fdsaf? ... #
두 번째 단락의 주요 기능은 프로그램의 진입점입니다. Flex는 이러한 코드를 그대로 lex.yy.c 파일 끝에 복사합니다. 마지막 줄의 yywrap 함수인 flex에는 이러한 함수가 필요합니다.
%% [0-9]+ printf("?"); # return 0; . ECHO; %%
컴파일되고 실행됩니다
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视频教程》
위 내용은 리눅스 플렉스가 뭐야?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!