翻译一份lex & yacc教程,希望不要烂尾

译者按:打算翻译一份lex& yacc教程,每天一点点,这个是原文的第一部分,介绍。

1. 介绍

    直到1975年,写一个编译器还是一个非常耗时的里程。然后Lesk和Johnson发布了关于lex和yacc的论文。这些工具极大地简化了编译器的构造。lex和yacc的实现细节可以在 Aho[1986]里找到。

    Lex和Yacc可以在以下地方找到
    1. Mortice Kern Systems(MKS),http://www.mks.com
    2.GNU flex and bison, at http://www.gnu.org,
    3.Ming, at http://agnes.dida.physik.uni-essen.de/~janjaap/mingw32,
    4.Cygnus, at http://www.cygnus.com/misc/gnu-win32, and
    5.my version of Lex and Yacc, at http://epaperpress.com

    MKS是高质量的商业产品,零售要300刀一份。GUN软件是免费的,到1.24版本时,flex的输出都可以用在商业软件里,bison也是一样的。Ming和Cygnus是32位windows 95/NT上的GUN软件移植。我自己版本基本Ming的,但是用Visual C++编译,并包含一些bug fix的函数。如果你下载了我的版本,记得一定要保持你解压时的目录结构。

            源码         a = b + c * d
                              |
                              v
                           词法分析
                              |
                              V
                           语法分析
                              |
                              V
            语法树             =
                            /   \
                          id1    +
                                /  \
                              id2   *
                               |   / \
                               |  id3 id4
                           代码生成
                               |
                               V
            生成的代码      load id3
                           mul id4
                           add id2
                           store id1
                   图1.1 编译顺序
   
Lex生成词法分析的C代码,或者说是扫描器。它使用这样一种模式,匹配输入字串,并将字串转化成符号(token)。符号是这些字串的数字表示。上图可以说明。

   当Lex在输入流中找到了变量名,就把它们放入符号表。符号表也同时保存着其它一些信息,比如数据类型(整形还是实形)和变量在内存中的地址。接下来所有对变量的引用都会通过符号表+索引的形式来实现。

    Yacc生成语法分析的C代码,或者说是解析器。Yacc利用语法规则,来分析Lex产生的符号,并构造语法树。语法树把符号理清了层次结构。下一步,代码生成,对语法树进行深度优先的遍历来生成代码。有些编译器产生机器码,另外一些,如上图所示,输出的是汇编码。

                        (yyparse)        source
        bas.y -> yacc -> y.tab.c            |
                  |             \           |
                  |              \          v
                y.tab.h            cc -> bas.exe
                  |              /          |
                  |             /           |
        bas.l -> lex -> lex.yy.c            v
                        (yylex)          编译输出

                图1.2 用Lex/Yacc构造一个编译器

    图1.2说明了保用lex和yacc时文件名的转换。我们先设定我们的目标是写一个BASIC编译器。首先,我们使用lex来识别所有的模式匹配,使用yacc来识别语法规则。创建你自己的编译器,bas.exe,的命令,如下:

    yacc –d bas.y                 # 创建 y.tab.h, y.tab.c
    lex bas.l                     # 创建 lex.yy.c
    cc lex.yy.c y.tab.c –obas.exe # 编译链接

    Yacc从bas.y中读出语法描述,并生成解析器,主要部分是y.tab.c文件中的yyparse。bas.y包含了符号声明的头文件,-d的参数使yacc生成符号的定义并把它们放置在头文件y.tab.h中。Lex读出bas.l中的模式描述,包含y.tab.h头文件,并生成词法分析器,主要部分是yylex,在文件lex.yy.c中。

    最后,词法分析器和语法解析器都被编译,并链接在一起,形成一个可执行文件,bas.exe。在它的main函数中,我们调用yyparse来驱动整个编译器。函数yyparse中自动调用yylex来获得每一个符号。

你可能感兴趣的:(数据结构,C++,c,Flex,C#)