第1章 词法分析

1.1 词法分析

为了跟源代码打交道,我们需要将其转换为更易访问的形式。在编辑器中,源代码就像纯文本那样易于处理。但是如果在一门编程语言中将字符形式的源代码作为另一门编程语言来解释,就没那么简单了。

为了解释源代码,需要将其转换成其他易于处理的形式。具体来说,在最终对代码求值之前,需要两次转换源代码的表示形式,如图1-1所示。

图1-1

第一次是用词法分析器将源代码转换为词法单元,这个过程称为词法分析。词法分析器有时也称词法单元生成器(tokenizer)或扫描器(scanner)。有些资料用这些术语表示在行为上有细微差别的程序,但它们在本书中都是一个意思。

词法单元本身是短小、易于分类的数据结构。它会被传给语法分析器。在第二次转换中,语法分析器会将词法单元转换成抽象语法树。

来看一个例子。这是给词法分析器的输入:

"let x = 5 + 5;"

其生成的结果如下所示:

[
  LET,
  IDENTIFIER("x"),
  EQUAL_SIGN,
  INTEGER(5),
  PLUS_SIGN,
  INTEGER(5),
  SEMICOLON
]

所有这些词法单元都附带了对应的源代码表示形式。LET附带的是letPLUS_SIGN附带的是+,以此类推。上例中的IDENTIFIERINTEGER也附带了具体值:INTEGER附带的是数值5(不是字符串"5");IDENTIFIER附带的是字符串"x"。不同词法分析器实现所生成的词法单元会有所区别。例如,某些词法分析器在解析阶段或更靠后的阶段才会将字符串"5"转换为整数,而有些是在构造词法单元的时候就转换。

这个例子中有一点需要注意,那就是空白字符不会被识别成词法单元。这完全没问题,因为在Monkey语言中,空白的长度对代码含义没有影响,仅用于充当其他词法单元的分隔符。来看下面的代码:

let x = 5;

以下代码的含义与上面的相同:

let   x   =   5;

在Python等其他语言中,空白的长度会影响代码含义。这意味着此时词法分析器不能直接跳过空白字符和换行符,而必须将其输出为词法单元。之后语法分析器会处理这些词法单元,要么赋予特定的含义,要么在空白字符数量不合要求的时候报错。

具有完整功能的词法分析器还可以将行号、列号和文件名附加到词法单元中。这么做是为了在后面的语法分析阶段输出更有用的报错消息。例如,相比于"error: expected semicolon token",下面这条报错消息更详细:

"error: expected semicolon token. line 42, column 23, program.monkey"

不过本书不会在这方面花费精力,不是因为添加这些信息很麻烦,而是因为这会让词法单元和词法分析器变得更加复杂,增加理解难度。