9.1 Лексические соглашения
Пробелы
Следующие символы считаются пробелами: пробел, горизонтальная табуляция, возврат каретки, перевод строки и подача формы. Пробелы игнорируются, но они разделяют смежные идентификаторы, литералы и ключевые слова, которые в противном случае могли бы быть приняты за один идентификатор, литерал или ключевое слово.
Комментарии
Комментарии начинаются с двух символов (*, без пробелов между ними, и завершаются символами *), без пробелов между ними. Комментарии обрабатываются как пробельные символы. Комментарии не могут быть внутри строковых или символьных литералов. Вложенные комментарии обрабатываются корректно.
(* single line comment *)
(* multiple line comment, commenting out part of a program, and containing a
nested comment:
let f = function
| 'A'..'Z' -> "Uppercase"
(* Add other cases later... *)
*)
Идентификаторы
|
Идентификаторы — это последовательности букв, цифр, _ (символ нижнего подчеркивания) и ' (одинарная кавычка), начинающиеся с буквы или символа нижнего подчеркивания. Буквы включают по меньшей мере 52 строчные и прописные буквы из набора ASCII. В текущей реализации также распознаются некоторые символы из набора 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 для восьмеричного — это буква О). Целочисленный литерал может быть последован одной из букв l, L или n для указания того, что этот целое число имеет тип int32, int64 или nativeint соответственно, вместо типа по умолчанию int для целочисленных литералов. Интерпретация целочисленных литералов, которые выходят за пределы диапазона представимых целочисленных значений, не определена.
Для удобства и удобочитаемости допускаются символы нижнего подчеркивания (_) внутри целочисленных литералов.
# let house_number = 37
let million = 1_000_000
let copyright = 0x00A9
let counter64bit = ref 0L;;
val house_number : int = 37
val million : int = 1000000
val copyright : int = 169
val counter64bit : int64 ref = {contents = 0L} Литералы с плавающей точкой
|
Числовые литералы с плавающей точкой в десятичной форме состоят из целой части, дробной части и экспоненциальной части. Целая часть — это последовательность одной или более цифр, необязательно предваряемая знаком минус. Дробная часть — это десятичная точка, за которой следуют ноль, одна или более цифр. Экспоненциальная часть — это символ e или E, за которым следует необязательный знак + или -, а затем одна или более цифр. Она интерпретируется как степень числа 10. Дробная или экспоненциальная части могут быть опущены, но не обе одновременно, чтобы избежать неоднозначности с целыми литералами. Интерпретация литералов с плавающей точкой, выходящих за пределы диапазона представимых значений с плавающей точкой, не определена.
Числовые литералы с плавающей точкой в шестнадцатеричной форме обозначаются префиксом 0x или 0X. Синтаксис аналогичен синтаксису десятичных литералов с плавающей точкой, с следующими отличиями. Целая и дробная части используют шестнадцатеричные цифры. Экспоненциальная часть начинается с символа p или P. Она записывается в десятичной форме и интерпретируется как степень двойки.
Для удобства и читаемости символы подчеркивания (_) допускаются (и игнорируются) внутри литералов с плавающей точкой.
# let pi = 3.141_592_653_589_793_12 let small_negative = -1e-5 let machine_epsilon = 0x1p-52;; val pi : float = 3.14159265358979312 val small_negative : float = -1e-05 val machine_epsilon : float = 2.22044604925031308e-16
Литералы символов
|
Литералы символов ограничены символами ' (одинарная кавычка). Две одинарные кавычки заключают в себя либо один символ, отличный от ' и \, либо одну из следующих последовательностей экранирования:
| Последовательность | Обозначаемый символ |
| \\ | обратная косая черта (\) |
| \" | двойная кавычка (") |
| \' | одинарная кавычка (') |
| \n | перевод строки (LF) |
| \r | возврат каретки (CR) |
| \t | горизонтальная табуляция (TAB) |
| \b | ввод пробела назад (BS) |
| \space | пробел (SPC) |
| \ddd | символ с кодом ASCII ddd в десятичной форме |
| \xhh | символ с кодом ASCII hh в шестнадцатеричной форме |
| \oooo | символ с кодом ASCII ooo в восьмеричной форме |
# let a = 'a' let single_quote = '\'' let copyright = '\xA9';; val a : char = 'a' val single_quote : char = '\'' val copyright : char = '\169'
Строковые литералы
|
Строковые литералы ограничены символами " (двойные кавычки). Две двойные кавычки заключают последовательность символов, отличных от " и \, или последовательностей экранирования из таблицы выше для символьных литералов, или последовательности экранирования Unicode-символа.
Последовательность экранирования Unicode-символа подставляется с использованием кодировки UTF-8 указанного значения скалярного Unicode-символа. Значение скалярного Unicode-символа, целое число в диапазонах 0x0000...0xD7FF или 0xE000...0x10FFFF, определяется с использованием от 1 до 6 шестнадцатеричных цифр; ведущие нули допускаются.
# let greeting = "Hello, World!\n"
let superscript_plus = "\u{207A}";;
val greeting : string = "Hello, World!\n"
val superscript_plus : string = "⁺" Для возможности разбиения длинных строковых литералов на несколько строк, последовательность \новая строка пробелы или табуляции (обратная косая черта в конце строки, за которой следует любое количество пробелов и горизонтальных табуляций в начале следующей строки) игнорируется внутри строковых литералов.
# let longstr =
"Call me Ishmael. Some years ago — never mind how long \
precisely — having little or no money in my purse, and \
nothing particular to interest me on shore, I thought I\
\ would sail about a little and see the watery part of t\
he world.";;
val longstr : string =
"Call me Ishmael. Some years ago — never mind how long precisely — having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world." Ценные строковые литералы предоставляют альтернативный лексический синтаксис для строковых литералов. Они полезны для представления строк произвольного содержимого без экранирования. Ценные строки ограничены парными { quoted-string-id | и | quoted-string-id } с одинаковым quoted-string-id с обеих сторон. Ценные строки не интерпретируют ни один символ особым образом, но требуют, чтобы последовательность | quoted-string-id } не встречалась в самой строке. Идентификатор quoted-string-id — это (возможно, пустая) последовательность строчных букв и подчеркиваний, которую можно свободно выбрать, чтобы избежать таких проблем.
# let quoted_greeting = {|"Hello, World!"|}
let nested = {ext|hello {|world|}|ext};;
val quoted_greeting : string = "\"Hello, World!\""
val nested : string = "hello {|world|}" Текущая реализация практически не накладывает ограничений на длину строковых литералов.
Именованные метки
Чтобы избежать неоднозначности, именованные метки в выражениях не могут быть определены просто синтаксически как последовательность трех токенов ~, 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, могут вставлять директивы номеров строк в свой вывод, чтобы сообщения об ошибках, создаваемые компилятором, содержали номера строк и имена файлов, относящиеся к исходному файлу до препроцессирования, а не после препроцессирования. Директива номера строки начинается в начале строки, состоит из # (знака решетки), за которым следует положительное целое число (номер исходной строки), за которым следует строка символов (имя исходного файла). Директивы номеров строк обрабатываются как пробелы во время лексического анализа.
© 1995-2022 INRIA.
https://v2.ocaml.org/releases/4.14/htmlman/lex.html