Spec-Zone.ru › OCaml 5.0

11.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... *)
*)

Идентификаторы

ident ::= (letter ∣ _) { letter ∣ 0…9 ∣ _ ∣ ' }
capitalized-ident ::= (A…Z) { letter ∣ 0…9 ∣ _ ∣ ' }
lowercase-ident ::= (a…z ∣ _) { letter ∣ 0…9 ∣ _ ∣ ' }
letter ::= A…Z ∣ a…z

Идентификаторы — это последовательности букв, цифр, символа _ (подчеркивание) и символа ' (одиночная кавычка), начинающиеся с буквы или подчеркивания. Буквы включают как минимум 52 строчные и прописные буквы из набора ASCII. В текущей реализации также распознаются некоторые символы из набора ISO 8859-1 (символы 192–214 и 216–222 как прописные буквы; символы 223–246 и 248–255 как строчные буквы). Эта функция устарела и должна быть избегаема для обеспечения совместимости в будущем.

Все символы в идентификаторе имеют значение. Текущая реализация принимает идентификаторы длиной до 16000000 символов.

Во многих местах OCaml различает идентификаторы, начинающиеся с заглавной буквы, и идентификаторы, начинающиеся со строчной буквы. Символ подчеркивания считается строчной буквой для этой цели.

Целочисленные литералы

integer-literal ::= [-] (0…9) { 0…9 ∣ _ }
∣ [-] (0x ∣ 0X) (0…9 ∣ A…F ∣ a…f) { 0…9 ∣ A…F ∣ a…f ∣ _ }
∣ [-] (0o ∣ 0O) (0…7) { 0…7 ∣ _ }
∣ [-] (0b ∣ 0B) (0…1) { 0…1 ∣ _ }

Целочисленный литерал — это последовательность одной или более цифр, необязательно предваряемая знаком минус. По умолчанию целочисленные литералы находятся в десятичной системе (основание 10). Следующие префиксы выбирают другое основание:

(Начальная 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}

Литералы с плавающей точкой

float-literal ::= [-] (0…9) { 0…9 ∣ _ } [. { 0…9 ∣ _ }] [(e ∣ E) [+ ∣ -] (0…9) { 0…9 ∣ _ }]
∣ [-] (0x ∣ 0X) (0…9 ∣ A…F ∣ a…f) { 0…9 ∣ A…F ∣ a…f ∣ _ } [. { 0…9 ∣ A…F ∣ a…f ∣ _ }] [(p ∣ P) [+ ∣ -] (0…9) { 0…9 ∣ _ }]

Числовые литералы с плавающей точкой в десятичной форме состоят из целой части, дробной части и экспоненциальной части. Целая часть — это последовательность одной или более цифр, необязательно предваряемая знаком минус. Дробная часть — это десятичная точка, за которой следуют ноль, одна или более цифр. Экспоненциальная часть — это символ 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

Литералы символов

char-literal ::= ' regular-char '
∣ ' escape-sequence '
escape-sequence ::= \ (\ ∣ " ∣ ' ∣ n ∣ t ∣ b ∣ r ∣ space)
∣ \ (0…9) (0…9) (0…9)
∣ \x (0…9 ∣ A…F ∣ a…f) (0…9 ∣ A…F ∣ a…f)
∣ \o (0…3) (0…7) (0…7)

Литералы символов ограничены символами ' (одинарная кавычка). Две одинарные кавычки заключают в себя либо один символ, отличный от ' и \, либо одну из следующих последовательностей экранирования:

Последовательность Обозначаемый символ
\\ обратная косая черта (\)
\" двойная кавычка (")
\' одинарная кавычка (')
\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'

Строковые литералы

string-literal ::= " { string-character } "
∣ { quoted-string-id | { any-char } | quoted-string-id }
quoted-string-id ::= { a…z ∣ _ }
string-character ::= regular-string-char
∣ escape-sequence
∣ \u{ { 0…9 ∣ A…F ∣ a…f }+ }
∣ \ newline { space ∣ tab }
END_OF_DOCUMENT_MARKER

Строковые литералы ограничены символами " (двойные кавычки). Две двойные кавычки заключают последовательность символов, отличных от " и \, или последовательностей экранирования из таблицы выше для символьных литералов, или последовательности экранирования 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-name ::= lowercase-ident
label ::= ~ label-name :
optlabel ::= ? label-name :

Именованные метки бывают двух типов: label для обычных аргументов и optlabel для необязательных. Они просто различаются по первому символу, либо ~, либо ?.

Несмотря на то, что label и optlabel являются лексическими сущностями в выражениях, их расширения ~ label-name : и ? label-name : будут использоваться в грамматиках ради удобочитаемости. Обратите также внимание, что внутри выражений типов это расширение можно воспринимать буквально, т.е. есть действительно 3 токена с необязательными пробелами между ними.

Префиксные и инфиксные символы

infix-symbol ::= (core-operator-char ∣ % ∣ <) { operator-char }
∣ # { operator-char }+
prefix-symbol ::= ! { operator-char }
∣ (? ∣ ~) { operator-char }+
operator-char ::= ~ ∣ ! ∣ ? ∣ core-operator-char ∣ % ∣ < ∣ : ∣ .
core-operator-char ::= $ ∣ & ∣ * ∣ + ∣ - ∣ / ∣ = ∣ > ∣ @ ∣ ^ ∣ |

См. также следующие расширения языка: расширенные операторы, расширенные операторы индексирования и операторы связывания.

Последовательности «символов операторов», такие как <=> или !!, читаются как один токен из класса 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    $     $$    $:    <:    <<    >>    ??

Неоднозначности

Лексические неоднозначности разрешаются по правилу «самое длинное совпадение»: когда последовательность символов может быть разложена на два токена различными способами, сохраняется разложение с самым длинным первым токеном.

Директивы номеров строк

linenum-directive ::= # { 0…9 }+ " { string-character } "

Препроцессоры, генерирующие исходный код OCaml, могут вставлять директивы номеров строк в свой вывод, чтобы сообщения об ошибках, создаваемые компилятором, содержали номера строк и имена файлов, относящиеся к исходному файлу до препроцессирования, а не после препроцессирования. Директива номера строки начинается в начале строки, состоит из # (знака решетки), за которым следует положительное целое число (номер исходной строки), за которым следует строка символов (имя исходного файла). Директивы номеров строк обрабатываются как пробелы во время лексического анализа.

© 1995-2022 INRIA.
https://v2.ocaml.org/releases/5.0/htmlman/lex.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API