Skip to content

Latest commit

 

History

History
200 lines (123 loc) · 18.8 KB

Notational-Conventions.md

File metadata and controls

200 lines (123 loc) · 18.8 KB

句法和词法

上下文无关文法

上下文无关文法由一系列的产生式组成。每个产生式的左边部分是一个被称为非终结符的抽象符号,右边部分是零或多个非终结符终结符的序列。任何文法,其终结符都来自指定的字母集

从一个名为目标符的由特殊非终结符组成的句子开始,给定的上下文无关文法就表示了语言,即:将产生式右边序列的非终结符当作左边,进行反复替换,其结果就成为可能的终结符序列集合(该集合可能无限)。

词法和正则表达式文法

第7章给出了ECMAScript的词法。该文法的终结符字符(Unicode代码单元)符合第6章定义的*SourceCharacter的规则。该词法定义了一组产生式,从目标符InputElementDivInputElementRegExp*开始,描述了如何将诸如此类的字符序列转换成一个输入元素序列。

空白字符注释之外的输入元素构成了ECMAScript句法的终结符,同时这些输入元素被称为 ECMAScript的Token。这些Token是ECMAScript语言的保留字标识符字面量标点符号。此外,行终止符虽然不被视为Token,但会成为输入元素流的一部分,用于引导处理自动插入分号空白字符单行注释会被简单地丢弃,而不会出现在句法的输入元素流中。如果一个多行注释(即形式为/*...*/的注释,不管其是否跨行)不包含行终止符也会被简单地丢弃;但如果一个多行注释包含一个或多个行终止符,那么注释会被替换为一个行终止符,进而成为句法输入元素流的一部分。

15.10给出了ECMAScript的正则表达式文法。该文法的终结符也由*SourceCharacter定义。该文法定义了一组产生式,从目标符Pattern*开始,描述了如何将诸如此类的字符序列翻译成一个正则表达式模式。

双冒号::作为分隔符分割了词法和正则表达式的文法产生式。同时,词法和正则表达式的文法可共享某些产生式

数字字符串文法

用于将字符串转换为数字值的另一种文法。此文法与部分词法类似,都与数字字面量有关;该文法有作为终结符的*SourceCharacter*。此文法将出现在9.3.1

三冒号:::作为分隔符分割数字字符串文法的产生式

句法

11121314章给出了ECMAScript的句法。句法将由词法所定义的ECMAScript Token作为它的终结符5.1.2)。句法定义了一组起始于*Program*目标符的产生式,描述了Token序列如何才能形成句法上正确的ECMAScript程序。

当一个字符流被解析为ECMAScript程序时,它首先通过词法应用程序反复转换为一个输入元素流;然后再通过一个句法应用程序解析该输入元素流。当输入元素流没有更多的Token时,如果存在Token不能被解析为*Program*目标非终结符的实例,那么程序在句法上存在错误。

单冒号:作为分隔符分割句法的产生式

事实上,第11121314章所给出的句法,并不能完全说明一个正确的ECMAScript程序所能接受的Token序列。故而需要接受一些额外的Token序列,比如说,某些特殊位置(如行结束符前)加入分号可以被文法接受。此外,当终止符出现在某些“尴尬”的位置时,有些文法所描述的Token序列并不会被接受。

JSON文法

JSON文法将描述ECMAScript对象的字符串转换为实际的对象。15.12.1给出了JSON文法。

JSON文法由JSON词法和JSON句法组成。JSON词法用于将字符序列转换为Token,类似于ECMAScript词法。JSON句法描述了JSON词法Token序列如何才能形成句法上正确的JSON对象。

双冒号::作为分隔符分割JSON词法的产生式。JSON词法使用了ECMAScript词法的某些产生式。JSON句法类似于ECMAScript句法。JSON句法的产生式被单冒号:作为分隔符分割。

文法标记法

每当文本直接引用诸如词法、正则表达式文法、数字字符串文法及其他文法的终结符时,就使用等宽字体来显示;这些都在文法产生式中,并且贯穿该文档。这些终结符都会出现在程序中,正如写的那样。所有以这种方式指定的终结符,都可以理解为ASCII范围内完整的Unicode字符,而不是任何其他乌焉成马范围内的Unicode字符。

