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

前面几篇实际上只是执行了scanner.Initialize方法,并未开始全面解析,继续跑流程。

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模式,可以看一眼严格模式定义。

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

由于这个语句必须出现在最前面,所以会在进行全面转换前判断待编译字符串的第一个Token是不是严格等于这个字符串,来设置编译模式。

这里还有另外一个新鲜的配置,即"use asm",大部分人不会接触到这个东西,asm是JavaScript的一个子集,虽然语法总的来说也是JS的,但是非常难阅读,对于机器来说更加友好。如果用了这个配置,v8会跳过一些阶段,直接将代码编译成机器指令(贴一个介绍链接)。

如果不配置模式,v8会以普通模式来编译代码,随后底部的while循环指向了全面的AST转换。

先简单介绍一下AST的容器body,初始化代码如下。

/**
* 构造函数参数是一个指针 指向一个内容为任意指针的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。

最新文章

  1. 在Android中,使用Kotlin的 API请求简易方法
  2. bzoj 2141: 排队
  3. atitit.团队建设总结o6o fix
  4. 【解决方案】HTTP could not register URL http://+:6001/
  5. 【mysql】关于innodb_file_format
  6. cocos基础教程(12)点击交互的三种处理
  7. Spring Data Solr教程(翻译) 开源的搜索服务器
  8. 【转】让apache支持中文路径或者中文文件
  9. 使用WebGL实现一个Viewer来显示STL文件
  10. AVR文章7课时:动态数字化控制
  11. Javascript技巧实例精选(5)—显示当前的日期和时间
  12. Java学习笔记9---类静态成员变量的存储位置及JVM的内存划分
  13. 【LeetCode每天一题】Longest Palindromic Substring(最长回文字串)
  14. maven使用fingbugs插件
  15. OpenCV学习系列(零) Mac下OpenCV + xcode环境搭建
  16. 中国省市 Json 二级联动
  17. jqGrid设置符合条件的行选中
  18. 编写高质量代码改善C#程序的157个建议——建议64:为循环增加Tester-Doer模式而不是将try-catch置于循环内
  19. hibernate反向工程 (eclipse和myeclipse)【转】
  20. 通过SectionIndexer实现微信通讯录

热门文章

  1. 别忘了在使用MES系统之前,还有关键一步!
  2. 电信NBIOT 2 - 数据上行(中间件获取电信消息通知)
  3. 【原创】Airflow调用talend
  4. seafile部署安装
  5. 3-1 Pandas-概述
  6. Grafana中mysql作为数据源的配置方法
  7. Bandit
  8. JDOJ 1790: 高精度A-B
  9. elasticsearch入门及安装
  10. 如何确保redis中都是热数据