从编译原理视角理解JavaScript

1,060 阅读8分钟

关于作者:

雷庭,任职于北京优锘科技,前端架构师,从事前端开发及架构工作17年,擅长可视化领域的前端开发,前端沟通交流可加作者微信ltlt820706

导读:本节只对产生式做扫盲级的科普,适合两类读者:

  • 计算机专业的读者:做一次知识点回顾;
  • 不是计算机专业的读者:对文法产生式有一个大概的了解,便于更深入地理解语法的作用,为后续自我深造打下基础;

为什么要学产生式?这里给出类比:

  • 如果你是一位Vue或者React框架的使用者,你只要学好这2个框架的特性,语法糖就可以写出一个很好的应用,但是这只能做一个在框架约束下的应用开发者;
  • 如果你想把应用写的更优秀(无人能敌),你就得绕到Vue/React的背后去看他们的实现原理,从更高一个层次去学习和了解他,就像一个教中学的老师必须是大学毕业,教本科的老师必须是硕士或者博士一样的道理;

∴同理:产生式是定义一门语言的工具,掌握它你就相当于从顶层去了解JavaScript是怎么定义出来的,未来挑战更有竞争力的技术也变的更有可能。

如果想进一步了解产生式,可以购买专业的《编译原理》书籍

1 语言

如上图所示,

  • 啥玩意->啥玩意;
  • 中午点啥->中午点啥;
  • 呢->咋呢;

上面几句是中文,也是我们日常交流的北方方言,但南方人也能听得懂,所以我们日常使用的语言没有严格的语法定义,高兴和不高兴的时候对同一句话都有不同的表达方式,这类被归纳为“非形式化语言

形式语言 计算机编程语言里大部分语言都是“形式语言”,他有严格的语法定义,书写时必须按照约定进行,否则运行时就可能无法达到预期。 按照[乔姆斯基谱系]对形式语言进行分类

  • 0-型:无限制文法
  • 1-型:上下文相关文法
  • 2-型:上下文无关文法
  • 3-型:正则文法

0123是一种包含关系,例如:3包含前面012

2 语法、语义、文法

  • 语法

描述该语言程序的正确形式,语法是给人类使用者看的;

  • 语义

定义了程序的含义,即程序在运行过程中每个语法特征可以做什么;

  • 文法(上文中提到0123型文法)

用于描述语言语法结构的形式规则,文法是给计算机编译器看的; 文法包含:

JavaScript的LL(1)文法请参考

JavaScript官方语法、词法定义中文翻译版请参考

LL(1):第一个“L”表示从左侧向右扫描输入;第二个“L”表示产生向左推导;“1”表示在每一步中只需向前看一个输入符号来决定语法分析动作。

BNF-巴科斯范式 BNF是一种形式化符号,用来描述给定语言的语法,它是由一个系列的符号集组成的元语言,它不仅能够严格的表示语法规则,而且描述的描述的语法是与上下文无关的。

  • BNF常用元字符及其含义如下:
在双引号中的字 "word" 代表着这些字符本身。而double_quote用来代表双引号;
在双引号外的字(有可能有下划线)代表着语法部分;
尖括号 < > 内包含的为必选项;
方括号 [ ] 内包含的为可选项;
大括号 { } 内包含的为可重复0至无数次的项;
圆括号 ( ) 内包含的所有项为一组,用来控制表达式的优先级;
竖线 | 表示在其左右两边任选一项,相当于"OR"的意思;
::= 是“被定义为”的意思;
...  表示术语符号;
  • BNF表示语法规则的方式
    • 非终结符用尖括号括起来
    • 每条规则的左侧是非终结符,右侧是有非终结符和终结符组成的一串符号,中间用“:==”或者“:=”或者“->”隔开,如下图

  • 具有相同左部的规则公用一个左部,各右部之间用“|”隔开
  • 非终结符:在产生式中能够被再次推导的符号,或者说除了终结符都是非终结符
  • 终结符:在产生式中不能被再次推导的形式化符号,比如for、let、const等关键字

3 产生式

在计算机中源代码经过编译器的词法分析、语法分析后得到的一系列符合文法规则(BNF)的语句叫产生式,BNF是常用的产生式一种,除此之外还有EBNF,ABNF都是在BNF的基础上做了语法扩展,所以一般来说每个语言标准里面,都会自定义一个产生式的书写方式。 JavaScript中也有自己的产生式书写方式,如下:

// JavaScript中function的产生式(ES5版)
Element:
  function Identifier ( ParameterListOpt ) CompoundStatement
  Statement

