我的好兄弟之Flex&Bison 第一章 实现人生的第一个Flex!
前面的话:在此之前,如果我接到一个解析文本的工作,我会逐行读取并存储我想要的数据再去处理数据。最近,工作中需要去解析verilog代码,相信verilog有许多人都用过,各关键字有相对应的含义和用法,很明显不能通过上述的方法来做,大概浏览了github,给我这个没有学过编译原理的人指出了一条明路:yacc&lex,或者,flex&bison。
本系列文章:我写这个系列的博客主要是记录收获的知识和踩过的坑,初学者的缘故,并不对其他人具有指导意义。当然,也可能你也和我有相同的问题或者感想,我们可以好好讨论一下。
我的目标:以后如果碰到需要解析的工作,一个下午搞定。
实现人生的第一个Flex!
经典的lex和yacc由贝尔实验室在20世纪70年代开发,flex和bison是他们的现代版本。其中lex和flex是词法分析器,yacc和bison是语法分析器。
1、词法分析和语法分析
解析工作通常可以分成两个部分:词法分析(lexical analysis 或者 scanning)和语法分析(syntax analysis 或者 parsing)。简单的说,词法分析是将输入分割成为一个个有意义的词块,成为记号(token),而语法分析是确定这些记号如何彼此关联的。下例所示:
A = B + C ;
词法分析器会将上面的例子拆分成 A、等号、B、加号、C、分号。语法分析器会确定B + C是一个表达式,并且表达式结果赋予给了A。
2、正则表达式
| 字符 | 含义 |
| A-Z,0-9,a-z | 构成了部分模式的字符和数字 |
| . | 匹配任意字符,除了\n |
| - | 用来指定范围。例如:A-Z指从A到Z之间的所有字符 |
| [] | 一个字符集合。匹配括号内的任意字符。如果第一个字符是^那么它表示否定模式。例如:[abC]匹配a,b,C中的任何一个 |
| * | 匹配0个或者多个上述的模式 |
| + | 匹配1个或者多个上述模式 |
| ? | 匹配0个或者1个上述模式 |
| $ | 作为模式的最后一个字符匹配一行的结尾 |
| {} | 指出一个模式可能出现的次数。例如:A{1,3}表示A可能出现1次或者3次 |
| \ | 用来转义元字符。同样用来覆盖字符在此表中定义的特殊意义,只取字符的本意 |
| ^ | 否定 |
| | | 表达式间的逻辑或 |
| "<一些符号>" | 字符的字面含义。元字符具有 |
| / | 向前匹配。如果在匹配的模板中的"/"后跟有后续表达式,只匹配模板中"/"前面的部分。如:如果输入A01,那么在模板A0/1中的A0是匹配的 |
| () | 将一系列常规表达式分组 |
3、第一个Flex程序
开始进入我们的正题,直接上代码!
%{ int chars = 0; int words = 0; int lines = 0; %}
%% [a-zA-Z]+ {words++; chars += strlen(yytext);} \n chars++; lines++;} . {chars++;} %% main(int argc,char **argv){ yylex(); printf("%8d %8d %8d\n" ,lines, words, chars); }
打眼看,这不就是C?
等等,"%{","%%"这是什么?
flex程序通常分为三个部分,各部分之间通过仅有"%%"的行来分割。第一部分包含声明和选项设置。第二部分是一系列模式和动作,第三部分则是会被拷贝到词法分析器里的C代码
第一部分,声明部分通过"%{"、"%}"包裹,声明部分会被照抄到生成的C文件开头。在上述例子中,声明部分设置了行数、单词数和字符数的变量。
第二部分,行开头是每个模式,采用正则表达来定义,之后的花括号内是模式匹配时需要执行的C代码。
比如例中的第一个模式"[a-zA-Z]+",用来匹配由一个或多个大小写字母构成的单词,读取到一个就将words变量++,来统计单词的数量。值得一提的是,在任意一个flex动作中,变量yytext总是被设为只想本次匹配的输入文本。第二个模式"\n"用来匹配换行符。第三个模式是一个点,它是指任何一个字符,关联的动作也是统计一共出现了多少个字符。
末尾的第三个模式是我们的主程序,它负责调用flex提供的词法分析例程yylex(),并输出结果。在没有任何改变的情况下,词法分析器将读取标准输入。
粗略的了解了flex程序,我们来执行看看:
$ flex text.l $ cc lex.yy.c -lfl $ ./a.out
这里需要清楚的是,我们创建的文件名为text.l;通过flex编译生成默认名为lex.yy.c的C程序;将他与相应的flex库文件(-lfl)链接。运行它;然后就可以提供一段输入供词法解析。

ps:图里的flex和bison拼错了~
可以看到,我输入的"my bro flex and bsion"是4行、5个单词、22个字符(包括空格和转行符)组成的。
4、遇到的问题
(1) premature EOF
flex对间距非常敏感,即有可能是"%{"、"%}"、"%%"之前出现了空格或写错了。
(2)cannot find -lfl
你需要安装flex-devel,这玩意也是必须的,虽然我也不知道为什么,哈哈。
(3)结束输入
ctrl+d
好了,人生的第一个Flex程序已经大功告成~
加油:)
浙公网安备 33010602011771号