以下字符被视为空格:空格、水平制表符、回车符、换行符和换页符。空格会被忽略,但它们会分隔相邻的标识符、字面量和关键字,否则这些标识符、字面量或关键字会被误认为一个整体。
注释以两个字符 (*(中间没有空格)开头,并以字符 *)(中间没有空格)结束。注释被视为空格字符。注释不会出现在字符串或字符字面量内部。嵌套注释会被正确处理。
|
标识符是由字母、数字、_(下划线字符)和'(单引号)组成的序列,以字母或下划线开头。字母至少包含 ASCII 集中的 52 个小写和大写字母。当前实现还将 ISO 8859-1 集中的一些字符识别为字母(字符 192–214 和 216–222 作为大写字母;字符 223–246 和 248–255 作为小写字母)。此功能已弃用,应避免使用,以确保将来兼容性。
标识符中的所有字符都有意义。当前实现接受长度最长达 16000000 个字符的标识符。
在许多地方,OCaml 区分以大写字母开头的标识符和以小写字母开头的标识符。为此,下划线字符被视为小写字母。
|
整数字面量是一个或多个数字的序列,前面可以可选地带有一个减号。默认情况下,整数字面量为十进制(基数 10)。以下前缀选择不同的基数
前缀 | 基数 |
0x,0X | 十六进制(基数 16) |
0o,0O | 八进制(基数 8) |
0b,0B | 二进制(基数 2) |
(初始 0 是数字零;八进制的 O 是字母 O。)整数字面量后面可以跟一个字母 l、L 或 n,以表示该整数的类型分别为 int32、int64 或 nativeint,而不是整数字面量的默认类型 int。超出可表示整数范围的整数字面量的解释是未定义的。
为方便起见并提高可读性,下划线字符 (_) 在整数字面量中被接受(并被忽略)。
|
浮点十进制字面量由整数部分、小数部分和指数部分组成。整数部分是一个或多个数字的序列,前面可以可选地带有一个减号。小数部分是一个小数点,后面跟着零个、一个或多个数字。指数部分是字符 e 或 E,后面跟着一个可选的 + 或 - 符号,后面跟着一个或多个数字。它被解释为 10 的幂。小数部分或指数部分可以省略,但不能同时省略,以避免与整数字面量产生歧义。超出可表示浮点范围的浮点字面量的解释是未定义的。
浮点十六进制字面量用 0x 或 0X 前缀表示。语法类似于浮点十进制字面量,但有以下区别。整数部分和小数部分使用十六进制数字。指数部分以字符 p 或 P 开头。它以十进制编写,并被解释为 2 的幂。
为方便起见并提高可读性,下划线字符 (_) 在浮点字面量中被接受(并被忽略)。
|
字符字面量由 '(单引号)字符分隔。这两个单引号包含一个与 ' 和 \ 不同的字符,或以下转义序列之一
序列 | 表示的字符 |
\\ | 反斜杠 (\) |
\" | 双引号 (") |
\' | 单引号 (') |
\n | 换行符 (LF) |
\r | 回车符 (CR) |
\t | 水平制表符 (TAB) |
\b | 退格符 (BS) |
\空格 | 空格 (SPC) |
\ddd | ASCII 码为十进制ddd的字符 |
\xhh | ASCII 码为十六进制hh的字符 |
\oooo | ASCII 码为八进制ooo的字符 |
|
字符串字面量由"(双引号)字符分隔。这两个双引号包含一系列字符,这些字符要么与"和\不同,要么是上面字符字面量表中给出的转义序列,要么是 Unicode 字符转义序列。
Unicode 字符转义序列由指定 Unicode 标量值的 UTF-8 编码替换。Unicode 标量值(范围在 0x0000...0xD7FF 或 0xE000...0x10FFFF 之间的整数)使用 1 到 6 个十六进制数字定义;允许前导零。
换行序列是一个换行符,前面可选地带有一个回车符。从 OCaml 5.2 开始,字符串字面量中出现的换行序列被规范化为单个换行符。
为了允许跨行拆分长字符串字面量,序列\换行 空格或制表符(一行末尾的反斜杠后跟下一行开头任意数量的空格和水平制表符)在字符串字面量中被忽略。
转义的换行符提供了比非转义的换行符更方便的行为,因为缩进不被视为字符串字面量的一部分。
带引号的字符串字面量为字符串字面量提供了另一种词法语法。它们用于表示任意内容的字符串,无需转义。带引号的字符串由一对匹配的{ quoted-string-id | 和 | quoted-string-id }分隔,两侧使用相同的quoted-string-id。带引号的字符串不会以特殊方式解释任何字符1,但要求序列| quoted-string-id }不会出现在字符串本身中。标识符quoted-string-id是(可能是空的)小写字母和下划线的序列,可以自由选择以避免此类问题。
当前的实现对字符串字面量的长度几乎没有限制。
为了避免歧义,表达式中命名标签不能仅仅在语法上定义为三个标记~、ident和:的序列,而必须在词法级别定义。
|
命名标签有两种类型:label 用于普通参数,optlabel 用于可选参数。它们只是通过其第一个字符(~ 或 ?)来区分。
尽管label 和 optlabel 是表达式中的词法实体,但它们的扩展~ label-name : 和 ? label-name : 将用于语法,以提高可读性。还要注意,在类型表达式内部,此扩展可以按字面意思理解,即实际上有 3 个标记,它们之间可选地有空格。
|
另请参阅以下语言扩展:扩展操作符、扩展索引操作符和绑定操作符。
“操作符字符”序列,例如<=> 或 !!,作为infix-symbol 或 prefix-symbol 类中的单个标记读取。这些符号在表达式内部作为前缀和中缀操作符进行解析,但在其他情况下则表现得像普通标识符。
以下标识符作为关键字保留,不能以其他方式使用。
and as assert asr begin class constraint do done downto else end exception external false for fun function functor if in include inherit initializer land lazy let lor lsl lsr lxor match method mod module mutable new nonrec object of open or private rec sig struct then to true try type val virtual when while with
以下字符序列也是关键字。
!= # & && ' ( ) * + , - -. -> . .. .~ : :: := :> ; ;; < <- = > >] >} ? [ [< [> [| ] _ ` { {< | |] || } ~
请注意,以下标识符是现已不再维护的 Camlp4 系统的关键字,出于向后兼容性的原因,应避免使用。
parser value $ $$ $: <: << >> ??
词法歧义根据“最长匹配”规则解决:当字符序列可以以几种不同的方式分解成两个标记时,保留的分解方式是第一个标记最长的那个。
|
生成OCaml源代码的预处理器可以在其输出中插入行号指令,以便编译器生成的错误消息包含行号和文件名,这些文件名指的是预处理前的源文件,而不是预处理后的源文件。行号指令从行首开始,由一个#(井号)开头,后跟一个正整数(源代码行号),再后跟一个字符字符串(源文件名)。在词法分析期间,行号指令被视为空格。