字句の構造
ドキュメント
M "ドキュメント" は、順序付けられた Unicode 文字のシーケンスです。 M では、M ドキュメントのさまざまな部分で Unicode 文字のさまざまなクラスを使用できます。 Unicode 文字クラスの詳細については、Unicode Standard, Version 3.0 のセクション 4.5 を参照してください。
ドキュメントは、正確に 1 個の "式" で構成されているか、"セクション" にまとめられた "定義" のグループで構成されています。 セクションについては、第 10 章で詳しく説明されています。 概念的に言えば、ドキュメントから式を読み取るには次の手順を使用します。
ドキュメントは、文字エンコード スキームに従って Unicode 文字のシーケンスにデコードされます。
字句解析が実行され、それによって Unicode 文字のストリームがトークンのストリームに変換されます。 このセクションの残りのサブセクションでは、字句解析について説明します。
構文解析が実行され、それによってトークンのストリームが評価可能な形式に変換されます。 このプロセスについては、以降のセクションで説明します。
文法規則
字句と構文の文法は、"文法プロダクション" を使用して表されます。 各文法プロダクションによって、非終端記号と、その非終端記号から非終端記号または終端記号のシーケンスへの可能な展開が定義されます。 文法プロダクションでは、"非終端の +" 記号は斜体で表示され、"終端" 記号は固定幅フォントで表示されます。
文法プロダクションの最初の行は、定義される非終端記号の名前と、その後にコロンを付けたものです。 連続してインデントされた各行には、非終端記号または終端記号のシーケンスとして表された、非終端要素の可能な展開が含まれます。 たとえば、次のようなプロダクションの場合:
if-expression:
if
条件 then
true-expressionelse
false-expression
if-expression が、トークン if
と、その後に続く if-condition、トークン then
、true-expression、トークン else
、false-expression で構成されることを定義しています。
1 つの非終端記号に可能な展開が複数ある場合は、代替の展開が別の行に示されます。 たとえば、次のようなプロダクションの場合:
variable-list:
変数
variable-list ,
variable
variable-list が variable で構成されるか、後に variable が続く variable-list で構成されることを定義しています。 つまり、定義は再帰的で、変数リストが 1 つ以上の変数で構成され、それがコンマで区切られていることを示します。
省略可能な記号を示すには、添字サフィックス "opt" が使用されます。 次のようなプロダクションの場合:
field-specification:
optional
opt field-name =
field-type
これは次の短縮形です。
field-specification:
field-name =
field-type
optional
field-name =
field-type
これは、field-specification がオプションで終端記号 optional
で始まり、その後に field-name、終端記号 =
、field-type が続くことを定義しています。
通常、代替の展開は別の行に示されます。ただし、多数の代替がある場合は、1 行に示された展開の一覧の前に "次のいずれか" という語句が含まれることがあります。 これは、それぞれの代替を別々の行に一覧表示することに対する簡便な方法です。 たとえば、次のようなプロダクションの場合:
decimal-digit: one of
0 1 2 3 4 5 6 7 8 9
これは次の短縮形です。
decimal-digit:
0
1
2
3
4
5
6
7
8
9
字句解析
lexical-unit プロダクションでは、M ドキュメント用の字句の文法が定義されます。 すべての有効な M ドキュメントは、この文法に準拠しています。
lexical-unit:
lexical-elementsopt
lexical-elements:
lexical-element
lexical-element
lexical-elements
lexical-element:
whitespace
トークン コメント
字句レベルでは、M ドキュメントは "空白"、"コメント"、および "トークン" 要素のストリームで構成されます。 次の各セクションで、それぞれのプロダクションについて説明します。 構文の文法においては、"トークン" 要素のみが有効です。
空白文字
空白は、M ドキュメント内のコメントとトークンを区切るために使用されます。 空白には、空白文字 (Unicode クラス Zs の一部) と、水平および垂直のタブ、フォーム フィード、改行文字シーケンスが含まれます。 改行文字シーケンスには、復帰、ライン フィード、復帰の後に続くライン フィード、次の行、段落区切り文字が含まれます。
whitespace:
Unicode クラス Zs の任意の文字
水平タブ文字 (U+0009
)
垂直タブ文字 (U+000B
)
フォーム フィード文字 (U+000C
)
復帰文字 (U+000D
) の後にライン フィード文字 (U+000A
)
改行文字
new-line-character:
復帰文字 (U+000D
)
ライン フィード文字 (U+000A
)
次の行の文字 (U+0085
)
行区切り文字 (U+2028
)
段落区切り文字 (U+2029
)
ファイルの終端マーカーを追加するソース コード編集ツールとの互換性を確保し、適切に終端された行のシーケンスとしてドキュメントを表示できるようにするには、次の変換を順番に M ドキュメントに適用します。
ドキュメントの最後の文字が制御 Z 文字 (
U+001A
) の場合、この文字は削除されます。ドキュメントが空でなく、ドキュメントの最後の文字が復帰 (
U+000D
)、ライン フィード (U+000A
)、行区切り記号 (U+2028
)、段落区切り記号 (U+2029
) のいずれでもない場合は、ドキュメントの末尾に復帰文字 (U+000D
) が追加されます。
コメント
単一行コメントと区切られたコメントという 2 つの形式のコメントがサポートされています。 "単一行コメント" は、//
文字で始まり、ソース行の末尾まで拡張されます。 "区切られたコメント" は、/*
文字で始まり、*/
文字で終わります。
区切られたコメントは、複数行にまたがる場合があります。
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:
次を除く任意の Unicode 文字: new-line-character
delimited-comment:
/*
delimited-comment-textopt アスタリスク /
delimited-comment-text:
delimited-comment-section delimited-comment-textopt
delimited-comment-section:
/
asterisksopt not-slash-or-asterisk
asterisks:
*
asterisksopt
not-slash-or-asterisk:
*
または /
を除く Unicode 文字
コメントは入れ子になりません。 文字シーケンス /*
と */
は単一行コメント内で特別な意味を持ちません。また、//
と /*
の文字シーケンスは、区切られたコメント内で特別な意味を持ちません。
コメントは、テキスト リテラル内では処理されません。 例を示します。
/* Hello, world
*/
"Hello, world"
これには区切られたコメントが含まれています。
例を示します。
// Hello, world
//
"Hello, world" // This is an example of a text literal
複数の単一行コメントが示されています。
トークン
"トークン" は識別子、キーワード、リテラル、演算子、または区切り記号です。 空白とコメントはトークンを区切るために使用されますが、トークンとは見なされません。
token:
identifier
キーワード (keyword)
リテラル
operator-or-punctuator
文字エスケープ シーケンス
M のテキスト値には任意の Unicode 文字を含めることができます。 ただし、テキスト リテラルはグラフィック文字に限定されており、非グラフィック文字に対しては "エスケープシーケンス" を使用する必要があります。 たとえば、復帰、ライン フィード、またはタブ文字をテキスト リテラルに含めるには、#(cr)
、#(lf)
、および #(tab)
の各エスケープ シーケンスをそれぞれ使用できます。 テキスト リテラルにエスケープ シーケンス文字 #(
を埋め込むには、#
自体をエスケープする必要があります。
#(#)(
エスケープ シーケンスには、短い (4 桁の 16 進数) または長い (8 桁の 16 進数) Unicode コード ポイント値を含めることもできます。 したがって、次の 3 つのエスケープ シーケンスは同等です。
#(000D) // short Unicode hexadecimal value
#(0000000D) // long Unicode hexadecimal value
#(cr) // compact escape shorthand for carriage return
複数のエスケープ コードをコンマで区切って、1 つのエスケープ シーケンスに含めることができます。次の 2 つのシーケンスは同等です。
#(cr,lf)
#(cr)#(lf)
次に、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:
#
リテラル
リテラルは、値のソース コード表現です。
literal:
logical-literal
number-literal
text-literal
null-literal
verbatim-literal
null リテラル
null リテラルは、null
値を記述するために使用されます。 null
値は、存在しない値を表します。
null-literal:
null
論理リテラル
true
および false
の値を記述するために使用される論理リテラルでは、論理値が生成されます。
logical-literal:
true
false
数値リテラル
数値を記述するために使用される数値リテラルでは、数値が生成されます。
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: 次のいずれか
0 1 2 3 4 5 6 7 8 9
exponent-part:
e
signopt decimal-digits
E
signopt decimal-digits
sign: 次のいずれか
+ -
hexadecimal-number-literal:
0x
hex-digits
0X
hex-digits
hex-digits:
hex-digit hex-digitsopt
hex-digit: 次のいずれか
0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f
数字を 16 進数形式で指定するには、"16 進数" の前に 0x
文字を付けます。 例:
0xff // 255
数値リテラルに小数点が含まれている場合は、その後に少なくとも 1 桁の数字を含める必要があることにご注意ください。 たとえば、1.3
は数値リテラルですが、1.
と 1.e3
は数値リテラルではありません。
テキスト リテラル
Unicode 文字のシーケンスを記述するために使用されるテキスト リテラルでは、テキスト値が生成されます。
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:
"
(U+0022
) と #
(U+0023
) を除くあらゆる文字に (
(U+0028
) を続けたもの
double-quote-escape-sequence:
""
(U+0022
、 U+0022
)
テキスト値に引用符を含めるには、次のように引用符を繰り返します。
"The ""quoted"" text" // The "quoted" text
"文字エスケープ シーケンス" プロダクションを使用すると、ドキュメント内に Unicode 文字として直接エンコードしなくても、テキスト値の中に文字を記述できます。 たとえば、復帰とライン フィードは、次のようにテキスト値で記述できます。
"Hello world#(cr,lf)"
逐語的リテラル
逐語的リテラルは、ユーザーがコードとして入力したものの、コードとして正しく解析できない Unicode 文字のシーケンスを格納するために使用されます。 実行時には、エラー値が生成されます。
verbatim-literal:
#!"
text-literal-charactersopt "
識別子
"識別子" は、値を参照するために使用される名前です。 識別子は、標準識別子または引用符で囲まれた識別子とすることができます。
identifier:
regular-identifier
quoted-identifier
regular-identifier:
available-identifier
available-identifier dot-character regular-identifier
available-identifier:
keyword-or-identifier (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:
Unicode 文字 (クラス Lu、Ll、Lt、Lm、Lo、Nl)
combining-character:
Unicode 文字 (クラス Mn、Mc)
decimal-digit-character:
Unicode 文字 (クラス Nd)
connecting-character:
Unicode 文字 (クラス Pc)
formatting-character:
Unicode 文字 (クラス Cf)
"引用符で囲まれた識別子" を使用すると、キーワード、空白、コメント、演算子、区切り記号など、0 個以上の Unicode 文字の任意のシーケンスを識別子として使用できます。
quoted-identifier:
#"
text-literal-charactersopt "
エスケープ シーケンスと二重引用符をエスケープするには、"引用符で囲まれた識別子" を "テキスト リテラル" の場合と同様に使用できます。
次の例では、スペース文字を含む名前を表す識別子を引用符で囲んで使用しています。
[
#"1998 Sales" = 1000,
#"1999 Sales" = 1100,
#"Total Sales" = #"1998 Sales" + #"1999 Sales"
]
次の例では、識別子を引用符で囲んで使用して、識別子に +
演算子を含めています。
[
#"A + B" = A + B,
A = 1,
B = 2
]
一般化された識別子
M には、空白を含む識別子や、キーワードまたは数値リテラルである識別子によってあいまいさが導入されることがない場所が 2 つあります。 これらの場所は、レコード リテラル内およびフィールド アクセス演算子 ([ ]
) 内にあるレコード フィールドの名前です。M では、引用符で囲まれた識別子を使用しなくても、このような識別子をそれらの場所で使用できます。
[
Data = [ Base Line = 100, Rate = 1.8 ],
Progression = Data[Base Line] * Data[Rate]
]
フィールドの名前付けとアクセスに使用される識別子は、"一般化された識別子" と呼ばれ、次のように定義されます。
generalized-identifier:
generalized-identifier-part
generalized-identifier 空白でのみ区別 (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
キーワード
"キーワード" は、識別子のように予約された文字のシーケンスであり、"識別子を引用符で囲むメカニズム" を使用する場合、または "一般化された識別子を使用できる" 場合を除き、識別子として使用することはできません。
keyword: 次のいずれか
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
演算子と区切り記号
いくつかの種類の演算子と区切り記号があります。 演算子は、1 つ以上のオペランドに関係する操作を記述するために、式で使用されます。 たとえば、式 a + b
では、+
演算子を使用して、a
および b
の 2 つのオペランドが追加されます。 区切り記号は、グループ化と分離のためのものです。
operator-or-punctuator: 次のいずれか
, ; = < <= > >= <> + - * / & ( ) [ ] { } @ ! ? ?? => .. ...