v8中的visitor模式

在設計模式中,有一種visitor模式,它給出了一種在編譯器構造時使用的經典模式,如下圖所示:
語法樹的節點存在不同的類型,在不同的編譯階段對這些節點的操作是不同的,爲了避免操作與數據的耦合,產生了visitor模式,如下圖所示:

實際上,基於以下的矩形空間考慮,可以理解的更加清楚
  AssignmentNode VariableNode
TypeChecking
TypeChecking-AssignmentNode
TypeChecking-VariableNode
CodeGenerate
CodeGenerate-AssignmentNode
CodeGenerate-VariableNode

這裏有兩方面內容,在同一個編譯階段,針對不同的Node,操作是不同的;在不同的編譯階段,針對同一個Node,操作也是不同的,visitor模式就是用來處理這種耦合的。
首先,不同的visitor就區分了不同的編譯階段的操作,把同一個階段,針對所有節點的操作聚合到一起,在遍歷節點的時候,調用Node提供的虛函數Accept,同時把自己作爲參數傳遞給Accept,由於虛函數的特性,實現了不同Node節點操作的區分。由於此時節點的類型已經可以確定,所以節點的Accept操作又把操作委託給參數visitor的相應類型的操作。

下面我們來看看v8是如何實現這種模式的,在v8中AstVisitor是Visitor模式的基類,以v8::internal::Processor和v8::internal::FullCodeGenerator爲例

ProcessorAstVisitor繼承,它在rewriter中調用,負責遍歷list中的statement,並改寫它們

void Processor::Process(ZoneList<Statement*>* statements) {

  for (int i = statements->length() - 1; i >= 0; --i) {

    Visit(statements->at(i));

  }

}

我們來看Visit函數的實現,它本身是AstVisitor類的虛函數,其定義如下:

virtual void Visit(AstNode* node) {                               \

    if (!CheckStackOverflow()) node->Accept(this);                  \

  }

我們看到Processor把功能委託給AstNode來實現,這是我們在區分不同對象不同處理的時候,常用的方法之一,AstNode::Accept是個虛函數,在ast.cc中給出了統一的定義

#define DECL_ACCEPT(type)                                       \

  void type::Accept(AstVisitor* v) { v->Visit##type(this); }

AST_NODE_LIST(DECL_ACCEPT)

#undef DECL_ACCEPT

這裏是visitor模式的關鍵,v8通過宏定義的形式定義了AstNode一系列繼承類的Accept虛函數,注意它的實現,v->Visit##type(this); ,即調用了visitor的相應的Visit##type函數,這裏採用了一種編譯期的類型區分,它不同於虛函數,虛函數是運行期的類型區分,具體到Processor而言,就是調用了Processor的對應的Visit##type函數,在Processor類中,我們看到很多形如這樣的函數,對於AstNodeExpressionStatement而言,對應的函數如下:

void Processor::VisitExpressionStatement(ExpressionStatement* node) {

  // Rewrite : <x>; -> .result = <x>;

  if (!is_set_ && !node->expression()->IsThrow()) {

    node->set_expression(SetResult(node->expression()));

    if (!in_try_) is_set_ = true;

  }

}

此時Node中存放着一個Expression,這裏通過改寫把它變成一個賦值表達式,如註釋所言,

Rewrite : <x>; -> .result = <x>;

同樣的,FullCodeGenerator類也是從AstVisitor繼承的,它也定義了很多的visit##type函數,用於生成Code



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章