概述

太久不用这玩意都忘得差不多了,索性记下来。

Flex是一款开源的词法分析工具,可以按照指定规则自动生成词法分析器,通常配合Yacc一同使用。

Flex开源主页

语法结构


定义段

%%

规则段

%%

用户代码段

定义段

正则表达式规则

Patterns 说明 举例
x 字符’x’。
rs 在表达式r之后紧跟一个表达式s
r|s 表达式r或表达式s。
^r 除了表达式r。
r$ r后面紧跟行尾,行尾在DOS中为’\r’,其它情况均为‘\n’。
. 除了空格以外的所有字符。
[xyz] 一个x或一个y或一个z。
[a-z] 任意一个小写字母。
[A-Z] 任意一个大写字母。
[0-9] 任意一位数字。
r* 重复r零次或多次。
r+ 重复r至少一次。
r? 重复r零次或一次。
r{m} 重复r m次。
\xa 表示字符编码的十六进制值为a的字符。
(r) 括号内的Pattern将作为一个独立的Pattern,一般用于后接*实现同时对多个Pattern的匹配。
?(# comment) 忽略括号内的内容,常常用于注释。

(?x:r)

  • x:可以是s,i,x,-s,-i这几个字符,并且可以组合,但是i,-is,-s不能同时出现。
    • i:不区分大小写。
    • -i:区分大小写。
    • s:改变’.’的含义,匹配\x00~\xFF中任意一个字符。
    • -s:改变’.’的含义,匹配除了\n以外的任意一个字符。
    • x:忽略r中的注释和空格,除非空格被反斜杠转义或包含在“”中或出现在字符类中。

token定义

name definition
  • name:token的名称
  • definition:正则表达式
  • name和definition之间可以隔若干个空格和制表符

例如

DIGIT       [0-9]
ID          [a-z][a-z0-9]*
INTERGER    {DIGHT}+

上面的规则定义的内容:

  • 定义了名为DIGHT的token,代表0~9中任意一个数字组成的文本。
  • 定义了名为ID的token,代表一个以小写字母开头,后接零个或多个小写字母或数字组成的文本。
  • 定义了名为INTERGER的token,代表由至少一个数字构成的文本。

其它定义

%{
  #include <stdio.h>
%}

%{...%}中的内容会被原样复制,但是在生成文件中的位置不确定。

%top{
  #include <stdio.h>
}

%top{...}%{...%}功能类似,但是其中的内容会出现在生成的文件的顶部。

规则段

pattern   action
  • pattern:正则表达式。
  • action:扫描到此token后执行的代码。
  • 靠上的规则会被优先匹配到。

NUMBER    [0-9]+

%%

[0-9]+        {puts("NUMBER");}
{NUMBER}      {puts("NUMBER");}

%%

上面的例子中两个规则是等价的。

用户代码段

此段可以为空,如果有内容其内容会被复制到生成文件中。

内置函数/变量说明

ECHO

输出当前token到yyout中。

int yyleng

当前token的长度。

FILE* yyin

每当调用yylex()时都会从yyin(默认为stdin)中扫描token。 一直持续到到达文件结尾(此时它返回值0)或其中一个动作执行return语句为为止。

FILE* yyout

ECHO以及其它提示信息会被输出到yyout(默认为stdout)。

void yylex()

扫描yyin中的token,直到yyin返回0或其中一个动作执行return语句为止。

int yywrap()

当文件扫描完毕的时候会调用yywrap,如果返回0则认为yyin已经指向了另外一个文件并重新启动扫描。反之则停止扫描,程序结束。

生成

flex [opions] inputfile

flex源文件的后缀一般为.lex或.l

例子

一个匹配实数和加减乘除并原样输出的例子。

文件:demo.lex

DIGIT             [0-9]
INTERGER          {DIGIT}+
DECIMAL           [1-9]{DIGIT}*

%%

{INTERGER}        {ECHO;}
{DECIMAL}         {ECHO;}
(\+|\-|\*|\/)     {ECHO;}

%%

int yywrap() { 
   return (1); 
}

void yyerror (char const *s)
{
  fprintf (stderr, "error: %s\n", s);
}

int main(int argc, char **argv) {
    ++argv, --argc;
    if (argc > 0)
        yyin = fopen( argv[0], "r" );
    else
        yyin = stdin;
    yylex();
}
flex demo.lex
gcc lex.yy.c
./a.out

之后输入任何算术表达式摁下回车都会原样输出。