2021SC@SDUSC
目录
ASTNodeOrgin类
上一篇博客中,我们分析到,ASTNode类对象的成员数据中可能包含一个ASTOrigin对象,根据项目源代码中ASTNode中与ASTOrigin有关的注释,可以知道这个类可能是用来指明ASTNode所源自的对象。
下面来分析一下这个类
public class ASTNodeOrigin {
private final String objectType;
private final String objectName;
private final String objectDefinition;
private final String usageAlias;
private final ASTNode usageNode;
public ASTNodeOrigin(String objectType, String objectName,
String objectDefinition, String usageAlias, ASTNode usageNode) {
this.objectType = objectType;
this.objectName = objectName;
this.objectDefinition = objectDefinition;
this.usageAlias = usageAlias;
this.usageNode = usageNode;
}
public String getObjectType() {
return objectType;
}
public String getObjectName() {
return objectName;
}
public String getObjectDefinition() {
return objectDefinition;
}
public String getUsageAlias() {
return usageAlias;
}
public ASTNode getUsageNode() {
return usageNode;
}
}
// End ASTNodeOrigin.java
可以看到,这个类的结构很简单,主要是成员数据的定义和一些简单的函数,从上到下五个函数的主要功能是:
getObjectType() | 返回一个ASTNode产生的对象的类型,例如 视图。 |
getObjectName() | 返回产生ASTNode的对象的名称,例如“v” |
getObjectDefinition() | 返回一个ASTNode产生的对象的定义。 |
getUsageAlias() | 返回产生ASTNode的对象的别名,例如“v1” (这可以帮助调试上下文相关的扩展) |
getUsageNode() | 返回触发对象使用的表达式节点 例如:v as v1(这可以帮助调试上下文相关的扩展) |
这里,不免产生一些疑惑,ASTNode的来源是ASTNodeOrigin的,但ASTNodeOrigin并不是ASTNode的父类,这里,ASTNodeOrigin和ASTNode在工作中是什么样的一种关系呢?
其官方介绍中的介绍给到我很大的理解上的帮助。
/**
* ASTNodeOrigin contains contextual information about the object from whose
* definition a particular ASTNode originated. For example, suppose a view v is
* defined as <code>select x+1 as y from t</code>, and we're processing a query
* <code>select v1.y from v as v1</code>, and there's a type-checking problem
* with the expression <code>x+1</code> due to an ALTER TABLE on t subsequent to
* the creation of v. Then, when reporting the error, we want to provide the
* parser location with respect to the definition of v (rather than with respect
* to the top-level query, since that represents a completely different
* "parser coordinate system").
*
*<p>
*
* So, when expanding the definition of v while analyzing the top-level query,
* we tag each ASTNode with a reference to an ASTNodeOrign describing v and its
* usage within the query.
上面这段话大概意思如下
ASTNode可能包含一个ASTNodeOrigin对象,后者包含了该ASTNode来源(由于哪个对象/表的定义,才导致这个ASTNode的出现)信息。
就例如,假设有一个视图v被这样定义:
select x+1 as y from t
在视图定义之后,又通过如下命令
alter table
修改了表t,使得x的类型不再是数值。那么之后,当我们需要处理了如下的命令时:
select v1.y from v as v1
在处理这个query的时候,会进行视图的“展开,然后会发生类型检查错误:比如,x+1”这个表达式类型不合法。我们必须报告错误。问题就在于,我们报告错误时,希望报告视图v定义的地方,而不是发生这个query的地方。因此,在分析query的过程中,对视图v进行展开的时候,我们会为每个展开的ASTNode对象设置一个ASTNodeOrigin对象,这个ASTNodeOrigin对象描述视图v及它在展开它的query中的使用。
综合前文所述,结合分析可知,ASTNodeOrigin主要对ASTNode起到一个辅助作用,ASTNode对象表示一个AST节点。它是对CommonTree的一个简单封装,提供追踪ASTNodeOrigin的功能、并实现Node和Serializable接口。
回顾补充
在了解了AST基本结构和作用后,我又回过头,捋了一遍整个流程。
前面的语法分析、词法分析中, Hive.g文件中定义了一些逻辑Token(即所谓的imaginary token)。这些token都以TOK_开头。这些token一般作为AST中的节点出现,用于表示以这个节点为根节点的子树的逻辑语义。
例如:
•^(TOK_SELECT hintClause? SelectList)
表示一棵Select子树(语义),它的根是TOK_SELECT,它的两个分支分别是hintClause和selectList产生的子树。
•^(TOK_SELECT ^(TOK_SELEXPR trfmClause))
也是一棵Select子树(语义),它的根同样也是TOK_SELECT,它只有一个分支,就是以TOK_SELEXPR为根的select表达式子树。
另外,Hive.g中为HiveParser定义了一个Stack msgs成员,这个成员主要用处是报告错误。在每条parser规则应用之前向msgs中压栈这条规则的名字,在应用之后msgs弹栈。这样,在出现错误的时候,栈顶就是正在被应用的parser规则,栈中则包含了parser规则应用的完整路径。
之后,在生成了HiveLexer和HiveParser类之后,ParseDriver负责组织、驱动整个词法、语法分析流程,并得到分析后的AST。
其中,在使用生成的Parser的时候,会给它设置该适配器对象。Parser每当需要使用某个token创建一个AST节点的时候,会调用该对象的create(token)进行创建。这里,适配器对象会创建一个ASTNode并返回。
这样,整个语法分析、词法分析、AST的生成,我们就有了一个整体的了解