非终结符斜体显示。非终结符的定义由非终结符名称和其后定义的一个或多个冒号给出。(冒号的数量表示产生式所属的文法。)非终结符的右侧有一个或多个替代子紧跟其后的行。 例如,句法定义:

 WhileStatement :
   while ( Expression ) Statement

表示非终结符WhileStatement代表whileToken,及其后跟着的左括号TokenExpression、右括号TokenStatement。这里出现的ExpressionStatement本身也是非终结符。另一个例子,句法定义:

 ArgumentList :
   AssignmentExpression
   ArgumentList , AssignmentExpression

表示ArgumentList可以代表一个AssignmentExpression或者ArgumentList及其后跟一个逗号和AssignmentExpression。该ArgumentList的定义是递归的,也就是说,它定义了其自身。其结果是,一个ArgumentList可能包含用逗号隔开的任意正整数个参数,每个参数表达式是一个AssignmentExpression。像这样的非终结符递归定义很普遍。

终结符非终结符可带有后缀下标opt,表示它是可选符号。实际上,包含可选符号的替代子指定了两个右边部分:一个是省略可选元素的,另一个是包含可选元素的。这意味着:

 VariableDeclaration :
   Identifier Initialiseropt

是下面的一种简写:

 VariableDeclaration :
   Identifier
   Identifier Initialiser

并且:

 IterationStatement :
   for ( ExpressionNoInopt ; Expressionopt ; Expressionopt ) Statement

是下面的一种简写:

 IterationStatement :
   for ( ; Expressionopt ; Expressionopt ) Statement
   for ( ExpressionNoIn ; Expressionopt ; Expressionopt ) Statement

相应的是下面的一种简写 :

 IterationStatement :
   for ( ; ; Expressionopt ) Statement
   for ( ; Expression ; Expressionopt) Statement
   for ( ExpressionNoIn ; ; Expressionopt) Statement
   for ( ExpressionNoIn ; Expression ; Expressionopt) Statement

也即是下面的一种简写:

 IterationStatement :    for ( ; ; ) Statement
   for ( ; ; Expression ) Statement
   for ( ; Expression ; ) Statement
   for ( ; Expression ; Expression ) Statement
   for ( ExpressionNoIn ; ; ) Statement
   for ( ExpressionNoIn ; ; Expression ) Statement
   for ( ExpressionNoIn ; Expression ; ) Statement
   for ( ExpressionNoIn ; Expression ; Expression ) Statement

因此,非终结符IterationStatement 实际上有8个右侧替代子。

如果文法定义的冒号后面出现“one of”字样,那么其后的一行或多行出现的每个终结符都是一个选择定义。例如,ECMAScript词法产生式:

 NonZeroDigit :: one of
   1 2 3 4 5 6 7 8 9

仅仅是下面的一种简写:

 NonZeroDigit ::
   1
   2
   3
   4
   5
   6
   7
   8
   9

如果产生式的右侧出现“[empty]”,则说明该产生式的右侧既不包含终结符也不包含非终结符

如果产生式的右侧出现“[lookahead ? set]”,则说明给定set的成员不得成为产生式紧随其后的Token。该set可以写成一个大括号括起来的终结符列表。为方便起见,set也可以写成一个非终结符,在这种情况下,它代表该非终结符可扩展到的所有终结符集合。例如,给出定义:

 DecimalDigit :: one of
   0 1 2 3 4 5 6 7 8 9

 DecimalDigits ::
   DecimalDigit    DecimalDigits DecimalDigit

再定义:

 LookaheadExample ::
   n [lookahead ? {1 , 3 , 5 , 7 , 9}] DecimalDigits
   DecimalDigit [lookahead ? DecimalDigit]

匹配,字母n后跟随由偶数起始的一个或多个十进制数字,或者一个十进制数字后面跟随一个非十进制数字。

