许多其他的编程语言,都使用 lex和 yacc 来生成分析应用程序以分析和理解文本,并将其转换为所需的信息或数据结构。
Lex 是一种词法分析工具,它可以用来从源文本识别特定结构的文本字符串。
Yacc 是一种语法分析器,它可以读取文本并用来将单词序列转换为便于处理的结构化的格式。
在本教程中,首先您将研究如何使用 lex 和 yacc 来构建一个计算器。
使用该计算器作为示例,您将进一步研究 lex 和 yacc 系统生成的输出和信息,并学习如何使用它来分析其他类型的信息。
使用 lex 进行词法分析编写文本分析器的第一步是要能够识别所读取的内容。
有许多不同的方法可以完成这项任务,但是最简单的方法是使用 lex,它是将输入信息转换为一系列标记的工具。
什么是词法分析?当使用编程语言编写程序或在命令行中输入命令时,您是否想过究竟执行了什么操作将您输入的内容转换为一组指令呢?这个处理过程非常简单,却又相当复杂。
它很复杂,这是因为对于可能输入的信息,表面上看起来似乎存在无限种可能的组合和序列。
例如,要使用 Perl 语言遍历一个哈希表,您可以使用如清单 1 所示的序列。
清单 1. 在 Perl 中遍历一个哈希表foreach key keys hash...其中的每一项都是有意义的,虽然方式有所不同,这正是该处理过程的简单明了之处。
清单 1 中所示的表达式存在一个对应的结构,也就是说,与人类语言一样,编程语言中也存在着特定的规则。
因此,如果将输入分解为您所看到的和该信息结构的组合,那么对该内容的分析过程则相当简单。
要理解提供给文本分析应用程序的信息,通常有两个阶段。
第一个阶段是识别输入的或提供给应用程序的内容是什么。
您必须能够从输入源中识别关键字、短语或字符序列,以便能够确定对其进行何种处理。
第二个处理阶段是理解该信息的结构,即语法,以便对输入进行验证和操作。
有关语法的一个很好的示例是,大多数编程语言中圆括号的使用。
很明显,下面的表达式是错误的: function 其中,大括号不匹配,而圆括号的出现顺序错误。
为了让分析器理解和识别表达式,那么分析器必须知道正确的序列,以及匹配该序列后应该进行何种操作。
词法分析首先进行识别输入数据的处理,并且可以使用 lex 工具来完成该处理过程。
回页首lex 工具lex 工具(或 GNU 工具 flex)使用一个配置文件来生成相应的 C 源代码,然后,可以用它来创建独立的应用程序,或者在您自己的应用程序中使用它。
配置文件定义了需要在待分析的文件中查找的字符序列,以及当发现该序列之后应该进行什么操作。
该文件的格式十分简单,即指定输入序列和相应的结果,用空格(或制表符)隔开。
例如:sequence do-something清单 2 显示了一个非常简单的定义,它可以接受单词并根据提供的单词打印出一个字符串。
清单 2. 简单的 lex 定义include ltstdio.hgtbegin printfquotStartednquothello printfquotHello yourselfnquotthanks printfquotYour welcomenquotend printfquotStoppednquot代码中的第一块由 ... 定义,表示将其中的文本插入到生成的 C 源代码中。
在本示例中,因为后面使用了 printf 函数,所以必须确保包含了 stdio.h Header。
代码中的第二块由 序列标识,其中包含了要识别的字符串输入和相应结果的定义。
在上述的这些情况下,对于一个简单的单词,将打印出合适的响应。
回页首生成 C 源代码要生成能够真正分析输入文本的 C 源代码,可以对清单 1 所示的文件运行 lex(或 flex) Lex/flex 文 。
件点号后缀为 l,所以上面的文件可能名为 exampleA.l。
要生成相应的 C 源代码: flex exampleA.l不管您使用哪种工具,其输出都将为 lex.yy.c。
缺乏勇气的人往往不敢仔细研究这个文件,分析器内部的处理过程的确非常复杂,并且建立在基于表格的复杂分析系统的基础上,该系统可以根据原始 lex 定义中的定义对输入文本进行匹配。
因为存在这样的关联,所以该代码相当占用内存,特别是对于那些很大且很复杂的文件。
与 lex 相比,flex 的优点在于它提供了大量附加的选项以改进性能(针对内存或速度)、调试选项和对扫描器行为更好的控制(例如,可以忽略某些情况)。
在生成