编译原理——词法分析(1)

在咱们学习词法分析时,就会思考如何构造一个词法分析器?
一个词法分析器能够经过手工构造;也能够经过如下方式自动生成一个词法分析器:向一个词法分析器生成工具描述出词素的模式,而后将这些模式编译为具备动词分析器功能的代码。正则表达式

如何对正则表达式进行转换?
首先转换为不肯定有穷自动机,而后再转换为肯定有穷自动机。安全

词法分析器的做用:
1.读入源程序的输入字符、将他们组成词素,生成并输出一个词法单元序列,每一个词法单元对应于一个词素。这个词法单元序列被输出到语法分析器进行语法分析。
2.词法分析器一般还要和符号表进行交互。当词法分析器发现了一个标识符的词素时,它要将这个词素添加到符号表中。在某些状况,词法分析器会从符号表中读取有关标识符种类的信息,以肯定向语法分析器传送哪一个词法单元。
3.完成一些识别词素以外的其余任务。(1)过滤掉源程序中的注释和空白(空格、换行符、制表符以及在输入中用于分隔词法单元的其余字符)(2)将编译器生成的错误信息与源程序的位置联系起来。例如词法分析器能够负责记录遇到的换行符的个数,以便给每一个出错信息赋予一个行号。若是源程序使用了一个宏预处理器,则宏的扩展也能够由词法分析器完成。工具

词法分析器与语法分析器的交互过程:一般,交互是由语法分析器调用词法分析器来实现的,其中图中的命令getNextToken所指示的调用使得词法分析器从它的输入中不断读取字符,知道它识别出下一个词素为止。词法分析器根据这个词素生成下一个词法单元并返回给语法分析器。学习

词法分析器分红两个级联的处理阶段:
    1.扫描阶段,主要负责完成一些不须要生成词法单元的简单处理,好比删除注释和将多个连续的空白字符压缩成一个字符。
    2.词法分析阶段,处理扫描阶段的输出并生成词法单元。优化

词法分析中,常见的三个术语。词法单元,模式和词素
词法单元(token):词法单元由一个词法单元名和一个可选的属性值组成。词法单元名是一个表示某种词法单位的抽象符号,是由语法分析器处理的输入符号。可是,在不少状况下,词法分析器不只仅向语法分析器返回一个词法单元名字,还会返回一个描述该词法单元的词素的属性值。词法单元的名字将影响语法分析过程当中的决定,而这个属性则会影响语法分析以后对这个词法单元的翻译。一个标识符的属性值是一个指向符号表中该标识符对应条目的指针。
模式(pattern):描述了一个词法单元的词素可能具备的形式。
词素(lexeme):是源程序中的一个字符序列,它和某个词法单元的模式匹配,并被词法分析器识别为该词法单元的一个实例。
光从概念上来看,会以为十分抽象很难理解,可是结合例子来理解,就会明白他们三者的关系。翻译

正则表达式:正则表达式是一种能够很方便地描述词素模式的方法,能够高效地描述在处理词法单元时要用到的模式类型。设计

在不少程序设计语言中,下面的类别覆盖了大部分或全部的词法单元:
    (1)每一个关键字有一个词法单元。一个关键字的模式就是该关键字自己。好比:if else
    (2)表示运算符的词法单元。它能够表示单个运算符,也能够像comparison那样,表示一类运算符。
    (3)一个表示全部标识符的词法单元。
    (4)一个或多个表示常量的词法单元,好比数字和字面值字符串。
    (5)每个标点符号有一个词法单元,好比左右括号、逗号和分号。3d

当词法错误时,可能采起的其余错误恢复动做包括:
    (1)从剩余的输入中删除一个字符。
    (2)向剩余的输入中插入一个遗漏的字符。
    (3)用一个字符来替换另外一个字符。
    (4)交换两个相邻的字符。
不过最简单的策略是看一下是否能够经过一次变换将剩余输入的某个前缀变成一个合法的词素。指针

输入缓冲
    双缓冲区方案,加快源程序读入速度的方法,这种方案能安全处理向前看多个符号问题.-,=,< 多是->,==,<=这样双字符运算符的开始,咱们将考虑一种改进方法,这种方法用哨兵标记来节约检查缓冲区末端的时间。blog

什么叫缓冲区对?
        因为在编译一个大型程序须要处理大量的字符,处理这些字符须要不少时间,由此开发了一些特殊的缓冲技术来减小用于处理单个输入字符的时间开销。一种重要机制是利用两个交替读入的缓冲区。

    缓冲区对的具体实现流程
        每一个缓冲区容量都是N个字符,一般N是一块磁盘块大小,如4096字节
            1.程序为输入维护了两个指针 
                lexemeBegin指针:该指针指向当前词素的开始处.当前咱们正试图肯定这个词素的结尾.
                forward指针:它一直向前扫,直到发现某个模式被匹配到为止 
           2. 一旦肯定下一个词素,forward指针将指向该词素结尾的字符. 
                词法分析器将这个词素做为某个词法单元记录下来并返回,而后使lexemeBegin指针指向刚找到词素后的第一个位置
          处理完后,forward指针也会前移一个位置
           3.若是forward指针前移,要求咱们首先检查是否已经到达某个缓冲区的末尾。(哨兵标记优化的地方) 
                若是是,咱们将N个新字符读到另外一个缓冲区末尾,且将forward指针指向这个新载入符的头部.
        

哨兵标记:

如何优化检测缓冲区末尾?

检查是否到了末尾,而且肯定读入的字符

优化后:在缓冲区末尾扩展一个绝对不会使用的符号,叫作哨兵(sentinel)字符,一个天然的选择是eof.