如果产生式的右侧出现“[no LineTerminator here]”,则说明此产生式产生式是受限的:如果*LineTerminator*在输入流的指定位置出现,那么此产生式将不会被使用。例如,产生式

 ThrowStatement :
   throw [no LineTerminator here] Expression ;

表示如果程序中throw TokenExpression之间的出现*LineTerminator*,那么不得使用此产生式。

*LineTerminator*除了禁止出现在受限的产生式中,可以在输入元素流的任何两个 Token之间出现任意次数,而不会影响程序的句法验证。

当一个词法产生式或者数字字符串文法中出现多字符,它表示此字符序列将注册一个Token

使用词组“but not”可以指定某些不允许在产生式右侧的扩展,进而说明该扩展将被排除。例如,产生式

 Identifier ::
   IdentifierName but not ReservedWord

表明该非终结符Identifier可被替换成任何可以替代IdentifierName的字符序列,而不能替换成等同于ReservedWord的字符序列。

最后,对于实际上不可能列出其全部可变元的少量非终结符,我们用普通字体写出的描述性短语来描述它们:

 SourceCharacter ::
   any Unicode code unit

算法约定

本规范通常使用带编号的列表来指定算法的步骤。这些算法用来精确地指定ECMAScript语言结构所需的语义。算法无意暗示任何具体实现所使用的技术。实践中,也许可使用更有效的算法来实现一个给定功能。

为便于在本规范多个部分使用某些算法,使用可传参函数化形式来命名和编写这些算法,谓之抽象操作,进而可在其他算法中通过名来称引用它们。

当算法用来产生返回值时,“return x”指令说明该算法的返回值是x,而算法应该终止。“第n步的结果”可简写成Result(n)。

为表达清晰,算法的步骤可细分为有序的子步骤。子步骤被缩进,也可以将子步骤自身进一步细分为缩进子步骤。大纲编号约定用于识别分步骤:第一层次的子步骤适用小写字母标记,第二层次的子步骤使用小写罗马数字标记。如果需要超过三个层次,则重复这些规则,即第四层次使用数字标记。例如:

  1. Top-level step
    1. Substep.
    2. Substep
      1. Subsubstep.
      2. Subsubstep.
        1. Subsubsubstep
          1. Subsubsubsubstep

算法步骤或子步骤可使用断言“如果”作为其子步骤的条件。在这种情况下,当断言为真时子步骤才适用。如果步骤或子步骤由“否则”开始,那么它也是一个断言,其含义与前面的同一层级的断言“如果”正好相反。

算法步骤可以表示其子步骤的迭代应用程序。

算法步骤可以断言该算法的一个不变的条件。这些断言用于明确那些本可能是隐式的算法不变式。这些断言并没有增添额外的语义要求,因此无需执行检查。它们仅仅为了澄清算法。

诸如加法、减法、取反、乘法、除法等数学运算,以及本节稍后定义的数学函数,往往被理解为精确计算数学实数的数学结果,其中既不包括无穷大,也不包括用于区别正零的负零。本标准中的浮点运算算法模型,包括明确的步骤,在必要情况下处理无穷大和有符号零,并执行四舍五入。如果一个数学运算或函数应用于一个浮点数,它应该被应用于代表此浮点数的确切的数学值;这样浮点数必须是有限的,如果它是**+0-0**,则相应的数学值就是0

数学函数abs(x)产生x的绝对值:如果x是负数(小于零),其结果是-x,否则是x本身。

如果x是正数,数学函数sign(x)产生1;如果x是负数,则产生**-1**。本标准中x为零的情况下不使用sign函数。

符号xmoduloyy必须有限且非零)计算一个满足以下条件的k值:ky同号(或是零);abs(k) < abs(y),并且对某些整数q满足x-k = k×k

数学函数floor(x)产生不大于x的最大整数(最大可为正无穷)。

注:floor(x) = x - (xmodulo1)

如果算法定义了“抛出一个异常”,则算法的执行将被终止,且没有返回结果。已调用的算法也会被终止,直到算法步骤使用术语“如果一个异常被抛出 ...”明确给出异常处理。一旦遇到这种算法步骤,异常将不再被视为已发生过。