安装flex
在Ubuntu下安装flex非常简单,只需要在终端中输入
sudo apt-get install flex
即可;
如果说找不到flex,可能你需要更新系统的源,百度一下“Ubuntu更新源”,应该可以解决;
flex
什么是flex?
flex是指 fast lexical analyzer generator,快速词法分析器生成器,也就是说,flex用于产生词法分析器;
flex的输入是文件或输入设备,这些输入中的信息以正则表达式和C代码的形式组成,这些形式被称为规则(rule);
flex的默认输出是C语言的源码文件:lex.yy.c,也可以重命名;该文件通过编译生成可执行的文件;
当可执行文件被执行时,其分析输入中可能存在的符合规则的内容,当找到任何一个正则表达式相匹配内容时,相应的C代码将被执行;
flex的输入文件由3段组成,用一行中只有%%来分隔;
定义:definition
%%
规则:rules
%%
用户代码:code
定义部分
其中定义有变量声明,正则表达式声明;
变量声明有两种:
例1:
%{
int a;
int b;
%}
例2:
int a;
int b;
需要有tab键缩进;
正则表达式声明方式:
表达式名称 表达式
在使用时需要将表达式名称用{}括起来;
规则部分
一个规则一行,每行有两部分构成:
正则表达式 {动作函数}
动作函数可以调用在用户代码中定义的函数;
例子1
编码过程
编写一个名为t1.lex的文件:
/*t1.lex*/
%option main /*生成main函数*/
%{
int fun();
%}
%%
/*第一个%%之后是规则部分*/
apple {fun();}
%%
int fun(){
printf("banana");
return 0;
}
这个文件的规则为如果遇到“apple”,执行代码“printf(“banana”)”,及将输入中的apple替换为banana;
通过:flex t1.lex生成lex.yy.c文件;
通过编译该c语言文件:gcc lex.yy.c
生成一个可执行文件a.out
实验过程
在终端输入:echo 123apple123 | a.out
输出为:123banana123
例子2
编写一个简单的对c语言能够解析的lex文件,代码t2.lex如下所示:
/*t2.lex*/
%option main
%{
int line=1;
%}
DIGIT [0-9]
OINTEGER [1-9]{DIGIT}*
INTEGER ("+"|"-")?{OINTEGER}
DECIMAL {INTEGER}(.{OINTEGER})?
LETTER [a-zA-Z]
ID ({LETTER}|_)({LETTER}|_|{DIGIT})*
OPT ("+="|"-="|"*="|"/="|"+"|"-"|"*"|"/"|"<="|">="|"=="|"=")
%%
\n {++line;}
(int|float|double|short) {printf("line%d:(type,%s)\n",line,yytext);}
for {printf("line%d:(for,)\n",line);}
{INTEGER} {printf("line%d:(integer,%s)\n",line,yytext);}
{DECIMAL} {printf("line%d:(decimal,%s)\n",line,yytext);}
{ID} {printf("line%d:(identify,%s)\n",line,yytext);}
("("|")"|"{"|"}"|"["|"]") {printf("line%d:(bracket,\"%s\")\n",line,yytext);}
"\"" {printf("line%d:(QUOTE,)\n",line);}
{OPT} {printf("line%d:(OPT,%s)\n",line,yytext);}
. {}
%%
/*辅助过程部分*/
代码说明:
3~5行:全局变量的说明,需要用“%{”和“%}”括起来;
6行:类似于C语言中的宏定义,翻译规则中的{DIGIT}将被“[0-9]”所替换;”[0-9]”是一个正则表达式,表示字符’0’、’1’、…、’8’、’9’中的任意一个;
8行:+号需要用引号括起来,因为正则表达式也有+号;同理,-号也需要括起来;
21行:引号需要有反斜杠进行转义;
实验过程
创建一个test文件:
int main(){
int a = 10;
double b = -20.9;
if(a<=b)
a+=b;
return a;
}
在终端中分别输入:
flex -o t2.c t2.lex
gcc t2.c -o ./a.out
./a.out < test
实验结果如下:
输出格式为:
元素所在行:{ID号,属性}
注意点:
- 正规定义中[xy]等价于(x|y)
- 定义部分一些在翻译规则中使用的变量的声明,需要由%{和%}包围起来,这部分声明将被直接抄写在lex.yy.c中,不作为正规定义和翻译规则的一部分;
- 如果变量的声明不在%{和%}之间,那么需要在声明部分进行缩进(使用tab缩进);
- 辅助过程是一些函数,能够被抄入到生成的c文件中,在规则后面的动作中可以调用;
- 规则后面的动作可以通过return返回词法单元的记号;在动作、辅助过程中可以使用变量yylval、yytext、yyleng,这些变量为全局变量,通过yylval传送记号属性给语法分析器,yytext为解析出的词法单元字符串的指针,yyleng为词法单元字符串长度;
- 若两个表达式同时匹配一个词法单元,如表达式if和[a-z]+同时匹配if\s,(注意\s表示空格),那么按照两个表达式在翻译规则中的顺序选择动作;而表达式<和<=匹配<=\s时,<可以匹配1个单词,<=可以匹配两个单词,那么选择匹配元素多的<=;