# 符号约定

# 句法和词法语法

# 上下文无关文法

上下文无关文法由许多产生式组成。每个产生式的左侧都有一个称为非终结符的抽象符号,右侧是零个或多个非终结符和终结符的序列。对于每个语法,终结符号都是从指定的字母表中提取的。

链式产生式是在其右侧恰好有一个非终结符以及零个或多个终结符的产生式。

从一个由单个可区分的非终结符组成的句子开始,称为目标符号,给定的上下文无关文法指定一种语言,即(可能是无限的)可能的终结符号序列集,这些终结符号序列可以通过重复替换目标符号中的任何非终结符而产生。序列具有产生式的右侧,其非终结符是左侧。

# 词法和正则表达式文法

ECMAScript的词汇语法在条款中给出12. 该文法的终结符号是符合以下规则的 Unicode 代码点源字符定义在11.1. 它定义了一组产生式,从目标符号 InputElementDiv,输入元素模板尾, 或者输入元素正则表达式, 或者InputElementRegExpOrTemplateTail,它描述了如何将这些代码点的序列转换为输入元素的序列。

除空格和注释之外的输入元素构成 ECMAScript 句法语法的终端符号,称为 ECMAScript标记。这些代币是保留字、ECMAScript 语言的标识符、文字和标点符号。此外,行终止符虽然不被视为标记,但也成为输入元素流的一部分并指导自动分号插入的过程(12.9)。简单的空格和单行注释将被丢弃,并且不会出现在句法语法的输入元素流中。一个多行注释(即/*……形式的注释,*/不管它是否跨越多行)如果它不包含行终止符,同样会被简单地丢弃;但如果一个多行注释包含一个或多个行终止符,然后将其替换为单行终止符,该行终止符成为句法语法输入元素流的一部分。

ECMAScript的RegExp 文法在22.2.1. 该文法还具有定义的代码点作为其终结符号源字符. 它定义了一组产生式,从目标符号 图案,它描述了如何将代码点序列转换为正则表达式模式。

词法文法和正则文法的产生式以两个冒号“ :: ”作为分隔标点符号来区分。词汇和 RegExp 语法共享一些产生式。

# 数字字符串语法

另一种语法用于将字符串转换为数值。该文法类似于与数字文字有关的词汇文法部分,并以终端符号为源字符. 这个语法出现在7.1.4.1.

数字字符串语法的产生通过三个冒号“ ::: ”作为标点来区分。

# 句法文法

ECMAScript的句法语法在子句中给出13通过16. 该文法具有由词法文法定义的 ECMAScript 标记作为其终结符号 (5.1.2)。它定义了一组产生式,从两个备选方案开始目标符号 脚本和模块,它描述了标记序列如何形成 ECMAScript 程序的语法正确的独立组件。

将代码点流解析为 ECMAScript 时脚本或者模块,首先通过词法文法的反复应用,转化为输入元素流;然后,该输入元素流由句法语法的单个应用程序解析。如果输入元素流中的标记不能被解析为目标非终结符的单个实例(脚本或者模块),没有留下任何令牌。

当解析成功时,它会构造一个解析树,一个有根的树结构,其中每个节点都是一个解析节点。每个 Parse Node 都是语法中符号的一个实例;它表示可以从该符号派生的源文本的范围。解析树的根节点,代表整个源文本,是解析的一个实例目标符号. 当 Parse Node 是一个非终结符的实例时,它也是以该非终结符为左侧的某个产生式的一个实例。此外,它有零个或多个子节点,对应于产生式右侧的每个符号:每个子节点都是一个解析节点,它是相应符号的一个实例。

每次调用解析器都会实例化新的解析节点,即使是相同的源文本,也不会在解析之间重用。当且仅当解析节点表示相同的源文本跨度,是相同语法符号的实例并且由相同的解析器调用产生时,解析节点才被视为相同的解析节点。

# 语法符号

在 ECMAScript 语法中,一些终端符号以fixed-width字体显示。这些将完全按照书面形式出现在源文本中。以这种方式指定的所有终端符号代码点都应被理解为来自基本拉丁语范围的适当 Unicode 代码点,而不是来自其他 Unicode 范围的任何类似外观的代码点。终结符号中的代码点不能用\ Unicode转义序列.

在终结符号是单个 Unicode 码点的文法中(即词汇文法、正则表达式文法和数字字符串文法),一个产生式中出现的多个固定宽度码点的连续运行是相同码点序列的简单速记,写为独立的终端符号。

# 算法约定

规范通常使用编号列表来指定算法中的步骤。这些算法用于精确地指定 ECMAScript 语言构造所需的语义。这些算法并不意味着使用任何特定的实现技术。在实践中,可能有更有效的算法来实现给定的特征。

