Estructura léxica

Documentos

Un documento de M es una secuencia ordenada de caracteres Unicode. En M se permiten diferentes clases de caracteres Unicode en diferentes partes de un documento de M. Para obtener información sobre las clases de caracteres Unicode, vea el Estándar Unicode, versión 3.0, sección 4.5.

Un documento consta de exactamente una expresión, o bien de grupos de definiciones organizadas en secciones. Las secciones se describen en detalle en el Capítulo 10. En términos conceptuales, se usan los pasos siguientes para leer una expresión de un documento:

  1. El documento se descodifica según su esquema de codificación de caracteres en una secuencia de caracteres Unicode.

  2. Se realiza el análisis léxico, con lo que se traduce la secuencia de caracteres Unicode en una secuencia de tokens. En las subsecciones restantes de esta sección se describe el análisis léxico.

  3. Se realiza el análisis sintáctico, con lo que se traduce el flujo de tokens en un formato que se puede evaluar. Este proceso se describe en secciones posteriores.

Convenciones gramaticales

Las gramáticas léxicas y sintácticas se presentan mediante producciones gramaticales. En cada producción gramatical se define un símbolo que no es de terminal y las posibles expansiones de ese símbolo en secuencias de símbolos terminales o no terminales. En las producciones gramaticales, los símbolos no terminales se muestran en cursiva y los símbolos terminales se muestran en una fuente de ancho fijo.

La primera línea de una producción gramatical es el nombre del símbolo que no es de terminal que se define, seguido de un signo de dos puntos. Cada línea con sangría sucesiva contiene una posible expansión del símbolo de no terminal proporcionada como una secuencia de símbolos terminales o no terminales. Por ejemplo, la producción:

if-expression:
      ifif-conditionthentrue-expressionelsefalse-expression

define if-expression que consta del token if, seguido de if-condition, seguido del token then, seguido de true-expression, seguido del token else, seguido de false-expression.

Cuando hay más de una expansión posible de un símbolo que no es de terminal, las alternativas se enumeran en líneas independientes. Por ejemplo, la producción:

variable-list:
      variable
      variable-list
,variable

define una variable-list que consta de una variable o de una variable-list seguida de una variable. En otras palabras, la definición es recursiva y especifica que una lista de variables consta de una o más variables, separadas por comas.

Se usa un sufijo de subíndice "opt" para indicar un símbolo opcional. La producción:

field-specification:
      optionalopt field-name=field-type

es la abreviatura de:

field-specification:
      field-name
=field-type
      optionalfield-name=field-type

y define una instancia de field-specification que, de manera opcional, puede empezar con el símbolo de terminal optional, seguido de un valor field-name, el símbolo de terminal = y un valor field-type.

Las alternativas se muestran normalmente en líneas independientes, aunque en casos donde hay muchas alternativas, la frase "uno de" puede preceder a una lista de expansiones indicadas en una sola línea. Esto es simplemente una abreviatura para enumerar cada una de las alternativas en una línea independiente. Por ejemplo, la producción:

decimal-digit: uno de
      0 1 2 3 4 5 6 7 8 9

es la abreviatura de:

decimal-digit:
      0
      1
      2
      3
      4
      5
      6
      7
      8
      9

Análisis léxico

En la producción lexical-unit se define la gramática léxica para un documento de M. Cada documento de M válido se ajusta a esta gramática.

lexical-unit:
      lexical-elementsopt
lexical-elements:
      lexical-element
      lexical-element
      lexical-elements
lexical-element:
      whitespace
      token comment

En el nivel léxico, un documento de M está formado por una secuencia de elementos whitespace, comment y token. Cada una de estas producciones se explica en las secciones siguientes. Solo los elementos token son significativos en la gramática sintáctica.

Espacio en blanco

El espacio en blanco se usa para separar los comentarios y los tokens dentro de un documento de M. El espacio en blanco incluye el carácter de espacio (que forma parte de la clase Zs de Unicode), así como las secuencias de caracteres de tabulación horizontal y vertical, avance de página y nueva línea. Las secuencias de caracteres de nueva línea incluyen retorno de carro, avance de línea y retorno de carro seguido de los caracteres separadores de avance de línea, línea siguiente y párrafo.

whitespace:
      Cualquier carácter con la clase Zs de Unicode
      Carácter de tabulación horizontal (U+0009)
      Carácter de tabulación vertical (U+000B)
      Carácter de avance de página (U+000C)
      Carácter de retorno de carro (U+000D) seguido de un carácter de avance de línea (U+000A)
      new-line-character
new-line-character:
      Carácter de retorno de carro (U+000D)
      Carácter de avance de línea (U+000A)
      Carácter de línea siguiente (U+0085)
      Carácter de línea siguiente (U+2028)
      Carácter separador de párrafo (U+2029)

