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:
El documento se descodifica según su esquema de codificación de caracteres en una secuencia de caracteres Unicode.
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.
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:
if
if-conditionthen
true-expressionelse
false-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:
optional
opt field-name=
field-type
es la abreviatura de:
field-specification:
field-name=
field-type
optional
field-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:
e
signopt decimal-digits
E
signopt decimal-digits
sign: one of
+ -
hexadecimal-number-literal:
0x
hex-digits
0X
hex-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.
y 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
, ; = < <= > >= <> + - * / & ( ) [ ] { } @ ! ? ?? => .. ...