它的开头是用缩进来表示的,就是相当于产生式左边的非终结符,非终结符之后跟着一个冒号,之后给了两个空格的缩进。然后在 JavaScript 的标准中,它的非终结符,加号、减号是用加粗的黑字体来表示终结符的。

对Javascript语言更深入的了解请点击

文法产生式描述比较简洁的文章请参考

如何利用LL(1)语法分析器生成AST请参考

4 JavaScript ESTree

这一张是上面一篇的部分回顾,ESTree是业界统一遵从的标准,它定义了JavaScript中所有涉及到的语法的表达形式,对语法元素描述进行统一标准的定义,并且ES在不断的升级过程中ESTree也会伴随着进行升级。

要点

  • JavaScript在进行语法分析过程中生成AST;
  • 语法分析是将词法分析得到的Tokens带入到产生式(BNF)中去替换非终结符(替换的规则遵从LL(1));
  • 替换后得到的AST结构就是由ESTree定义的。

横线下面的部分是ESTree数据结构,可以不用仔细看,用到的时候当翻阅参考即可。

Node

Node 对象类似JS里的超类Object,是所有对象的父类,包含与类型及位置相关的信息

interface Node {
    type: string;
    loc: SourceLocation | null;
}

interface SourceLocation {
    source: string | null;
    start: Position;
    end: Position;
}

interface Position {
    line: number; // >= 1
    column: number; // >= 0
}

Identifier

标识符就是指自定义的各种名字,比如变量名、方法名、类名、参数名等。

interface Identifier <: Expression, Pattern {
    type: "Identifier";
    name: string;
}

Literal

字面量,用于描述不同数据类型的值

interface Literal <: Expression {
    type: "Literal";
    value: string | boolean | null | number | RegExp | bigint;
}

interface RegExpLiteral <: Literal {
  regex: {
    pattern: string;
    flags: string;
  };
}

interface BigIntLiteral <: Literal {
  bigint: string;
}

Programs

用于描述模块的类型,通过sourceType来判断是一个导出模块还是整篇script文档

interface Program <: Node {
    type: "Program";
    sourceType: "script" | "module";
    body: [ Statement | ModuleDeclaration ];
}

Functions

用于描述一个函数,其不会直接使用,是FunctionDeclaration的父类

interface Function <: Node {
    id: Identifier | null;
    async: boolean;
    generator: boolean;
    params: [ Pattern ];
    body: FunctionBody;
}

Statements

对语句范畴的定义描述

interface ExpressionStatement <: Statement {
    type: "ExpressionStatement";
    expression: Expression;
}

interface Directive <: Node {
    type: "ExpressionStatement";
    expression: Literal;
    directive: string;
}

interface BlockStatement <: Statement {
    type: "BlockStatement";
    body: [ Statement ];
}

interface FunctionBody <: BlockStatement {
    body: [ Directive | Statement ];
}

interface EmptyStatement <: Statement {
    type: "EmptyStatement";
}

dinterface DebuggerStatement <: Statement {
    type: "DebuggerStatement";
}

interface WithStatement <: Statement {
    type: "WithStatement";
    object: Expression;
    body: Statement;
}

interface ReturnStatement <: Statement {
    type: "ReturnStatement";
    argument: Expression | null;
}

interface LabeledStatement <: Statement {
    type: "LabeledStatement";
    label: Identifier;
    body: Statement;
}

interface BreakStatement <: Statement {
    type: "BreakStatement";
    label: Identifier | null;
}

interface IfStatement <: Statement {
    type: "IfStatement";
    test: Expression;
    consequent: Statement;
    alternate: Statement | null;
}

interface SwitchStatement <: Statement {
    type: "SwitchStatement";
    discriminant: Expression;
    cases: [ SwitchCase ];
}

interface SwitchCase <: Node {
    type: "SwitchCase";
    test: Expression | null;
    consequent: [ Statement ];
}

interface ThrowStatement <: Statement {
    type: "ThrowStatement";
    argument: Expression;
}

interface TryStatement <: Statement {
    type: "TryStatement";
    block: BlockStatement;
    handler: CatchClause | null;
    finalizer: BlockStatement | null;
}

interface CatchClause <: Node {
    type: "CatchClause";
    param: Pattern | null;
    body: BlockStatement;
}

interface WhileStatement <: Statement {
    type: "WhileStatement";
    test: Expression;
    body: Statement;
}

interface DoWhileStatement <: Statement {
    type: "DoWhileStatement";
    body: Statement;
    test: Expression;
}

