编译原理笔记-源码学习-序篇

401 阅读2分钟

Acorn

A tiny, fast JavaScript parser, written completely in JavaScript.

babel的解析器也是基于acorn进行开发出来的一个解析器, 与babel不同的是, acorn使用的是js开发, 并且它不支持解析ts/tsx等. 所以它缺失的部分为--类型推导, 类型分析.

但对于编译原理学习-词法分析/语法分析来说, 使用acorn进行学习是足够了的. 由于够小, 没有冗余的代码, 所以可以更清晰的看出作者的实现思路, 和编译原理的运行.

首先是acorn代码结构

src
  -bin
     --acorn.js acorn的入口函数, 负责导出执行
  -generated
     --xxx.js 使用代码生成的一些变量内容.
  expression.js 表达式解析
  identifier.js 变量类型解析
  index.js 
  location.js 定义使用position的函数
  locutil.js  定义position, 用于解析时显示未知
  lval.js 可执行表达式的解析.
  node.js  解析出来的astNode定义
  options.js 负责配置, 可以忽略
  parseutil.js
  regexp.js 正则表达式的解析
  scope.js 作用域方法
  scopeflags.js 作用域类型定义
  state.js parser的定义位置
  statement.js 解析声明类型的代码位置
  tokencontext.js 执行token的时候的上下文配置项
  tokenize.js 词法分析所在的代码位置
  tokentype.js 定义tokentype接口类型, 并且生成tokentype列表, 定义nodeType
  unicode-property-data.js unicode的判断配置项
  util.js 常用函数如hasOwn
  whitespace.js 顾名思义, 用于判断空格与换行符

通用模块

whitespace.js

顾名思义, 这个文件用于判断空格, 比如说

export function isNewLine(code) {
  return code === 10 || code === 13 || code === 0x2028 || code === 0x2029
}

util.js

通用函数的放置

/**
 * 将unicode表示的字符串转成字符串
 * @param {number} code
 * @returns {string}
 * */
export function codePointToString(code) {
  // UTF-16 Decoding
  if (code <= 0xFFFF) return String.fromCharCode(code)
  code -= 0x10000
  return String.fromCharCode((code >> 10) + 0xD800, (code & 1023) + 0xDC00)
}

locutil.js

定义position, 标识当前解析的位置

/** 标识第几行第几列 */
export class Position {
  /**
   * @param {number} line 
   * @param {number} col 
   */
  constructor(line, col) {
    this.line = line
    this.column = col
  }

  offset(n) {
    return new Position(this.line, this.column + n)
  }
}

scope.js

作用域的定义

class Scope {
  constructor(flags) {
    this.flags = flags // 用于判断当前作用域类型
    // A list of var-declared names in the current lexical scope
    this.var = []
    // A list of lexically-declared names in the current lexical scope
    this.lexical = []
    // A list of lexically-declared FunctionDeclaration names in the current lexical scope
    this.functions = []
    // A switch to disallow the identifier reference 'arguments'
    this.inClassFieldInit = false
  }
}