深刻V8引擎-AST(6)

花了5篇才把一個字符串詞法給解析完,不知道要多久才能刷完整個流程,GC、複雜數據類型的V8實現那些估計又是幾十篇,天吶,真是給本身挖了個大坑。segmentfault

前面幾篇實際上只是執行了scanner.Initialize方法,並未開始全面解析,繼續跑流程。app

FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) {
  // ...
  /**
   * 前面完成了這一步
   */
  scanner_.Initialize();
  if (FLAG_harmony_hashbang) {
    scanner_.SkipHashBang();
  }
  // 接下來進這個方法
  FunctionLiteral* result = DoParseProgram(isolate, info);
  // ...
  return result;
}

後面的方法域都在Parser類下,畢竟這是整個AST的執行類,parseInfo只是一個編譯信息的存儲類,直接進DoParseProgram方法。函數

FunctionLiteral* Parser::DoParseProgram(Isolate* isolate, ParseInfo* info) {
  // ...
  FunctionLiteral* result = nullptr;
  {
    // ...
    ScopedPtrList<Statement> body(pointer_buffer());
    int beg_pos = scanner()->location().beg_pos;
    if (parsing_module_) {
      // ...
    } else if (info->is_wrapped_as_function()) {
      ParseWrapped(isolate, info, &body, scope, zone());
    } else {
      // 進入這裏
      this->scope()->SetLanguageMode(info->language_mode());
      ParseStatementList(&body, Token::EOS);
    }
    // ...
  }
  // ...
  return result;
}

這裏對編譯描述類進行查詢,判斷待編譯字符串是不是模塊、包裝函數,會進入不一樣的分支,因爲測試代碼只是兩個字符串相加,因此進入最後的分支。測試

void ParserBase<Impl>::ParseStatementList(StatementListT* body, Token::Value end_token) {
  // ...

  /**
   * 當以前初始化的第一個Token是字符串時
   * 判斷多是設置模式
   */
  while (peek() == Token::STRING) {
    bool use_strict = false;
    bool use_asm = false;

    Scanner::Location token_loc = scanner()->peek_location();
    /**
     * 作字符串嚴格斷定
     * 聲明相似於"use  strict"、"use \nstrict"、"use \x73trict"都是不合法的
     */
    if (scanner()->NextLiteralExactlyEquals("use strict")) {
      use_strict = true;
    } else if (scanner()->NextLiteralExactlyEquals("use asm")) {
      use_asm = true;
    }
    
    // 這裏提早進行解析
    StatementT stat = ParseStatementListItem();
    // ...

    if (use_strict) {
      // 進入嚴格模式
    } else if (use_asm) {
      // 進入asm模式
    } else {
      // 非配置字符串 進入普通模式
      RaiseLanguageMode(LanguageMode::kSloppy);
    }
  }

  TargetScopeT target_scope(this);
  /**
   * 其餘狀況全面解析AST
   */
  while (peek() != end_token) {
    StatementT stat = ParseStatementListItem();
    if (impl()->IsNull(stat)) return;
    if (stat->IsEmptyStatement()) continue;
    body->Add(stat);
  }
}

這一步v8對以前解析的第一個詞法進行了判斷,來選擇是否開啓嚴格模式或者asm模式,能夠看一眼嚴格模式定義。ui

To invoke strict mode for an entire script, put the exact statement "use strict"; (or 'use strict';) before any other statements.this

因爲這個語句必須出如今最前面,因此會在進行全面轉換前判斷待編譯字符串的第一個Token是否是嚴格等於這個字符串,來設置編譯模式。spa

這裏還有另一個新鮮的配置,即"use asm",大部分人不會接觸到這個東西,asm是JavaScript的一個子集,雖然語法總的來講也是JS的,可是很是難閱讀,對於機器來講更加友好。若是用了這個配置,v8會跳過一些階段,直接將代碼編譯成機器指令(貼一個介紹連接)。指針

若是不配置模式,v8會以普通模式來編譯代碼,隨後底部的while循環指向了全面的AST轉換。code

先簡單介紹一下AST的容器body,初始化代碼以下。blog

/**
 * 構造函數參數是一個指針 指向一個內容爲任意指針的vector
 * std::vector<void*>* pointer_buffer() { return &pointer_buffer_; }
 * std::vector<void*> pointer_buffer_;
 * ScopedPtrList<Statement>的簡寫類型爲StatementListT 定義以下
 * using StatementListT = typename Types::StatementList;
 * using Types = ParserTypes<Impl>;
 * struct ParserTypes<Parser> { using StatementList = ScopedPtrList<v8::internal::Statement>; }
 */
ScopedPtrList<Statement> body(pointer_buffer());

這裏的類型包含兩部分,一個是容器類ScopePtrList,一個是內容Statement,先看容器。

template <typename T>
class ScopedPtrList final {
  public:
    void Add(T* value) {
      buffer_.push_back(value);
      ++end_;
    }
  private:
    std::vector<void*>& buffer_;
    size_t start_;
    size_t end_;
}

象徵性的給一些屬性和方法,傳統的vector一把梭,知道一個Add方法就差很少了,反正都那樣。

至於Statement類則是標準的抽象語法樹節點類,簡單看一下定義就好了,其自己沒有什麼東西,大量的枚舉類型都定義在父類上,暫時不展開。

class Statement : public AstNode {
 protected:
  Statement(int position, NodeType type) : AstNode(position, type) {}

  static const uint8_t kNextBitFieldIndex = AstNode::kNextBitFieldIndex;
};

轉換的AST會以Statement類存儲,並經過Add方法加到容器中。

這一篇感受啥都沒寫,先這樣吧,下一篇開始正式全面解析AST。

相關文章
相關標籤/搜索