interface ForStatement <: Statement {
    type: "ForStatement";
    init: VariableDeclaration | Expression | null;
    test: Expression | null;
    update: Expression | null;
    body: Statement;
}

interface ForInStatement <: Statement {
    type: "ForInStatement";
    left: VariableDeclaration |  Pattern;
    right: Expression;
    body: Statement;
}

interface ForOfStatement <: ForInStatement {
    type: "ForOfStatement";
    await: boolean;
}

Declarations

函数和变量的定义

interface FunctionDeclaration <: Function, Declaration {
    type: "FunctionDeclaration";
    id: Identifier;
}

// 变量定义描述,不包含赋值
interface VariableDeclaration <: Declaration {
    kind: "var" | "let" | "const";
    declarations: [ VariableDeclarator ];
}

// 变量本身描述,包含赋值
interface VariableDeclarator <: Node {
    type: "VariableDeclarator";
    id: Pattern;
    init: Expression | null;
}

Expressions

表达式,例如:

  • var a = 1 + 1;这句话后面的1 + 1就是一个表达式(BinaryExpression);
  • const fn = function () { } 绿色部分就是一个函数表达式FunctionExpression
interface Expression <: Node { }

interface SpreadElement <: Node {
    type: "SpreadElement";
    argument: Expression;
}

// this.fn = b中的this.fn是ThisExpression
interface ThisExpression <: Expression {
    type: "ThisExpression";
}

// [1,2,3]是数组表达式
interface ArrayExpression <: Expression {
    type: "ArrayExpression";
    elements: [ Expression | SpreadElement | null ];
}

interface ObjectExpression <: Expression {
    type: "ObjectExpression";
    properties: [ Property | SpreadElement ];
}

interface Property <: Node {
    type: "Property";
    key: Expression;
    value: Expression;
    kind: "init" | "get" | "set";
    method: boolean;
    shorthand: boolean;
    computed: boolean;
}

interface FunctionExpression <: Function, Expression {
    type: "FunctionExpression";
}

interface UnaryExpression <: Expression {
    type: "UnaryExpression";
    operator: UnaryOperator;
    prefix: boolean;
    argument: Expression;
}

enum UnaryOperator {
    "-" | "+" | "!" | "~" | "typeof" | "void" | "delete"
}

interface UpdateExpression <: Expression {
    type: "UpdateExpression";
    operator: UpdateOperator;
    argument: Expression;
    prefix: boolean;
}

enum UpdateOperator {
    "++" | "--"
}

interface BinaryExpression <: Expression {
    type: "BinaryExpression";
    operator: BinaryOperator;
    left: Expression;
    right: Expression;
}

enum BinaryOperator {
    "==" | "!=" | "===" | "!=="
         | "<" | "<=" | ">" | ">="
         | "<<" | ">>" | ">>>"
         | "+" | "-" | "*" | "**" | "/" | "%"
         | "|" | "^" | "&" | "in"
         | "instanceof"
}

interface AssignmentExpression <: Expression {
    type: "AssignmentExpression";
    operator: AssignmentOperator;
    left: Pattern | Expression;
    right: Expression;
}

enum AssignmentOperator {
    "=" | "+=" | "-=" | "*=" | "**=" | "/=" | "%="
        | "<<=" | ">>=" | ">>>="
        | "|=" | "^=" | "&="
        | "||=" | "&&=" | "??="
}

interface LogicalExpression <: Expression {
    type: "LogicalExpression";
    operator: LogicalOperator;
    left: Expression;
    right: Expression;
}

enum LogicalOperator {
    "||" | "&&" | "??"
}

interface MemberExpression <: Expression, Pattern, ChainElement {
    type: "MemberExpression";
    object: Expression | Super;
    property: Expression;
    computed: boolean;
}

interface ConditionalExpression <: Expression {
    type: "ConditionalExpression";
    test: Expression;
    alternate: Expression;
    consequent: Expression;
}

interface CallExpression <: Expression, ChainElement {
    type: "CallExpression";
    callee: Expression | Super;
    arguments: [ Expression | SpreadElement ];
}

interface NewExpression <: Expression {
    type: "NewExpression";
    callee: Expression;
    arguments: [ Expression | SpreadElement ];
}

interface SequenceExpression <: Expression {
    type: "SequenceExpression";
    expressions: [ Expression ];
}

interface ArrowFunctionExpression <: Function, Expression {
    type: "ArrowFunctionExpression";
    body: FunctionBody | Expression;
    expression: boolean;
}

interface YieldExpression <: Expression {
    type: "YieldExpression";
    argument: Expression | null;
    delegate: boolean;
}

