内容选自《编译原理》龙书第 2 版 72 页。

编译大型源程序时需要处理大量字符,其需要很多时间,因此引入了一些特殊的缓冲技术来减少用于处理单个输入字符的时间开销。一种重要的机制就是利用两个交替读入的缓冲区。

每个缓冲区的容量都是 N 个字符,通常 N 是一个磁盘块的大小,比如 4096 字节。我们可以一次性将 N 个字符读入到缓冲区。如果输入文件中的剩余字符不足 N 个,则会有一个特殊字符(用 eof 表示)来标记源文件结束。

程序为输入维护 2 个指针:

  • lexemeBegin 指针:指向当前词素的开始处
  • forward 指针:一直向前扫描,直到发现某个模式被匹配为止

一旦确定了下一个词素,forward 指针将指向该词素结尾的字符。词法分析器将这个词素作为词法单元的属性值纪录下来,而该词法单元会返回给语法分析器。然后使 lexemeBegin 指针指向刚刚找到的词素之后的第一个字符。

将 forward 指针前移要求我们首先检查是否已经到达某个缓冲区的末尾。如果是,则必须将 N 个新字符读到另一个缓冲区中,且将 forward 指针指向这个新载入字符的缓冲区的头部。只要我们从不需要越过实际词素向前看很远,以至于这个词素的长度加上向前看的距离大于 N,我们就绝不会在识别这个词素之前覆盖掉这个尚在缓冲区的词素。

按照以上方案,在每次移动 forward 指针时,都必须检查是否到达了缓冲区的末尾。因此每次读入一个字符,都需要座两次测试:

  • 检查是否到达缓冲区末尾
  • 确定读入的字符是什么

假如我们扩展每个缓冲区,使它们在末尾包含一个“哨兵(sentinel)”字符,就可以把对缓冲区末端的测试和对当前字符的测试合二为一。该哨兵字符必须是一个不会在源程序中出现的特殊字符,一个自然选择就是eof,但是它仍然可以标记整个输入的结尾。

词法单元:是一个表示某种词法单位的抽象符号,比如特定的关键字,或代表标识符的输入字符序列。由一个词法单元名和一个可选的属性值组成。
模式:描述了词法单元的词素可能具有的形式。
词素:源程序中的一个字符序列,它和某个词法单元的模式匹配,并被词法分析器识别为该词法单元的一个实例。