词法结构

Swift 的 词法结构 描述了怎么样的语言字符序列才能形成有效标记。这些有效标来自底层的语言构建块,用来描述随后章节里的其它语言。一个标记由标识符,关键字,标点符号,文字或者运算符组成。

在大部分情况下,标记是通过输入文本中最长可能输入的子句来从 Swift 源文件的特征中生成。这种行为参考自 最长匹配 或者 最大匹配


空白和注释

空白有两个用处:在源文件中分隔标记以及帮助决定运算符是前缀还是后缀 (参见 运算符), 但是在其它情况下会被忽略。以下的字符会被认为是空白:空格 (U+0020), 换行符 (U+000A), 回车 (U+000D), 水平制表符 (U+0009), 垂直制表符 (U+000B), 换页 (U+000C) 和空白 (U+0000).

注释被编译器当作空白处理。单行注释由 // 开始直至遇到换行符(U+000A)或者回车符(U+000D)。多行注释由 */ 开始,以  /* 结束。注释允许嵌套,但注释标记必须匹配。

注释可以包含附加的格式和标记,如 Markup Formatting Reference.

空白语法

空白  → 空白项 whitespace opt

空白项  → 断行符

空白项  → 注释

空白项  → 多行注释

空白项  →U+0000, U+0009, U+000B, U+000C, 或 U+0020

断行符  → U+000A

断行符  → U+000D

断行符  → U+000D followed by U+000A

注释  → // 注释文本 断行符

多行注释 → /* 多行注释文本 */

注释文本  → 注释文本项 注释文本 opt

注释文本项  → Any Unicode scalar value except U+000A 或 U+000D

多行注释文本  → 多行注释文本项 多行注释文本 opt

多行注释文本项  → 多行注释

多行注释文本项  → 注释文本项

多行注释文本项  → Any Unicode scalar value except /* 或 */


标识符

标识符 Identifiers  可以由以下的字符开始:大写或小写的字母 A 到 Z、下划线 (_) 、基本多文种平面(Basic Multilingual Plane)中非字符数字组合的 Unicode 字符以及基本多文种平面以外的非个人专用区字符。在首字符之后,允许使用数字和组合 Unicode 字符。

