1700436660
1700436661
图5-2 乔恩·本特利,约1981年(杰勒德·霍尔兹曼供图)
1700436662
1700436663
Yacc结合了先进的解析技术、极高的效率和方便的用户界面,成为早期语法分析器生成软件中的仅存硕果。今天,除了以完整的独立软件形式出现,它还在其他软件(如由它衍生出来的Bison)中存在,并且在另外几种编程语言中得以重新实现、继续发挥作用。
1700436664
1700436665
2. Lex
1700436666
1700436667
1700436668
1700436669
1700436670
1700436671
1975年,迈克尔·莱斯克(图5-3)写出词法分析器生成软件Lex,它与Yacc交相辉映。Lex程序由一连串的模式(正则表达式)组成,这些模式定义了要识别的“词元”(lexical token)。对于编程语言来说,这些标记是保留字、变量名、运算符、标点符号等元素。与Yacc一样,Lex可以给每个指定标记附加用C语言编写的语义操作。由此,Lex生成C语言程序,该程序读取字符流,识别它找到的标记,并执行相关的语义操作。
1700436672
1700436673
1700436674
1700436675
1700436676
图5-3 迈克尔·莱斯克,约1981年(杰勒德·霍尔兹曼供图)
1700436677
1700436678
迈克[4]写了Lex的第1版。1976年夏天,一位刚从普林斯顿大学毕业的实习生很快对它做了修改。迈克回忆说:
1700436679
1700436680
“埃里克·施密特(Eric Schmidt)在暑期实习时几乎重写了Lex。我之前的版本采用非确定性分析器,无法处理超过16个状态的规则。阿尔·阿霍很不爽,给我找了个暑期生来修复。埃里克适逢其会。”
1700436681
1700436682
埃里克后来在伯克利分校获得博士学位,并于2001年至2011年担任谷歌公司首席执行官一职。
1700436683
1700436684
Yacc和Lex紧密协同。解析过程中,Yacc会反复调用Lex,Lex每次读取足够多的输入来构造完整词元,并将其传回给Yacc。Yacc/Lex组合将编译器的前端组件机械化,能够同时处理复杂的语法和词法结构。例如,有些编程语言的运算符长达两三个字符,如C语言中的++运算符,当词法分析器看到符号+的时候,要接着看,才能知道待处理的运算符是++还是普通的+。手工写这种代码并不算难,但若有人代劳就尤其方便。使用Lex,人们只需要写
1700436685
1700436686
“++” { return PLUSPLUS; }“+” { return PLUS; }
1700436687
1700436688
1700436689
1700436690
1700436691
1700436692
就能区别开上述两种情形。(PLUS和PLUSPLUS是数学符号的名称,这样C语言代码就比较容易处理。)
1700436693
1700436694
图5-4展示了在创建C语言程序时如何使用Yacc和Lex。该程序是某种语言的编译器。Yacc为语法分析器生成一个C语言文件,Lex为词法分析器生成另一个C语言文件。这两个C语言文件与其他包含语义的C语言文件组合在一起,由C语言编译器编译成可执行程序。这张图是用Pic程序制作的,Pic的结构也正是如此。
1700436695
1700436696
1700436697
1700436698
1700436699
图5-4 使用Yacc和Lex创建编译器
1700436700
1700436701
尽管Lex如此简单而强大,但长期以来,它并没有像Yacc那样得到广泛应用。也许这是因为对于相对缺乏经验的程序员来说,为复杂的语言编写语法分析器令人生畏,而编写词法分析器则不然。但是,亲手编写词法分析器,无论看起来多么简单直接,都未必是个好主意。
1700436702
1700436703
我在awk脚本语言上的经验(本章后文将讨论)可以借鉴。awk的第1版实现使用Yacc处理语法,使用Lex分解输入内容。然而,当我们试图将awk移植到非Unix环境时,Lex要么无法使用,要么虽然能用但生成了错误的词法分析器。几年后,我勉力用C语言重写了awk的词法部分,这样它就可以移植到所有环境中。但在之后的几年里,那段手工写出来的词法代码产生了许多缺陷和小问题,这些麻烦在Lex生成的版本中原本不存在。
1700436704
1700436705
这证明了一个普遍规则:程序帮你写的代码会比你自己手写的更正确、更可靠。如果改进了生成器,例如能生成更好的代码,那么每个人都会受益;相反,对手写程序的改进并不能改善其他程序。像Yacc和Lex这样的工具是这一规则的极好例子,Unix也提供了许多其他工具。编写程序的程序总是值得尝试。就像道格·麦基尔罗伊所言,“任何你必须重复做的事都有待自动化。”
1700436706
1700436707
3. Make
1700436708
1700436709
[
上一页 ]
[ :1.70043666e+09 ]
[
下一页 ]