flex学习笔记

flex学习笔记
1、flex的安装和使用(系统Ubuntu14.04)
$ sudo apt-get install flex
2、编译
flex代码的源文件往往是以.l为后缀名的。 
.l文件通过以下命令编译(以文件名为scanner.l为例):
$ flex scanner.l
编译后在源代码相同目录下会生成一个lex.yy.c,这就是生成的能够执行上述scanner.l功能的c语言代码。使用gcc编译即可生成词法分析程序1:
$ gcc lex.yy.c -o scanner
然后将需要分析的文件(以input.txt为例)作为参数传递给scanner执行分析:
$ ./scanner input.txt
flex语法格式
词法规范定义文件给出了单词构成规则。词法文件在习惯上用字母l(即L的小写)来作为后缀。Flex文件由三个部分组成。或者说三个段。三个段之间用两个%%分隔。

定义段(definitions)

%%

规则段(rules)

%%

用户代码段(user code)

定义段                                                                                                                                                                         
定义段包含着一些简单名字的定义(name definitions),旨在简化扫描器的规范。定义名字的方法如下:

name definition

名字可以由字母或下划线开头,后跟零个或多个字母、数字、下划线、或短横线。名字的定义则从其后的第一个非空白字符(non-white-space)开始直到行尾。下面是一个例子,定义了一个名字DIGIT,其定义就是指一个数字,如下所示:

DIGIT [0-9]

当在后面引用这个名字时,用一对花括号({})括住该名字即可。它会被展开成一对圆括号括住的该名字的定义,即:

{name} 展开成 (definition)

例如:

{DIGIT}+"."{DIGIT}*

就等价于:

([0-9])+"."([0-9])*

定义段中还可以加入启动条件(start conditions)的声明。顾名思义,启动条件就如同C语言中的条件编译一样,根据指定的启动条件去激活一条规则,并用这条规则去匹配读入的字符。关于启动条件,后面还有更详细的介绍。
规则段                                                                                                                                                                            
规则由模式(pattern)和动作(action)两个部分组成。模式就是一个正则表达式,FLEX加入了一些自己的扩展。而动作一般就是一些C语句。模式指出了一个单词是如何构成的,当分析出一个符合该规则的单词时,就执行相应的动作。

模式一定要位于一行的开头处,不能有缩进。而动作的开头一定要与模式在同一行。当动作是用一对花括号{}括起来时,可以将左花括号放在与规则相同的行,而其余部分则可以从下一行开始。
用户代码段                                                                                                                                                                      
所有用户代码都被原样拷贝到文件lex.yy.c中。在这里可以定义一些辅助函数或代码,供扫描器yylex()调用,或者调用扫描器(一般来说就是main()了)。这一部分是可有可无的。如果没有的话,Flex文件中第二个%%是可以省略的。

在定义段或者规则段中,任何一行有缩进的文本或者包含在一对%{和%}之间的文本,都被原样拷贝到最后生成的C代码文件中(当然%{和%}会被移走)。在书写时%{和%}都必须在一行的开始处,不能缩进。

在规则段中,第一条规则之前的任何未缩进的文本或者在%{和%}之间的文本,可以用来为扫描器声明一些本地变量和代码。一旦进入扫描器的代码,这些代码就会被执行。规则段内其他的缩进的文本或者%{和%}之间的文本还是被原样拷贝输出,但是他们的含义是尚未有明确定义,很可能引起编译时(compile-time)错误(这一特性是为了与POSIX兼容而提供的)。

在定义段中,没有缩进的注释也会被原样拷贝到最后生成的C代码文件中,例如以/*开始的一行注释,直到遇到*/,这中间的文本会被原样拷贝输出
一个简单的扫描器实例                                                                                                                                                      
%{
#include "stdio.h"
#include "stdlib.h"
%}

INT_DEX [1-9][0-9]*|[0]
INT_HEX [0][Xx]([1-9][0-9]*|[0])
INT_OCT [0][0-7]
FLOAT [0-9]*[.][0-9]+([eE][+-]?[0-9]*|[0])?f?
SEMI [;]
COMMA [,]
ASSIGNOP [=]
RELOP [>]|[<]|[>][=]|[<][=]|[=][=]|[!][=](^[=])
PLUS [+]
MINUS [-]
STAR [*]
DIV [/]
AND [&][&]
OR [|][|]
DOT [.]
NOT [!]
TYPE int|float
LP \(
RP \)
LB \[
RB \]
LC \{
RC \}
STRUCT struct
RETURN return
IF if
ELSE else 
WHILE while
SPACE [ \n\t]
ID [a-zA-Z_][a-zA-Z_0-9]*
/*end of definition*/

%%
{SEMI} {
    printf("get semmi : %s\n", yytext);

}

{COMMA} {
    printf("get comma : %s\n", yytext);
}
{ASSIGNOP} {
    printf("get assignop : %s\n", yytext);
}

{INT_DEX} |
{INT_HEX} |
{INT_OCT} {
    printf("get an integer: %s\n", yytext);
}

{FLOAT} {
    printf("get a float: %s\n", yytext);
}

{PLUS} | 
{MINUS} |
{DIV} |
{STAR} {
    printf("get an operator: %s\n", yytext);
}

{RELOP} {
    printf("get a relop: %s\n", yytext);
}

{AND} |
{OR} |
{NOT} {
    printf("get a logic operator: %s\n", yytext);
}

{DOT} {
    printf("get a dot: %s\n", yytext);
}
{STRUCT} |
{RETURN} |
{IF} |
{ELSE} |
{WHILE} {
    printf("get keyword: %s\n", yytext);
}

{TYPE} {
    printf("get type: %s\n", yytext);
}

{LP} |
{RP} |
{LB} |
{RB} |
{LC} |
{RC} {
    printf("get brackets : %s\n", yytext);
}

{SPACE} |
. {
/*ABANDON THESE CHARACTORS*/
}

{ID} {
    printf("get an ID: %s\n", yytext);
}
%%

int yywrap() {
  return 1;
}

int main(int argc, char** argv) {
   if (argc > 1) {
       if (!(yyin = fopen(argv[1], "r"))) {   
           perror(argv[1]);
           return 1;
       }
   }
   while (yylex());
   return 0;
}

转载于:https://my.oschina.net/u/2358894/blog/1600221

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值