使用保留字作为标识符,需要在其前后增加反引号 (`)。例如,class 不是合法的标识符,但可以使用 class 。反引号不属于标识符的一部分,x 和 x表示同一标识符。

闭包中如果没有明确指定参数名称,参数将被隐式命名为  $0$1$2 等等。这些命名在闭包作用域范围内是合法的标识符。

标识符语法

标识符  → 头部标识符标识符字符组 opt

标识符  → ` 头部标识符 标识符字符组 opt `

标识符  → 隐式参数名称

标识符列表  → 标识符标识符 , 标识符列表

头部标识符  →Upper- or lowercase letter A through Z

头部标识符  → _

头部标识符  →U+00A8, U+00AA, U+00AD, U+00AF, U+00B2--U+00B5, 或 U+00B7--U+00BA

头部标识符  →U+00BC--U+00BE, U+00C0--U+00D6, U+00D8--U+00F6, 或 U+00F8--U+00FF

头部标识符  →U+0100--U+02FF, U+0370--U+167F, U+1681--U+180D, 或 U+180F--U+1DBF

头部标识符  →U+1E00--U+1FFF

头部标识符  →U+200B--U+200D, U+202A--U+202E, U+203F--U+2040, U+2054, 或 U+2060--U+206F

头部标识符  →U+2070--U+20CF, U+2100--U+218F, U+2460--U+24FF, 或 U+2776--U+2793

头部标识符  →U+2C00--U+2DFF 或 U+2E80--U+2FFF

头部标识符  →U+3004--U+3007, U+3021--U+302F, U+3031--U+303F, 或 U+3040--U+D7FF

头部标识符  →U+F900--U+FD3D, U+FD40--U+FDCF, U+FDF0--U+FE1F, or U+FE30--U+FE44

头部标识符  →U+FE47--U+FFFD

头部标识符  →U+10000--U+1FFFD, U+20000--U+2FFFD, U+30000--U+3FFFD, 或 U+40000--U+4FFFD

头部标识符  →U+50000--U+5FFFD, U+60000--U+6FFFD, U+70000--U+7FFFD, 或 U+80000--U+8FFFD

头部标识符  →U+90000--U+9FFFD, U+A0000--U+AFFFD, U+B0000--U+BFFFD, 或 U+C0000--U+CFFFD

头部标识符  →U+D0000--U+DFFFD 或 U+E0000--U+EFFFD

标识符字符组  → 数值 0 - 9

标识符字符组  → U+0300--U+036F, U+1DC0--U+1DFF, U+20D0--U+20FF, 或 U+FE20--U+FE2F

标识符字符组  → 头部标识符

标识符字符组  → 标识符字符组 标识符字符组 opt

隐式参数名称  → $ 十进制数字


关键字和标点符号

下面这些被保留的关键字不允许用作标识符,除非使用反引号转义,具体描述请参考 标识符。除了 inoutvar 以及 let 之外的关键字可以用作某个函数声明或者函数调用当中的外部参数名,不用添加反引号转义。
当一个成员与关键字具有相同的名称时,对该成员的引用不需要用反勾来转义,除非在引用该成员和使用关键字——例如 selfType 和  Protocol  ——之间有歧义,在显式成员表达中具有特殊含义。n,所以必须在上下文中用后退来逃跑。

  • 用在声明中的关键字:associatedtypeclassdeinitenumextensionfileprivatefuncimportinitinoutinternalletopenoperatorprivateprotocolpublicstaticstructsubscripttypealias, 以及 var.

  • 用在语句中的关键字: breakcasecontinuedefaultdeferdoelsefallthroughforguardifinrepeatreturnswitchwhere, 和 while.

  • 用在表达式和类型中的关键字: asAnycatchfalseisnilrethrowssuperselfSelfthrowthrowstrue, 以及 try.

  • 用在模式中的关键字: _.

  • 以井字号 (#) 开头的关键字 #available#colorLiteral#column#else#elseif#endif#error#file#fileLiteral#function#if#imageLiteral#line#selector#sourceLocation, 以及 #warning.

  • 特定上下文中被保留的关键字: associativityconveniencedynamicdidSetfinalgetinfixindirectlazyleftmutatingnonenonmutatingoptionaloverridepostfixprecedenceprefixProtocolrequiredrightsetTypeunownedweak, 以及 willSet。这些关键字在特定上下文之外可以被用做标识符。

以下符号被当作保留符号,不能用于自定义运算符: (){}[].,:;=@#&(作为前缀运算符)、->、`、?、!(作为后缀运算符)。


字面量

字面量 literal  用来表示源码中某种特定类型的值,比如一个数字或字符串。

下面是字面量的一些示例:

42              // 整数字面量
3.14159         // 浮点数字面量
"Hello, world!" // 字符串字面量
true            // 布尔值字面量

字面量本身并不包含类型信息。事实上,一个字面量会被解析为拥有无限的精度,然后 Swift 的类型推导会尝试去推导出这个字面量的类型。比如,在 let x: Int8 = 42 这个声明中,Swift 使用了显式类型标注 (: Int8) 来推导出 42 这个整数字面量的类型是 : Int8 。如果没有可用的类型信息, Swift 则会从标准库中定义的字面量类型中推导出一个默认的类型。整数字面量的默认类型是 Int ,浮点数字面量的默认类型是 Double ,字符串字面量的默认类型是  String,布尔值字面量的默认类型是 Bool 。比如,在  let str = "Hello, world" 这个声明中,字符串  "Hello, world" 的默认推导类型就是 String

当为一个字面量值指定了类型标注的时候,这个标注的类型必须能通过这个字面量值实例化。也就是说,这个类型必须符合这些 Swift 标准库协议中的一个:整数字面量的 ExpressibleByIntegerLiteral 协议、浮点数字面量的 ExpressibleByFloatLiteral 协议、字符串字面量的 ExpressibleByStringLiteral 协议以及布尔值字面量的 ExpressibleByBooleanLiteral 协议。比如,Int8 符合  ExpressibleByUnicodeScalarLiteral 协议,对于仅包含单个扩展字形组的字符串文本。例如,Int8 符合 ExpressibleByIntegerLiteral 协议,因此它能在 let x: Int8 = 42 这个声明中作为整数字面量42 的类型标注。

字面量语法

字面量  → 数值字面量 | 字符串字面量 | 布尔字面量 |  nil 字面量

数值字面量  → -opt 整数字面量 | -opt 浮点数字面量

布尔字面量  → truefalse

nil 字面量  → nil

整数字面量

整数字面量 Integer literals  表示未指定精度整数的值。整数字面量默认用十进制表示,可以加前缀来指定其他的进制。二进制字面量加  0b,八进制字面量加 0o,十六进制字面量加 0x

十进制字面量包含数字 0 至 9。二进制字面量只包含 0 或 1,八进制字面量包含数字 0 至 7,十六进制字面量包含数字  0 至 9  以及字母 A至  F(大小写均可)。

负整数的字面量在整数字面量前加负号 (-) ,比如 -42

整型字面面可以使用下划线 (_) 来增加数字的可读性,下划线会被系统忽略,因此不会影响字面量的值。同样地,也可以在数字前加 (0),这同样也会被系统所忽略,并不会影响字面量的值。

除非特别指定,整数字面量的默认推导类型为 Swift 标准库类型中的  Int。Swift 标准库还定义了其他不同长度以及是否带符号的整数类型,请参考 整数

整数字面量语法

整数字面量  → 二进制字面量

整数字面量  → 八进制字面量

整数字面量  → 十进制字面量

整数字面量  → 十六进制字面量

二进制字面量  → 0b二进制数字 二进制字面量字符组 opt

二进制字面量  → 数值 0 或 1

二进制字面量字符组  → 二进制数字 | _

二进制字面量字符组  → 二进制字面量字符组 二进制字面量字符组opt

八进制字面量  → 0o 八进制数字 八进制字面量字符组 opt

八进制数字  → 数值 0 到 7

八进制字面量字符组  → 八进制数字 | _

八进制字面量字符组  → 八进制字面量字符组 八进制字面量字符组opt

十进制字面量  → 十进制数字 十进制字面量字符组 opt

十进制数字  → Digit 0 through 9

十进制数字  → 十进制数字 十进制数字 opt

十进制字面量字符组  → 十进制数字 | _

十进制字面量字符组  → 十进制字面量字符组 十进制字面量字符组opt

十六进制字面量 → 0x 十六进制数字 十六进制字面量字符组 opt

十六进制数字  →数值 0 到 9, 字母 a 到 f, 或 A 到 F

十六进制字面量字符组  → 十六进制数字 | _

十六进制字面量字符组  → 十六进制字面量字符组 十六进制字面量字符组 opt

浮点数字面量

浮点数字面量 Floating-point literals  表示未指定精度浮点数的值。

浮点数字面量默认用十进制表示(无前缀),也可以用十六进制表示(加前缀 0x)。

十进制浮点数字面量由十进制数字串后跟小数部分或指数部分(或两者皆有)组成。十进制小数部分由小数点 (.) 后跟十进制数字串组成。指数部分由大写或小写字母 e 为前缀后跟十进制数字串组成,这串数字表示 e 之前的数量乘以 10 的几次方。例如:1.25e2 表示 1.25 x 10^2^,也就是 125.0 ;同样,1.25e-2 表示 1.25 x 10^-2^,也就是 0.0125

十六进制浮点数字面量由前缀  0x 后跟可选的十六进制小数部分以及十六进制指数部分组成。十六进制小数部分由小数点后跟十六进制数字串组成。指数部分由大写或小写字母 p 为前缀后跟十进制数字串组成,这串数字表示  p 之前的数量乘以 2 的几次方。例如:0xFp2 表示 15 x 2^2^,也就是 60 ;同样,0xFp-2 表示 15 x 2^-2^,也就是 3.75

负数的浮点数字面量由负号 (-) 和浮点数字面量组成,例如 -42.5

浮点数字面量允许使用下划线 (_) 来增强数字的可读性,下划线会被系统忽略,因此不会影响字面量的值。同样地,也可以在数字前加 (0) ,并不会影响字面量的值。

除非特别指定,浮点数字面量的默认推导类型为 Swift 标准库类型中的  Double,表示 64 位浮点数。Swift 标准库也定义了 Float 类型,表示 32 位浮点数。

浮点数字面量语法

浮点数字面量  → 十进制字面量 十进制分数 opt 十进制指数 opt

浮点数字面量  → 十六进制字面量 十六进制分数 opt 十六进制指数

十进制分数  → . 十进制字面量

十进制指数 → 浮点数 e 签名 opt 十进制字面量

十六进制分数  → . 十六进制数字 十六进制字面量字符组 opt

十六进制指数  → 浮点数 p 签名 opt 十进制字面量

浮点数 e  → eE

浮点数 p  → pP

签名  → + | -

字符串字面量

字符串字面量是被引号包括的一串字符组成。 单行字符串字面量被包在双引号中的一串字符组成,形式如下:

"characters"

字符串字面量中不能包含未转义的双引号 (") 、未转义的反斜线 (\) 、回车符、换行符。

多行字符串字面量被包在三个双引号中的一串字符组成,形式如下:

"""
characters
"""

与单行字符串字面量不同的是,多行字符串字面量可以包含不转义的双引号 (") ,回车以及换行。它不能包含三个非转义的连续双引号。

 """ 之后的回车或者换行开始多行字符串字面量,不是字符串的一部分。 """ 之前回车或者换行结束字面量,也不是字符串的一部分。要让多行字符串字面量的开始或结束带有换行,就在第一行或者最后一行写一个空行。

多行字符串字面量可以使用任何空格或制表符组合进行缩进;这些缩进不会包含在字符串中。 """  的结束符号决定了缩进:字面量中的任何一个非空行必须起始于多行字符串字面量结束符号的前面;空格和制表符不会被转换。你可以包在缩进后含额外的空格和制表符;这些空格和制表符会在字符串中出现。

多行字符串字面量中的一行结束使用规范化的换行符号。尽管你的源代码混用了回车和换行符,字符串中所有的行结束都必须一样.

在多行字符串字面量里, 在行末用反斜线 (\) 可以省略字符串行间中断。 反斜线之间的空白和行间中断也可以省略。 你可以在你的代码里用这种语法硬包裹多行字符串字面量,不需要改变产生的字符串的值。

可以在字符串字面量中使用的转义特殊符号如下:

  • 空字符 (\0)
  • 反斜线 (\\)
  • 水平制表符 (\t)
  • 换行符 (\n)
  • 回车符 (\r)
  • 双引号 (\")
  • 单引号 (\')
  • Unicode 标量 (\u{n}), n 为一到八位的十六进制数字

字符串字面量允许在反斜杠 (\) 后的括号 () 中插入表达式的值。插入表达式可以包含字符串字面量,但不能包含未转义的反斜线(\)、回车符以及换行符。

例如,以下所有字符串字面量的值都是相同的:

"1 2 3"
"1 2 \("3")"
"1 2 \(3)"
"1 2 \(1 + 2)"
let x = 3; "1 2 \(x)"

字符串字面量的默认推导类型为 String 。更多有关 String 类型的信息请参考 字符串和字符 和 字符.

使用 + 运算符连接的字符型字面量是在编译时连接的。例如,在下面的例子中 textA 和 textB 的值是完全一致的---textA 没有任何运行时的连接操作。

let textA = "Hello " + "world"
let textB = "Hello world"

字符串字面量语法

字符串字面量  → 静态字符串字面量 | 插值字符串字面量

静态字符串字面量 → " 引用文本 opt "

静态字符串字面量 → """ 多行引用文本 opt """

引用文本  → 引用文本项 引用文本 opt

引用文本项  → 转义字符

引用文本项  →除了 "\, U+000A, or U+000D 外所有的 Unicode 字符

多行引用文本  → 多行引用文本项 多行引用文本 opt

多行引用文本项  → 转义字符

多行引用文本项  → 除了 \ 外的所有 Unicode 字符

多行引用文本项  → 转到新行

插值字符串字面量  → " 插值文本 opt "

插值字符串字面量  → """ 多行插值文本 opt """

插值文本  → 插值文本项 插值文本 opt

插值文本项  → \( 表达式 ) | 引用文本项

多行插值文本  → 多行插值文本项 多行插值文本 opt

多行插值文本项  → \( 表达式 ) | 多行引用文本项

转义字符 → \0 | \\ | \t | \n | \r | \" | \'

转义字符 → \u { unicode 标量数字 }

unicode 标量数字  → 一到八位的十六进制数字

转到新行  → \ 空白区 opt 换行


操作符

Swift 标准库定义了大量操作符供使用, 见讨论 基本操作符 和 高阶操作符。该章描述了哪些字符能被用来定义一些自定义操作符。

自定义操作符开始于 ASCII 字符表中字符集 /、 =、 -、 +、 !、 *、 %、 <、 >、 &、 |、 ^、 ?、 或 ~ , 或一个 Unicode 字符集中的字符 ( 数学操作符 、 混合符号装饰符 Unicode 块等)。 第一个字符后面,允许连接 Unicode 字符。

你也能定义自定义操作符用点(.)开始。 操作符也能包含点。 例如, .+. 被处理为单个操作符。 如果一个操作符不是从点(.)开始,那么它后面也不能包含点。 例如, +.+ 被处理成一个 + 操作符和一个 .+ 操作符。

鉴于这些规则,运算符前的字符 ([ 和 { ,运算符后的字符  )], 和 },以及字符 ,;, 和 : 都被视为空白。

以上规则需注意一点,如果预定义运算符 ! 或 ? 左侧没有空白,则不管右侧是否有空白都将被看作后缀运算符。如果将 ? 用作可选链式调用运算符,左侧必须无空白。如果用于条件运算符 (? :),必须两侧都有空白。

在某些特定的设计中 ,以 < 或 > 开头的运算符会被分离成两个或多个符号,剩余部分可能会以同样的方式被再次分离。因此,在  Dictionary<String, Array<Int>> 中没有必要添加空白来消除闭合字符 >  的歧义。在这个例子中, 闭合字符  > 不会被视为单独的符号,因而不会被错误解析为 >> 运算符。

要学习如何自定义运算符, 请参考 自定义运算符 和 运算符声明. 要学习如何重载运算符,请参考 运算符函数.

运算符语法

运算符  → 头部运算符运算符字符组 opt

运算符  → 头部点运算符 点运算符字符组

头部运算符  → / |= | - | + | ! | * | % | < | > | & | | | ^ | ~ | ?

头部运算符  →U+00A1--U+00A7

头部运算符  →U+00A9 或 U+00AB

头部运算符  →U+00AC 或 U+00AE

头部运算符  →U+00B0--U+00B1, U+00B6, U+00BB, U+00BF, U+00D7, 或 U+00F7

头部运算符  →U+2016--U+2017 或 U+2020--U+2027

头部运算符  →U+2030--U+203E

头部运算符  →U+2041--U+2053

头部运算符  →U+2055--U+205E

头部运算符  →U+2190--U+23FF

头部运算符  →U+2500--U+2775

operator-head  →U+2794--U+2BFF

头部运算符  →U+2E00--U+2E7F

头部运算符  →U+3001--U+3003

头部运算符  →U+3008--U+3030

运算符字符组 → 头部运算符

运算符字符组 → U+0300--U+036F

运算符字符组 → U+1DC0--U+1DFF

运算符字符组 → U+20D0--U+20FF

运算符字符组 → U+FE00--U+FE0F

运算符字符组 → U+FE20--U+FE2F

运算符字符组 → U+E0100--U+E01EF

运算符字符组  → 运算符字符组 运算符字符组 opt

头部点运算符 → .

点运算符字符组  → . | 运算符字符组

点运算符字符组  → 点运算符字符组 点运算符字符组opt

二元运算符  → 运算符

前缀运算符  → 运算符

后缀运算符  → 运算符

本文章首发在 LearnKu.com 网站上。
上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~