ECMAScript 2017:从非终结符StringLiteral到String值的解析咨询
我来帮你把这个转换逻辑拆解得明明白白,结合你提到的标准细节一步步捋:
第一步:先过词法解析的“入门关”
首先,ECMAScript 2017的词法规则(标准第11章)是整个转换的基础——它把源码里的每个字符都当作SourceCharacter(也就是10.1节定义的Unicode码点)来处理,然后根据不同的语法场景,从InputElementDiv、InputElementTemplateTail这些起始符号开始解析。说白了,这一步就是先把你写的字符串字面量(不管是双引号、单引号还是模板字符串)从一堆代码里“揪”出来,确保不会和除法运算符、正则表达式这类容易混淆的语法元素搞混。
第二步:字符串字面量的“内部加工”
当词法分析器认准这是个字符串字面量后,就会开始处理里面的内容:
- 普通转义序列(比如
\n换行、\"转义双引号)会直接替换成对应的UTF-16代码单元; - Unicode转义序列分两种:
\uXXXX(四位十六进制)会直接转成单个代码单元,\u{XXXXX}(大括号里的码点)如果是超出基本多语言平面的字符,会拆成两个代理对(比如表情😀会被拆成0xD83D和0xDE00两个代码单元); - 如果是模板字符串,里面的
${表达式}部分会先把表达式的结果算出来,再转成字符串插入到对应位置。
第三步:生成最终的String值
经过上面的加工后,所有内容都会被转换成UTF-16代码单元的序列——这就是你最终拿到的String值。要记住:ECMAScript里的String本质是一串16位无符号整数,每个整数对应一个UTF-16代码单元,而不是直接存Unicode码点,这也是为什么有些复杂字符会占用两个“位置”的原因。
再补充下你提到的标准摘录的含义:
5.1.2 词法与正则表达式语法,ECMAScript的词法语法在第11章给出,其终结符为符合10.1节定义的SourceCharacter规则的Unicode码点,它定义了一组产生式,起始于目标符号InputElementDiv、InputElementTemplateTail或InputElementRegExp...
这段其实是在说词法分析的“启动规则”:不同的上下文要用不同的起始符号,比如在a / b里,/是除法运算符,这时候用InputElementDiv来解析;在let re = /abc/里,/是正则的开头,就用另一个起始符号;模板字符串的后半段也有专门的InputElementTemplateTail来处理——这么做就是为了避免语法歧义,保证字符串字面量在任何场景下都能被正确识别。
举个直观的例子:
你写的"hello\n\u{1F600}",经过转换后:
\n变成代码单元0x000A\u{1F600}变成代理对0xD83D+0xDE00- 最终的String值就是由
h(0x0068)、e(0x0065)、l(0x006C)、l(0x006C)、o(0x006F)、0x000A、0xD83D、0xDE00这些代码单元组成的序列。
内容的提问来源于stack exchange,提问作者Magnus

