語彙結構
文件
M 「文件」是 Unicode 字元的排序序列。 M 允許在 M 文件的不同部分中使用不同 Unicode 字元類別。 如需 Unicode 字元類別的資訊,請參閱「Unicode 標準 3.0 版」,第 4.5 節。
文件可以僅由單一「運算式」組成,或由組織成「區段」的一組「定義」組成。 第 10 章會詳細描述區段。 概念上而言,下列步驟用於從文件讀取運算式:
文件會根據其字元編碼配置來解碼為 Unicode 字元序列。
會執行語彙分析,藉此將 Unicode 字元串流轉譯成權杖串流。 本節的其餘小節將討論語彙分析。
會執行語法分析,藉此將權杖串流轉譯為可評估的格式。 後續章節將會討論此程序。
文法慣例
語彙和語法文法會使用「文法生產」來呈現。 每個文法生產都會將非終端符號及該非終端符號的可能擴充定義於非終端或終端符號序列中。 在文法生產中,「非終端 +」符號會以斜體樣式顯示,而「終端」符號會以固定寬度的字型顯示。
文法生產的第一行是所要定義非終端符號名稱,後面接著冒號。 每個後續的縮排行,都包含語法的可能擴充,並以非終端或終端符號序列的形式提供。 例如,生產:
if-expression:
if
if-condition then
true-expression else
false-expression
會定義 if-expression 以包含權杖 if
,然後依序接著 if-condition、權杖 then
、true-expression、權杖 else
以及 false-expression。
當非終端符號有多個可能的擴充時,替代項目會列於個別的行上。 例如,生產:
variable-list:
variable
variable-list ,
variable
會定義 variable-list,其中包括 variable,或包含 variable-list,後面接著 variable。 換句話說,定義是遞迴的,並指定變數清單由一或多個變數組成 (以逗號分隔)。
下標尾碼 "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。
替代項目通常會列在個別行上,但在有許多替代項目的情況下,片語 "one of" 可能會位於單一行上指定的擴充清單前面。 這是在個別行上列出每個替代項目的簡略版。 例如,生產:
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
token comment
在語彙層級,M 文件是由 whitespace、comment 和 token 元素的串流組成。 下列章節將討論這些生產。 只有 token 元素在語法文法中是重要的。
空格
空白用來分隔 M 文件內的註解和權杖。 空白包含空白字元 (Unicode 類別 Zs 的一部分),以及水平和垂直定位、換頁字元和新行字元序列。 新行字元序列包括歸位字元、換行字元、換行字元後面接著歸位字元、下一行和段落分隔符號字元。
空白字元:
任何具有 Unicode 類別 Zs 的字元
水平定位字元 (U+0009
)
垂直定位字元 (U+000B
)
換頁字元 (U+000C
)
歸位字元 (U+000D
),後面接著換行字元 (U+000A
)
new-line-character
new-line-character:
歸位字元 (U+000D
)
換行字元 (U+000A
)
新行字元 (U+0085
)
分行符號字元 (U+2028
)
段落分隔符號字元 (U+2029
)
為了與可新增檔案結尾標記的原始程式碼編輯工具相容,並讓文件視為適當終止行的序列,下列轉換將會依序套用至 M 文件:
如果文件的最後一個字元是 Control-Z 字元 (
U+001A
),則會刪除此字元。如果文件不是空白,且文件的最後一個字元不是歸位字元 (
U+000D
)、換行字元 (U+000A
)、分行符號 (U+2028
) 或段落分隔符號 (U+2029
),則會將歸位字元 (U+000D
) 新增至文件結尾。
註解
支援兩種形式的註解:單行註解和分隔註解。 「單行註解」以 //
字元開頭,並延伸至來源行的結尾。 「分隔註解」以 /*
字元開頭,並以 */
字元結尾。
分隔註解可能會跨越多行。
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:
除了 new-line-character 以外的任何 Unicode 字元
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:
除了 *
或 /
以外的任何 Unicode 字元
註解不會巢狀化。 /*
和 */
的字元序列在單行註解內不具特殊意義,且 //
和 /*
的字元序列在分隔註解內不具特殊意義。
註解不會在文字常值中處理。 範例
/* Hello, world
*/
"Hello, world"
包含分隔註解。
範例
// Hello, world
//
"Hello, world" // This is an example of a text literal
顯示數個單行註解。
語彙基元
token 是識別碼、關鍵字、常值、運算子或標點符號。 空白和註解用來分隔權杖,但不會視為權杖。
token:
identifier
keyword
literal
operator-or-punctuator
字元逸出序列
M 文字值可以包含任意 Unicode 字元。 不過,文字常值僅限於圖形字元,並需要針對非圖形字元使用「逸出序列」。 例如,若要在文字常值中包含歸位字元、換行字元或定位字元,則可以分別使用 #(cr)
、#(lf)
和 #(tab)
逸出序列。 若要將逸出序列起始字元內嵌至 #(
文字常值中,則 #
本身必須逸出:
#(#)(
逸出序列也可以包含簡短 (四個十六進位數字) 或較長 (八個十六進位數字) 的 Unicode 字碼指標值。 因此,下列三個逸出序列是相等的:
#(000D) // short Unicode hexadecimal value
#(0000000D) // long Unicode hexadecimal value
#(cr) // compact escape shorthand for carriage return
多個逸出程式碼可以包含在單一逸出序列中並以逗號分隔;因此下列兩個序列是相等的:
#(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: 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
在 hex-digits 前面加上 0x
字元,就可以用十六進位格式指定數字。 例如:
0xff // 255
請注意,如果數字常值中包含小數點,則其後面必須至少要有一個數字。 例如,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:
若要在文字值中包含引號,則引號會重複,如下所示:
"The ""quoted"" text" // The "quoted" text
character-escape-sequence 生產可用來在文字值中撰寫字元,不需要在文件中直接將其編碼為 Unicode 字元。 例如,歸位字元與換行字元可以使用文字值來撰寫,如下所示:
"Hello world#(cr,lf)"
逐字常值
逐字常值用於儲存使用者輸入為程式碼的 Unicode 字元序列,但無法正確剖析為程式碼。 其在執行階段會產生錯誤值。
verbatim-literal:
#!"
text-literal-charactersopt "
Identifiers
「識別碼」是用來參考值的名稱。 識別碼可以是一般識別碼,或引號識別碼。
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:
underscore-character:
letter-character:
Lu、Ll、Lt、Lm、Lo 或 Nl 類別的 Unicode 字元
combining-character:
Mn 或 Mc 類別的 Unicode 字元
decimal-digit-character:
Nd 類別的 Unicode 字元
connecting-character:
Pc 類別的 Unicode 字元
formatting-character:
Cf 類別的 Unicode 字元
quoted-identifier 可用來允許任何零或多個 Unicode 字元序列作為識別碼使用,包括關鍵字、空白、註解、運算子和標點符號。
quoted-identifier:
#"
text-literal-charactersopt "
請注意,可在「引號識別碼」中使用逸出序列和雙引號來逸出引號,如同 text-literal。
下列範例會針對包含空白字元的名稱使用識別碼引號:
[
#"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]
]
用來命名和存取欄位的識別碼稱為「一般化識別碼」,並以如下方式定義:
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: one of
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
兩個運算元相加。 標點符號用於分組和分隔。
operator-or-punctuator: one of
, ; = < <= > >= <> + - * / & ( ) [ ] { } @ ! ? ?? => .. ...