zoukankan      html  css  js  c++  java
  • 深入V8引擎-AST(2)

      先声明一下,这种长系列的大块头博客只能保证尽可能的深入到每一行源码,有些代码我不乐意深究就写个注释说明一下作用。另外,由于本地整理的比较好,博客就随心写了。

      整个Compile过程目前只看到asmjs之前,简单的过了几遍,大部分方法没有点进去看,实在是太复杂了。上一篇的结尾指出了AST的入口,也就是命名空间parsing的一个公共方法,如下。

    bool ParseProgram(ParseInfo* info, Isolate* isolate) {
      // ...
      /**
       * 生成一个Parser实例
       * 调用内部方法启动转换
       */
      Parser parser(info);
      FunctionLiteral* result = nullptr;
      /**
       * 转换AST后将结果赋值给ParseInfo的literal_
       */
      result = parser.ParseProgram(isolate, info);
      info->set_literal(result);
      // ...
      return (result != nullptr);
    }

      所需要关心的核心代码就是这些,非常简单,Parser对象的初始化属性非常多,这里就不列出来了。

      接下来进入第二个核心方法,即ParseProgram。

    FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) {
      // ...
      /**
       * scanner_为Parser类的一个私有属性
       * 这里仅仅进行初始化
       */
      scanner_.Initialize();
      FunctionLiteral* result = DoParseProgram(isolate, info);
    
      // ...
      return result;
    }

      同样,所需要关心代码只有两行,其中第一步则是启动了scanner的初始化,第二步则是开始全面解析。

      Scanner包含scanner、scanner-character-strams两个部分,其中stream则是经过初步处理的源String,必须转换后才能进行解析。处理的过程在之前省略的代码中,这里稍微给出大概的转换流程。

    bool ParseProgram(ParseInfo* info, Isolate* isolate) {
      // ...
      /**
       * 1、info->script()返回的是字符串的描述信息 source是Local<String>类型的源字符串
       * 2、ScannerStream是scanner-character-streams头文件的类 内部方法均为静态类型 可以直接调用
       * 3、返回的具体类型根据String类型不同而不同 但是由于均继承于Utf16CharacterStream 所以直接用父类接
       */
      Handle<String> source(String::cast(info->script()->source()), isolate);
      std::unique_ptr<Utf16CharacterStream> stream(ScannerStream::For(isolate, source));
      info->set_character_stream(std::move(stream));
      // ...
    }
    
    /**
     * 有四种特殊的String类型 分别new不同的子类
     * ScannerStream::For(isolate, data, 0, data->length());
     */
    Utf16CharacterStream* ScannerStream::For(Isolate* isolate, Handle<String> data, int start_pos, int end_pos) {
      size_t start_offset = 0;
      // ...
      if (data->IsSeqOneByteString()) {
        return new BufferedCharacterStream<OnHeapStream>(
            static_cast<size_t>(start_pos), Handle<SeqOneByteString>::cast(data),
            start_offset, static_cast<size_t>(end_pos));
      }
    }

      常规的字符串一般都是OneByteString,这里就不细讲了。最后返回一个特殊Stream类,其属性记录字符串的长度、当前的解析进度、解析的开始与结束标记等等。

      将字符串转换后,就可以利用Scanner来进行逐步解析,在此之前,需要对Scanner类有一个简单的了解,如下。

    /**
     * Scanner类
     * 跟Utf16CharacterStream一个文件
     */
    class V8_EXPORT_PRIVATE Scanner {
      public:
        // 返回next_的token类型
        Token::Value peek() const { return next().token; }
        // 返回current_的位置信息
        const Location& location() const { return current().location; }
      private:
        // 当前字符的Unicode编码 -1表示结尾(typedef int32_t uc32)
        uc32 c0_;
        TokenDesc* current_;    // desc for current token (as returned by Next())
        TokenDesc* next_;       // desc for next token (one token look-ahead)
        TokenDesc* next_next_;  // desc for the token after next (after PeakAhead())
        // 从Handle<String>转换后的类型 负责执行解析的实际类
        Utf16CharacterStream* const source_;
    }

      选取了一些比较简单的属性和方法,Scanner内部有三个游标属性负责遍历字符串,分别是current_、next_、next_next_,字面意思理解就行了。source_则是之前说的转换Stream类,所有的解析实际上都是调用这个属性的方法。而两个结构体TokenDesc、Location也非常重要,一个负责词法描述,一个负责记录词法位置信息,如下。

    /**
     * 词法结构体
     * 每一个TokenDesc代表单独一段词法
     */
    struct TokenDesc {
      /**
       * 词法所在位置
       * 该结构体比较简单 就不展开了 两个值代表起始、结束位置
       * 例如sample中 "'Hello' + ' World'" 'Hello'会被解析为TOKEN::STRING location为{0, 7}
       */
      Location location = {0, 0};
      /**
       * 字符串词法相关
       */
      LiteralBuffer literal_chars;
      LiteralBuffer raw_literal_chars;
      /**
       * 词法的枚举类型
       * 例如 '(' 是 TOKEN::LPAREN '===' 是 TOKEN::EQ_STRICT
       * 所有类型可见token.h
       */
      Token::Value token = Token::UNINITIALIZED;
      MessageTemplate invalid_template_escape_message = MessageTemplate::kNone;
      Location invalid_template_escape_location;
      // 小整数
      uint32_t smi_value_ = 0;
      bool after_line_terminator = false;
    }

      通过这个结构体和一些方法,就能完整的将源字符串逐步转换为抽象语法树。但是实际转换过程非常复杂,分支极多,后面再继续探究。

  • 相关阅读:
    欧拉函数(线性筛)(超好Dong)
    欧拉函数(线性筛)(超好Dong)
    线性素数筛(欧拉筛)(超级好的MuBan)
    线性素数筛(欧拉筛)(超级好的MuBan)
    Fire Game (FZU 2150)(BFS)
    Fire Game (FZU 2150)(BFS)
    Fantasy of a Summation (LightOJ
    Java——接口
    Java——异常处理
    Java——数组
  • 原文地址:https://www.cnblogs.com/QH-Jimmy/p/11115324.html
Copyright © 2011-2022 走看看