1. 程式人生 > >[Scala 基礎]-- 詞彙語法

[Scala 基礎]-- 詞彙語法

英文原文:https://www.scala-lang.org/files/archive/spec/2.11/01-lexical-syntax.html#integer-literals

詞法語法

Scala程式使用Unicode Basic Multilingual Plane(BMP)字符集編寫; 目前不支援Unicode補充字元。本章定義了Scala的詞法語法的兩種模式,即Scala模式和XML模式。如果沒有另外提及,Scala令牌的以下描述引用Scala模式,文字字元'c'引用ASCII片段 \u0000\u007F

在Scala模式下,Unicode轉義符由具有給定十六進位制程式碼的相應Unicode字元替換。

UnicodeEscape ::= ‘\’ ‘u’ {‘u’} hexDigit hexDigit hexDigit hexDigit
hexDigit      ::= ‘0’ | … | ‘9’ | ‘A’ | … | ‘F’ | ‘a’ | … | ‘f’

要構造標記,根據以下類別區分字元(括號中給出的Unicode常規類別):

  1. 空白字元。\u0020 | \u0009 | \u000D | \u000A
  2. 信,包括小寫字母(Ll),大寫字母(Lu),首字母大寫字母(Lt),其他字母(Lo),字母數字(Nl)和兩個字元\u0024 ‘$’\u005F ‘_’,這既算作大寫字母。
  3. 數字‘0’ | … | ‘9’
  4. 括號‘(’ | ‘)’ | ‘[’ | ‘]’ | ‘{’ | ‘}’
  5. 分隔符字元‘`’ | ‘'’ | ‘"’ | ‘.’ | ‘;’ | ‘,’
  6. 操作員角色。它們由所有可列印的ASCII字元組成 \u0020\u007F它們不在上面的集合中,數學符號(Sm)和其他符號(So)。

身份標識

op       ::=  opchar {opchar}
varid    ::=  lower idrest
plainid  ::=  upper idrest
           |  varid
           |  op
id       ::=  plainid
           |  ‘`’ stringLiteral ‘`’
idrest   ::=  {letter | digit} [‘_’ op]

有三種方法可以形成識別符號。首先,識別符號可以以字母開頭,後面可以是任意字母和數字序列。其後可以是下劃線‘_‘ 字元和由字母和數字或運算子字元組成的另一個字串。其次,識別符號可以以操作符字元開頭,後跟任意操作符字元序列。前兩種形式稱為普通識別符號。最後,識別符號也可以由後引號之間的任意字串形成(主機系統可以對哪些字串對於標識符合法施加一些限制)。然後,識別符號由除反引號本身之外的所有字元組成。

像往常一樣,適用最長匹配規則。例如,字串

big_bob++=`def`

分解為三個識別符號big_bob++=和 def。模式匹配的規則進一步區分 變數識別符號常量識別符號變數識別符號以小寫字母開頭,而 常量識別符號則不是。

' $ '字元保留用於編譯器合成的識別符號。使用者程式不應定義包含' $ '字元的識別符號。

以下名稱是保留字,而不是id詞法識別符號的語法類的成員。

abstract    case        catch       class       def
do          else        extends     false       final
finally     for         forSome     if          implicit
import      lazy        macro       match       new
null        object      override    package     private
protected   return      sealed      super       this
throw       trait       try         true        type
val         var         while       with        yield
_    :    =    =>    <-    <:    <%     >:    #    @

Unicode的運營商\u21D2“ ⇒⇒'和\u2190' ←←”,其中具有ASCII當量=><-,也是保留。

以下是識別符號的示例:

    x         Object        maxIndex   p2p      empty_?
    +         `yield`       αρετη     _y       dot_product_*
    __system  _MAX_LEN_

當需要訪問Scala中保留字的Java識別符號時,請使用反引號括起的字串。例如,該語句Thread.yield()是非法的,因為它yield是Scala中的保留字。但是,這是一個解決方法:Thread.`yield`()

換行符

semi ::= ‘;’ |  nl {nl}

Scala是一種面向行的語言,語句可以用分號或換行符終止。如果滿足以下三個條件,則Scala源文字中的換行符將被視為特殊標記“nl”:

  1. 緊接在換行符之前的令牌可以終止語句。
  2. 緊接在換行符之後的令牌可以開始宣告。
  3. 令牌顯示在啟用換行符的區域中。

可以終止語句的標記是:文字,識別符號和以下分隔符和保留字:

this    null    true    false    return    type    <xml-start>
_       )       ]       }

可以開始宣告的標記都是Scala標記, 以下分隔符和保留字除外

catch    else    extends    finally    forSome    match
with    yield    ,    .    ;    :    =    =>    <-    <:    <%
>:    #    [    )    ]    }

一個case令牌可以開始只有當後跟一個宣告 classobject標記。

在以下位置啟用換行符:

  1. 所有Scala原始檔,除了禁用換行的巢狀區域,以及
  2. 匹配{}大括號標記之間的間隔,但禁用換行符的巢狀區域除外。

新線被禁用:

  1. 匹配()括號標記之間的間隔,除了啟用換行的巢狀區域,和
  2. 匹配[]括號標記之間的間隔,但啟用了換行符的巢狀區域除外。
  3. case令牌與其匹配 =>令牌之間的間隔,但啟用了換行符的巢狀區域除外。
  4. XML模式下分析的任何區域。

請注意,{...}XML和字串文字中轉義的大括號字元不是標記,因此不會包含啟用換行符的區域。

通常,nl即使兩個令牌之間存在多條線,也只在一個位於不同線路上的兩個連續非換行令牌之間插入一個令牌。但是,如果兩個令牌被至少一個完全空行(即不包含可列印字元的行)分開,則nl插入兩個令牌。

Scala語法(在這裡完整給出)包含可選nl令牌但不接受分號的產品。這導致其中一個位置的換行不終止表示式或語句。這些職位可歸納如下:

在以下位置接受多個換行符令(請注意,在每種情況下,用分號代替換行符都是非法的):

接受單個新行令牌

  • 在開口括號'{'前面,如果該括號是當前陳述或表達的合法延續,
  • 在中綴運算子之後,如果下一行的第一個標記可以啟動表示式,
  • 引數子句前面,和
  • 註釋之後

兩行之間的換行符不被視為語句分隔符。

if (x > 0)
  x = x - 1

while (x > 0)
  x = x / 2

for (x <- 1 to 10)
  println(x)

type
  IntList = List[Int]
new Iterator[Int]
{
  private var x = 0
  def hasNext = true
  def next = { x += 1; x }
}

使用其他換行符時,相同的程式碼將被解釋為物件建立,後跟本地塊:

new Iterator[Int]

{
  private var x = 0
  def hasNext = true
  def next = { x += 1; x }
}
  x < 0 ||
  x > 10

使用額外的換行符,相同的程式碼將被解釋為兩個表示式:

  x < 0 ||

  x > 10
def func(x: Int)
        (y: Int) = x + y

使用額外的換行符,相同的程式碼被解釋為抽象函式定義和語法上的非法語句:

def func(x: Int)

        (y: Int) = x + y
@serializable
protected class Data { ... }

使用額外的換行符時,相同的程式碼將被解釋為屬性和單獨的語句(在語法上是非法的)。

@serializable

protected class Data { ... }

字面

有整數,浮點數,字元,布林值,符號,字串的文字。這些文字的語法在每種情況下都與Java一樣。

Literal  ::=  [‘-’] integerLiteral
           |  [‘-’] floatingPointLiteral
           |  booleanLiteral
           |  characterLiteral
           |  stringLiteral
           |  symbolLiteral
           |  ‘null’

整數文字

integerLiteral  ::=  (decimalNumeral | hexNumeral)
                       [‘L’ | ‘l’]
decimalNumeral  ::=  ‘0’ | nonZeroDigit {digit}
hexNumeral      ::=  ‘0’ (‘x’ | ‘X’) hexDigit {hexDigit}
digit           ::=  ‘0’ | nonZeroDigit
nonZeroDigit    ::=  ‘1’ | … | ‘9’

整數文字通常是型別Int,或者Long後跟一個L或 l字尾的型別 。型別的值Int都是-2之間的整數31- 231和231- 1231- 1, 包括的。型別的值Long都是-2之間的整數63- 263和 263- 1263- 1, 包括的。如果整數文字表示超出這些範圍的數字,則會發生編譯時錯誤。

然而,如果期望的型別PT在表達一個字面的或者是ByteShort,或Char 與整數在由型別所定義的數值範圍配合,則數字被轉換成鍵入PT和文字的型別是。這些型別給出的數值範圍是:

   
Byte - 27- 27到27- 127- 1
Short - 215- 215到215- 1215- 1
Char 00到216- 1216- 1
0          21          0xFFFFFFFF       -42L

浮點文字

floatingPointLiteral  ::=  digit {digit} ‘.’ digit {digit} [exponentPart] [floatType]
                        |  ‘.’ digit {digit} [exponentPart] [floatType]
                        |  digit {digit} exponentPart [floatType]
                        |  digit {digit} [exponentPart] floatType
exponentPart          ::=  (‘E’ | ‘e’) [‘+’ | ‘-’] digit {digit}
floatType             ::=  ‘F’ | ‘f’ | ‘D’ | ‘d’

浮點文字是型別的Float,隨後當由浮點型別字尾Ff,並且是型別的Double說明。該型別Float 包括所有IEEE 754 32位單精度二進位制浮點值,而該型別Double包含所有IEEE 754 64位雙精度二進位制浮點值。

如果程式中的浮點字面值後跟一個以字母開頭的標記,則兩個標記之間必須至少有一個插入的空白字元。

0.0        1e30f      3.14159f      1.0e-100      .1

該短語1.toString分析為三個不同的標記:整數文字1,a .和識別符號toString

1.不是有效的浮點文字,因為.缺少後的強制數字。

布林文字

booleanLiteral  ::=  ‘true’ | ‘false’

布林文字truefalse型別的成員Boolean

字元文字

characterLiteral  ::=  ‘'’ (printableChar | charEscapeSeq) ‘'’

字元文字是用引號括起來的單個字元。該字元是可列印的unicode字元或由轉義序列描述。

'a'    '\u0041'    '\n'    '\t'

請注意,'\u000A'不是一個有效的字元文字,因為Unicode轉換完成之前字面解析和Unicode字元\u000A(換行)不是一個可列印字元。可以使用轉義序列'\n'或八進位制轉義'\12'參見此處)。

字串文字

stringLiteral  ::=  ‘"’ {stringElement} ‘"’
stringElement  ::=  printableCharNoDoubleQuote  |  charEscapeSeq

字串文字是雙引號中的字元序列。字元是可列印的unicode字元或由轉義序列描述 。如果字串文字包含雙引號字元,則必須對其進行轉義,即"\""。字串文字的值是類的例項String

"Hello,\nWorld!"
"This string contains a \" character."

多行字串文字

stringLiteral   ::=  ‘"""’ multiLineChars ‘"""’
multiLineChars  ::=  {[‘"’] [‘"’] charNoDoubleQuote} {‘"’}

多行字串文字是用三引號括起來的字元序列""" ... """。字元序列是任意的,除了它可能只在最後包含三個或更多連續引號字元。字元不一定是可列印的; 也允許換行或其他控制字元。Unicode轉義符可以像其他地方一樣工作,但這裡沒有解釋轉義序列。

  """the present string
     spans three
     lines."""

這會產生字串:

the present string
     spans three
     lines.

Scala庫包含一個實用程式方法stripMargin ,可用於從多行字串中去除前導空格。表達方式

 """the present string
   |spans three
   |lines.""".stripMargin

評估為

the present string
spans three
lines.

方法stripMargin在類scala.collection.immutable.StringLike中定義 。因為有一個預定義的 隱式轉換String到 StringLike,該方法適用於所有的字串。

轉義序列

在字元和字串文字中可識別以下轉義序列。

charEscapeSeq 統一 名稱 燒焦
‘\‘ ‘b‘ \u0008 退格 BS
‘\‘ ‘t‘ \u0009 水平標籤 HT
‘\‘ ‘n‘ \u000a 換行 LF
‘\‘ ‘f‘ \u000c 形式飼料 FF
‘\‘ ‘r‘ \u000d 回車 CR
‘\‘ ‘"‘ \u0022 雙引號 "
‘\‘ ‘'‘ \u0027 單引號 '
‘\‘ ‘\‘ \u005c 反斜線 \

Unicode在0到255之間的字元也可以用八進位制轉義表示,即反斜槓'\'後跟最多三個八進位制字元的序列。

如果字元或字串文字中的反斜槓字元未啟動有效的轉義序列,則為編譯時錯誤。

符號文字

symbolLiteral  ::=  ‘'’ plainid

符號文字'x是表示式的簡寫 scala.Symbol("x")Symbol是一個案例類,定義如下。

package scala
final case class Symbol private (name: String) {
  override def toString: String = "'" + name
}

伴隨物件的apply方法Symbol快取對Symbols的弱引用,從而確保相同的符號文字在引用相等方面是等價的。

空白和評論

標記可以用空格字元和/或註釋分隔。評論有兩種形式:

單行註釋是一系列字元,以行開頭 //並延伸到行尾。

多行註釋是/*和之間的一系列字元 */。多行註釋可以巢狀,但需要正確巢狀。因此,類似的評論 /* /* */將被拒絕為具有未終止的評論。

XML模式

為了允許文字包含XML片段,在下列情況下遇到開放尖括號“<”時,詞法分析從Scala模式切換到XML模式:'<'必須在空格,左括號或開頭之前大括號後面緊跟一個開始XML名稱的字元。

 ( whitespace | ‘(’ | ‘{’ ) ‘<’ (XNameStart | ‘!’ | ‘?’)

  XNameStart ::= ‘_’ | BaseChar | Ideographic // as in W3C XML, but without ‘:’

如果有的話,掃描器從XML模式切換到Scala模式

  • 由初始“<”啟動的XML表示式或XML模式已成功解析,或者是否已成功解析
  • 解析器遇到嵌入的Scala表示式或模式,並強制掃描程式返回正常模式,直到成功解析Scala表示式或模式。在這種情況下,由於程式碼和XML片段可以巢狀,因此解析器必須維護一個堆疊,以充分反映XML和Scala表示式的巢狀。

請注意,沒有Scala令牌在XML模式下構造,並且註釋被解釋為文字。

以下值定義使用帶有兩個嵌入式Scala表示式的XML文字:

val b = <book>
          <title>The Scala Language Specification</title>
          <version>{scalaBook.version}</version>
          <authors>{scalaBook.authors.mkList("", ", ", "")}</authors>
        </book>