仓颉实战系列 - 词法结构 标识符和关键字
词法结构
本章主要介绍仓颉编程语言的词法结构,完整的词法和语法的 BNF 表示请参见附录 A。
注:为了增加文档的可读性,正文中的语法定义会和附录中的语法定义略有不同,正文中会将符号和关键字替换为它们的字面表示(而非词法结构中的名字)。
标识符和关键字
标识符可以用作变量、函数、类型、package 和 module 等等的名字。将标识符分为普通标识符和原始标识符(raw identiffer),普通标识符是除了关键字以外,由字母(大写和小写的 ASCII 编码的拉丁字母 A-Z和 a-z)或下划线(ASCII 编码的 _)开头,后接任意长度的字母、数字(ASCII 编码的数字 0-9)或下划线(ASCII 编码的 _)组合而成的字符串,原始标识符是在普通标识符的外面加上一对反引号(“..”),并且反引号内可以使用关键字。标识符的语法定义为:
identifier
: Identifier
| PUBLIC
| PRIVATE
| PROTECTED
| OVERRIDE
| ABSTRACT
| SEALED
| OPEN
| REDEF
| GET
| SET
;
Identifier
: '_'* Letter (Letter | '_' | DecimalDigit)*
| '`' '_'* Letter (Letter | '_' | DecimalDigit)* '`';
Letter
: [a-zA-Z]
2 第一章 词法结构;
DecimalDigit
: [0-9]
;
关键字是不能作为标识符使用的特殊字符串,仓颉语言的关键字如下表所示:


上下文关键字是可以作为标识符使用的特殊字符串,它们在部分语法中作为关键字存在,但也可以作为普通标识符使用。

