空白、改行、水平タブ、キャリッジリターン、ラインフィード、フォームフィードはブランクと見なされます。ブランクは基本的に無視されますが、識別子、リテラル、キーワードを区切るために使われます(間にブランクがないと複数の識別子が 1 つの識別子と見なされてしまいます)。
コメントは (*
で始まり *)
で終わります。
(* や *) の間にブランクを挟んではいけません。
コメントはブランクとして扱われます。
文字列や文字リテラルの中にコメントは入れられません。
コメントは入れ子にすることも可能です。
ident | ::= | ( letter | _ ) { letter | 0...9 | _ | ' } |
letter | ::= | A...Z | a...z |
識別子は英文字、数字、_
(アンダースコア)、 '
(シングルクォート)の列です。ただし最初の文字には英文字かアンダースコアしか使えません。英文字は少なくとも ASCII 文字集合の大文字と小文字をあわせた 52 文字が使えます。現在の実装では(MacOS 以外では) ISO 8859-1 (ISO Latin 1)文字集合のアクセント付き文字も英文字として認識します。識別子の文字はすべて意味を持ち、現在の実装では 16000000 文字までの識別子を受け付けます。
integer-literal | ::= | [-] { 0...9 }+ |
| | [-] (0x | 0X) { 0...9 | A...F | a...f }+ | |
| | [-] (0o | 0O) { 0...7 }+ | |
| | [-] (0b | 0X) { 0...1 }+ |
整数リテラルは 1 つ以上の数字の列です。先頭にマイナス符号をつけることもできます。デフォルトでは整数リテラルは 10 進数ですが、以下の接頭辞を付けることで別の基数を指定することもできます。
接頭辞 | 基数 |
---|---|
0x, 0X | 16 進数 |
0o, 0O | 8 進数 |
0b, 0B | 2 進数 |
(先頭の 0
は数字のゼロで、8 進数の O
は英文字の O
です)整数で表せる範囲を外れた整数リテラルをどのように解釈するかは未定義です。
読み易さと便利のために、整数リテラルにはアンダースコア文字(_
)を入れることができます(単純に無視されます)。
float-literal | ::= | [ - ] ( 0...9 ) { 0...9 | _ } [ . { 0...9 | _ } ] [ ( e | E ) [ + | - ] ( 0...9 ) { 0...9 | _ } ] |
浮動小数点数は整数部、小数部、指数部の 3 つに分かれます。整数部は 1 つ以上の数字の列でマイナス符号がつけることもできます。小数部は小数点に 0 個以上の数値を続けたものです。指数部はまず文字 e
か E
があり、その後に省略可能な +
か -
が続き、最後に数字が 1 つ以上続きます。小数部や指数部は省略可能ですが、整数リテラルと区別がつかないものは許されません。浮動小数点数が表せる範囲を外れた浮動小数点数リテラルをどのように解釈するかは未定義です。
char-literal | ::= | ' regular-char ' |
| | ' escape-sequence ' | |
escape-sequence | ::= | \ ( \ | " | ' | n | t | b | r ) |
| | \ ( 0...9 ) ( 0...9 ) ( 0...9 ) |
文字リテラルは '
(シングルクォート)文字で区切ります。
2 つのシングルクォートで、 '
や \
以外の文字、もしくは以下のエスケープシーケンスのいずれかを囲みます。
エスケープシーケンス | 表される文字 |
---|---|
\\ | バックスラッシュ(\) |
\" | ダブルクォート(") |
\' | シングルクォート(') |
\n | ラインフィード(LF) |
\r | キャリッジリターン(CR) |
\t | 水平タブ(TAB) |
\b | バックスペース(BS) |
\ ddd | ASCII コード ddd (10 進数)で表される文字 |
\x hh | ASCII コード hh (16 進数)で表される文字 |
string-literal | ::= | " { string-character } " |
string-character | ::= | regular-char |
| | escape-sequence |
文字列リテラルは " (ダブルクォート)で区切られます。
2 つのダブルクォートで、 "
や \
以外の文字か、上の文字リテラルの条の表のエスケープシーケンスのいずれかを並べたものを囲みます。
複数行にまたがるような長い文字列リテラルを書けるよう、文字列リテラル中では \
(行末に newline
blanks
\
、それに続いて次の行頭に任意個のブランク)という並びは無視されます。
現在の実装では、実際上文字列リテラルの長さに制限はありません。
名前付きラベルは ~
、ident、:
の 3 つのトークン列と文法を定義すると曖昧性が生じるため、字句解析レベルで定義されています。
label | ::= | ~ ( a...z ) { letter | 0...9 | _ | ' } : |
optlabel | ::= | ? ( a...z ) { letter | 0...9 | _ | ' } : |
名前付きラベルには、通常の引数用の label と、省略可能引数用の optlabel の 2 種類があります。これは単純に最初の文字が ~
であるか ?
であるかで区別されます。
infix-symbol | ::= | ( = | < | > | @ | ^ | | | & | + | - | * | / | $ | % ) { operator-char } |
prefix-symbol | ::= | ( ! | ? | ~ ) { operator-char } |
operator-char | ::= | ! | $ | % | & | * | + | - | . | / | | < | = | > | ? | @ | ^ | | | ~ |
<=>
や !!
のような演算子文字の列は infix-symbol や prefix-symbol クラスの 1 つのトークンとみなされます。これらのシンボルは式中では前置演算子や中置演算子として構文解析されますが、一方で識別子のようにも振る舞います。
以下の識別子はキーワードとして予約されているため、その他の用途には利用できません。
and as assert asr begin class constraint do done downto else end exception external false for fun function functor if in include inherit initializer land lazy let lor lsl lsr lxor match method mod module mutable new object of open or private rec sig struct then to true try type val virtual when while with
以下の文字の並びもキーワードです。
!= # & && ' ( ) * + , - -. -> . .. : :: := :> ; ;; < <- = > >] >} ? ?? [ [< [> [| ] _ ` { {< | |] } ~
また、次の識別子は Camlp4 拡張の予約語であり、互換性の理由から避けるべきであることにも注意してください。
parser << <: >> $ $$ $:
字句解析の曖昧性は「最長マッチング」規則に従って解決されます。例えばある文字列を 2 つのトークンに分ける方法が複数ある場合、1 つ目のトークンが最長になる分け方が採用されます。
linenum-directive | ::= | # { 0...9 }+ |
| | # { 0...9 }+ " { string-character } " |
Caml のソースコードのプリプロセッサで出力に行番号指示語を加えるようにすると、エラーメッセージ中の行番号とソースファイル名を前処理前のものにすることが出来ます。行番号指示子は #
(シャープ)で始まり、整数(行番号)、それに続く省略可能な文字列(ソースファイル名)で構成されます。行番号指示子は字句解析中ではブランクとして扱われます。