Por compatibilidad con las herramientas de edición de código fuente que agregan marcadores de fin de archivo y para permitir que un documento se vea como una secuencia de líneas terminadas correctamente, se aplican las transformaciones siguientes, en orden, a un documento de M:

  • Si el último carácter del documento es un carácter Control-Z (U+001A), se elimina.

  • Un carácter de retorno de carro (U+000D) se agrega al final del documento si ese documento no está vacío y si el último carácter del documento no es un retorno de carro (U+000D), un avance de línea (U+000A), un separador de línea (U+2028) o un separador de párrafo (U+2029).

Comentarios

Se admiten dos formatos de comentarios: de una sola línea y delimitados. Los comentarios de una sola línea comienzan con los caracteres // y se extienden hasta el final de la línea de código fuente. Los comentarios delimitados comienzan con los caracteres /* y terminan con los caracteres */.

Los comentarios delimitados pueden abarcar varias líneas.

comment:
      single-line-comment
      delimited-comment
single-line-comment:

      //single-line-comment-charactersopt
single-line-comment-characters:
      single-line-comment-character single-line-comment-charactersopt
single-line-comment-character:

      Any Unicode character except a new-line-character
delimited-comment:

      /*delimited-comment-textopt asterisks/
delimited-comment-text:
      delimited-comment-section delimited-comment-textopt
delimited-comment-section:

      /
      asterisksopt not-slash-or-asterisk
asterisks:

      *asterisksopt
not-slash-or-asterisk:

      Cualquier carácter Unicode menos * o /

Los comentarios no se anidan. Las secuencias de caracteres /* y */ no tienen ningún significado especial en un comentario de una sola línea y las secuencias de caracteres // y /* tampoco lo tienen dentro de un comentario delimitado.

Los comentarios no se procesan dentro de los literales de texto. En el ejemplo

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

se incluye un comentario delimitado.

En el ejemplo

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

se muestran varios comentarios de una línea.

Tokens

Un token es un identificador, palabra clave, literal, operador o signo de puntuación. Los espacios en blanco y los comentarios se usan para separar los tokens, pero no se consideran tokens.

token:
      identificador
      palabra clave
      Literal
      operator-or-punctuator

Secuencias de escape de caracteres

Los valores de texto de M pueden contener caracteres Unicode arbitrarios. Pero los literales de texto se limitan a los caracteres gráficos y requieren el uso de secuencias de escape para los caracteres no gráficos. Por ejemplo, para incluir un carácter de retorno de carro, avance de línea o tabulación en un literal de texto, se pueden usar las secuencias de escape #(cr), #(lf) y #(tab), respectivamente. Para insertar los caracteres de inicio de secuencia de escape #( en un literal de texto, se debe aplicar la secuencia de escape al propio carácter #:

#(#)(

Las secuencias de escape también pueden contener valores de punto de código de Unicode cortos (cuatro dígitos hexadecimales) o largos (ocho dígitos hexadecimales). Por tanto, las tres secuencias de escape siguientes son equivalentes:

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

Se pueden incluir varios códigos de escape en una sola secuencia de escape, separados por comas; por tanto, las dos secuencias siguientes son equivalentes:

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

A continuación se describe el mecanismo estándar de escape de caracteres en un documento de M.

character-escape-sequence:
      #(escape-sequence-list)
escape-sequence-list:
      single-escape-sequence
      single-escape-sequence
,escape-sequence-list
single-escape-sequence:
      long-unicode-escape-sequence
      short-unicode-escape-sequence
      control-character-escape-sequence
      escape-escape
long-unicode-escape-sequence:
      hex-digit hex-digit hex-digit hex-digit hex-digit hex-digit hex-digit hex-digit
short-unicode-escape-sequence:
      hex-digit hex-digit hex-digit hex-digit
control-character-escape-sequence:
      control-character
control-character:

      cr
      lf
      tab
escape-escape:
      #

Literales

Un literal es una representación de código fuente de un valor.

literal:
      logical-literal
      number-literal
      text-literal
      null-literal
      verbatim-literal

Literales NULL

El literal NULL se usa para escribir el valor null. El valor null representa un valor ausente.

null-literal:
      null

Literales lógicos

Un literal lógico se usa para escribir los valores true y false, y genera un valor lógico.

logical-literal:
      true
      false

Literales numéricos

Un literal numérico se usa para escribir un valor numérico y genera un valor de número.

number-literal:
      decimal-number-literal
      hexadecimal-number-literal
decimal-number-literal:
      decimal-digits
.decimal-digits exponent-partopt
      .decimal-digits exponent-partopt
      decimal-digits exponent-partopt
decimal-digits:
      decimal-digit decimal-digitsopt
decimal-digit:
one of
      0 1 2 3 4 5 6 7 8 9
exponent-part:
      esignopt decimal-digits
      Esignopt decimal-digits
sign:
one of
      + -
hexadecimal-number-literal:
      0xhex-digits
      0Xhex-digits
hex-digits:
      hex-digit hex-digitsopt
