关于作者:
雷庭,任职于北京优锘科技,前端架构师,从事前端开发及架构工作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 的标准中,它的非终结符,加号、减号是用加粗的黑字体来表示终结符的。
文法产生式描述比较简洁的文章请参考
如何利用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;
}