JAVA语言规范学习笔记(3)

开始学习JAVA的词汇结构了。JAVA程序是用unicode来表示的,比如我们常用到的换行符。所有的unicode都会强制转化为一系列的input elements,包括空格,注释,和tokens。JAVA的发展和unicode的发展是密不可分的。unicode的发展我们可以参考它的官方网站:http://www.unicode.org。JAVA编程语言是用UTF-16来描述文本的,只有少数的API类使用UTF-32,JAVA的平台提供了两者之间转化的方法。除了注释,标识符,字符常量,字符串常量,所有的input elements都是ASCII码组成。

Lexical Translations

词汇的翻译我们以后称之为Lexical Translations分为三步:

1、原始的unicode stream所有的转义字符转化为对应的unicode字符。转义字符的形式是/uXXXX,其中XXXX代表的是十六进制的值。用ASCII码字符的程序在这个转化中也是适用的。

2、利用第一步转化来的unicode字符,将其变为input elements和换行符。

3、使用第二步转化来的input elements和换行符,去掉其中的空格、注释,就形成了我在JAVA语言规范学习笔记(2)中提到的tokens,然后利用这些tokens做语法分析。

Lexical Translations的实现里,首先就必须识别出转义字符,以后我就称它Unicode Escapes,它是用/u后面紧接着是XXXXUTF-16的十六进制值表示的,将它转化为对应的UTF-16 unicode 字符。而描述那些辅助字符的时候,就需要两个转义符。使用我在JAVA语言规范学习笔记(2)学到的表示形式,那么这一步的转化就可以这样来表示:

UnicodeInputCharacter:
        UnicodeEscape
        RawInputCharacter
UnicodeEscape:
        / UnicodeMarker HexDigit HexDigit HexDigit HexDigit
UnicodeMarker:
        u
        UnicodeMarker u
RawInputCharacter:

        any Unicode character

HexDigit: one of

        0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F

在这里,/uXXXX,这些都是ASCII码字符。在这个处理过程中,它会考察“/”后面还有多少“/”。XXXX只能为偶数不可以为奇数。比如“//u2297-/2297”这种情况会怎样处理?它处理后会变成“//u2297-”。一个合法的转义字符“/”后面紧接着一个或多个“u”,但是最后一个“u”后面却没有“XXXX”,编译时就会报错。

再看一个“/u005cu005a”,因为“005c”的值是“/”,那么它就变成“/u005a”,而转化后的后续字符串不会再来一次转义的转化了。

JAVA语言中也详细描述了如何将一个用unicode character编写的程序转化为一个用ASCII码字符的程序,这样就方便使用ASCII码字符的工具来处理它。如果你的系统里没有相应的字符,那么实现里就会用“/uXXXX”这种形式来代替。其实,这个里面涉及到的还和一些JAVA的编译法则有关,我们不必去深究编译上到底如何实现,只是利用这些编译上的法则或者说方法来学习JAVA语言的技术细节。

实现下一步通过line terminators来给程序的unicode character形式来分行。line terminators是由JAVA编译器或其他系统组件来处理的。在注释里用“//”的形式来表现的。

LineTerminator:
        the ASCII LF character, also known as "newline"
        the ASCII CR character, also known as "return"
   the ASCII CR character followed by the ASCII LF character

InputCharacter:
        UnicodeInputCharacter but not CR or LF

这就是我们开始将到的第二步所处理得到的结果

经过第一步和第二步的处理,我们得到了input characterline terminators,开始第三步的处理了。要将它们变成input element,就是没有空格、注释,只有语法分析才能接受的terminal symbols,叫做tokens。这个过程是这样表示的。


在原始的输入流中,如果“x”是在“y”之前的,在这里我们称作,“x”是在“y”的左边;而“y”是在“x”的右边。因为在输入流中所有的换行符已经被替换为unicode characters了。
而在上面的定义里White Space包括:ASCII码的空格、水平制表符、换页符合换行符。
WhiteSpace:
        the ASCII SP character, also known as "space"
        the ASCII HT character, also known as "horizontal tab"
        the ASCII FF character, also known as "form feed"
        LineTerminator
再来看注释的定义:
Comment:
       
TraditionalComment
        EndOfLineComment
TraditionalComment:
        / * CommentTail
