🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 46.3\. 分析器阶段 _分析器阶段_含两个部分: * 在`gram.y`和`scan.l`里定义的_分析器_ 是使用 Unix 工具bison和flex创建的。 * _转换处理_对分析器返回的数据结构进行修改和增补。 ## 46.3.1\. 分析器 分析器必须检查(以纯 ASCII 文本方式到来的)查询字符串的语法。如果语法正确, 则创建一个_分析树_并将之传回,否则,返回一个错误。 实现分析器和词法器使用了著名的 Unix 工具bison和flex。 _词法器_在文件`scan.l`里定义, 负责识别_标识符_和 _SQL 关键字_等。 对于发现的每个关键字或者标识符都会生成一个_记号_并且传递给分析器。 分析器在文件`gram.y`里定义并且包含一套_语法规则_ 和触发规则时执行的_动作_。动作代码(实际上是 C 代码)用于建立分析树。 文件`scan.l`用flex转换成 C 源文件 `scan.c`,而`gram.y`用bison 转换成`gram.c`。在完成这些转换后,一个通用的 C 编译器就可以用于创建分析器。 千万不要对生成的 C 源文件做修改,因为下一次调用flex 或bison时会把它们覆盖。 > **Note:** 上面提到的转换和编译是使用跟随PostgreSQL发布的 _makefiles_自动完成的。 对bison或者`gram.y` 里的语法规则的详细描述超出本文的范围。有很多关于flex 和bison的书籍和文档。你在开始研究`gram.y` 里给出的语法之前应该对bison很熟悉,否则你是看不懂那里面的内容, 理解不了发生了什么事情的。 ## 46.3.2\. 转换处理 分析器阶段只使用和 SQL 语法结构相关的固定规则创建一个分析树。它不会查找任何系统表, 因此就不可能理解请求查询里面的详细的语意。在分析器技术之后, _转换处理_接受分析器传过来的分析树然后做进一步处理,解析哪些查询中引用了哪个表、 哪个函数、哪个操作符的语意。所生成的表示这个信息的数据结构叫做_查询树_。 把裸分析和语意分析分成两个过程的原因是系统表查找只能在一个事务中进行, 而不想在一接收到查询字符串就发起一个事务。裸分析阶段已经足够可以标识事务控制命令( `BEGIN`,`ROLLBACK`等),并且这些东西不用任何进一步的分析就可以执行。 一旦知道正在处理一个真正的查询(比如`SELECT`或`UPDATE`), 就可以发起一个事务了(如果还没开始这么一个)。只有这个时候可以调用转换处理。 转换处理生成的查询树结构上在很大程度上类似于裸分析树,但是在细节上有很多区别。 比如,在分析树里的`FuncCall`节点代表那些看上去像函数调用的东西。 根据引用的名字是一个普通函数还是一个聚集函数,这个可能被转换成一个`FuncExpr` 或`Aggref`节点。同样,有关字段和表达式结果的具体数据类型也添加到查询树中。