50.3. 解析器阶段

解析器阶段由两部分组成:

  • gram.yscan.l中定义的* parser *是使用 Unix 工具 bison 和 flex 构建的。

  • “转换过程”对解析器返回的数据结构进行了修改和扩充。

50.3.1. Parser

解析器必须检查查询字符串(以纯文本形式到达)的有效语法。如果语法正确,则将构建* parse tree *并将其退回;否则返回错误。解析器和词法分析器使用著名的 Unix 工具 bison 和 flex 实现。

  • lexer 在文件scan.l中定义,并负责识别 identifiers SQL 关键字等。对于找到的每个关键字或标识符,都会生成一个 token *并将其交给解析器。

解析器在文件gram.y中定义,由一组语法规则操作组成,它们在触发规则时都会执行。操作代码(实际上是 C 代码)用于构建解析树。

使用程序 flex 将文件scan.l转换为 C 源文件scan.c,并使用野牛将gram.y转换为gram.c。完成这些转换后,可以使用普通的 C 编译器来创建解析器。切勿对生成的 C 文件进行任何更改,因为它们将在下次调用 flex 或 bison 时被覆盖。

Note

上面提到的转换和编译通常是使用 PostgreSQL 源代码发行版随附的* makefiles *自动完成的。

对野牛或gram.y中给出的语法规则的详细描述将超出本文的范围。有许多有关 flex 和 bison 的书籍和文档。在开始研究gram.y中给出的语法之前,您应该熟悉野牛,否则您将不了解在那里发生的事情。

50 .3.2. 转型过程

解析器阶段仅使用有关 SQL 语法结构的固定规则来创建解析树。它不会在系统目录中进行任何查找,因此无法理解所请求操作的详细语义。解析器完成后,“转换过程”将解析器返回的树作为 Importing,并进行语义解释以了解查询所引用的表,函数和运算符。用于表示此信息的数据结构称为查询树

将原始解析与语义分析分开的原因是,系统目录查找只能在事务内完成,并且我们不希望在收到查询字符串后立即开始事务。原始解析阶段足以识别事务控制命令(BEGINROLLBACK等),然后可以正确执行这些命令而无需任何进一步的分析。一旦知道要处理的是实际查询(例如SELECTUPDATE),就可以开始进行事务处理(如果我们还不在其中)。只有这样,才能调用转换过程。

在大多数地方,由转换过程创建的查询树在结构上与原始解析树相似,但是在细节上有许多差异。例如,解析树中的FuncCall节点表示某种在语法上看起来像函数调用的东西。可以将其转换为FuncExprAggref节点,具体取决于所引用的名称是普通函数还是聚合函数。同样,有关列和表达式结果的实际数据类型的信息也添加到查询树中。