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

  整个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 = ;
// ...
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 = {, };
/**
* 字符串词法相关
*/
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_ = ;
bool after_line_terminator = false;
}

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

深入V8引擎-AST(2)的更多相关文章

  1. 深入V8引擎-AST(1)

    没办法了,开坑吧,接下来的几篇会讲述JavaScript字符串源码在v8中转换成AST(抽象语法树)的过程. JS代码在V8的解析只有简单的几步,其中第一步就是将源字符串转换为抽象语法树,非常类似于v ...

  2. 深入V8引擎-AST(3)

    上篇简单介绍了入口方法的流程以及scanner类相关的部分内容,这一篇主要讲scanner的初始化,即 scanner_.Initialize(); 注意,这不是调用静态方法.实际上Parser实例生 ...

  3. 深入V8引擎-AST(6)

    花了5篇才把一个字符串词法给解析完,不知道要多久才能刷完整个流程,GC.复杂数据类型的V8实现那些估计又是几十篇,天呐,真是给自己挖了个大坑. 前面几篇实际上只是执行了scanner.Initiali ...

  4. 深入V8引擎-AST(4)

    (再声明一下,为了简单暴力的讲解AST的转换过程,这里的编译内容以"'Hello' + ' World'"作为案例) 上一篇基本上花了一整篇讲完了scanner的Init方法,接下 ...

  5. 深入V8引擎-AST(5)

    懒得发首页了,有时候因为贴的代码太多会被下,而且这东西本来也只是对自己学习的记录,阅读体验极差,所以就本地自娱自乐的写着吧! 由于是解析字符串,所以在开始之前介绍一下词法结构体中关于管理字符串类的属性 ...

  6. [翻译] V8引擎的解析

    原文:Parsing in V8 explained 本文档介绍了 V8 引擎是如何解析 JavaScript 源代码的,以及我们将改进它的计划. 动机 我们有个解析器和一个更快的预解析器(~2x), ...

  7. 精读《V8 引擎 Lazy Parsing》

    1. 引言 本周精读的文章是 V8 引擎 Lazy Parsing,看看 V8 引擎为了优化性能,做了怎样的尝试吧! 这篇文章介绍的优化技术叫 preparser,是通过跳过不必要函数编译的方式优化性 ...

  8. Javascript的V8引擎研究

    1.针对上下文的Snapshot技术 什么是上下文(Contexts)?实际是JS应用程序的运行环境,避免应用程序的修改相互影响,例如一个页面js修改内置对象方法toString,不应该影响到另外页面 ...

  9. V8引擎——详解

    前言 JavaScript绝对是最火的编程语言之一,一直具有很大的用户群,随着在服务端的使用(NodeJs),更是爆发了极强的生命力.编程语言分为编译型语言和解释型语言两类,编译型语言在执行之前要先进 ...

随机推荐

  1. python 和为S的两个数字

    输入一个递增排序的数组和一个数字S,在数组中查找两个数,是的他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的. 运用到的知识; 1.判断是否是统一类型: if not isinsta ...

  2. 从零开始学习 asp.net core 2.1 web api 后端api基础框架(二)-创建项目

    原文:从零开始学习 asp.net core 2.1 web api 后端api基础框架(二)-创建项目 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.ne ...

  3. Entity相互关系

    查看 1.图表(.edmx) Model First可以2.代码 内部包含对方(回溯) 1:1   1   2 1:N   3   4 N:M   5   6

  4. 如何设置程序UAC控制

    在做项目的过程中,有很多情况会涉及到权限问题,要求必须以管理员的身份才能运行,如何强制我们的程序必须以管理员身份运行呢?在调查的过程中发现有很多方式,此处介绍一种简单的方式. 1.在VS中,右键点击工 ...

  5. https://www.jianshu.com/p/4da29fa310d2

    wampserver显示红色.橙色的解决方案   拿笔的小鑫 关注 2016.10.15 14:38* 字数 2643 阅读 5083评论 0喜欢 3赞赏 1 </br></br&g ...

  6. Expression Blend学习动画基础

    原文:Expression Blend学习动画基础 什么是动画(Animation)? 动画就是时间+换面的组合,画面跟着时间变化.最常见的是flash的动画,还有GIF动态图片. 动画的主要元素 时 ...

  7. 图像滤镜艺术---Oilpaint油画滤镜

    原文:图像滤镜艺术---Oilpaint油画滤镜  Oilpaint油画滤镜     图像油画效果实际上是将图像边缘产生一种朦胧,雾化的效果,同时,将一定的边缘模糊化,这样图像整体上看去像素与像素之间 ...

  8. Win8Metro(C#)数字图像处理--2.11图像锐化

    原文:Win8Metro(C#)数字图像处理--2.11图像锐化  [函数名称] 图像锐化函数SharpeningProcess(WriteableBitmap src,double sharpe ...

  9. apache本地服务器的配置流程

    安装Apache 一.目的: 1. 能够有一个测试的服务器,不是所有的特殊网络服务都能找到免费的! 二.为什么是 "Apache" 1. 使用最广的 Web 服务器 2. Mac自 ...

  10. mysql 配置 explicit_defaults_for_timestamp

    在之前的配置中,除了目录之外,唯独添加了这一项配置,为什么? 因为mysql中timestamp类型和其他的类型不一样: 在之前先了解一下current timestamp和on update cur ...