查看原文
其他

从编译原理到 JavaScript

前端二叔 前端大全 2022-06-29

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

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

「为什么要学产生式?」

  • 如果你是一位Vue或者React框架的使用者,你只要学好这2个框架的特性,语法糖就可以写出一个很好的应用,但是这只能做一个在框架约束下的应用开发者;

  • 如果你想把应用写的更优秀(特别优秀),你就得绕到Vue/React的背后去看他们的实现原理,从更高一个层次去学习和了解他,就像一个教中学的老师必须是大学毕业,教本科的老师必须是硕士或者博士一样的道理;

    而学习产生式可以帮助前端工程师更好的理解JavaScript这么语言的构成,语法背后的语义等知识,让我们对语言由更高纬度的认知。

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

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

1 语言

图片

如上图所示,

  • 整啥玩意->干啥玩意;
  • 中午整点啥->中午吃点啥;
  • 咋整呢->咋办呢;

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

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

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

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

2 语法、语义、文法

  • 语法

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

  • 语义

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

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

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

图片

JavaScript的LL(1)文法请参考[1]。

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

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语言更深入的了解请点击

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

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

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;
}

Reference

[1]

JavaScript LL(1):https://hepunx.rl.ac.uk/~adye/jsspec11/llr.htm

[2]

JavaScript官方语法、词法定义:https://www.wenjiangs.com/doc/es51-grammar-and-lexical-grammar

[3]

文法产生式好文:https://www.cnblogs.com/friedCoder/p/12762089.html

[4]

如何利用LL(1)语法分析器生成AST:https://www.sohu.com/a/290137938_120054144



- EOF -

推荐阅读  点击标题可跳转

1、前端与编译原理:用 JS 写一个 JS 解释器

2、JavaScript 中哪一种循环最快呢?

3、终于有人把内卷和囚徒困境讲明白了


觉得本文对你有帮助?请分享给更多人

推荐关注「前端大全」,提升前端技能

点赞和在看就是最大的支持❤️

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存