lex官方文档翻译

13 篇文章 2 订阅

3

flex是一个扫描器,一个扫描器是一个可以认识文本词汇模式的程序,flex程序读取给定的输入文件,或者如果没有文件提供的话读取它的标准输入,依赖一个描述来生成。这个描述就是规则,是正则和C代码两种格式组成,flex生成一个c源文件,默认名字叫做lex.yy.c,文件定义了一个函数叫yylex(),这个文件可以被编译,链接着flex运行时库就可以成为可执行文件,程序运行起来就会分析输入文件,如果匹配上了其中一个正则表达式,则会执行对应的C代码。

4 几个简单的例子

下面这个flex输入描述这样一个规则:当遇到username字符串,就会把字符串替换成用户登录名字

%%

username printf("%s",getlogin())

默认情况,所以没有匹配上flex描述文件规则的都被复制到输出,所以这个输入文件的效果就是把username替换成printf这个动作,%%这个符号是规则的开始。

这里是另外一个简单的例子:

int num_lines = 0, num_chars = 0;
%%
\n ++num_lines; ++num_chars;
. ++num_chars;
%%
int main()
{
yylex();
printf( "# of lines = %d, # of chars = %d\n",
num_lines, num_chars );
}
这个扫描程序会计算输入文件有多少个字符和多少行,它没有任何输出,只有最后的输出结果,第一行声明了两个全局变量,num_lines和num_chars,yylex和main两个函数都会使用。有两条规则,一条匹配到换行之后,增加行和字符计数,一条是匹配除了换行之后的任意字符。
一个更复杂一点的例子:
/* scanner for a toy Pascal-like language */
%{
/* need this for the call to atof() below */
#include <math.h>
%}
DIGIT [0-9]
ID [a-z][a-z0-9]*
%%
{DIGIT}+ {
printf( "An integer: %s (%d)\n", yytext,
atoi( yytext ) );
}
{DIGIT}+"."{DIGIT}* {
printf( "A float: %s (%g)\n", yytext,
atof( yytext ) );
}
if|then|begin|end|procedure|function {
printf( "A keyword: %s\n", yytext );
}
{ID} printf( "An identifier: %s\n", yytext );
"+"|"-"|"*"|"/" printf( "An operator: %s\n", yytext );
"{"[\^{}}\n]*"}" /* eat up one-line comments */
[ \t\n]+ /* eat up whitespace */
. printf( "Unrecognized character: %s\n", yytext );
%%
int main( int argc, char **argv )
{
++argv, --argc; /* skip over program name */
if ( argc > 0 )
yyin = fopen( argv[0], "r" );
else
yyin = stdin;
yylex();
}
这是一个简单的扫描器像pascal,它区分不同的token类型和上报识别到的。

5

输入文件规则

有三个段,三个段 被只包含了%%的行分开

格式为:

definitions
%%
rules
%%
user code
5.1
Definition段格式
定义段包含一些简单的名字定义,可以简化scanner规格,声明开始条件
名字定义的格式:
name definition
name是以一个字符或者下划线后面跟0个以上的字符数字_-。定义是从名字之后第一个非空字符开始直到行的结束,这个定义可以被接下来通过name调用,就会被扩展为definition。例如:
                定义:DIGIT [0-9]
                可以这样使用:{DIGIT}+,表示1个或者多个数字
{DIGIT}+"."{DIGIT}* ([0-9])+"."([0-9])*是相同的表示方法,都是表示小数
没有缩进的注释(以/*开始的行)会全部拷贝到输出直到遇到下一个*/
所有缩进的文本或者被%{和%}包围的文本也会完全复制到输出文件,%{和%}必须在行里面没有缩进。
%top块和%{和%}块是相同的,%top块里面的代码会被放到生成文件的首部,在任何flex定义之前,%top块在这些情况非常有用:如果想定义特定的预处理宏或者特定的引用文件出现在生成的code之前,{和}是%top块的界定,下面就是一个例子:
%top{
/* This code goes at the "top" of the generated file. */
#include <stdint.h>
#include <inttypes.h>
}
多重%top块也是被允许的
5.2规则段格式
flex的输入规则段包含了一系列如下格式的规则:
pattern action
pattern必须出现在一行开始,action的开始也必须在同一行
在规则段,在第一行规则出现之前的所有缩进或者被%{%}包围的行是用来声明变量,可以被后面的scaner的各个函数使用,不论scan会从哪里进入。其它缩进或者被%{%}包围的行仍然会被拷贝到输出文件,但是这个意义并没有被约定好,可能会引起编译错误。
%{%}必须出现在行首,不能缩进。
5.3 用户代码段格式
用户代码段直接拷贝到lex.yy.c,通常是scaner的内部函数或者被调用,用户代码段是可选的,如果没有用户代码段,第二个%%也会被跳过
5.4 输入文件的注释
Flex支持C风格的注释,/**/无论何时flex遇到注释,仅仅拷贝注释到生成的源文件,注释可能出现在任何地方,如下是特殊情况:
1、注释不能出现在rule section的第一个字符,但是可以在rule section段先加1或者多个空格,然后再加注释
2、注释不能出现在%option行

6

'x' 匹配字符x

'.' 匹配除了换行以外的任意字符

'[xyz]' 匹配xyz中的一个

'[abj-oZ]' 匹配a b 从j-o 或者Z 中的一个

'[^A-Z] 匹配除了大写字符以外的字符

'[^A-Z]\n 匹配除了大写字符和换行以外的字符

r* 匹配0或者多次r
r+ 匹配一次或者多次r
r?匹配0或者一次r
[a-z]{-}[aeiou] 匹配除了 aeiou以外的小写字符
r{2,5} ’ 匹配2-5个r
r{2,} ’ 匹配大于等于2个r
r{4}’ 匹配4个r‘{name}’ name是类型,可以定义一个类型直接引用,
'{name}' 如上自定义的类型名字
"[xyz]\"foo"’   等同于‘ [xyz]"foo  xyz中的某一个
\X 如果是a b f n r t 或者v,就是ANSI-C解释的\x。其它的就是一个字符X
\0 NULL 字符
\123 八进制值123
\x2a 十六进制2a
(r)匹配r,括号被用来防止预处理
(?r-s:pattern)
解释模式时,使用选项 r 忽略s,选项可以没有,或者是i s x中的一个或者多个
i指示的是大小写不敏感 -i指的是大小写敏感
s和.是同一个意思,匹配任何单个字符  -s匹配任何除了\n的字符。
x是指不管注释和空白,除非空格用反斜杠转义,包含在“”“里面
The following are all valid:
(?:foo) same as (foo)
(?i:ab7) same as ([aA][bB]7)
(?-i:ab) same as (ab)
(?s:.) same as [\x00-\xFF]
(?-s:.) same as [^\n]
(?ix-s: a . b) same as ([Aa][^\n][bB])
(?x:a b) same as ("ab")
(?x:a\ b) same as ("a b")
(?x:a" "b) same as ("a b")
(?x:a[ ]b) same as ("a b")
(?x:a
/* comment */
b
c) same as (abc)
(?# comment )
忽略括号里面的所有内容,注意注释里面不能有右括号,注释可以分行
‘rs’ r紧跟着s
r|s r或者s
r/s 匹配r,但是后面必须是s
^r 匹配r,且r出现在行首
r$ 匹配r,且r出现在行尾
<s>r 匹配r,但是只有在起始状态s的时候
<s1,s2,s3>r 匹配r,但是只是在起始状态是s1 s2 s3中其中一种的时候
<*>r 任意起始状态
<<EOF>> 文件结尾
<s1,s2> <<EOF>> 在s1和s2起始状态下的文件结束符
foo|bar* 和 (foo)|(ba(r*))表示的是一样的
如果想表示0或者多个bar应该使用
foo|(bar)*
如果想表示零个或者多个foo或者bar应该使用(foo|bar)*
{-}操作符:
[a-c]{b-z}等于a-c里面的字符减去b-z,也就是只匹配a
{+}操作符
把前后两部分相加
一条规则最多只能有一个实例在尾部上下文(说的就是/和$),还有^和<<EOF>>只能出现在模式的开头,/和$不能在括号里面被分组,^不出现在开头或者$不出现在规则的最后,就遗失了它的特殊属性就是正常的字符。
foo/bar$等同于foo/bar\n
foo|(bar$)
foo|^bar 上面这两种情况$和^就是普通字符。
7 输入是如何匹配
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值