ECMA262 词法约定

winter 发了篇 javascript 词法,的总结帖: http://www.cnblogs.com/winter-cn/archive/2012/04/17/2454229.html
 
我就借花献佛的把,自己的注解笔记也放出来吧. 做个参考 (不过依然是格式问题,懒得整理了.evernote里贴过来总是这么郁闷)
 
 
 
 
 
词法
 
 
  ECMAScript程序的源代码,首先会被分转化为一系列的输入元素(input elements),包括:标记或记号(tokens), 行终结符(line terminators), 注释(comments),或空白(white space).
 
     词法文法(lexical grammar)有两个目标符号(goal symbols). 
          .其中除法的输入元素符(The InputElementDiv symbol),是在那些,允许使用(/)符号,或(/=)符号的,语法文法(syntactic grammar contexts)上下文中使用的. 
          .输入元素正则表达式符(InputElementRegExp symbol),则是在其它语法文法上下文中使用的.
 
     Note : Edition3
     需要注意的是,语法文法上下文中,同时出现(/)符号和正则表达式直接量( 如/\d/).且都被语法文法所允许的情况. 当除法输入元素这一目标符号,存在于此种情况下时,则斜杠符号(/),不能被当做该上下文中,一个正则表达式直接量的起始位置. 那么作为变通的办法.可以把真正的正则表达式直接量用括号括起来.
 
     Note : Edition5
     同时允许除号(/)或除等于(/=),和正则表达式符号(/),存在的语法文法上下文.是不存在的. 
     下面的例子中,也不受自动分号补全机制所影响 : (所谓不受影响就是指,此类情况不发生自动分号补全) 
               a = b
               /hi/g.exec(c)/map(d);          
     当一个行终结符后面是一个斜杠(/)(包括空白符或注释后面紧跟的是/的情况.),并且其所在语法上下文中,允许除号(/)或 除等于号(/=)时,不会发生分号自动补全.所以上面与下面的代码是等价的:
               a = b/hi/ g.exec(c).map(d); // 抛出异常...
     

语法 :
InputElementDiv ::
    WhiteSpace
    LineTerminator
    Comment
    Token
    DivPunctuator
InputElementRegExp ::
    WhiteSpace
    LineTerminator
    Comment
    Token
    RegularExpressionLiteral

 

空白(WhiteSpace)
    
 空白符,可以提高源代码的可读性,以及分割项链的的两个标记(token,即不可分割的,文法单位).除此之外,没有其他别的作用了. 空白符,可以存在于两个标记(token)之间.也可以存在于一个字符串直接量内部.这时候空白符,仅仅当做字符串的一部分. 但是空白符永远不能出现在任何一种标记(token)内部.
    
空白符表
uncode编码 空白符名称 正式名称 转意表示
\u0009 Tab(制表符) <TAB> \t
\u000B Vertical Tab(垂直制表符) <VT> \v
\u000C Form Feed(换页符,打印用.) <FF> \f
\u0020 Space(空格) <SP> 不知道...
\u00A0 No-break space(无间断空格) <NBSP> 不知道...
其他种类"Zs". 任何其他 Unicode空白分隔符. <USP> \s 正则表示
 
语法:
    
Whitespace::
          <TAB>
          <VT>
          <FF>
          <SP>
          <NBSP>
          <USP>
 
 
行终结符(Line Terminators)
     和空白符类似,行终结符也是用于提高可读性,和分割两个标记(token,即不可分割的文法单位). 和空白符不同的是,行终结符,会对语法文法(syntactic grammar)的行为有影响. 一般来说,行终结符,可以出现在两个标记(token)之间.但是在某些地方.行终结符,被语法文法所禁用. 一个行终结符,也不能出现在任何一种记号(token) 内部.甚至连一个字符串内也不允许出现.行符,还会影响分号自动插入(补全)的过程.
 
终结符表
uncode编码 终结符名称 正式名称 转义表示
\u000A Line Feed(换行符) <LF> \n
\u000D Carriage Return(回车符) <CR> \r
\u2028 Line separator(行分隔符) <LS> 不知道...
\u2029 Paragraph separator(段落分隔符) <PS> 不知道...
 
语法:
    
行终结符::
          <LF>
          <CR>
          <LS>
          <PS>
 
 
注释(Comments)
    注释分单行和多行两种.多行注释不允许嵌套.因为单行注释,可以包含除行终结符外的任何字符. 还有一个原因是标记(token)都是尽可能长的.  
     一个单行注释总是包含所有从 //开始一直到行尾的所有字符. 不过从词法文法上看,行尾的行终结符,不应该被认为是单行注释的一部分.而从语法文法上来说,亦是如此.且行终结符,因被看做是输入元素流的一部分.这一点是非常重要的,因为这意味着,有没有单行注释.都不会影响 分号自动插入(补全)的过程.
     注释的行为总是像空白符那样被忽略或抛弃.仅当一个多行注释内部包含一个行终结符.时,才会在语法文法上当成一个 行符来对待.
 

语法

Comment::
  MultiLineComment(多行注释)
  SingleLineComment(单行注释)

MultiLineComment ::
  /* MultiLineCommentChars-opt (多行注释字符,opt下标即本项存在性是可选的.即可有可无的) */

MultiLineCommentChars ::
  MultiLineNotAsteriskChar(多行,非星号"*"字符) MultiLineCommentChars-opt(可选多行字符)
  * PostAsteriskCommentChars-opt(可选星号字符)

PostAsteriskCommentChars(星号字符) ::
  MultiLineNotForwardSlashOrAsteriskChar(多行非斜线(/)、非星号字符) MultiLineCommentChars-opt(可选多行字符)
  * PostAsteriskCommentChars-opt(可选星号字符)

MultiLineNotAsteriskChar (多行非星号字符)::
  SourceCharacter but not asterisk * (不包括 星号 "*"的字符)

MultiLineNotForwardSlashOrAsteriskChar(多行非斜杠和星号的字符) ::
  SourceCharacter but not forward-slash / or asterisk * (不包括斜杠"/"和星号"*"的字符)