EndOfLineComment:
        / / CharactersInLineopt
CommentTail:
       
* CommentTailStar
        NotStar CommentTail
CommentTailStar:
       
/
        * CommentTailStar
        NotStarNotSlash CommentTail
NotStar:
       
InputCharacter but not *
        LineTerminator
NotStarNotSlash:
       
InputCharacter but not * or /
        LineTerminator
CharactersInLine:
       
InputCharacter
        CharactersInLine InputCharacter
还要注意一点,注释是不会内嵌的。
 
标识符,必须由Java LettersJava Digit组成,不限长度,但开头的必须是Java Letters,它不能是关键字、boolean常量、null常量。定义如下:
Identifier:
        IdentifierChars but not a Keyword or BooleanLiteral or NullLiteral
IdentifierChars:
        JavaLetter
        IdentifierChars JavaLetterOrDigit
JavaLetter:
        any Unicode character that is a Java letter
JavaLetterOrDigit:
        any Unicode character that is a Java letter-or-digit
只要是unicode characters中的字符都可以,甚至如中文、韩文、日文都可以用来做标识符。不信?你可以在你的系统上试试。你可以用Character.isJavaIdentifierStart(int)方法来判断这个字符是否为Java Letters,用Character.isJavaIdentifierPart(int)来判断这个字符是否为Java LettersJava Digits。如果是,就返回true,否则返回falseJava Letters包括ASCII码中的拉丁字母A-Za-z,由于历史上的原因,下划线_$也是。Java Digits则是ASCII码中的数字0-9。两个标识符相等时,那么它们中的字母和数字所对应的unicode也必须相等。
关键字,这个不必多讲。中间有两个需要提及,constgoto这两个是JAVA中的保留字。
常量的定义:
Literal:
        IntegerLiteral
        FloatingPointLiteral
        BooleanLiteral
        CharacterLiteral
        StringLiteral
        NullLiteral
首先来看IntegerLiteral,可以用十进制、十六进制、八进制三种形式
IntegerLiteral:
        DecimalIntegerLiteral
        HexIntegerLiteral      
        OctalIntegerLiteral
DecimalIntegerLiteral:
        DecimalNumeral IntegerTypeSuffixopt
HexIntegerLiteral:
        HexNumeral IntegerTypeSuffixopt
OctalIntegerLiteral:   
        OctalNumeral IntegerTypeSuffixopt
IntegerTypeSuffix: one of
        l L
Long型的常量后面要加上ASCII码字符的lL来表示,建议用L,以免和1混淆。
十进制的常量是用ASCII码字符的0~9来表示的,其语法定义如下:
DecimalNumeral:
        0
        NonZeroDigit Digitsopt
Digits:
        Digit
        Digits Digit
Digit:
        0
        NonZeroDigit
NonZeroDigit: one of
        1 2 3 4 5 6 7 8 9
十六进制则是用0x或者0X作为前缀,后面是ASCII码字符中数字的0~9和字母的A~Za~z来表示,定义如下:
HexNumeral:
        0 x HexDigits
        0 X HexDigits
HexDigits:
        HexDigit
        HexDigit HexDigits
HexDigit: one of
        0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F
八进制的表示是用0作为前缀,后面是ASCII码字符中数字的0~7来表示,定义如下:
OctalNumeral:
        0 OctalDigits
OctalDigits:
        OctalDigit
        OctalDigit OctalDigits
OctalDigit: one of
        0 1 2 3 4 5 6 7
每一种整形的常量都有其表示数的范围,如果你使用整型常量赋值时,如果超出了它的范围,那么在编译时就会报错。
浮点型常量是由一个整型部分、一个小数点、一个小数部分、一个指数部分和一个类型的后缀表示的。如果是用十进制的形式来表示,如果有指数部分,那么是在数字后面用一个“e”或者“E”加上一个带符号的数字来表示。而用十六进制表是时,如果有指数部分,那么是在数字后面用一个“p”或者“P”加上一个带符号的数字来表示。
如果浮点类型是float时,那么后缀为ASCII码字符fF;如果浮点类型是double时,那么后缀为ASCII码字符dD。定义如下:
FloatingPointLiteral:
        DecimalFloatingPointLiteral
        HexadecimalFloatingPointLiteral
