lex与yacc是词法分析与语法分析工具中的利器,而词法与语法分析也绝不仅仅是各种代码编译器才会涉及到的领域,在我们日常的开发工作中,也有很多时候是可以派上用场的,比如一个固定语法格式的配置文件以及一些协议分析等。
lex用于词法分析工具,它可以将输入分解成一个个的“token”,并根据不同的token类型来做不同的事情,比如上报给调用者,它主要以正则表达式为描述工具,对于一些很简单的语法来说,lex也可以胜任。yacc则主要用于语法分析,它的语法规则以上下文无关的文法来描述,通过调用外部函数来获得“终端符号”(Terminal Symbol),进而来分析文法的正确性。lex和yacc都需要以C语言来辅助来完成相应的任务(通过一些选项设置也可以使用C++)。下面主要介绍lex和yacc的输入文件格式。
lex的输入文件分为三个区域:定义区、规则区、用户代码区,各区域之间使用双百分号(%% )来分隔,如下所示:
...定义区...
%%
...规则区...
%%
...用户代码区...
其中定义区包含词法扫描器的一些设置选项以及一些正则表达式的预定义,同时,在这个区域的顶部也可以通过%{...%}来包含C语言代码,其中可以进行一些头文件包含、变量定义等。
规则区则定义了单词匹配的一系列规则,每行定义一个规则,格式为:
rule action
rule是规则的定义,之后的action是匹配规则后执行的C语言代码。如果action为空,则lex默认的行为是输出rule所匹配的单词内容
用户代码区包含一组C语言代码,用户可以根据需要进行填充,lex会将它们直接转移到最后生成的.c文件中去
介绍完lex,再来看看yacc。yacc的文件格式和lex基本一致,也是分为如下几个区域:
%{
Prologue
%}
Bison declarations
%%
Grammar rules
%%
Epilogue
各区域功能与lex大体一致,不再叙述。
另外,有一个很重要的问题,lex与yacc在linux环境下似乎对换行符很敏感,我曾经在windows下写完输入文件后上传到linux环境中,编译都没有问题,最后运行时无论如何就是不能正确匹配我想到的符号,在漫长地排查过程后,终于发现,只要将输入文件中的windows换行符0D0A替换成linux下的0A,就没有问题了。
![](https://img-blog.csdnimg.cn/2022010622044242290.png)