(个人觉得都是废话,总结起来一句话/* 此注释部分,不允许出现"*/".... */ )

SingleLineComment ::
  // SingleLineCommentChars-opt (单行注释字符-可选)

SingleLineCommentChars ::
  SingleLineCommentChar SingleLineCommentChars-opt

SingleLineCommentChar ::
  SourceCharacter but not LineTerminator

(好吧甭废话,总结起来就一句. // 单行注释部分,不能包含换行符.)

 

     
标记 ,语言符号(Tokens) 
     语法
     标记(Token)::
          ReservedWord(保留字)(Edition 5中,保留字并没有算做Token大项的一种,而是算作一种标识符了.....定义:保留字是不能像标识符那样使用的一个标识符名.)
          Identifier(标识符) (IdentifierName ES5改变, 与Identifier的区别是,IdentifierName允许保留字出现)
          Punctuator(标点符号)
          NumericLiteral(数字直接量)
          StringLiteral(字符串直接量)
     
     保留字(ReservedWord):
           解释 : 那些不能当做标识符来使用的词汇(标识符名).
      
     
     语法:
                    ReservedWord::
                         Keyword(关键字)
                         FutureReservedWord(预保留字)
                         NullLiteral (null直接量) (null)
                         BooleanLiteral(Boolean直接量) (true,false)
                         (权威指南第四版中,把null, true,false 归结为关键字.但准确来说.仅应属于保留字.当然关键字是保留字的子集.)
 
                    Keywords(关键字):
                         下列标记(tokens) 即就是ECMAScript-edition 3的25个关键字.以及edtion5 额外追加的 debugger 关键字.共26个关键字.
                              break else new var case finally return void catch for switch while continue function this with default if throw delete in try do instanceof typeof [debugger]
 
                    Future Reserved Words(预保留字):
     
     
     
     
     预保留字是,用作将来的扩展而预留的.也作为关键字使用的一些单词.
                         下列单词为edtion 3的 31个预保留字:
                              abstract enum int short boolean export interface static byte extends long super char final native synchronized class float package throws const goto private 
                              transient debugger implements protected volatile double import public
                         下列单词为edition5的 7个预保留字:
                              class enum extends super const export import
                         下列标记(tokens)为edition5中 严格模式下,任何上下文中不允许出现的9个预保留字,一但出现,必须抛出异常:
                              implements let private public yield interface package protected static
     
      标识符(Identifiers)
 
     
     
解释 : 
          标识符定义,是在5.16章节所描述的,即将发布的 Unicode 3.0标准(注1)所给出的文法,基础上做了少部分修改而成. 此文法同时基于文法约定和 Unicode标准所定义的字符类信息规范.
          而之前的Unicode2.1标准所定义的字符类信息也必须,在遵守ECMAScript实现的语言中,也被视为符合当前字符类信息规范的.
     
     
然而基于今后发布的Unicode标准,而附加的标识符也应该被依照ECMASCript实现的语言所承认.
          
          本标准在,违背Unicode标准所给出文法的前提下定义有, 美元符号($)和下划线(_),可以存在于一个标志符的任何位置.其中美元符号,应该只出现在机器生成的代码中.(注2)
 
标识符中允许出现,Unicode转义序列(会被转意为一个字符的)(注3).转换方式参见 7.8.4章节的关于Unicode转义序列的CV(character values)转换算法部分.
在一个Unicode转义序列(UnicodeEscapeSequence)(注4)前面出现的斜杠(\),不会被当做一个字符处理.
而一个Unicode转义序列,转意后的结果,对于标识符是非法的.那么 "\Unicode" 也是非法的.(注5)
 
按照Unicode标准相同的两个标识符是不等价的(注6),除非它们是通过完完全全相同的一系列code points(注7)表示的(换句话说,ECMA实现只需要在标识符上做按位比较),这意味着传入的源代码在到达编译器之前,已经转换成了规范C格式(注8)
  
 
          语法:
      
     
     Identifier::
      
     
     
     IdentifierName but not ReservedWord 
               
     
     
     IdentifierName::
                    IdentifierStart
                    IdentifierName IdentifierPart
 
               IdentifierStart:: (标识符起始位置,即一个标识符职能用一下4种字符作为标识符的第一个字符.)
                    Unicode Letter 
                    $ 
                    _
                    \ UnicodeEscapeSequence (即\ + Unicode转意序列,如\u0001)
 
               IdentifierPart::
                    IdentifierStart
                    UnicodeCombiningMark
                    UnicodeDigit
                    UnicodeConnectorPunctuation
                    \ UnicodeEscapeSequence
               
               UnicodeLetter  (Unicode文字)
                    下列中的任何一种都属于Unicode文字
                         Uppercase letter (大写字母)
                         Lowercase letter (小写字母)
                         Titlecase letter (首字母大写字母、标题字母)
                         Modifier letter (修饰符字母)(注9)
                         Other letter (其他字母.如中国汉字...)
                         Letter number (注10)
                    
                UnicodeCombiningMark (Unicode合并记号) (注11)  所有被称作 Non-spacing mark 或 Combining spacing mark的字符.
 
                UnicodeDigit (就是常说的数字啦) Unicode被定义为普通十进制数字的那些字符.
 
                UnicodeEscapeSequence (见 7.8.4章节关于 Unicode转意序列的描述.) (注12)
                     u
    HexDigit :: 
                                   0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F

                             
 
 
 
 
     
Punctuators (标点符号)
 
     
     
语法
      
     
     Punctuator(标点符号) :: one of
                  
{ } ( ) [ ]
. ; , < > <=
>= == != === !==  
+ - * % ++ --
<< >> >>> & | ^
! ~ && || ? :
= += -= *= %= <<=
>>= >>>= &= |= ^=  
     
     
     
     
               DivPunctuator(除法符号) :: one of 
                    /          /=
               (所以单独拿出来,请参考词法约定中,关于词法文法中两种目标符号(goal symbols)部分的说明.)
     
     直接量(Literals)
         语法
               Literal :: 
                    NullLiteral (null 直接量)- null
                    BooleanLiteral (布尔直接量)- true,false
                    NumericLiteral (数字直接量) 
                    StringLiteral (字符串直接量)
                    RegularExpressionLiteral (正则表达式直接量) (Edition 5才放到此处)
                    
           
          Numeric Literals(数字直接量)
               语法
                    NumericLiteral :: 
                         DecimaLiteral (十进制直接量)
                         HexIntegerLiteral (十六进制整数直接量)
                    
                    DecimalLiteral ::
                         DecimalIntegerLiteral(十进制整数直接量)     .DecimalDigits-opt(可选十进制数字)      ExponentPart-opt(可选指数部分) (注13)
                         .DecimalDigits(十进制数字)     ExponentPart-opt(可选指数部分) (注14)
                         DecimalIntegerLiteral(十进制整数直接量)     ExponentPart-opt(可选指数部分) (注15)
                    
                    DecimalIntegerLiteral ::
                         0 - 0
                         NonZeroDigit(单个非零数字) DecimalDigits-opt(多个可选数字) - 1,10,123 etc...
 
                    DecimalDigits(十进制数字,视情况也可视为,十进制小数.) ::                    
                         DecimalDigit(单个十进制数字)
                         DecimalDigits(多个十进制数字)     DecimalDigit(单个十进制数字) (我靠,这类式子好纠结.)
 
                    DecimalDigit(单个十进制数字) :: one of
                         0     1     2     3     4     5     6     7     8     9
 
                    NonZeroDigit(单个非零十进制数字) :: one of 
                         1     2     3     4     5     6     7     8     9
 
                    
                    ExponentPart(指数部分) ::
                         ExponentIndicator(指数指示符)     SignedIneger(有符号整数) (e1,E-1,部分构成指数部分)
 
                    ExponetIndicator :: one of 
                         e     E
 
                    SignedInteger(有符号整数) :: 
                         DecimalDigits(单个或多个十进制数字)
                         +DecimalDigits(+单个或多个十进制数字)
                         -DecimalDigits(-单个或多个十进制数字)
 
                    HexIntegerLiteral(十六进制整数直接量) ::
                         0xHexDigit(0小写x十六进制数字)
                         0XHexDigit(0大写X十六进制数字)
                         HexIntegerLiteral(十六进制整数直接量)     HexDigit(十六进制数字) (如0xff)
               
                    HexDigit :: one of (摘自Edition 5,Edition 3则在unicodeEscapeSequence 中已说明.
                         0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F
 
                 对于数字直接量来说,紧跟其后的字符,不能是一个标识符起始位置,或另一个数字.
                 note 比如:
                         3in
                 这里会有一个异常, 3in不会被解析成两个元素,而如果是一个元素.它又不是一个合法的token.              
 
                    
                 Semantics(语义)
                      一个数字直接量可以代替(代表)一个 Number类型的值. 这个值取决于两个步骤:
                           1. 根据直接量推演出的,数学角度上的值(mathematical value - MV). 
                           2. 根据下面所描述的方式,舍入这个数学值.
                      
                         . NumericLiteral 的 MV(数学值) :: 
                              DecimalLiteral 就是其自身的数学值.
                              HexIntegerLiteral 就是其自身的数学值.
                      
                         . DecimalLiteral 的数学值 ::
                              DecimalIntegerLiteral(如 123)  就是其自身的数学值.
                              DecimalIntegerLiteral.DecimalDigits (指浮点数,如1.23) 其数学值就是 DecimalIntegerLiteral的数学值,加上DecimalDigits的数学值,乘以10的-n次方, n等于DecimalDigits的位数.
                              DecimalIntegerLiteral.ExponentPart (如 123.e2 实际等价于123e2) 其数学值是DecimalIntegerLiteral的数学值,乘以10的e次方, e即ExponentPart部分的数学值(E2的数学值是指数2).
      
     
     
     
     
      .DecimalIntegerLiteral.DecimalDigits ExpontPart(如 123.4e5)其数学值就是 123.4*10的5次方.(此处未直接按原文翻译,原文太罗嗦.参考上面两项.)
     .DecimalDigits(如 .123 相当于0.123)的数学值,就是DecimalDigits的数学值,乘以10的-n次方,其中n是DecimalDigits的位数.
     .DecimalDigits ExponentPart(如 .123e4 相当于 0.123e4)的数学值,就是DecimalDigits的数学值,乘以10的n-e次方,其中n是DecimalDigits的位数,e是ExponentPart的数学值.
     .DecimalIntegerLiteral ExponentPart(如 123e4)的数学值,就是DecimalIntegerLiteral的数学值,乘以10的e次方,其中e即ExponentPart部分的数学值.
   
      
     
     
     
     . 
DecimalIntegerLitera ::
     0的数学值就是0.
     NonZeroDigit(首个非零数字,如000123中的1) DecimalDigits 的数学值是,NonZeroDigit的数学值,乘以10的n次方,加上DecimalDigits的数学值.其中n是DecimalDigits的位数
     
     
     
     
     
     
     
     
     
     
     . DecimalDigits ::
                              DecimalDigit的数学值就是其自身.
     
     
     
     
     
     DecimalDigits DecimalDigit 的数学值,就是DecimalDigits的数学值,乘以10,在加上 DecimalDigit的数学值.(如 123,中12看做DecimalDigits部分,3看做DecimalDigit部分)
                              
                         . ExponentPart ::
                              ExponentIndicator SignedInteger(如e2,e为指数指示器,2为有符号整数,即+2) 的数学值,就是 SignedInteger的数学值.
     
                         . SignedInteger ::
                              +DecimalDigits 的数学值就是 DecimalDigits的数学值.
                              -DecimalDigits 的数学值就是 负的DecimalDigits的数学值.
 
                         . DecimalDigit :: 
                              十进制0,或十六进制的0 ,其数学值就是0.
                              十进制或十六进制,或非零数字(NonZeroDigit)的1-9,其数学值都是其自身.
 
                         . HexDigit ::
                              十六进制的 a 或 A 的数学值是 10. 
                              十六进制的 b 或 B 的数学值是 11. 
                              十六进制的 c 或 C 的数学值是 12. 
                              十六进制的 d 或 D 的数学值是 13. 
                              十六进制的 e 或 E 的数学值是 14. 
                              十六进制的 f  或 F 的数学值是 15. 
                          
                         .HexIntegerLiteral ::
                              0x HexDigit 的数学值就是 HexDigit的数学值.
                              0X HexDigit 的数学值就是 HexDigit的数学值.
                              HexIntegerLiteral HexDigit (如0xAB)的数学值,就是HexIntegerLiteral的数学值,乘以16,加上 HexDigit的数学值.
                              
                    一但一个数字直接量的数学值被确定下来,那么就把这个数学值按规则舍入成为一个Number类型(参见8.5章节.). 如果数学值是0,那么舍入的值就是+0.
                    其舍入值,必须是其数学值的Number(此处应,指ECMAScript所定义的Number Type)值. 
                    除非该直接量,是一个具有超过20个有小数位的,十进制直接量.在这种情况下, 此数字的值是下面两种之一:
                         . 20位有效数字后面的数字全部用数字0替换掉.
                         . 20为有效数字后面的数字全部用数字0替换掉后,为第20位有效数位+1.(此处标记下,暂时没找到浏览器实现的证明.似乎并没遵守此两条.)
 
                    有效数字的概念-对于一个数位来说: 
                         . 如果他不属于指数部分,并且不是0.的情况 ,或
                         . 它左边是一个非0的数字,右边是一个非零且非ExponentPart(不属于指数部分)的数字.的情况
                    (数学上有效数字的概念:一个近似数,从左边第一个不是0的数位起,到其精确的数位止.其中所有的数字都叫这个数的有效数字. 标准中描述应参考这个准则.即在此前提下理解)
 
 
          字符串直接量(String Literals)
               字符串直接量是指0个或多个在一对闭合的单引号或双引号之间的字符.每个字符也可以被转义序列代表.
               (Edition5 的补充:字符串中的连续字符只会被作为闭合标记的,引号、反斜杠(\)、回车、行分隔符、段落分隔符和换行符打断.)
               (个人认为Edition5的说法有问题,其中的 反斜杠(\), "abc\def" 完全合法,也没有被打断呀.表示疑惑中...)
          
     
     
     语法
                    StringLiteral ::
                         "DoubleStringCharacters-opt"
      
     
     
     
     'SingleStringCharacters-opts'
 
                    DoubleStringCharacters
(可选多个双引号字符串字符)
 :: 
                         DoubleStringCharacter(单个双引号字符串字符) DoubleStringCharachters-opt(可选多个双引号字符串字符)
 
      
     
     
    SingleStringCharacters
 (可选单引号字符串字符) ::
                         SingleStringCharacter(单个单引号字符串字符) SingleStringCharacters-opt(可选多个单引号字符串字符)                         
 
     
               DoubleStringCharacter (单个双引号字符串字符)::
     
     
     
     
      SourceCharacter(非双引号(")、反斜杠(\)、以及行终结符的源字符)
                         \ EscapeSequence(转义序列)
      
     
     
     
     LineContinuation(行延续符)
 
      
     
     
     LineContinuation ::
      
     
     
     
     \LineTerminatorSequence(行
 终结符)(注16)
                    
      
     
     
     EscapeSequence(
 转义序列) ::
      
     
     
     
     CharacterEscapeSequence(字符转意序列)
      
     
     
     
     0[lookahead 
 ∉ DecimalDigit] (注17)
                          HexEscapeSequence(16进制转义序列)
     
     
     
     
      UnicodeEscapeSequence(Unicode转义序列)
               
                    CharacterEscapeSequence(字符转意序列) ::
                         SingleEscapeCharacter
                         NonEscapeCharacter
 
                    SingleEscapeCharacter(独立转意字符) :: one of
                         '     "     \     b     f     n     r     t     v
 
                    NonEscapeCharacter(非转意字符) ::
                         SourceCharacter but not EscapeCharacter or LineTerminator (所有非转义字符以及非行终结符的,元字符, 如\a,作为字符转意序列,转意成a)
          
                    EscapeCharacter(转意字符)
                         SingleEscapeCharacter(独立转意字符,这玩意即属于转义字符,又属于字符转意序列)
                         DeciamalDigit(单个十进制数字)(参考-注17中的ASCII编码的8进制转意序列)
                         x (\x)
                         u (\u)
                    
                    HexEscapeSequence ::
                         x HexDigit HexDigit (如\xff,ASCII编码的16进制转意序列.)
 
     
     
     
     UnicodeEscapeSequence ::
     
                      
u HexDigit HexDigit HexDigit HexDigit (如\u0061)
               
 
 
               Semantics(语义)
 
                    关于nonterminal(非结束)HexDigit(十六进制数) 的定义,参见Edition3 - 7.8.3章节. Edition5 - 7.6章节.
                    关于SourceCharacter(源字符)参见第二章和第六章.
 
                    一个字符串直接量可以替代(代表)一个 String类型(String Type)的值. 
                    字符串值(string value - SV),正如相关条款中所描述饿那样.由字符串直接量的各个字符值(character value -CV)所构成.
                    有些情况下,有些字符串直接量中的字符,会被解释为,具备一个数学值(MV). 
                    解析过程如下  (部分内容参见 7.8.3章节):
 
                         .StringLiteral(字符串直接量)的SV(字符串值) :: 
                              "" 的字符串值的SV,就是空字符序列.
                              '' 的字符串值的SV,就是空字符序列.
                              "DoubleStringCharacters"的SV,就是 DoubleStringCharacters 的SV.
                              'SingleStringCharacters'的SV,就是 SingleStringCharacters的SV.
                              
                         .DoubleStringCharacters::
                              DoubleStringCharacter 的SV,就是这个字符的序列(sequence , code point?),也就是这个字符的 CV.
                              DoubleStringCharacter DoubleStringCharacters 的SV就是一个DoubleStringCharacter的CV的序列,后面跟着一坨按顺序排列的字符的SV.(都是废话啊..)
       
                         .SingleStringCharacters ::
                              SingleStringCharacter
                              SingleStringCharacter SingleStringCharacters    (参考DoubleStringCharacters的两项.)
                         
                         .LineContinuation(行延续符) ::
                              \LineTerminatorSequence(\行终结符序列)的SV 就是一个空字符序列.     
                              
                         .DoubleStringCharacter ::
                              SourceCharacter but not double-quote " or \ or LineTerminator(非双引号或行终结符的源字符) 的CV,是该字符自身.
                              \ EscapeSequence (\转义序列)的CV,就是EscapeSequence的CV.
                              
 
                         .SingleStringCharacter
                              SourceCharacter but not single-quote ' or \ or LineTerminator(非单引号或行终结符的源字符)的CV,是该字符自身.
                              \ EscapeSequence 的CV,就是EscapeSequence的CV.
 
                         .EscapeSequence
                              CharacterEscapeSequence 的CV,就是其自身.
                              0[lookahead ∉ DecimalDigit] 的CV,就是<Nul>字符(如'\0a'中的\0部分,Unicode 值是0000的,Firefox里看起来像个麻将里的四桶的东东,不等同于空字符).
                        +    HexEscapeSequence(十六进制转意序列)的CV,就是其自身.
                              UnicodeEscapeSequence的CV,就是其自身.
 
                         .CharacterEscapeSequence(字符转意序列) ::
                              SingleEscapeCharacter 的CV,参照下标中的 Code Point Value部分.
                   
转意序列 Code Point Value代码点 名称 符号
\b \u0008 倒车 <BS>
\t \u0009 制表符 <HT>
\n \u000A 换行符 <LF>
\v \u000B 垂直制表符 <VT>
\f \u000C 分页符 <FF>
\r \u000D 回车符 <CR>
\" \u0022 双引号 "
\' \u0027 单引号 '
\\ \u005C 反斜杠 \
           
                              NonEscapeCharacter的CV,就是其自身.
 
                         .NonEscapeCharacter ::
                              SourceCharacter but not EscapeCharacter or LineTerminator (非转义符或行终结符的源字符)的CV,就是其自身.
                                                  
                         .HexEscapeSequence ::
                              x HexDigit HexDigit 的CV就是代码点(ASCII值)为16乘第一个HexDigit的数学值 ,加上第二个HexDigit的数学值的,那个字符. (如:\xff)
                         
                         .UnicodeEscapeSequence ::
                              u HexDigit HexDigit HexDigit HexDigit 的CV,就视其为一个4位16进制数,按规则转换为10进制后, 其值作为Code Point(Unicode值) 所对应的字符.(如:\u0061对应字符 a)(注18)
                              
                    Edition5: 遵守标准的实现应该是,在进入严格模式后,不应该在语法上扩展支持8进制的转义序列. 其相关解释,包括8进制转义序列的解释,都在Edition5的附录中有说明.参考B.1.1和B.1.1               
                    Note:
                         一个行终结符(行终结符),不能出现在一个字符串直接量中,除非它是一个行延续符的一部分(如\行终结符).
 
 
          正则表达式直接量(Regular Expression Literals)
               Edition3:
               一个正则表达式直接量,是一个在其被词法扫描后,会转换为一个RegExp object(参见15.10章节.)的元素.
               这个对象,是在其所在程序被执行前,就被创建好的.(词法分析后,执行期之前).
               而每次执行到该正则表达式直接量的时候,仅仅是产生一个,对那个词法扫描后转换的,RegExp object的引用,而不是创建一个新的object.(注19)
               两个正则表达式直接量所产生的正则表达式对象(RegExp object),不相等,即使他们的内容完全相同.
               (对于Edition3来说-词法扫描每此遇到,即使内容完全一样的正则表达式直接量,则会产生新的RegExp object).
               还有一种在运行时创建RegExp object的方法,就是使用 new RegExp,或者像调用函数那样,去调用RegExp方法(构造器).(参见 15.10.4 和 15.10.3)
 
               Edition5:(注19)
     
     
     一个正则表达式直接量,每次执行时,都会转成一个RegExp object(参见 15.10章).
 
     
            
两个正则表达式直接量所产生的正则对象,不相等.即使他们的内容完全相同.     
               还有一种在运行时创建RegExp object的方法,就是使用 new RegExp 或者想调用函数那样,去调用RegExp方法(构造器).(参见 15.10.4 和 15.10.3)(此处同Edition3)
 
               下面的产生式,解释了正则表达式直接量的语法,以及如何扫描并找到一个正则表达式直接量的结尾.
               包含正则表达式主体和标记(指Modifier-修饰符-g m i)的字符串,被直接传递给正则表达式构造器,并使用更严格的文法,来解释这些字符串. 
                一个ECMAScript的实现,可以扩展正则表达式构造所使用的文法,但是不可以扩展正则表达式主体和标记的产生式,以及使用(依赖)此产生式的其他产生式.(注20)
     
 
               语法:
                    RegulaExpressionLiteral (正则表达式直接量)::
                         / RegularexpressionBody / RegularExpressionFlags (如/\d/g)
               
                    RegularExpressionBody ::
                         RegularExpressionFirstChar RegularExpressionChars
 
                    RegularExpressionChars ::
                         [empty](针对RegularExpressionBody中的FirstChar 后面的部分.可以没有. 比如/a/)
                         RegularExpressionChars RegularExpressionChar
 
                    RegularExpressionFirstChar ::
                         NonTerminator but not * or \ or / (非行终结符、非*、非\、非/)
                         BackslashSequence(反斜杠序列)
 
                    BackslashSequence :: 
                         \NonTerminator (如\. , \d 神马的, 但\后不能出现行终结符)
 
                    NonTerminator ::
                         SourceCharacter but not LineTerminator (非行终结符的 源字符)
               
                    RegularExpressionFlags :: 
                         [empty] (无Flags的情况.)
                         RegulaExpressionFlags IdentifierPart (如 /\d/igm,部分.在某些正则表达式实现中,也被称作修饰符-Modifier).
 
                          Note :
                          正则表达式直接量不能是空的,因为一个空的正则表达式直接量,被解析成了// 单行注释..
                          定义一个空正则表达式,可以参考 /(?:)/ (在各个引擎中的 new RegExp() 空正则对象,对应的正则表达式即 (?:) )
 
               语义:
                         Edition3:
     
     
     
     
     一个正则表达式直接量,
 代表一个Object类型的值.这个值通过两个步骤获取:     
     
                          1.通过从对包含正则表达式主体(RegularExpressionBody),和正则表达式修饰符(RegularExpressionFlags)的字符串,
                                 获取到未处理(解释)的,分别代表模式(Pattern)和标记(修饰符,Flags)的两个字符串.(如/abc/gi,对应pattern-abc,对应flags-gi)
                              2.然后把Pattern和Flags作为参数,来调用 new RegExp构造器,用其返回值,作为正则表达式直接量的值(引用关系).
                                   
                         如果调用new RegExp时产生了一个异常,那么根据情况,要么在词法解分析时,就抛出异常,要么就在执行环境中,执行到正则表达式直接量的的过程中,抛出异常.(废话啊.还是Edition5靠谱)
 
     
     
     
     
     
Edition5:
                         一个正则表达式直接量的执行,就是去执行一个内置构造器RegExp的实例对象.这个值通过两个步骤获取:                         
                              1.通过从对包含正则表达式主体(RegularExpressionBody),和正则表达式修饰符(RegularExpressionFlags)的字符串,
                                 获取到未处理(解释)的,分别代表模式(Pattern)和标记(修饰符,Flags)的两个字符串.(如/abc/gi,对应pattern-abc,对应flags-gi)
                              2.然后,每次执行到这个正则表达式直接量的时候,就会像执行new RegExp(Pattern,Flags)那样创建一个新的正则表达式对象.(RegExp是指内置的RegExp构造器.)
                                
                         新被创建的正则对象成为正则表达式直接量此时的值(引用关系).如果调用new RegExp构造器,产生一个异常的话,那么这个异常必须是一个早期错误,(参见十六章).(注21)
 
                    
 
分号自动插入(Automatic Semicolon Insertion)
     某些ECMAScript的语句(statements,包括:空语句、变量声明、表达式、do-while、continue、break、return、throw,语句)必须以分号结束.
     这些分号可以总是显示的出现在源文本中. 但是有些情况下,为了方便,这些分号可以源文本中,被省略掉. 这种情况下,所谓分号自动插入机制,就要把分号自动插入到源代码的分词流中(token stream).
     
     分号自动插入规则
          . 当程序被从左到右的分析时(指词法分析),遇到一个文法产生式(production of grammar,指文法规则),所不允许的token(我们称它为唐突标记--offending token)时,如果满足下面两个条件任何一个,
            就在这个唐突标记前面自动插入一个分号.(注22)
               条件1: 这个唐突标记,与他前一个标记,被至少一个行终结符分开.
               条件2: 这个唐突标记是右闭合花括号 } .
 
          . 当程序被从左到右的分析时(指词法分析),当解析器达到某一个标记的输入流(input stream - 指输入字符串,即构成token的字符们.)的末尾时,
            如果确定,标记流(token stream),无法被解析成一个完整的ECMASCript程序.这种情况下, 就要在标记的输入流,中的结束位置,自动插入一个分号(应该是容错机制的一种,但我找不到具体实现的证据)
               
          . 当程序被从左到右的分析时(指词法分析),遇到一个,受限制的文法产生式所允许的token,并且此token是一个终结符(注23)或非终结符的,首个token.
            而这个终结符或非终结符,正好符合,NOTE部分对于  "[No LineTerminator here]" 受限制产生式说明部分所描述的情况. 
            (之前提到的tokien,被称作受限制token)受限制token和其前一个token之间至少被一个或多个行终结符所分离,这时候,一个分号将被自动插入到这个受限制token的前面.
               
     不管怎样,之前所描述的规则,有一个种特殊情况:如果分号将被解析成为一个空语句,或者当一个分号将成为 for语句中两个分号之一时(参见:12.6.3章节),就不要自动插入分号.
 
     NOTE 下面的是文法中所有受限制的产生式:
 
          PostFixExpression(后缀表达式) :
               LeftHandSideExpression [no LineTerminator here] ++     
               LeftHandSideExpression [no LineTerminator here] --
 
          ContinueStatement  :
               continue [no LineTerminator here] Identifier-opt;
 
          BreakStatement :
               break [no LineTerminator here] Identifier-opt;
 
          ReturnStatement :
               return [no LineTerminator here] Expression-opt;
 
          ThrowStatement:
               throw [no LineTerminator here] Expression;
 
     受限制的产生式的实际效果:
          .当一个 ++ 或 -- token 被扫描到,解释器会试图把它们当做一个后缀运算符,如果 ++ -- 和其前面的token之间至少有一个行终结符,则自动在 ++ -- 运算符前面自动插入一个分号.(注24)
          .如果 continue , break , return 或 throw ,这些token 与其后面的token 被至少一个行终结符所分离,则在 这些token后面自动插入一个分号.
     
     这些结果,实际上在告诉我们,对于ECMAScript来说 :
          .一个后缀运算符 ++ 或 -- 应该和它的运算元在一行上.
          .作为 return 或 throw 语句中的表达式的起始位置,应该和他们在一行.
          .作为 break 或 continue 语句中的标识符,应该和他们在一行.
 
 
 
     分号自动插入的例子
          源码:
 
      
     
     { 1 2 } 3
 
          不是一个能通过的ECMAScript 文法验证的句子.即使 自动分号插入规则被应用后.
      
     相反,源码:
 
                 { 1
                 2 } 3   
 
           也不是一个合法的ECMAScript句子,单体当自动分号插入机制被应用后, 其被转换为下面的形式:
               
                { 1
                ;2 ;} 3;
          这样,就成为了一个合法的ECMAScript句子.
 
          源码:
 
               for (a; b
               )
 
          也不是一个合法的ECMAScript句子,并且不会被分号自动插入机制所影响.因为分号对于for 语句来说,是一个必要的头(标记).自动插入机制永远在,for语句的两个必要分号之一的情况下,起作用.
 
          源码:
 
               return 
               a + b 
 
          会被分号自动插入机制,转换为:
 
               return; 
               a + b;
 
          Note: 表达式 a + b ,是不会被当做 return 语句的返回值来处理的.因为表达式 a + b,和作为前一个token 的 return,被一个行终结符所分割.
 
          源码:
 
               a = b
               ++c
          
          被分号自动插入机制,转换为下面的形式:
 
               a = b;
               ++c;
          
          token ++ 不会被当做变量b的后缀运算符,因为有一个行终结符在 b和++之间.
 
          源码:
 
               if (a > b)
               else c = d
 
          不是一个合法的ECMAScript句子,并且在else token前面也不会自动插入一个分号,尽管没有文法产生式被应用在这里,但是由于有一个分号要被解释成一个空语句.所以不会发生分号自动插入.
 
          源码:
 
               a = b + c
               (d + e).print()
 
          不会被自动分号插入机制所影响,因为第二行首的,括号内的表达式部分,可以被解释为一个函数调用的参数列表:
          
               a =  b + c(d + e).print()
          
          这种,一个赋值语句,存在必须以一个左括号为起始的情况, 那么对于程序员来说,在赋值语句后面,显式的提供一个分号,而不是依赖分号自动插入机制,是一个好注意.
          (程序员要自己在 c后面加一个分号.来避免歧义)
          
          补: 此段描述有个问题, 原文用到 assignment statement . 此处,虽然我翻译作赋值语句.但个人觉得.这里有点,难以解释的地方.
               
               左值表达式    赋值运算符   一般表达式               
               a                   =                   b + c
          
          这是个完整的赋值表达式,如果加上 ";"分号.即构成一个赋值语句, 全部很符合上述描述. 
         
                a
                (1)
          
          那么,应该是所有语句中,只要出现行首,是一个左括号的情况,就会被理解为函数调用.那么这个左括号,和其前一个token之间,虽然有行终结符,但也不会自动插入分号.
          所以依然需要程序员显示的写入分号.
 
 
 
 


注释:
 
注1 . 虽然目前的unicode编码标准,是2009年10月发布的v5.2,且6.0也即将发布. 但即使是ECMA Edition5 也仍然沿用 Edition3 unicode编码标准.
 
注2 . 这个意向,并没有被尊重.不然也不会有jquery 的$大行其道了. 所以Edition5 干脆取消了这个意向.而且.也完全不提,什么违背Unicode标准文法神马的了.
 
注3 . 参考下列代码:(已知a的unicode编码为0x0061)
      var \u0061 = 123; 
      alert(a)//打印123.         
 
注4 . Unicode转义序列基本格式为 uxxxx (其中xxxx对应为,有效Unicode编码). 而斜杠 (\),其作用是告知词法解析器,这里是一个转义序列,而\uxxxx才会被理解为一个Unicode转意序列.
 
注5 . 也就是说,这里不可能有二次转意发生. 如\u005cu0061 .其中005c是 斜杠(\)的Unicode编码. 虽然转意后 会成为\u0061. 但是不会发生2次转换. 所以遇到\就认为不符合 标识符命名规范.则抛出illegal character(非法字符)异常.
 
注6 . 就是指那种看起来一样,但实际上编码不同的字符. 比如两个看起来都是空格的,但是code point完全不同的字符.当然不能视为相等. 
 
注7 . 此处原文为.code points . 即代码点. 比如某些Unicode字符是组合字符(combining character,combining mark) 即有两个代码点组合而成的,仅代表一个字符的. 结合代码点.如 字符(
)
其代码点为"u0061+u0300".  测试代码: alert("\u0061\u0300"); 即两组转意序列在一起转意出一个字符.
 
注8 . 参考章节6 Source Text (源码文本部分). 所谓 from C (canonical composition 规范性、典型的构成) ,详见Unicode技术报告#15.
 
注9 . 参考 : http://everything2.com/title/Spacing+modifier+letters/  \u02b0 - ʰ  \u02b1 - ʱ   \u02b6 - ʶ  ...etc.
     ʰ = 123 ; alert (ʰ);
 
注10. 如\u0417 - З 等都属于Unicode定义的标示数字的那些字符.应该就是所谓Leter number.
           参考代码: 
                    var \u0417 = 123;
                    alert(З); //打印 123.
 
注11 . 参考代码: 
          var \u0061\u0300 = 123;
         alert(à);//打印123
         alert( 'à'.length);//打印2
à 即 合并字符. 但下面代码测试说明. 合并字符居然可以出现在 IdentifierStart的位置....各个浏览器均如此
 
 
注12 . 简单来说,大概那些代表符号类的 都不行.还有就是比如转意出的那些明确,不能出现在token中的空白符、行终结符等等.
关于 unicode转义序列描述,参见7.8.4章节-The CV of UnicodeEscapeSequence部分. 
 
 
注13 . 如合法数字直接量 123.4e5 中
          十进制整数直接量为 : 整数位 123部分. 
          .可选十进制数字为 : .4 部分
          可选指数部分中为 : e5 部分.
 
注14 . 如合法数字直接量  .4e5 中
          .十进制数字为 : .4 部分
          可选
指数
部分中为 : e5 部分
 
注15 . 如合法数字直接量 1e2 中
     
     
 十进制整数直接量为 : 1 
           可选指数部分为 : e2
 
注16 . 这就是伟神马这样是可以的:
              var a = '我是第一行\
                          我是第二行\
                          我是第三行';
          原因就是\后面是一个行终结符,比如上面代码中的\r,\n神马的. 就会被当做一个不可见的行连接符处理.
 
          但是要尤其注意的是 : 字符串直接量中 不能出现 "\u2028 - Line separator ,\u2029 - Paragraph separator" 这俩字符. 类似的这些视觉上,可能不会导致换行的行终结符.你要让他们出现在字符串直接量中.就要在他们前面+ "\" 转意.
 
注17 . 
0[lookahead 
∉ DecimalDigit] 基本意思就是指,0后面必须不是十进制数字的情况.如 \0a,\0,\0你好,神马的.但是就是不能是 \01 之类的东西.
     其中 lookahead 可以理解成 正则中的断言,或前瞻. 而 ∉ 则是指类似补集的概念.只有DecimalDigit的补集(非DecimalDigit). 参考正则中的(?!\d).
          那么这种情况下的东西也叫属于EscapeSequence(转意序列的一种情况). 
          \0 视觉上转意成一个空字符. \0 等价于 \u0000 ,'\0'.length == 1.
          \0DecimalDigit 其中0 将被忽略.直接去看\DecimailDigit, \00Decimal也是如此.\000Decimal则不是. 因为255的8进制表示,377 最多3位.
          那么\DecimalDigit 实际上是 8进制 ASCII转码. 所以 不超过十进制255的,有效的8进制表示 前面加\ 都会被转换成对应的ASCII字符. 不知道什么原因此处没有被ECMA提及. 但各个浏览器都有实现. 也许是我漏读了某章节...
 
          另外 IE系列对\0实现有bug. 如 'a\0b' 打印出来的结果会只有'a'.且'a\0b' == 'a\000b' . 但是 'a\000b' ,肉眼看起来却是'ab' .也就是说,实现输出上有bug. 但实际上都是'a[nul]b'
 
注18 . x进制转10进制转换法则:从其最右边的位当做位0开始递增计算一直到第n为:  x的0次方*位0的数学值 + x的1次方*位1的数学值+x的n次方*位n的数学值.(如16进制的a的数学值-十进制值即是10)
注19 . Edition3的描述直接导致了一种悲剧. 参考如下代码:(firefox 3.6- ,chrome6-. opear9-,  maxthon3 beta版)
 
               var f = function(){return /\d/g;};
     
     
       
alert(f() == f());
 //true 
 
          在所有依照Edition3实现的浏览器中,就会有这个问题.本来即使这样也没什么. 但是这里会产生一个很深的坑给程序员.如:        
          
             for (var i = 0; i < 10; i++) document.writeln(/\d/g.test('' + i)); //true,false,true,false
    
          这种坑.钻进去的时候.要知道,原来根,就在Edition3的标准制定上. 当然.对于test来说,避免使用/g是更好的选择.
          好在IE系列,始终没有这个问题. 而Firefox4.0beta+、Safair3+(没有mac系统测不到更早的)、chrome7+ 、opera10+ 都按照Edition5的标准来实现了.   
          但是,站在遵守标准的角度来说.明显IE再次的我行我素了.虽然结果是好的.但还是不值得表扬啊.
     
          另外一个奇怪的问题发生在chrome身上. 参考代码:
               function f() {
                    return /(/;
               }
     只有chrome11- ,Safari5- 没有在解析期,抛出正则的语法错误.其他浏览器一盖抛出异常.
说明,chrome和safari,并没有在遇到 正则表达式目标符所构成的非终结符时,马上对它进行正则表达式的词法、语法分析. 这个问题奇怪的根源在于,根据Edition3的说,词法分析期,遇到正则直接量时,是要产生一个正则对象的.而如果chrome,并没有遵守此标准.那么就难以解释为什么chrome6- 六个版本都在之前的demo中打印true,false,true,false. 那么接着就进入一个悖论了.至少在Safari和Chrome两款浏览器中,不能简单的用这两个demo,就可以证明或推倒出.他们的某个版本.遵守Edition3,还是Edition5. 最终的猜测是,chrome在遵守Edition3,而创建的RegExp object,仅仅是一个空的正则对象.只有evaluate的时候才会根据其原始值(直接量所描述的)初始化这个正则对象.则样做的好处是.缩短词法解析的时间.
               
 
注20 .  产生式是指一系列如果—那么形式表示的规则.一个产生式是一个由条件和动作组成的指令,即所谓的条件—活动规则,(condition—action 简称C-A规则).
           产生式这一术语是在1943年由美国数学家E.L.Post首先提出的,它根据串替代规则提出了一种称为Post机的计算模型,模型中的每一条规则称为产生式.产生式通常用于表示具有因果关系的知识,其基本形式为:P→Q 或者 IF P THEN Q.
 
 
注21 . 早期异常(early error),详细说明参考Error 翻译新的部分. 简单来说就是执行期(运行时)之前抛出的异常.比如语法错误神马的.
 
注22 .  Edition3对自动插入分号机制的描述很诡异.参考如下两组代码:
               1.
     
     
     
     a = 1 //这里无分号,1后面是行终结符
                    b = 2;//b前面自动插入分号.-参考b的前后的输入元素.看b是不是会导致歧义的产生,如果是,那么他就是唐突的token.
               2. 
                  if(true){}alert(1) //alert前面,花括号后面也被自动插入分号.           
           
           总结起来说.可以简单的理解为,必须加分号的表达式,在遇到 行终结符的话,就要在行终结符后面插入分号.
           比如标识符b的问题,理解起作用的是 a = 1构成一个完整的赋值语句.而其后的换行符造成了自动插入分号. 前提是 a = 1 所构成的语句,是不是一个符合 文法产生式的东西.
              参考代码:
                    var a = 
                          1
                    alert(a) //好吧,个人建议还是加上分号的好. 
 
 
注23 . 终结符- terminal,terminal symbol.即文法终结符, 简单来说,就是文法中所约束的的最小元素.即无法再进一步推导的元素. 具体参见编译原理-2型文法相关概念.
          此处edition3的描述,让我很困惑.因为终结符已经是词法上不能再进一步推导的元素了,再说某个token处于它的起始位置,那除非token就是这个终结符.或者我对那句话理解有偏颇?
 
          非终结符- nonterminal,nonterminal symbol. 和终结符非此即彼东西.即可以进一步推导的元素,或者说可进一步拆分的元素.
 
          由文法产生语言句子的基本思想是:从识别符号开始,把当前产生的符号串中的非终结符号替换为相应规则右部的符号串,直到最终全由终结符号组成。这种替换过程称为推导或产生句子的过程,每一步成为直接推导或直接产生.
 
注24 . 参考代码:
          var a = 1,b=2;
          a
          ++
          b
          alert([a,b]) // 打印 1,3
 
 
 
posted @ 2012-04-18 02:17  Franky  阅读(...)  评论(...编辑  收藏