Lex & Flex 简介
Lex是lexical compiler的缩写,是Unix环境下非常著名的工具, Lex (最早是埃里克·施密特和 Mike Lesk 制作)是许多 UNIX 系统的标准词法分析器(lexical analyzer)产生程式,而且这个工具所作的行为被详列为 POSIX 标准的一部分。
Lex的基本工作原理为:由正则表达式生成NFA,将NFA变换成DFA,DFA经化简后,模拟生成词法分析器。
Lex 主要功能是生成一个词法分析器(scanner)的 C 源码,描述规则采用正则表达式(regular expression)。描述词法分析器的文件 *.l 经过lex编译后,生成一个lex.yy.c 的文件,然后由 C 编译器编译生成一个词法分析器。词法分析器,简言之,就是将输入的各种符号,转化成相应的标识符(token),转化后的标识符很容易被后续阶段处理,如Yacc 或 Bison,过程如图 :
在linux系统上,我们最常用的是Flex,Flex (fast lexical analyser generator) 是 Lex 的另一个替代品。它经常和自由软件 Bison 语法分析器生成器 一起使用。Flex 最初由 Vern Paxson 于 1987 年用C语言写成。Flex手册里对 Flex 描述如下:
FLEX (fast lexical analyzer generator) is a tool/computer program for generating lexical analyzers (scanners or lexers) written by Vern Paxson in C around 1987. It is used together with Berkeley Yacc parser generator or GNU Bison parser generator. Flex and Bison both are more flexible than Lex and Yacc and produces faster code.
Bison produces parser from the input file provided by the user. The function yylex() is automatically generated by the flex when it is provided with a .l file and this yylex() function is expected by parser to call to retrieve tokens from current/this token stream.
Lex & Flex 输入文件格式
Flex 的输入文件包含了三部分,分别是定义区(definitions)、规则区(rules)和用户代码区(user code)并且由单独占一行的两个连续的百分号("%%")分隔开:
definitions
%%
rules
%%
user code
下面对 Flex 输入文件的三个部分做出解释:
1 定义部分:定义部分包含变量的声明,正则定义,清单常量。在定义部分,文本放在“%{%}”括号中。用花括号括起来的所有内容都会直接复制到lex.yy.c文件中。
语法
%{
// Definitions
%}
2 规则部分:rules部分包含一系列规则,格式为:pattern action,并且模式 pattern 位于行首不能缩进,action 也应该起始于同一行,规则部分包含在“%% %%”中。
语法:
%%
pattern action
%%
下表显示了一些模式匹配。
Pattern
It can match with
[0-9]
all the digits between 0 and 9
[0+9]
either 0, + or 9
[0, 9]
either 0, ‘, ‘ or 9
[0 9]
either 0, ‘ ‘ or 9
[-09]
either -, 0 or 9
[-0-9]
either – or all digit between 0 and 9
[0-9]+
one or more digit between 0 and 9
[^a]
all the other characters except a
[^A-Z]
all the other characters except the upper case letters
a{2, 4}
either aa, aaa or aaaa
a{2, }
two or more occurrences of a
a{4}
exactly 4 a’s i.e, aaaa
.
any character except newline
a*
0 or more occurrences of a
a+
1 or more occurrences of a
[a-z]
all lower case letters
[a-zA-Z]
any alphabetic letter
w(x \
y)z
wxz or wyz
3 用户代码部分:这部分包含C语句和其他功能。我们还可以分别编译这些函数并使用词法分析器加载。
如何运行程序:
要运行该程序,首先应将其保存为扩展名.l或.lex。在终端上运行以下命令以运行程序文件。
步骤1:lex filename.l或lex filename.lex取决于扩展文件
步骤2:gcc lex.yy.c
步骤3:./ a.out
步骤4:在需要时将输入提供给程序
注意:按Ctrl + D或使用某些规则停止接受用户输入。请查看以下程序的输出图像以清除是否有疑问以运行程序。
简单例子
计算字符串中的字符数
/*** Definition Section has one variable
which can be accessed inside yylex()
and main() ***/
%{
int count = 0;
%}
/*** Rule Section has three rules, first rule
matches with capital letters, second rule
matches with any character except newline and
third rule does not take input after the enter***/
%%
[A-Z] {printf("%s capital letter\n", yytext);
count++;}
. {printf("%s not a capital letter\n", yytext);}
\n {return 0;}
%%
/*** Code Section prints the number of
capital letter present in the given input***/
int yywrap(){}
int main(){
// Explanation:
// yywrap() - wraps the above rule section
/* yyin - takes the file pointer
which contains the input*/
/* yylex() - this is the main flex function
which runs the Rule Section*/
// yytext is the text in the buffer
// Uncomment the lines below
// to take input from file
// FILE *fp;
// char filename[50];
// printf("Enter the filename: \n");
// scanf("%s",filename);
// fp = fopen(filename,"r");
// yyin = fp;
yylex();
printf("\nNumber of Captial letters "
"in the given input - %d\n", count);
return 0;
}
运行:
查找读取文本所有整数
%{
/*
用flex写一个查找读取文本所有整数的程序
*/
int count = 0;
%}
%%
[+-]?[0-9]+ { count++; printf("%s\n", yytext); } /* Print integers */
\n {} /* newline */
. {} /* For others, do nothing */
%%
void main() {
yylex();
printf("Number count is %d\n", count);
}
int yywrap() {
return 1;
}
运行:
参考文章: