Лексическая структура

Документы

Документ M представляет собой упорядоченную последовательностью символов Юникода. M допускает использование различных классов символов Юникода в разных частях документа M. Сведения о классах символов Юникода см. в разделе Стандарт Юникод, версия 3.0, подраздел 4.5.

Документ состоит либо только из одного выражения, либо из групп определений, упорядоченных в разделы. Разделы подробно описаны в Главе 10. По существу, для считывания выражения из документа используются следующие шаги.

  1. Документ декодируется в соответствии со схемой кодировки символов в последовательность символов Юникода.

  2. Затем выполняется лексический анализ, в результате которого поток символов Юникода преобразуется в поток токенов. В оставшихся подразделах этого раздела рассматривается лексический анализ.

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

Грамматические соглашения

Лексическая и синтаксическая грамматика представлены с помощью грамматических правил. Каждое грамматическое правило определяет неконечный символ и возможные расширения этого неконечного символа в последовательности неконечных или конечных символов. В грамматических правилах неконечные символы обозначаются курсивом, а конечные символы — шрифтом с фиксированной шириной.

Первая строка грамматического правила — это имя определяемого неконечного символа, за которым следует двоеточие. Каждая последующая строка с отступом содержит возможное расширение неконечного символа, представленная в виде последовательности неконечных или конечных символов. Например, следующее правило:

выражение-if:
      ifусловие-ifthenвыражение-trueelseвыражение-false

определяет, что выражение-if состоит из токена if, за которым следуют условие-if, токен then, выражение-true, токен else и выражение-false.

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

список переменных:
      Переменная
      список-переменных
,переменная

определяет, что список-переменных состоит либо из переменной, либо из списка-переменных, за которым следует переменная. Иными словами, определение является рекурсивным и указывает, что список переменных состоит из одной или нескольких переменных, разделенных запятыми.

Суффикс с индексом "необязательно" используется для указания необязательного символа. Правило:

спецификация-поля:
      optionalнеобязательно имя-поля=тип-поля

является сокращенным вариантом следующего:

спецификация-поля:
      имя-поля
=тип-поля
      optionalимя-поля=тип-поля

Это правило определяет, что спецификация-поля при необходимости может начинаться с конечного символа optional, за которым следуют имя-поля, конечный символ = и тип-поля.

Альтернативные варианты обычно перечисляются в отдельных строках, но в тех случаях, когда существует много альтернатив, списку расширений, заданных в одной строке, может предшествовать фраза "один из". Это простое сокращение для перечисления всех альтернативных вариантов в отдельной строке. Например, следующее правило:

десятичный-знак: один из
      0 1 2 3 4 5 6 7 8 9

является сокращенным вариантом следующего:

десятичный-знак:
      0
      1
      2
      3
      4
      5
      6
      7
      8
      9

Лексический анализ

Правило лексическая-единица в производстве определяет лексическую грамматику для документа M. Каждый допустимый документ M следует этой грамматике.

лексическая-единица:
      лексические-элементынеобязательно
лексические-элементы:
      лексический-элемент
      лексический-элемент
      лексические-элементы
лексический-элемент:
      whitespace
      комментарий токена

На лексическом уровне документ M состоит из потока элементов пробел, комментарий и токен. Каждое из этих правил описываются в следующих разделах. В синтаксической грамматике учитываются только элементы токен.

Пробел

Пробелы используются для разделения комментариев и токенов в документе M. Пробелы включают символ пробела (который является частью класса Zs Юникода), а также горизонтальную и вертикальную табуляции, перевод страницы и последовательности символов новой строки. Последовательности символов новой строки включают возврат каретки, перевод строки, возврат каретки, за которым следует символ перевода строки, следующей строки и разделителя абзацев.

пробел:
      Любой символ с классом Zs Юникода
      Символ горизонтальной табуляции (U+0009)
      Символ вертикальной табуляции (U+000B)
      Символ перевода страницы (U+000C)
      Символ возврата каретки (U+000D), за которым следует символ перевода строки (U+000A)
      символ-новой-строки
символ-новой-строки:
      Символ возврата каретки (U+000D)
      Символ перевода строки (U+000A)
      Символ следующей строки (U+0085)
      Символ разделителя строк (U+2028)
      Символ разделителя абзацев (U+2029)

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

  • Если последний символ документа является символом сочетания клавиш CTRL+Z (U+001A), этот символ удаляется.

  • Если этот документ не является пустым и если последний символ документа не является символом возврата каретки (U+000D), символом перевода строки (U+000A), разделителем строк (U+2028) или разделителем абзацев (U+2029), то в конец документа добавляется символ возврата каретки (U+000D).

Комментарии

Поддерживаются две формы комментариев: однострочные комментарии и комментарии с разделителями. Однострочные комментарии начинаются с символов // и дополняются до конца исходной строки. Комментарии с разделителями начинаются с символов /* и заканчиваются символами */.

Комментарии с разделителями могут включать несколько строк.

комментарий:
      однострочный-комментарий
      комментарий-с-разделителями
однострочный-комментарий:

      //символы-однострочного-комментариянеобязательно
символы-однострочного-комментария:
      символ-однострочного-комментария символы-однострочного-комментариянеобязательно
символ-однострочного-комментария:

      Любой символ Юникода, кроме символа-новой-строки
комментарий-с-разделителями:

      /*текст-комментария-с-разделителяминеобязательно звездочки/
текст-комментария-с-разделителями:
      раздел-комментария-с-разделителями текст-комментария-с-разделителяминеобязательно
раздел-комментария-с-разделителями:

      /
      звездочкинеобязательно не-косая-черта-или-звездочка
звездочки:

      *звездочкинеобязательно
не-косая-черта-или-звездочка:

      Любой символ Юникода, кроме * или /

Комментарии не предусматривают вложения. Последовательности символов /* и */ не имеют специального значения в однострочном комментарии, а последовательности символов // и /* не имеют специального значения в комментариях с разделителями.

Комментарии не обрабатываются в текстовых литералах. Пример

/* Hello, world 
*/ 
    "Hello, world"

содержит комментарий с разделителями.

Пример

// Hello, world 
// 
"Hello, world" // This is an example of a text literal

содержит несколько однострочных комментариев.

Токены

Токен — это идентификатор, ключевое слово, литерал, оператор или знак препинания. Пробелы и комментарии используются для разделения токенов, но не считаются токенами.

токен:
      идентификатор
      ключевое слово
      литерал
      оператор-или-знак-препинания

Escape-последовательности

Текстовые значения M могут содержать произвольные символы Юникода. Однако текстовые литералы ограничены графическими символами и требуют использования escape-последовательностей для неграфических символов. Например, чтобы включить в текстовый литерал символ возврата каретки, перевода строки или табуляции, можно использовать escape-последовательности #(cr), #(lf) и #(tab) соответственно. Чтобы внедрить символы начала escape-последовательности #( в текстовый литерал, необходимо экранировать сам символ #.

#(#)(

Escape-последовательности также могут содержать короткие (четыре шестнадцатеричные цифры) или длинные (восемь шестнадцатеричных цифр) значения кодовых точек Юникода. Таким образом, следующие три escape-последовательности эквивалентны:

#(000D)     // short Unicode hexadecimal value 
#(0000000D) // long Unicode hexadecimal value 
#(cr)       // compact escape shorthand for carriage return

В одну escape-последовательность можно добавить несколько escape-кодов, разделенных запятыми; таким образом, следующие две последовательности эквивалентны:

#(cr,lf) 
#(cr)#(lf)

Ниже описан стандартный механизм экранирования символов в документе M.

escape-последовательность:
      #(список-escape-последовательностей)
список-escape-последовательностей:
      одиночная-escape-последовательность
      одиночная-escape-последовательность
,список-escape-последовательностей
одиночная-escape-последовательность:
      длинная-управляющая-последовательность-Юникода
      короткая-управляющая-последовательность-Юникода
      escape-последовательность-с-управляющим-символом
      escape-escape