算法可以用一个有序的、逗号分隔的别名序列显式地参数化,这些别名可以在算法步骤中用来引用在该位置传递的参数。可选参数用括号([ ,name ])表示,与算法步骤中所需的参数没有区别。Rest 参数可能出现在参数列表的末尾,用前导省略号(,... name)表示。Rest 参数将在必需参数和可选参数之后提供的所有参数捕获到 List 中。如果没有这样的附加参数,则该 List 为空。

算法步骤可以细分为连续的子步骤。子步骤是缩进的,它们本身可以进一步划分为缩进的子步骤。大纲编号约定用于识别子步骤,其中第一级子步骤用小写字母字符标记,第二级子步骤用小写罗马数字标记。如果需要三个以上级别,则这些规则使用数字标签与第四个级别重复。例如:

1. Top-level step
  a. Substep.
  b. Substep.
    i. Subsubstep.
      1. Subsubsubstep
        a. Subsubsubsubstep
          i. Subsubsubsubsubstep

一个步骤或子步骤可以被写成一个“ if”谓词来限制它的子步骤。在这种情况下,仅当谓词为 true 时才应用子步骤。如果一个步骤或子步骤以单词“ else”开头,那么它是一个谓词,与前面的“ If”谓词步骤在同一级别上是否定的。

步骤可以指定其子步骤的迭代应用程序。

以“ Assert:”开头的步骤断言其算法的不变条件。这样的断言用于创建显式的算法不变量,否则这些不变量就是隐式的。这样的断言不会添加额外的语义需求,因此不需要由实现检查。它们只是用来澄清算法。

算法步骤可以使用表单“ Let x be some Value”声明任何值的命名别名。这些别名类似于引用,因为 x 和 some Value 都引用相同的底层数据,对其中一个的修改对两者都是可见的。想要避免这种类似引用的行为的算法步骤应该显式地创建右侧的副本: “ Let x be a copy of some Value”创建了 some Value 的浅拷贝。

一旦声明,别名可以在任何后续步骤中引用,而且不能在别名声明之前的步骤中引用。别名可以使用“ Set x to some OtherValue”格式进行修改。

# 抽象操作

为了便于在本规范的多个部分中使用,一些称为抽象操作的算法以参数化函数形式命名和编写,以便可以通过名称从其他算法中引用它们。抽象操作通常使用函数式应用程序样式(如 OperationName (arg1,arg2))引用。一些抽象操作被视为类规范抽象的多态分派方法。这种类似方法的抽象操作通常使用诸如 somValue 之类的方法应用程序样式来引用。操作名称(arg1,arg2)。

# 语法导向的操作

语法导向的操作是一种命名操作,其定义由算法组成,每个算法都与来自一个 ECMAScript 文法的一个或多个结果相关联。具有多个替代定义的产品通常对每个替代定义都有一个不同的算法。当一个算法与一个语法生成相关联时,它可能会参考生成选项的终结符与非终结符,就好像它们是算法的参数一样。以这种方式使用时,非终端符号指的是在解析源文本时匹配的实际替代定义。源文本由语法生成或从中派生的 Parse Node 匹配,它是源文本的一部分,从参与匹配的第一个终端开始,到参与匹配的最后一个终端结束。

# 运行时语义

指定必须在运行时调用的语义的算法称为运行时语义。运行时语义由抽象操作或语法导向的操作定义。

# 静态语义

无上下文文法不足以表达所有规则,这些规则定义输入元素流是否形成可以计算的有效 ECMAScript 脚本或模块。在某些情况下,需要额外的规则,这些规则可以使用 ECMAScript 算法约定或散文需求来表示。这样的规则总是与语法的产生相关联,称为产生的静态语义。

静态语义规则有名称,通常使用算法定义。命名静态语义规则与语法结果相关联,具有多个替代定义的产品通常为每个替代定义为每个适用的命名静态语义规则提供一个不同的算法。

一种特殊的静态语义规则是早错规则。早期错误规则定义了与特定语法结果相关联的早期错误条件(见条款17)。大多数早期错误规则的计算不会在此规范的算法中显式调用。符合规范的实现必须在第一次评估脚本或模块之前,验证用于解析该脚本或模块的结果的所有早期错误规则。如果违反了任何早期错误规则,则脚本或模块无效,无法进行计算。

# 数学运算

本规范引用了这些类型的数值:

  • 数学值: 任意的实数,用作默认的数值类型。
  • 扩展数学值: 与 + ∞和 -∞一起的数学值。
  • Numbers: IEEE 754-2019双精度浮点值。
  • BigInts: 表示双射中任意整数的 ECMAScript 语言值。

#

在此规范中,ECMAScript 语言值以粗体显示。示例包括 null、 true 或“ hello”。这些代码与较长的 ECMAScript 代码序列(如 Function.Prototype.application 或 let n = 42;)不同。

那些属于规范内部且不能从 ECMAScript 代码直接观察到的值用一个无衬线体表示。例如,CompletionRecord 的[[ Type ]]字段接受正常值、返回值或抛出值。