分号和换行符
有两个符号可以表示表达式或声明的结束:分号(;)和换行符。其中,; 的含义是固定的,无论出现在什么位置都表示表达式或声明的结束,可以将多个使用 ; 分隔的表达式或声明写在同一行。但换行符的含义并不固定,根据它出现的位置不同,既可以像空格符一样作为两个 token 的分隔符,也可以像 ; 一样作为表达式或声明的结束符。
换行符可以出现在任意两个 token 之间,但除了下面列出的禁止使用换行符作为两个 token 之间的分隔符的场景、字符串字面值和多行注释之外,其他情况下,将依据 “最长匹配” 原则(尽可能地将更多的 token组成一条合法的表达式或声明)确定将换行符处理为 token 间的分隔符拟或表达式或声明的结束符。“最长”匹配结束前遇到的换行符会被处理为 token 间的分隔符,匹配结束后的换行符被处理为表达式或声明的结束符。举例如下:
let width1: Int32 = 32 // The newline character is treated as a terminator.
let length1: Int32 = 1024 // The newline character is treated as a terminator.let width2: Int32 = 32; let length2: Int32 = 1024 // The newline character is
↪ treated as a terminator.
var x = 100 + // The newline character is treated as a connector.
200 * 300 - // The newline character is treated as a connector.
50 // The newline character is treated as a terminator.
禁止使用换行符作为两个 token 之间的分隔符的场景:
一元操作符和操作数之间禁止使用换行符做分隔符;
• 调用表达式中,( 和它之前的 token 之间禁止使用换行符做分隔符;
• 索引访问表达式中,[ 和它之前的 token 之间禁止使用换行符做分隔符;
• constant pattern 中,$ 和它之后的标识符之间禁止使用换行符做分隔符;
注:上述场景只是禁止了换行符作为两个 token 之间的分隔符的功能,并不代表这些场景中不能使用换行符(如果使用了换行符,会被直接处理为表达式或声明的结束符)。
字符串字面值和多行注释也不适用于 “最长匹配” 原则:
• 对于单行字符串,当遇到第一个匹配的非转义双引号,即停止匹配;
• 对于多行字符串,当遇到第一个匹配的非转义三个双引号,即停止匹配
对于多行原始字符串,当遇到第一个匹配的非转义双引号以及和开头相同个数的井号(#),即停止匹配;
• 对于多行注释,当遇到第一个匹配的 */,即停止匹配;
字面量
字面量是一种表达式,它表示的是一个不能被修改的值。
字面量也有类型,仓颉中拥有字面量的类型包括:整数类型、浮点数类型、Rune 类型、布尔类型和字符串类型。字面量的语法为:
literalConstant
: IntegerLiteral
| FloatLiteral
| RuneLiteral
| booleanLiteral
| stringLiteral
;
stringLiteral
: lineStringLiteral
| multiLineStringLiteral
| MultiLineRawStringLiteral;
整数类型字面量
整数类型字面量有 4 种进制表示形式:二进制(使用 0b 或 0B 前缀)、八进制(使用 0o 或 0O 前缀)、十进制(没有前缀)、十六进制(使用 0x 或 0X 前缀)。同时可以加可选的后缀来指定整数类型字面量的具体类型。
整数类型字面量的语法定义为:
IntegerLiteralSuffix
: 'i8' |'i16' |'i32' |'i64' |'u8' |'u16' |'u32' | 'u64';
IntegerLiteral
: BinaryLiteral IntegerLiteralSuffix?
| OctalLiteral IntegerLiteralSuffix?
| DecimalLiteral '_'* IntegerLiteralSuffix?
| HexadecimalLiteral IntegerLiteralSuffix?
;
BinaryLiteral
: '0' [bB] BinDigit (BinDigit | '_')*
;
BinDigit
: [01]
;
OctalLiteral
: '0' [oO] OctalDigit (OctalDigit | '_')*
字面量 5;
OctalDigit
: [0-7]
;
DecimalLiteral
: ([1-9] (DecimalDigit | '_')*) | DecimalDigit
;
DecimalDigit
: [0-9]
;
HexadecimalLiteral
: '0' [xX] HexadecimalDigits
;
HexadecimalDigits
: HexadecimalDigit (HexadecimalDigit | '_')*;
HexadecimalDigit
: [0-9a-fA-F]
;
IntegerLiteralSuffix 后缀与类型的对应为:

浮点数类型字面量
浮点数类型字面量有 2 种进制表示形式:十进制(没有前缀)和十六进制(使用 0x 或 0X 前缀)。十进制浮点数中,整数部分和小数部分(包含小数点)需要至少包含其一,并且无小数部分时必须包含指数部分(使用 e 或 E 前缀)。十六进制浮点中,整数部分和小数部分(包含小数点)需要至少包含其一,并且必须包含指数部分(使用 p 或 P 前缀)。同时可以加可选的后缀来指定浮点数类型字面量的具体类型。
浮点数数类型字面量的语法定义为:
FloatLiteralSuffix
: 'f16' | 'f32' | 'f64'
;
FloatLiteral
: (DecimalLiteral DecimalExponent | DecimalFraction DecimalExponent? |
↪ (DecimalLiteral DecimalFraction) DecimalExponent?) FloatLiteralSuffix?| (Hexadecimalprefix (HexadecimalDigits | HexadecimalFraction |
↪ (HexadecimalDigits HexadecimalFraction)) HexadecimalExponent)
DecimalFraction
: '.' DecimalFragment
;
DecimalFragment
: DecimalDigit (DecimalDigit | '_')*
;
DecimalExponent
: FloatE Sign? DecimalFragment
;
HexadecimalFraction
: '.' HexadecimalDigits
;
HexadecimalExponent
: FloatP Sign? DecimalFragment;
FloatE
: [eE]
;
FloatP
: [pP]
;
Sign
: [-]
;
Hexadecimalprefix
字面量 7: '0' [xX]
;
其中 FloatLiteralSuffix 后缀与类型的对应为:

布尔类型字面量
布尔类型字面量只有两个:true 和 false。booleanLiteral
: 'true'
| 'false'
;
字符串类型字面量
字符串字面量可以分为三类:单行字符串字面量,多行字符串字面量,多行原始字符串字面量。
单行字符串字面量使用一对单引号或双引号定义。引号中的内容可以是任意数量的任意字符。如果想要将引号或反斜杠 () 作为字符串本身的字符包括在内,需要在其前面加上 ()。单行字符串字面量不能通过包含换行符来跨越多行。
单行字符串字面量的语法定义为:
lineStringLiteral
: '"' (lineStringExpression | lineStringContent)* '"'
;
lineStringExpression
: '${' SEMI* (expressionOrDeclaration (SEMI+ expressionOrDeclaration?)*) SEMI*↪ '}'
;
lineStringContent
: LineStrText
;
LineStrText
: ~["\\\r\n]
| EscapeSeq;
多行字符串字面量开头结尾需各存在三个双引号(“ “ “)或三个单引号(’ ’ ’)。引号中的内容可以是任意数量的任意字符。如果要将用于括起字符串的三个引号(" 或’)或反斜杠(\)作为字符串本身的字符,则必须在它们前面加上反斜杠(\)。如果在开头的三个双引号后没有换行符,或在当前文件结束之前没有遇到非转义的三个双引号,则编译报错。不同于单行字符串字面量,多行字符串字面量可以跨越多行。
多行字符串字面量的语法定义为:
multiLineStringLiteral
: '"""' NL (multiLineStringExpression | multiLineStringContent)* '"""'
;
multiLineStringExpression
: '${' end* (expressionOrDeclaration (end+ expressionOrDeclaration?)*) end* '}';
multiLineStringContent
: MultiLineStrText
;
MultiLineStrText
: ~('\\')
| EscapeSeq
;
多行原始字符串字面量以一个或多个井号(#)和一个单引号或双引号('或")开头,后跟任意数量的合法字符,直到出现与字符串开头相同的引号和与字符串开头相同数量的井号为止。在当前文件结束之前,如果还没遇到匹配的双引号和相同个数的井号,则编译报错。与多行字符串字面量一样,原始多行字符串字面量可以跨越多行。不同支持在于,转义规则不适用于多行原始字符串字面量,字面量中的内容会维持原样(转义字符不会被转义)。
多行原始字符串字面量的语法定义为:
MultiLineRawStringLiteral
: MultiLineRawStringContent
;
fragment MultiLineRawStringContent
: '#' MultiLineRawStringContent '#'| '#' '"' .*? '"' '#'
;
Rune 类型字面量
一个 Rune 字面量由字符 r 开头,后跟一个(单引号或双引号)单行字符串字面量。字符串字面量内必须恰好包含一个字符。语法为:
操作符 9RuneLiteral
: 'r' '\'' (SingleChar | EscapeSeq) '\''
: 'r' '"' (SingleChar | EscapeSeq) '"'
;
fragment SingleChar
: ~['\\\r\n]
;
EscapeSeq
: UniCharacterLiteral
| EscapedIdentifier
;
fragment UniCharacterLiteral
: '\\' 'u' '{' HexadecimalDigit '}'
| '\\' 'u' '{' HexadecimalDigit HexadecimalDigit '}'
| '\\' 'u' '{' HexadecimalDigit HexadecimalDigit HexadecimalDigit '}'
| '\\' 'u' '{' HexadecimalDigit HexadecimalDigit HexadecimalDigit
↪ HexadecimalDigit '}'
| '\\' 'u' '{' HexadecimalDigit HexadecimalDigit HexadecimalDigit
↪ HexadecimalDigit HexadecimalDigit '}'
| '\\' 'u' '{' HexadecimalDigit HexadecimalDigit HexadecimalDigit
↪ HexadecimalDigit HexadecimalDigit HexadecimalDigit '}'
| '\\' 'u' '{' HexadecimalDigit HexadecimalDigit HexadecimalDigit
↪ HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit '}'| '\\' 'u' '{' HexadecimalDigit HexadecimalDigit HexadecimalDigit
HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit
HexadecimalDigit '}'
↪
↪
;
fragment EscapedIdentifier
: '\\' ('t' | 'b' | 'r' | 'n' |'\'' | '"' | '\\' | 'f' | 'v' | '0' | '$');
新一代开源开发者平台 GitCode,通过集成代码托管服务、代码仓库以及可信赖的开源组件库,让开发者可以在云端进行代码托管和开发。旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。
更多推荐


所有评论(0)