interface AwaitExpression <: Expression {
    type: "AwaitExpression";
    argument: Expression;
}

interface ChainExpression <: Expression {
  type: "ChainExpression"
  expression: ChainElement
}

interface ChainElement <: Node {
  optional: boolean
}

interface ImportExpression <: Expression {
  type: "ImportExpression";
  source: Expression;
}

Patterns

注意 Identifier 也属于Pattern的子类

interface Pattern <: Node { }

interface AssignmentProperty <: Property {
    type: "Property"; // inherited
    value: Pattern;
    kind: "init";
    method: false;
}

interface ObjectPattern <: Pattern {
    type: "ObjectPattern";
    properties: [ AssignmentProperty, RestElement];
}
// let {a, b} = c 左侧花括号中是ObjectPattern

interface ArrayPattern <: Pattern {
    type: "ArrayPattern";
    elements: [ Pattern | null ];
}
// let [a, ...c] = b; 左侧中括号是ArrayPattern

interface RestElement <: Pattern {
    type: "RestElement";
    argument: Pattern;
}
// funtion foo(a, ...c){} 中...c是RestElement

interface AssignmentPattern <: Pattern {
    type: "AssignmentPattern";
    left: Pattern;
    right: Expression;
}
// function foo(a = 1, b){} 中a=1是AssignmentPattern

Template Literals

interface TemplateLiteral <: Expression {
    type: "TemplateLiteral";
    quasis: [ TemplateElement ];
    expressions: [ Expression ];
}

interface TaggedTemplateExpression <: Expression {
    type: "TaggedTemplateExpression";
    tag: Expression;
    quasi: TemplateLiteral;
}

interface TemplateElement <: Node {
    type: "TemplateElement";
    tail: boolean;
    value: {
        cooked: string | null;
        raw: string;
    };
}

Classes

interface Super <: Node {
    type: "Super";
}

interface Class <: Node {
    id: Identifier | null;
    superClass: Expression | null;
    body: ClassBody;
}

interface ClassBody <: Node {
    type: "ClassBody";
    body: [ MethodDefinition ];
}

interface MethodDefinition <: Node {
    type: "MethodDefinition";
    key: Expression;
    value: FunctionExpression;
    kind: "constructor" | "method" | "get" | "set";
    computed: boolean;
    static: boolean;
}

interface ClassDeclaration <: Class, Declaration {
    type: "ClassDeclaration";
    id: Identifier;
}

interface ClassExpression <: Class, Expression {
    type: "ClassExpression";
}

interface MetaProperty <: Expression {
    type: "MetaProperty";
    meta: Identifier;
    property: Identifier;
}

Modules

Declearation结尾的节点类型可以独立成句,以Specifier结尾的节点类型Declearation结尾的节点类型的组成部分。官方文档是把这2种类型放在同一级的,本文档把Specifier结尾的节点类型放在了子一级,方便区分。

interface ModuleDeclaration <: Node { }

interface ModuleSpecifier <: Node {
    local: Identifier;
}

interface ImportDeclaration <: ModuleDeclaration {
    type: "ImportDeclaration";
    specifiers: [ ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier ];
    source: Literal;
}

interface ImportSpecifier <: ModuleSpecifier {
    type: "ImportSpecifier";
    imported: Identifier;
}

interface ImportDefaultSpecifier <: ModuleSpecifier {
    type: "ImportDefaultSpecifier";
}

interface ImportNamespaceSpecifier <: ModuleSpecifier {
    type: "ImportNamespaceSpecifier";
}

interface ExportNamedDeclaration <: ModuleDeclaration {
    type: "ExportNamedDeclaration";
    declaration: Declaration | null;
    specifiers: [ ExportSpecifier ];
    source: Literal | null;
}

interface ExportSpecifier <: ModuleSpecifier {
    type: "ExportSpecifier";
    exported: Identifier;
}

interface AnonymousDefaultExportedFunctionDeclaration <: Function {
    type: "FunctionDeclaration";
    id: null;
}

interface AnonymousDefaultExportedClassDeclaration <: Class {
    type: "ClassDeclaration";
    id: null;
}

interface ExportDefaultDeclaration <: ModuleDeclaration {
    type: "ExportDefaultDeclaration";
    declaration: AnonymousDefaultExportedFunctionDeclaration | FunctionDeclaration | AnonymousDefaultExportedClassDeclaration | ClassDeclaration | Expression;
}

interface ExportAllDeclaration <: ModuleDeclaration {
    type: "ExportAllDeclaration";
    source: Literal;
    exported: Identifier | null;
}