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

在我们学习词法分析时,就会思考如何构造一个词法分析器?
一个词法分析器可以通过手工构造;也可以通过以下方式自动生成一个词法分析器:向一个词法分析器生成工具描述出词素的模式,然后将这些模式编译为具有动词分析器功能的代码。

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

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

编译原理——词法分析(1)_第1张图片

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

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

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

编译原理——词法分析(1)_第2张图片

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

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

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

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

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

编译原理——词法分析(1)_第3张图片

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

哨兵标记:

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

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

编译原理——词法分析(1)_第4张图片

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

 

 

 

你可能感兴趣的:(compilers)