hex-digit:
one of
      0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f

Se puede especificar un número en formato hexadecimal si se colocan los caracteres 0x delante de hex-digits. Por ejemplo:

0xff // 255

Tenga en cuenta que si se incluye un separador decimal en un literal numérico, debe tener al menos un dígito después. Por ejemplo, 1.3 es un literal numérico, pero 1.1.e3 no lo son.

Literales de texto

Un literal de texto se usa para escribir una secuencia de caracteres Unicode y genera un valor de texto.

text-literal:
      "text-literal-charactersopt"
text-literal-characters:
      text-literal-character text-literal-charactersopt
text-literal-character:
      single-text-character
      character-escape-sequence
      double-quote-escape-sequence
single-text-character:

      Cualquier carácter excepto " (U+0022) o # (U+0023) seguido de ( (U+0028)
double-quote-escape-sequence:
      "" (U+0022, U+0022)

Para incluir comillas en un valor de texto, las comillas se repiten de la manera siguiente:

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

La producción character-escape-sequence se puede usar para escribir caracteres en valores de texto sin tener que codificarlos directamente como caracteres Unicode en el documento. Por ejemplo, un retorno de carro y un avance de línea se pueden escribir en un valor de texto como:

"Hello world#(cr,lf)"

Literales textuales

Los literales textuales se usan para almacenar una secuencia de caracteres Unicode que un usuario escribió como código, pero que no se puede analizar correctamente como código. En tiempo de ejecución, generan un valor de error.

verbatim-literal:
      #!"text-literal-charactersopt"

Identificadores

Un identificador es un nombre que se usa para hacer referencia a un valor. Los identificadores pueden ser normales o entre comillas.

identifier:
      regular-identifier
      quoted-identifier
regular-identifier:
      available-identifier
      available-identifier dot-character regular-identifier
available-identifier:

      A keyword-or-identifier that is not a keyword
keyword-or-identifier:
      identifier-start-character identifier-part-charactersopt
identifier-start-character:
      letter-character
      underscore-character
identifier-part-characters:
      identifier-part-character identifier-part-charactersopt
identifier-part-character:
      letter-character
      decimal-digit-character
      underscore-character
      connecting-character
      combining-character
      formatting-character
dot-character:

      . (U+002E)
underscore-character:
      _ (U+005F)
letter-character:
      Un carácter Unicode de las clases Lu, Ll, Lt, Lm, Lo o Nl
combining-character:
      Un carácter Unicode de las clases MN o MC
decimal-digit-character:
      Un carácter Unicode de la clase Nd
connecting-character:
      Un carácter Unicode de la clase Pc
formatting-character:
      Un carácter Unicode de la clase Cf

Se puede usar un identificador entre comillas para permitir que cualquier secuencia de cero o más caracteres Unicode se use como identificador, incluidas las palabras clave, los espacios en blanco, los comentarios, los operadores y los signos de puntuación.

quoted-identifier:
      #"text-literal-charactersopt"

Tenga en cuenta que las secuencias de escape y las comillas dobles para aplicar secuencias de escape a las comillas se pueden usar en una identificador entre comillas, al igual que en un literal de texto.

En el ejemplo siguiente se usa el identificador de comillas para los nombres que contienen un carácter de espacio:

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

En el ejemplo siguiente se usa el identificador de comillas para incluir el operador + en un identificador:

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

Identificadores generalizados

Hay dos lugares en M en los que no se generan ambigüedades por los identificadores que contienen espacios en blanco o que son palabras clave o literales numéricos. Estos lugares son los nombres de los campos de registro de un literal de registro y de un operador de acceso de campo ([ ]). Allí, M permite esos identificadores sin tener que usar identificadores entre comillas.

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

Los identificadores que se usan para asignar nombres a los campos y acceder a ellos se denominan identificadores generalizados y se definen de la siguiente manera:

generalized-identifier:
      generalized-identifier-part
      generalized-identifier
separated only by blanks (U+0020)
generalized-identifier-part
generalized-identifier-part:
      generalized-identifier-segment
      decimal-digit-character generalized-identifier-segment
generalized-identifier-segment:
      keyword-or-identifier
      keyword-or-identifier dot-character keyword-or-identifier

Palabras clave

Una palabra clave es una secuencia de caracteres similar a un identificador que está reservada y no se puede usar como identificador excepto cuando se utiliza el mecanismo de comillas de identificador o cuando se permite un identificador generalizado.

keyword: una de
       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

Operadores y signos de puntuación

Hay varios tipos de operadores y signos de puntuación. Los operadores se usan en expresiones para describir las operaciones con uno o varios operandos implicados. Por ejemplo, la expresión a + b usa el operador + para agregar los dos operandos a y b. Los signos de puntuación se usan para agrupar y separar.

operator-or-punctuator: one of
      , ; = < <= > >= <> + - * / & ( ) [ ] { } @ ! ? ?? => .. ...