分析(lexing)和解析(parsing)
2021年一月,词法分析器(lexer)和解析器(parser)正在进行重构, 以允许将它们提取到库(libraries)中。编译器要做的第一件事是将程序(Unicode字符)转换为比字符串更方便编译器使用的内容。这发生在词法分析(lexing)和解析(parsing)阶段。
词法分析(lexing)接受字符串并将其转换成 tokens 流(streams of tokens)。例如,
a.b + c 会被转换成 tokens a, ., b, +, c 。该词法分析器(lexer)位于
[rustc_lexer] 中。
解析(Parsing)接受 tokens 流(streams of tokens)并将其装换位结构化的形式,这对于编译器来说更加容易使用,通常成为抽象语法树(Abstract
Syntax Tree,AST)。AST 镜像内存中的Rust 程序的结构(structure),使用 Span 将特定的 AST 节点链接(link)回其源文本。
在 rustc_ast 中定义了 AST ,此外还有一些关于 tokens 和 tokens 流(tokens and token streams)的定义,用于变异的(mutating) ASTs 数据结构/特征(traits),以及用于编译器的其他 AST 相关部分的共享定义(如词法分析器和宏扩张)。
解析器(parser)是在 rustc_parse 中定义的,以及词法分析器(lexer)的高级接口和在宏展开后运行的一些验证例行程序。特别是,rustc_parse::parser 包含了解析器(parser)的实现
解析器的主入口是通过各种在 parser crate 中的parse_*函数和其他函数。它们允许你将SourceFile(例如单个文件的源文件)转换为 token 流(token stream ),从 token 流(token stream )创建解析器(parser),然后执行解析器(parser)去获得一个Crate(AST 的 root 节点)
为了减少复制的次数,StringReader 和 Parser 的生命周期都绑定到父节点 ParseSess。它包含了解析时所需要的所有信息以及 SourceMap 本身。
注意,在解析时,我们可能遇到宏定义或调用,我们把这些放在一旁以进行展开 (见 本章)。展开本身可能需要解析宏的输出,这可能会涉及到更多需要展开的宏,等等。
更多源于词法分析(Lexical Analysis)
词法分析的代码被分为两个箱子(crates):
-
rustc_lexercrate 负责将&str分解为组成标记的块。将分析器(lexer)作为生成的有限状态机来实现是很流行的,但rustc_lexer重的分析器(lexer)是手写的。 -
来自于
rustc_ast的StringReader将rustc_lexer与rustc详细的数据结构集成在一起。具体来说,它将Span信息添加到rustc_lexer和 interns 标识符返回的 tokens 中。