длинная-управляющая-последовательность-Юникода:
      шестнадцатеричный-знак шестнадцатеричный-знак шестнадцатеричный-знак шестнадцатеричный-знак шестнадцатеричный-знак шестнадцатеричный-знак шестнадцатеричный-знак шестнадцатеричный-знак
короткая-управляющая-последовательность-Юникода:
      шестнадцатеричный-знак шестнадцатеричный-знак шестнадцатеричный-знак шестнадцатеричный-знак
escape-последовательность-с-управляющим-символом:
      управляющий-символ
управляющий-символ:

      cr
      lf
      tab
escape-escape:
      #

Литералы

Литерал является представлением исходного кода значения.

литерал:
      логический-литерал
      числовой-литерал
      текстовый-литерал
      литерал-NULL
      буквальный-литерал

Литералы NULL

Литерал NULL используется для записи значения null. Значение null представляет отсутствующее значение.

литерал-NULL:
      null

Логические литералы

Логический литерал используется для записи значений true и false и создает логическое значение.

логический-литерал:
      true
      false

Числовые литералы

Числовой литерал используется для записи числового значения и дает числовое значение.

числовой-литерал:
      десятичный-числовой-литерал
      шестнадцатеричный-числовой-литерал
десятичный-числовой-литерал:
      десятичные-знаки
.десятичные-знаки показатель-степенинеобязательно
      .десятичные-знаки показатель-степенинеобязательно
      десятичные-знаки показатель-степенинеобязательно
десятичные-знаки:
      десятичный-знак десятичные-знакинеобязательно
десятичный-знак:
один из
      0 1 2 3 4 5 6 7 8 9
экспоненциальная-часть:
      eзнакнеобязательно десятичные-знаки
      Eзнакнеобязательно десятичные-знаки
знак:
один из
      + -
шестнадцатеричный-числовой-литерал:
      0xШестнадцатеричные знаки
      0XШестнадцатеричные знаки
шестнадцатеричные-знаки:
      шестнадцатеричный-знак шестнадцатеричные-знакинеобязательно
шестнадцатеричный-знак:
один из
      0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f

Число может быть представлено в шестнадцатеричном формате (шестнадцатеричные-знаки перед символами 0x). Например:

0xff // 255

Обратите внимание, что если в числовой литерал включена десятичная запятая, то после нее должна содержаться хотя бы одна цифра. Например, 1.3 является числовым литералом, но 1. и 1.e3 не являются таковыми.

Текстовые литералы

Текстовый литерал используется для записи последовательности символов Юникода и создает текстовое значение.

текстовый-литерал:
      "символы-текстового-литераланеобязательно"
символы-текстового-литерала:
      символ-текстового-литерала символы-текстового-литераланеобязательно
символ-текстового-литерала:
      одиночный-текстовый-символ
      escape-последовательность-символов
      escape-последовательность-двойных-кавычек
одиночный-текстовый-символ:

      Любой символ, кроме " (U+0022) или # (U+0023), за которым следует ( (U+0028)
escape-последовательность-двойных-кавычек:
      "" (U+0022, U+0022)

Чтобы включить кавычки в текстовое значение, знак кавычек повторяется следующим образом:

"The ""quoted"" text" // The "quoted" text

Правило символ-escape-последовательности можно использовать для записи символов в текстовые значения без необходимости непосредственно кодировать их как символы Юникода в документе. Например, символ возврата каретки и перевода строки можно записать в текстовое значение следующим образом:

"Hello world#(cr,lf)"

Буквальные литералы

Буквальный литерал используется для хранения последовательности символов Юникода, которые введены пользователем как код, но не могут быть обработаны должным образом в виде кода. Во время выполнения он выдает значение ошибки.

буквальный-литерал:
      #!"символы-текстового-литераланеобязательно"

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

Идентификатор — это имя, используемое для ссылки на значение. Идентификаторы могут быть либо обычными идентификаторами, либо нестандартными идентификаторами.

идентификатор:
      обычный-идентификатор
      нестандартный-идентификатор
