深入V8引擎-AST(4)

淡淡的烟草味﹌ 2021-11-27 03:50 483阅读 0赞

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

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

  1. /**
  2. * Scan
  3. * 仅仅只涉及next_指针
  4. */
  5. void Scanner::Scan() { Scan(next_); }
  6. void Scanner::Scan(TokenDesc* next_desc) {
  7. next_desc->token = ScanSingleToken();
  8. /**
  9. * 设置当前词法的结束位置
  10. */
  11. next_desc->location.end_pos = source_pos();
  12. }

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

  1. /**
  2. * 这个ScanSingleToken方法可TM太长了
  3. */
  4. V8_INLINE Token::Value Scanner::ScanSingleToken() {
  5. Token::Value token;
  6. do {
  7. /**
  8. * 设置当前词法的起始位置
  9. */
  10. next().location.beg_pos = source_pos();
  11. /**
  12. * Ascii码是从0 ~ 127
  13. * 简单的判断一下合法性
  14. */
  15. if (V8_LIKELY(static_cast<unsigned>(c0_) <= kMaxAscii)) {
  16. /**
  17. * 这是一个mapping数组
  18. * 对所有的Unicode => Ascii做了映射
  19. */
  20. token = one_char_tokens[c0_];
  21. /**
  22. * 包含非常多的case...先不展开了
  23. * 根据Token类型进行不同的处理
  24. */
  25. switch (token) {
  26. case Token::LPAREN:
  27. case Token::RPAREN:
  28. // 其他单符号...
  29. // One character tokens.
  30. return Select(token);
  31. case Token::STRING:
  32. return ScanString();
  33. // 更多...
  34. default:
  35. UNREACHABLE();
  36. }
  37. }
  38. /**
  39. * 处理结束符、空格、异常符号等特殊情况
  40. */
  41. // ...
  42. } while (token == Token::WHITESPACE);
  43. return token;
  44. }

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

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

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

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

  1. /**
  2. * 总结起来就是GetOneCharToken(0),GetOneCharToken(1),...,GetOneCharToken(127)全部调用一遍
  3. * 其中IsDecimalDigit负责判断是否是数字
  4. * 而IsAsciiIdentifier负责判断是否是标识符,例如$、_、a-z等等
  5. * 最后生成的one_char_tokens数组下标代表Unicode编码 值代表对应的Token类型
  6. */
  7. #define INT_0_TO_127_LIST(V) \
  8. V(0) V(1) V(2) V(3) V(4) V(5) V(6) V(7) V(8) V(9) \
  9. // ...
  10. V(120) V(121) V(122) V(123) V(124) V(125) V(126) V(127)
  11. static const constexpr Token::Value one_char_tokens[128] = {
  12. #define CALL_GET_SCAN_FLAGS(N) GetOneCharToken(N),
  13. INT_0_TO_127_LIST(CALL_GET_SCAN_FLAGS)
  14. #undef CALL_GET_SCAN_FLAGS
  15. };
  16. constexpr Token::Value GetOneCharToken(char c) {
  17. // clang-format off
  18. return
  19. c == '(' ? Token::LPAREN :
  20. c == ')' ? Token::RPAREN :
  21. // 其余字符...
  22. IsDecimalDigit(c) ? Token::NUMBER :
  23. IsAsciiIdentifier(c) ? Token::IDENTIFIER :
  24. Token::ILLEGAL;
  25. }

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

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

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

转载于:https://www.cnblogs.com/QH-Jimmy/p/11131749.html

发表评论

表情:
评论列表 (有 0 条评论,483人围观)

还没有评论,来说两句吧...

相关阅读

    相关 谷歌v8引擎详解

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

    相关 深入V8引擎-AST(1)

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

    相关 深入V8引擎-AST(5)

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

    相关 v8引擎详解

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