?uem/p1-90`ECMAScript
在若干情况下,词法输入元素的识别取决于使用这些输入元素的句法文法上下文。这就要求词法文法具有多个
使用多个词法目标可确保不存在会影响自动分号插入的词法歧义。例如,不存在同时允许开头为除法或除法赋值以及开头为
a = b
/hi/g.exec(c).map(d);
当
a = b / hi / g.exec(c).map(d);
Unicode 格式控制字符(即 Unicode 字符数据库中类别为“Cf”的字符,例如 LEFT-TO-RIGHT MARK 或 RIGHT-TO-LEFT MARK)是在缺少用于此目的的更高级协议(例如标记语言)时,用于控制一段文本格式的控制代码。
允许在源文本中使用格式控制字符有助于编辑和显示。所有格式控制字符都可以用于
U+FEFF (ZERO WIDTH NO-BREAK SPACE) 是一种格式控制字符,主要用于文本开头以将其标记为 Unicode,并允许检测文本的编码和字节顺序。用于此目的的 <ZWNBSP> 字符有时也可能出现在文本开头之后,例如文件连接的结果。在
空白码点用于提高源文本的可读性,并将标记(不可分割的词法单元)彼此分隔,但除此之外没有意义。空白码点可以出现在任意两个标记之间,也可以出现在输入的开头或结尾。空白码点可以出现在
ECMAScript 空白码点列于
| 码点 | 名称 | 缩写 |
|---|---|---|
U+0009
|
字符制表 | <TAB> |
U+000B
|
行制表 | <VT> |
U+000C
|
换页 (FF) | <FF> |
U+FEFF
|
零宽不换行空格 | <ZWNBSP> |
| 常规类别“Space_Separator”中的任意码点 | <USP> |
U+0020 (SPACE) 和 U+00A0 (NO-BREAK SPACE) 码点属于 <USP>。
除
与空白码点一样,行终止符码点用于提高源文本的可读性并将标记(不可分割的词法单元)彼此分隔。然而,与空白码点不同,行终止符对句法文法的行为具有一定影响。通常,行终止符可以出现在任意两个标记之间,但句法文法在少数位置禁止它们出现。行终止符还会影响自动分号插入过程(
行终止符可以出现在
正则表达式中由 \s 类匹配的空白码点集合
ECMAScript 行终止符码点列于
| 码点 | Unicode 名称 | 缩写 |
|---|---|---|
U+000A
|
换行 (LF) | <LF> |
U+000D
|
回车 (CR) | <CR> |
U+2028
|
行分隔符 | <LS> |
U+2029
|
段落分隔符 | <PS> |
只有
产生式
因为单行// 标记到行尾的所有码点组成。但是,行尾的
本节中的若干产生式在
Hashbang
本标准规定了特定码点的额外允许范围:U+0024 (DOLLAR SIGN) 和 U+005F (LOW LINE) 可以出现在
非终结符
非终结符 _。
具有 Unicode 属性“ID_Start”和“ID_Continue”的码点集合,分别
\ 不贡献任何码点。不能使用 \
根据 Unicode 标准规范等价的两个
关键字是匹配 fixed width 字体按字面形式出现在某个句法产生式中。ECMAScript 的关键字包括 if、while、async、await 等许多关键字。
保留字是不能用作标识符的 if 和 while 是保留字。await 仅在异步函数和模块内部是保留字。async 不是保留字;它可以不受
本规范结合文法产生式和await 和 yield 外,下面 await 和 yield 的例外情况使用参数化句法产生式在
始终允许作为标识符且不是关键字的名称,例如 Math、window、toString 和 _;
永远不允许作为标识符的名称,即下面列出的 await 和 yield 之外的名称;
根据上下文允许作为标识符的名称,即 await 和 yield;
在let、static、implements、interface、package、private、protected 和 public;
始终允许作为标识符、但也会在某些不允许 as、async、from、get、meta、of、set 和 target。
条件关键字或上下文关键字这两个术语有时用于指代后三类关键字,因此它们在某些上下文中可以用作标识符,在其他上下文中则用作关键字。
根据 \
\ els\u{65} 来声明名为“else”的变量。
enum 目前未在本规范中用作关键字。它是一个未来保留字,为将来的语言扩展用作关键字而保留。
类似地,implements、interface、package、private、protected 和 public 是
紧跟在
例如:3in 是错误的,而不是两个输入元素 3 和 in。
数值字面量表示
字符串字面量是由单引号或双引号包围的 0 个或多个 Unicode 码点。Unicode 码点也可以由转义序列表示。除闭合引号码点、U+005C (REVERSE SOLIDUS)、U+000D (CARRIAGE RETURN) 和 U+000A (LINE FEED) 外,所有码点都可以按字面形式出现在字符串字面量中。任何码点都可以转义序列的形式出现。字符串字面量求值为 ECMAScript String 值。生成这些 String 值时,按照
非终结符
除非作为 \n 或 \u000A 等转义序列。
字符串字面量可能出现在
function invalid() { "\7"; "use strict"; }
字符串字面量表示
| 转义序列 | 码元值 | Unicode 字符名称 | 符号 |
|---|---|---|---|
\b
|
0x0008
|
退格 | <BS> |
\t
|
0x0009
|
字符制表 | <HT> |
\n
|
0x000A
|
换行 (LF) | <LF> |
\v
|
0x000B
|
行制表 | <VT> |
\f
|
0x000C
|
换页 (FF) | <FF> |
\r
|
0x000D
|
回车 (CR) | <CR> |
\"
|
0x0022
|
双引号 |
"
|
\'
|
0x0027
|
撇号 |
'
|
\\
|
0x005C
|
反斜线 |
\
|
下面的产生式描述正则表达式字面量的语法,并由输入元素扫描器用于寻找正则表达式字面量的结尾。随后,会使用更严格的 ECMAScript 正则表达式文法(
实现可以扩展
正则表达式字面量不能为空;码元序列 // 不表示空正则表达式字面量,而是开始一个单行/(?:)/。
大多数 ECMAScript 语句和声明都必须以分号终止。这样的分号始终可以显式出现在源文本中。不过,为了方便,在某些情况下可以从源文本中省略这样的分号。这些情况通过表述为“在这些情况下,分号会自动插入源代码标记流中”来描述。
在以下规则中,“标记”是指按照条款
分号插入有三条基本规则:
从左向右解析源文本时,如果遇到一个文法中任何产生式都不允许的标记(称为违规标记),并且以下一个或多个条件成立,则会在该违规标记之前自动插入分号:
}。
),并且插入的分号随后会被解析为 do-while 语句(不过,前述规则还受一个额外的for 语句头部中的两个分号之一(参见
以下是文法中仅有的受限产生式:
这些受限产生式的实际效果如下:
++ 或 -- 标记,并且前一个标记与 ++ 或 -- 标记之间出现了至少一个 ++ 或 -- 标记之前自动插入分号。
using 标记,并且在 using 标记之后自动插入分号。
continue、break、return、throw 或 yield 标记,并且在下一个标记之前遇到 continue、break、return、throw 或 yield 标记之后自动插入分号。
=> 标记之前出现 async 标记之后在 function、( 标记之前出现 async 标记不会被视为与后续标记属于同一个表达式或类元素。
async 标记之后在 * 标记之前出现 由此给 ECMAScript 程序员带来的实际建议是:
++ 或 -- 运算符应与其操作数位于同一行。
using 声明中的 using 标记从同一行开始。
return 或 throw 语句中的 yield 表达式中的 return、throw 或 yield 标记从同一行开始。
break 或 continue 语句中的 break 或 continue 标记位于同一行。
=> 应位于同一行。
async 标记应与紧跟其后的标记位于同一行。
源文本
{ 1 2 } 3
即使应用自动分号插入规则,也不是 ECMAScript 文法中的有效句子。相比之下,源文本
{ 1
2 } 3
同样不是有效的 ECMAScript 句子,但会通过自动分号插入转换为以下形式:
{ 1
;2 ;} 3;
它是一个有效的 ECMAScript 句子。
源文本
for (a; b
)
不是有效的 ECMAScript 句子,并且不会通过自动分号插入进行更改,因为该分号是 for 语句头部所必需的。自动分号插入永远不会插入 for 语句头部中的两个分号之一。
源文本
return
a + b
会通过自动分号插入转换为以下形式:
return;
a + b;
表达式 a + b 不会被视为 return 语句要返回的值,因为它与标记 return 之间由
源文本
a = b
++c
会通过自动分号插入转换为以下形式:
a = b;
++c;
标记 ++ 不会被视为应用于变量 b 的后缀运算符,因为 b 和 ++ 之间存在
源文本
if (a > b)
else c = d
不是有效的 ECMAScript 句子,并且不会在 else 标记之前通过自动分号插入进行更改,即使此时没有任何文法产生式适用,因为自动插入的分号随后会被解析为空语句。
源文本
a = b + c
(d + e).print()
不会通过自动分号插入进行转换,因为第二行开头的括号表达式可以被解释为函数调用的参数列表:
a = b + c(d + e).print()
如果赋值语句必须以左括号开头,那么程序员最好在前一个语句末尾显式提供分号,而不是依赖自动分号插入。
ECMAScript 程序可以通过依赖自动分号插入,以只使用极少分号的风格编写。如上所述,并非每个换行处都会插入分号,而且自动分号插入可能取决于跨越行终止符的多个标记。
随着新的句法特性添加到 ECMAScript 中,可能会新增文法产生式,从而导致那些依赖在其前方进行自动分号插入的代码行在解析时改为匹配不同的文法产生式。
就本节而言,如果某个位置是否插入分号取决于其前面的源文本,则该自动分号插入情况被视为特殊情况。本节其余部分描述此版本 ECMAScript 中若干自动分号插入的特殊情况。
在
()。如果没有分号,两行会一起被视为 [)。如果没有分号,两行会一起被视为属性访问,而不是 `)。如果没有分号,两行会一起被解释为带标签的 Template(+ 或 -。如果没有分号,两行会一起被解释为相应二元运算符的使用。/ ECMAScript
本节其余部分描述此版本 ECMAScript 中若干使用“[no