DecimalFloatingPointLiteral:
        Digits . Digitsopt ExponentPartopt FloatTypeSuffixopt
      . Digits ExponentPartopt FloatTypeSuffixopt
      Digits ExponentPart FloatTypeSuffixopt
        Digits ExponentPartopt FloatTypeSuffix
ExponentPart:
        ExponentIndicator SignedInteger
ExponentIndicator: one of
        e E
SignedInteger:
        Signopt Digits
Sign: one of
        + -
FloatTypeSuffix: one of
        f F d D
HexadecimalFloatingPointLiteral:
        HexSignificand BinaryExponent FloatTypeSuffixopt
HexSignificand:
        HexNumeral
        HexNumeral .
        0x HexDigitsopt . HexDigits
        0X HexDigitsopt . HexDigits
BinaryExponent:
        BinaryExponentIndicator SignedInteger
BinaryExponentIndicator:one of
        p P
无论是floatdouble类型,它们分别用IEEE 754标准中的32-bit64-bit二进制格式来表示的。从unicode字符串转化为浮点类型时,使用的是FloatDouble这两个类的valueOf()方法,这两个类在java.lang.*这个package里。
同样,浮点类型也是有范围的,如果你使用时超出了它们的范围时,编译器也会报错的。那么如果你想在你的程序里表示无限大,但又不想让编译器报错,那可以使用FloatDouble这两个类的POSITIVE_INFINITYNEGATIVE_INFINITY这两个常量来表示。FloatDouble这两个类还有一个预定义的常量NaN,它表示这不是一个数字。
 
Boolean Literals
boolean类型只有两个常量形式,truefalse。定义如下:
BooleanLiteral: one of
        true false
 
Character Literals
字符常量可以用来表示字符或者转义字符,用一对单引号表示‘’。定义形式如下:
CharacterLiteral:
        ' SingleCharacter '
        ' EscapeSequence '
SingleCharacter:
        InputCharacter but not ' or /
如果字符常量SingleCharacterEscapeSequence不是以’结尾,那么编译时就会报错;如果行终结符出现在字符常量中的‘之后和’之前,那么编译时就会报错。
 
String Literals
字符串常量则是由一个或多个字符组成,用“”来表示。其定义如下:
StringLiteral:
        " StringCharactersopt "
StringCharacters:
        StringCharacter
        StringCharacters StringCharacter
StringCharacter:
        InputCharacter but not " or /
        EscapeSequence
由于unicode的转义在第一步中就完成了,所以在字符串中出现:“/u000a”在第一步中就完成和换行符第二步中也完成了的,是不正确的。但是我们可以用另外的一种形式来代替,比如换行“/n”,回车“/r”。字符串是不变的。
 
Escape Sequences for Character and String Literals
下面定义的是一些可以在字符常量和字符串常量中使用的转义字符:
EscapeSequence:
        / b                     /* /u0008: backspace BS                   */
        / t                     /* /u0009: horizontal tab HT              */
        / n                     /* /u000a: linefeed LF                    */
        / f                     /* /u000c: form feed FF           */
        / r                     /* /u000d: carriage return CR             */
        / "                     /* /u0022: double quote "             */
        / '                     /* /u0027: single quote '          */
        / /                     /* /u005c: backslash /                     */
        OctalEscape               /* /u0000 to /u00ff: from octal value   */
OctalEscape:
        / OctalDigit
        / OctalDigit OctalDigit
        / ZeroToThree OctalDigit OctalDigit
OctalDigit: one of
        0 1 2 3 4 5 6 7
ZeroToThree: one of
        0 1 2 3
如果在使用时不是按上述的形式来写,编译时就会报错。
 
The Null Literal
这个定义很简单:
NullLiteral:
        null
 
Separators
分隔符的定义:
Separator: one of
        (       )       {       }       [       ]       ;       ,       .
 
Operators
37个运算符的定义:
Operator: one of
        =       >    <    !       ~       ?       :
        ==      <=   >=   !=      &&      ||      ++      --
        +       -       *       /       &   |       ^       %       <<        >>        >>>
        +=      -=      *=      /=      &=  |=      ^=      %=      <<=       >>=       >>>=
 
至此,JAVA中的词汇结构就到这里给出了一个全貌。

你可能感兴趣的