обычный-идентификатор:
      доступный-идентификатор
      доступный-идентификатор символ-точки обычный-идентификатор
доступный-идентификатор:

      ключевое-слово-или-идентификатор, не являющееся ключевым словом
ключевое-слово-или-идентификатор:
      начальный-символ-идентификатора символы-части-идентификаторанеобязательно
начальный-символ-идентификатора:
      буквенный-символ
      символ-подчеркивания
символы-части-идентификатора:
      символ-части-идентификатора символы-части-идентификаторанеобязательно
символ-части-идентификатора:
      буквенный-символ
      символ-десятичного-знака
      символ-подчеркивания
      символ-соединения
      символ-объединения
      символ-форматирования
символ-точки:

      . (U+002E)
символ-подчеркивания:
      _ (U+005F)
буква:
      Символ Юникода класса Lu, Ll, Lt, Lm, Lo или Nl
символ-объединения:
      Символ Юникода класса Mn или Mc
десятичный-знак:
      Символ Юникода класса Nd
символ-соединения:
      Символ Юникода класса Pc
символ-форматирования:
      Символ Юникода класса Cf

Нестандартный идентификатор можно использовать, чтобы разрешить использование любой последовательности из нулей или других символов Юникода в качестве идентификатора, включая ключевые слова, пробелы, комментарии, операторы и знаки препинания.

нестандартный-идентификатор:
      #"символы-текстового-литераланеобязательно"

Обратите внимание, что в нестандартном идентификаторе можно использовать escape-последовательности и двойные кавычки для экранирования так же, как в текстовых литералах.

В следующем примере используется идентификатор, указывающий на имя, содержащее символ пробела:

[ 
    #"1998 Sales" = 1000, 
    #"1999 Sales" = 1100, 
    #"Total Sales" = #"1998 Sales" + #"1999 Sales"
]

В следующем примере используется идентификатор, указывающий на включение оператора + в идентификатор:

[ 
    #"A + B" = A + B, 
    A = 1, 
    B = 2 
]

Обобщенные идентификаторы

В M есть два места, где в идентификаторах, содержащих пробелы, ключевые слова или числовые литералы, нет неоднозначностей. Это имена полей записей в литерале записи и в операторе доступа к полю ([ ]). M позволяет использовать такие идентификаторы без необходимости использования нестандартных идентификаторов.

[ 
    Data = [ Base Line = 100, Rate = 1.8 ], 
    Progression = Data[Base Line] * Data[Rate]
]

Идентификаторы, используемые для именования полей и доступа к ним, называются обобщенными идентификаторами и определяются следующим образом:

обобщенный-идентификатор:
      часть-обобщенного-идентификатора
      обобщенный-идентификатор
разделяется только пробелами (U+0020)
часть-обобщенного-идентификатора
часть-обобщенного-идентификатора:
      сегмент-обобщенного-идентификатора
      символ-десятичного-знака сегмент-обобщенного-идентификатора
сегмент-обобщенного-идентификатора:
      ключевое-слово-или-идентификатор
      ключевое-слово-или-идентификатор символ-точки ключевое-слово-или-идентификатор

Ключевые слова

Ключевое слово является последовательностью символов, аналогичных идентификатору, которая зарезервирована и не может использоваться в качестве идентификатора, кроме случаев, когда используется нестандартный идентификатор или разрешено использование обобщенного идентификатора.

ключевое-слово: одно из
       and as each else error false if in is let meta not null or otherwise
       section shared then true try type #binary #date #datetime
       #datetimezone #duration #infinity #nan #sections #shared #table #time

Операторы и знаки препинания

Существует несколько видов операторов и знаков препинания. Операторы используются в выражениях для описания операций, включающих один или несколько операндов. Например, выражение a + b использует оператор + для добавления двух операндов a и b. Знаки препинания предназначены для группирования и разделения.

оператор-или-знак-препинания: один из
      , ; = < <= > >= <> + - * / & ( ) [ ] { } @ ! ? ?? => .. ...