Lexikalische Struktur
Dokumente
Ein M-Dokument ist eine geordnete Sequenz aus Unicode-Zeichen. M ermöglicht verschiedene Klassen von Unicode-Zeichen in verschiedenen Teilen eines M-Dokuments. Informationen zu Unicode-Zeichenklassen finden Sie in Abschnitt 4.5 unter Unicode-Standard-Version 3.0.
Ein Dokument besteht entweder aus genau einem Ausdruck oder aus Gruppen von Definitionen, die in Abschnitte unterteilt sind. Diese Abschnitte werden in Kapitel 10 ausführlich beschrieben. Konzeptionell werden die folgenden Schritte zum Lesen eines Ausdrucks aus einem Dokument verwendet:
Das Dokument wird gemäß seines Zeichenverschlüsselungsschemas in eine Sequenz aus Unicode-Zeichen decodiert.
Die lexikalische Analyse wird durchgeführt, wodurch der Stream aus Unicode-Zeichen in einen Stream aus Token übersetzt wird. Die verbleibenden untergeordneten Abschnitte dieses Abschnitts behandeln die lexikalische Analyse.
Die syntaktische Analyse wird durchgeführt, wodurch der Stream von Tokens in ein Formular übersetzt wird, das ausgewertet werden kann. Dieses Prozess wird in den nachfolgenden Abschnitten behandelt.
Grammatikalische Konventionen
Die lexikalische und syntaktische Grammatik wird mithilfe von Grammatikproduktionen dargestellt. Jede Grammatikproduktion definiert ein Nichtterminalsymbol und dessen mögliche Erweiterungen in Sequenzen aus Nichtterminal- oder Terminalsymbolen. In Grammatikproduktionen werden Nichtterminalsymbole kursiv und Terminalsymbole in einer Schriftart mit fester Schrittbreite dargestellt.
Die erste Zeile einer Grammatikproduktion entspricht dem Namen des Nichtterminalsymbols, das definiert wird, gefolgt von einem Doppelpunkt. Jede aufeinanderfolgende eingerückte Zeile enthält eine mögliche Erweiterung des Nichtterminalsymbols als Sequenz aus Nichtterminal- und Terminalsymbolen. Zum Beispiel wird bei der folgenden Produktion:
if-Ausdruck:
if
if-conditionthen
true-expressionelse
false-expression
definiert einen if-Ausdruck, der aus dem Token if
besteht, gefolgt von einer if-Bedingung, gefolgt vom Token then
, gefolgt von einem TRUE-Ausdruck, gefolgt vom Token else
, gefolgt von einem FALSE-Ausdruck.
Wenn es mehrere mögliche Erweiterungen eines Nichtterminalsymbols gibt, werden die Alternativen in separaten Zeilen aufgeführt. Zum Beispiel wird bei der folgenden Produktion:
variable-list:
-Variable
variable-list,
variable
eine Variablenliste so definiert, dass sie entweder aus einer Variable oder einer Variablenliste, gefolgt von einer Variable, besteht. Das bedeutet, die Definition ist rekursiv und legt fest, dass eine Variablenliste aus einer oder mehreren Variablen besteht, die durch Trennzeichen getrennt sind.
„opt“ wird als indexiertes Suffix verwendet, um optionale Symbole zu kennzeichnen. Die Produktion:
field-specification:
optional
opt field-name=
field-type
ist die Kurzform für:
field-specification:
field-name=
field-type
optional
field-name=
field-type
und definiert eine Feldspezifikation, die optional mit dem Terminalsymbol optional
, gefolgt von einem Feldnamen, dem Terminalsymbol =
und einem Feldtyp beginnt.
Alternativen werden normalerweise in separaten Zeilen aufgeführt. In einigen Fällen mit vielen Alternativen kann „One of“ („Eine von“) einer Liste von Erweiterungen vorangestellt werden, die in einer einzelnen Zeile angegeben werden. Dabei handelt es sich lediglich um eine Kurzform zum Auflisten aller Alternativen in einer separaten Zeile. Zum Beispiel wird bei der folgenden Produktion:
decimal-digit: one of
0 1 2 3 4 5 6 7 8 9
ist die Kurzform für:
decimal-digit:
0
1
2
3
4
5
6
7
8
9
Lexikalische Analyse
Die Produktion lexical-unit definiert die lexikalische Grammatik für ein M-Dokument. Jedes gültige M-Dokument entspricht dieser Grammatik.
lexical-unit:
lexical-elementsopt
lexical-elements:
lexical-element
lexical-element
lexical-elements
lexical-element:
whitespace
token comment
Auf lexikalischer Ebene besteht ein M-Dokument aus einem Stream aus den Elementen Leerraum, Kommentar und Token. All diese Produktionen werden in den folgenden Abschnitten beschrieben. Nur Tokenelemente sind in der syntaktischen Grammatik von Bedeutung.
Leerzeichen
Leerraum wird verwendet, um Kommentare und Token in einem M-Dokument voneinander zu trennen. Leerraum umfasst das Leerzeichen (das Teil der Unicode-Klasse „Zs“ ist) sowie horizontale und vertikale Tabstopp-, Seitenvorschub- und Zeilenumbruchzeichenfolgen. Zeilenumbruchzeichenfolgen umfassen Wagenrücklaufzeichen, Zeilenvorschubzeichen, Wagenrücklaufzeichen, gefolgt von Zeilenvorschubzeichen, Zeilenumbruchzeichen und Absatztrennzeichen.
Leerraum:
Beliebiges Zeichen der Unicode-Klasse „Zs“
Horizontales Tabstoppzeichen (U+0009
)
Vertikales Tabstoppzeichen (U+000B
)
Seitenvorschubzeichen (U+000C
)
Wagenrücklaufzeichen (U+000D
), gefolgt von einem Zeilenvorschubzeichen (U+000A
)
Zeilenumbruchzeichen
Zeilenumbruchzeichen:
Wagenrücklaufzeichen (U+000D
)
Zeilenvorschubzeichen (U+000A
)
Zeilenumbruchzeichen (U+0085
)
Zeilentrennzeichen (U+2028
)
Absatztrennzeichen (U+2029
)
Für die Kompatibilität mit Tools für die Quellcodebearbeitung, die Kennzeichnungen für das Dateiende hinzufügen, und damit ein Dokument als Sequenz ordnungsgemäß beendeter Zeilen angezeigt werden kann, werden die folgenden Transformationen in der entsprechenden Reihenfolge auf ein M-Dokument angewendet:
Wenn es sich bei dem letzten Zeichen des Dokuments um ein Substitutionszeichen (
U+001A
) handelt, wird dieses Zeichen gelöscht.Ein Wagenrücklaufzeichen (
U+000D
) wird zum Ende des Dokuments hinzugefügt, wenn das Dokument nicht leer ist und es sich bei dem letzten Zeichen des Dokuments nicht um ein Wagenrücklaufzeichen (U+000D
), ein Zeilenvorschubzeichen (U+000A
), ein Zeilentrennzeichen (U+2028
) oder ein Absatztrennzeichen (U+2029
) handelt.
Kommentare
Es werden zwei Arten von Kommentaren unterstützt: einzeilige Kommentare und durch Trennzeichen getrennte Kommentare. Einzeilige Kommentare beginnen mit den Zeichen //
und werden an das Ende der Quellzeile angefügt. Durch Trennzeichen getrennte Kommentare beginnen mit den Zeichen /*
und enden mit den Zeichen */
.
Durch Trennzeichen getrennte Kommentare können mehrere Zeilen umfassen.
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:
Beliebiges Unicode-Zeichen mit Ausnahme eines 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
Sternchen:
*
asterisksopt
not-slash-or-asterisk:
Beliebiges Unicode-Zeichen mit Ausnahme von *
oder /
Kommentare werden nicht geschachtelt. Die Zeichenfolgen /*
und */
verfügen innerhalb eines einzeiligen Kommentars über keine besondere Bedeutung, und die Zeichenfolgen //
und /*
verfügen in einem durch Trennzeichen getrennten Kommentar über keine besondere Bedeutung.
Kommentare werden nicht in Textliteralen verarbeitet. Das Beispiel
/* Hello, world
*/
"Hello, world"
enthält einen durch Trennzeichen getrennten Kommentar.
Das Beispiel
// Hello, world
//
"Hello, world" // This is an example of a text literal
enthält mehrere einzeilige Kommentare.
Token
Ein Token ist ein Bezeichner, Schlüsselwort, Literal, Operator oder Trennzeichen. Leerraum und Kommentare werden verwendet, um Token voneinander zu trennen, gelten aber nicht als Tokens.
token:
Bezeichner
Schlüsselwort (keyword)
literal
operator-or-punctuator
Escapezeichensequenzen
M-Textwerte können arbiträre Unicode-Zeichen enthalten. Textliterale werden jedoch auf grafische Zeichen beschränkt und erfordern Escapesequenzen für nicht grafische Zeichen. Zum Beispiel können jeweils die Escapesequenzen #(cr)
, #(lf)
und #(tab)
verwendet werden, um ein Wagenrücklauf-, Zeilenvorschub- oder Tabstoppzeichen in ein Textliteral einzufügen. Zum Einbetten der Startzeichen #(
für eine Escapesequenz in einem Textliteralzeichen, muss #
selbst mit einem Escapezeichen versehen werden:
#(#)(
Escapesequenzen können auch kurze (vier Hexadezimalziffern) oder lange (acht Hexadezimalziffern) Unicode-Codepunktwerte enthalten. Die folgenden drei Escapesequenzen sind daher äquivalent:
#(000D) // short Unicode hexadecimal value
#(0000000D) // long Unicode hexadecimal value
#(cr) // compact escape shorthand for carriage return
Mehrere Escapecodes können durch Trennzeichen getrennt in eine einzelne Escapesequenz eingefügt werden. Daher sind die folgenden zwei Sequenzen äquivalent:
#(cr,lf)
#(cr)#(lf)
Im Folgenden wird der Standardmechanismus für Escapezeichen für Zeichen in M-Dokumenten beschrieben.
Escapezeichensequenz:
#(
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
Steuerzeichen:
cr
lf
tab
Escape-Escape:
#
Literale
Ein Literal ist die Quellcodedarstellung eines Werts.
literal:
logical-literal
number-literal
text-literal
null-literal
verbatim-literal
NULL-Literale
NULL-Literale werden zum Schreiben der Werts null
verwendet. Der Wert null
stellt einen fehlenden Wert dar.
NULL-Literal:
null
Logische Literale
Logische Literale werden zum Schreiben der Werte true
und false
verwendet und erzeugen logische Werte.
logical-literal:
true
false
Zahlenliterale
Zahlenliterale werden zum Schreiben numerischer Werte verwendet und erzeugen einen numerischen Wert.
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: einer der folgenden Werte
0 1 2 3 4 5 6 7 8 9
exponent-part:
e
signopt decimal-digits
E
signopt decimal-digits
Vorzeichen: einer der folgenden Werte
+ -
Hexadezimalliteral:
0x
hex-digits
0X
hex-digits
hex-digits:
hex-digit hex-digitsopt
hex-digit: einer der folgenden Werte
0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f
Eine Zahl kann im Hexadezimalformat angegeben werden, indem hex-digits die Zeichen 0x
vorangestellt werden. Beispiel:
0xff // 255
Wenn ein Dezimaltrennzeichen in einem Zahlenliteral enthalten ist, müssen Sie darauf achten, dass mindestens eine Zahl ihm folgt. Zum Beispiel ist 1.3
ein Zahlenliteral, aber 1.
und 1.e3
nicht.
Textliterale
Textliterale werden zum Schreiben einer Sequenz von Unicode-Zeichen verwendet und erzeugen einen Textwert.
Textliteral:
"
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:
Beliebiges Zeichen außer "
(U+0022
) oder #
(U+0023
), gefolgt von (
(U+0028
)
Escapesequenz mit doppelten Anführungszeichen:
""
(U+0022
, U+0022
)
Zum Einfügen von Anführungszeichen in einen Textwert muss das Anführungszeichen wie folgt wiederholt werden:
"The ""quoted"" text" // The "quoted" text
Die Produktion character-escape-sequence kann zum Schreiben von Zeichen in Textwerte verwendet werden, ohne dass sie im Dokument als Unicode-Zeichen codiert werden müssen. Ein Wagenrücklauf und Zeilenvorschub kann beispielsweise wie folgt in einen Textwert geschrieben werden:
"Hello world#(cr,lf)"
Verbatim-Literale
Ein Verbatim-Literal, also ein wörtliches Literal, wird zum Speichern einer Sequenz von Unicode-Zeichen verwendet, die von einem Benutzer als Code eingegeben wurden aber nicht ordnungsgemäß als Code analysiert werden können. Zur Laufzeit wird ein Fehlerwert erzeugt.
Verbatim-Literal:
#!"
text-literal-charactersopt"
Bezeichner
Bezeichner sind Namen für Werte. Es gibt sowohl reguläre Bezeichner als auch Bezeichner in Anführungszeichen.
identifier:
regular-identifier
quoted-identifier
regular-identifier:
available-identifier
available-identifier dot-character regular-identifier
available-identifier:
Ein keyword-or-identifier, der kein keyword ist
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
)
Unterstrichzeichen:
_
(U+005F
)
letter-character:
Ein Unicode-Zeichen der Klassen „Lu“, „Ll“, „Lt“, „Lm“, „Lo“ oder „Nl“
Kombinationszeichen:
Ein Unicode-Zeichen der Klassen „Mn“ oder „Mc“
Dezimalziffer:
Ein Unicode-Zeichen der Klasse „Nd“
Verbindungszeichen:
Ein Unicode-Zeichen der Klasse „Pc“
Formatierungszeichen:
Ein Unicode-Zeichen der Klasse „Cf“
Ein Bezeichner in Anführungszeichen kann zum Verwenden beliebiger Sequenzen mit keinen oder mehreren Unicode-Zeichen verwendet werden, einschließlich Schlüsselwörter, Leerraum, Kommentare, Operatoren und Trennzeichen.
Bezeichner in Anführungszeichen:
#"
text-literal-charactersopt"
Beachten Sie, dass Escapesequenzen und doppelte Anführungszeichen für Anführungszeichen als Escapezeichen genau wie in einem Textliteral auch in einem Bezeichner in Anführungszeichen verwendet werden kann.
Im folgenden Beispiel werden Bezeichner für Namen in Anführungszeichen gesetzt, die ein Leerzeichen enthalten:
[
#"1998 Sales" = 1000,
#"1999 Sales" = 1100,
#"Total Sales" = #"1998 Sales" + #"1999 Sales"
]
Im folgenden Beispiel werden Bezeichner in Anführungszeichen gesetzt, um den +
-Operator in einen Bezeichner einzufügen:
[
#"A + B" = A + B,
A = 1,
B = 2
]
Generalisierte Bezeichner
In M gibt es zwei Stellen, an denen keine Mehrdeutigkeiten durch Bezeichner eingeführt werden, die Leerzeichen enthalten oder auf andere Weise Schlüsselwörter oder Zahlenliterale sind. Diese Stellen sind die Namen von Datensatzfeldern in einem Datensatzliteral und im Feldzugriffsoperator ([ ]
). M lässt solche Bezeichner zu, ohne dass Bezeichner in Anführungszeichen gesetzt werden müssen.
[
Data = [ Base Line = 100, Rate = 1.8 ],
Progression = Data[Base Line] * Data[Rate]
]
Die Bezeichner für die Benennung und den Zugriff auf Felder werden als generalisierte Bezeichner bezeichnet und folgendermaßen definiert:
generalized-identifier:
generalized-identifier-part
generalized-identifier nur durch Leerzeichen getrennt (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
Schlüsselwörter
Schlüsselwörter sind Bezeichnern ähnelnde Zeichenfolgen, die reserviert sind. Sie können nicht als Bezeichner verwendet werden, es sei denn, sie werden mit dem Mechanismus für in Anführungszeichen gesetzte Bezeichner verwendet oder generalisierte Bezeichner sind zulässig.
Schlüsselwort: eines von
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
Operatoren und Trennzeichen
Es gibt verschiedene Arten von Operatoren und Trennzeichen. Operatoren werden in Ausdrücken verwendet, um Vorgänge mit einem oder mehreren Operanden zu beschreiben. Der Ausdruck a + b
verwendet beispielsweise den Operator +
, um die zwei Operanden a
und b
hinzuzufügen. Trennzeichen werden zum Gruppieren und Trennen verwendet.
operator-or-punctuator: one of
, ; = < <= > >= <> + - * / & ( ) [ ] { } @ ! ? ?? => .. ...