(再声明一下,为了简单暴力的讲解AST的转换过程,这里的编译内容以"'Hello' + ' World'"作为案例)

上一篇基本上花了一整篇讲完了scanner的Init方法,接下来就是Scan了,Init的方法基本上都是在Stream类下操作,但是本节回到了scanner层级。

/**
* Scan
* 仅仅只涉及next_指针
*/
void Scanner::Scan() { Scan(next_); }
void Scanner::Scan(TokenDesc* next_desc) {
next_desc->token = ScanSingleToken();
/**
* 设置当前词法的结束位置
*/
next_desc->location.end_pos = source_pos();
}

虽然这里只有简简单单的两步(砍掉了所有的CHECK和DEBUG内容),但这个ScanSingleToken已经够讲了。从字面意思理解,就是对单个词法的解析,源码如下。

/**
* 这个ScanSingleToken方法可TM太长了
*/
V8_INLINE Token::Value Scanner::ScanSingleToken() {
Token::Value token;
do {
/**
* 设置当前词法的起始位置
*/
next().location.beg_pos = source_pos();
/**
* Ascii码是从0 ~ 127
* 简单的判断一下合法性
*/
if (V8_LIKELY(static_cast<unsigned>(c0_) <= kMaxAscii)) {
/**
* 这是一个mapping数组
* 对所有的Unicode => Ascii做了映射
*/
token = one_char_tokens[c0_];
/**
* 包含非常多的case...先不展开了
* 根据Token类型进行不同的处理
*/
switch (token) {
case Token::LPAREN:
case Token::RPAREN:
// 其他单符号...
// One character tokens.
return Select(token);
case Token::STRING:
return ScanString(); // 更多...
default:
UNREACHABLE();
}
}
/**
* 处理结束符、空格、异常符号等特殊情况
*/
// ...
} while (token == Token::WHITESPACE); return token;
}

作为一个词法解析方法,长度其实还是可以接受的,已经删掉了大部分的case判断,由于本系列专注于"'Hello' + ' World'"的编译,所以留下了STRING类型。

讲两个点,第一个是那个source_pos,位置的属性和方法是真的多,比较简单,看看就行了。

/**
* 上一篇解析了第一个字符 所以pos移动到了1
* 然而记录location需要从头开始 所以这里做了一个偏移
*/
static const int kCharacterLookaheadBufferSize = ;
int source_pos() {
return static_cast<int>(source_->pos()) - kCharacterLookaheadBufferSize;
}

然后那个mapping数组可以稍微给一下出处,源码如下。

/**
* 总结起来就是GetOneCharToken(0),GetOneCharToken(1),...,GetOneCharToken(127)全部调用一遍
* 其中IsDecimalDigit负责判断是否是数字
* 而IsAsciiIdentifier负责判断是否是标识符,例如$、_、a-z等等
* 最后生成的one_char_tokens数组下标代表Unicode编码 值代表对应的Token类型
*/ #define INT_0_TO_127_LIST(V) \
V() V() V() V() V() V() V() V() V() V() \
// ...
V() V() V() V() V() V() V() V() static const constexpr Token::Value one_char_tokens[] = {
#define CALL_GET_SCAN_FLAGS(N) GetOneCharToken(N),
INT_0_TO_127_LIST(CALL_GET_SCAN_FLAGS)
#undef CALL_GET_SCAN_FLAGS
}; constexpr Token::Value GetOneCharToken(char c) {
// clang-format off
return
c == '(' ? Token::LPAREN :
c == ')' ? Token::RPAREN :
// 其余字符...
IsDecimalDigit(c) ? Token::NUMBER :
IsAsciiIdentifier(c) ? Token::IDENTIFIER :
Token::ILLEGAL;
}

之前说过,c0_代表的是当前解析字符的Unicode编码,于是这里直接通过数组索引查找其对应的类型,按照例子中,我们的字符是一个单引号,而单引号的类型如下。

/**
* 单双引号均会被识别为字符串标记
* 而es6的模板字符串比较特殊 暂时不搞他
*/
c == '"' ? Token::STRING :
c == '\'' ? Token::STRING :
c == '`' ? Token::TEMPLATE_SPAN :

所以,当前token被赋值为Token::STRING,因此,case分支进入ScanString的方法。这个方法内容比较多,下一篇讲吧,午休时间。

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

  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(2)

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

  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. C# WPF 一直保持多个Topmost窗体的置顶顺序

    原文:C# WPF 一直保持多个Topmost窗体的置顶顺序 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/m0_37862405/article/ ...

  2. ASP.NET Core 登录登出 - ASP.NET Core 基础教程 - 简单教程,简单编程

    原文:ASP.NET Core 登录登出 - ASP.NET Core 基础教程 - 简单教程,简单编程 ASP.NET Core 登录登出 上一章节我们总算完善了注册的功能,而且也添加了一个用户,现 ...

  3. 努比亚Z7 mini刷机教程_recovery卡刷机教程

    之前小编分享努比亚Z7 mini电话访问Root权限.recovery刷机教程. 所以对于朋友谁搞机整机的爱,左边是写第三方手机刷包.那么下面刷的家小编与您分享努比亚Z7 mini刷机教程手机. 一. ...

  4. 如何删除您的注册js图书馆bower私人图书馆

    建立你自己bower 这样的私人图书馆参考http://blog.csdn.net/nsrainbow/article/details/35988611 本文 假设我们想注册自己的创作js私人图书馆图 ...

  5. 在React开发中遇到的问题——数组引用赋值

    在React开发中遇到了一个问题: 需求是在一个选择组件中选择数据mydata数组,确定后将mydata数组返回到父组件,再次打开该选择组件时,从父组件获取之前选择的数据mydata并显示为已选择. ...

  6. [WPF]获取鼠标指针下的元素

    原文:[WPF]获取鼠标指针下的元素   [WPF]获取鼠标指针下的元素 周银辉 以前写过一些GetElementUnderMouse之类的函数,要用到坐标换算而显得有些麻烦(特别是当元素有XXXTr ...

  7. EntityFrameworkCore 一对一 && 一对多 && 多对多配置

    基本数据结构 表设计如下: 入学记录 public class AdmissionRecord { [Key] public long Id { get; set; } public DateTime ...

  8. jquery多条件选择器

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...

  9. 浅谈.NET(C#)与Windows用户账户信息的获取

    原文:浅谈.NET(C#)与Windows用户账户信息的获取 目录 1. 用户账户名称 - 使用Environment类 2. 用户账户信息 - 使用WindowsIdentity和IdentityR ...

  10. Android零基础入门第37节:初识ListView

    原文:Android零基础入门第37节:初识ListView 之前我们学习的一些UI组件都比较简单,但是在实际开发中,会经常遇见列表界面设计,如通讯录.电话列表.信息列表等.那么从本节开始来详细学习列 ...