词法分析程序作用
lex是构建此法分析程序的工具,流程如下
- 编写模式和该模式对应的c处理程序
- lex生成lex.yy.c,然后可以通过调用yylex()来使用这个lex.yy.c
编写模式
- . 任意字符,除了\n
- * 前面表达式重复0-n次
- [] 括号内的任意字符,如[0-9]表示0到9的任一个数字
- ^ 行的开头,也作为[]内部第一个字符表示否定
- $ 行的末尾,可参考vim快捷键
- {} 括号内的数字表示重复的次数的范围,\d{2}表示两位的数字,包含名称,则用该名称替换
- \ 转移元字符
- + 前面表达式重复1-n次
- ? 前面表达式重复0-1次
- | 任选一种,比如a|b可匹配的为a,b
- " " 引号内的字符解释为字面意义
- / 匹配需要前后的条件都满足,但是只截取/的前半部分
- () 一个正则表达式的组合
格式
%{
%}
被称为定义段,为c代码编写,将被拷贝到lex.yy.c中去
%%
标记第一部分结束
第二部分是规则段,也就是许多条模式和对应动作
%%
标记规则段结束
第三部分是代码段,c语言编写,也是直接复制到lex.yy.c
实例,筛选小数
float.l
%{
%}
%%
-?(([0-9]+)|([0-9]*\.[0-9]+)) { printf("%s is a number\n",yytext); }
. ;
%%
main(){
yylex();
}
nosourcesmatoMacBook-Pro:lex nosources$ lex float.l
nosourcesmatoMacBook-Pro:lex nosources$ cc lex.yy.c -o float -ll
运行编译好的词法分析器,就可以筛选输入流里面的小数了
nosourcesmatoMacBook-Pro:lex nosources$ ./float
1.2 333 s.d 3.4
1.2 is a number
333 is a number
3.4 is a number
实例,单词计数器
wc.l
%{
unsigned int charCount = 0, wordCount = 0, lineCount = 0;
%}
%%
[0-9a-zA-Z]* {
wordCount++;
charCount += yyleng;
}
\n {
charCount++;
lineCount++;
}
. {
charCount++;
}
%%
int main(argc, argv)
int argc;
char** argv;
{
if (argc > 1){
FILE *file;
file = fopen(argv[1], "r");
if (!file){
fprintf(stderr, "could not open %s\n", argv[1]);
exit(1);
}
yyin = file;
}
yylex();
printf("word:%d, char:%d, line:%d\n", wordCount, charCount, lineCount);
return 0;
}
sdf adsfa asdf d
编译并且运行
mini2:wc nosources$ lex wc.l && cc lex.yy.c -o wc -ll
mini2:wc nosources$ ./wc test
word:4, char:17, line:1
wc2.l
%{
unsigned int charCount = 0, wordCount = 0, lineCount = 0;
%}
%%
[0-9a-zA-Z]* {
wordCount++;
charCount += yyleng;
}
\n {
charCount++;
lineCount++;
}
. {
charCount++;
}
%%
int main(argc, argv)
int argc;
char** argv;
{
yylex();
printf("word:%d, char:%d, line:%d\n", wordCount, charCount, lineCount);
return 0;
}
mini2:wc nosources$ lex wc2.l && cc lex.yy.c -o wc2 -ll
mini2:wc nosources$ ./wc2 < test
word:4, char:17, line:1
起始位置
遇到某一个匹配的时候,可以进入到一种特殊的匹配模式,这种模式下的匹配都以起始位置为开头,比如下面的程序可以知道一个函数有多少行
%{
%}
%s MAGIC
%%
<MAGIC>\} {
BEGIN 0; printf("\nEnd MAGIC:");
}
\{ {
BEGIN MAGIC; printf("\nBegin MAGIC\n");
}
\w {
ECHO;
}
%%
main(){
yylex();
}
mini2:startPosition nosources$ lex startPosition.l && cc lex.yy.c -o sp -ll
mini2:startPosition nosources$ ./sp
ad { int a = 1;}
ad
Begin MAGIC
int a = 1;
End MAGIC: