千家信息网

linux的中怎么安装和使用flex

发表于:2024-11-18 作者:千家信息网编辑
千家信息网最后更新 2024年11月18日,这篇"linux的中怎么安装和使用flex"文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这
千家信息网最后更新 2024年11月18日linux的中怎么安装和使用flex

这篇"linux的中怎么安装和使用flex"文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇"linux的中怎么安装和使用flex"文章吧。

在linux中,flex是一个词法分析工具,能够识别文本中的词法模式;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

然后在终端不停的敲入任意键并回车,可以发现,敲入的内容中,除数字外的字符都被原样的输出了,而每串数字字符都被替换成 ? 了。最后敲入 # 后程序退出了。如下:

eruiewdkfjeruiewdkfj1245?fdsaf4578fdsaf?...#
  • 当在命令行中运行 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 1int numChars = 0, numWords = 0, numLines = 0;%}WORD([^ \t\n\r\a]+)%%\n{ numLines++; numChars++; }{WORD}{ numWords++; numChars += yyleng; return T_WORD; }<>{ 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.lgcc -o word-spliter lex.yy.c./word-spliter < word-spliter.l输出:WORD:       %{WORD:       #define...WORD:       }Chars       Words   Lines470 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;      }<>             { 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_Htypedef 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: scannerscanner: lex.yy.c token.hgcc -o $@ $

以上就是关于"linux的中怎么安装和使用flex"这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注行业资讯频道。

文件 函数 模式 正则 表达式 输入 代码 字符 规则 内容 输出 程序 词法 生成 字符串 分析 运行 命令 就是 分析器 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 南京博达互联网科技有限公司 网络安全 开发语言 软件开发工程的设计过程 U点家庭服务器免费 软件工程和网络安全相似吗 软件开发维护服务方案 台湾服务器如何选择云服务器 甘肃网络技术转让概况 为祖国筑起网络安全长城 率土之滨藏宝阁游戏服务器维护中 图书馆大屏导航软件开发公司 对是计算机软件开发的认识 数据库触发器在哪里 重庆南岸生鲜管理软件开发 服务器行业 数据库实例开发 软件开发技术风险有哪些 上海数据软件开发过程服务标准 江西生鲜园区配送软件开发 姑苏区诚信软件开发活动 杭州领益互联网科技有限公司 c 控件连接数据库显示 网络服务器作用 上位机软件开发论文 重庆南岸生鲜管理软件开发 网络安全领域教案 服务器端如何遍历数组 云服务器架设传奇需要多大的 学校计算机软件开发的就业方向 怎么察看数据库的字段长度
0