字句の構成
Dでは、 字句解析は構文解析や意味解析とは独立しています。 字句解析器は文法に従ってソーステキストをトークンに分解しますが、 Dの字句解析の文法は、 特殊な規則をできる限り減らしてあるので、 正確で高速な解析器が簡単に書けるようになっています。 各トークンは、 C/C++に慣れた人にはわかりやすいものです。コンパイルの段階
コンパイル処理は複数の段階に分かれています。 各々の段階どうしには依存関係はありません。例えば、 構文解析器は意味解析の結果に依存していません。 このように段階ごとにわかれていることで、 予約語の色分けのできるエディタの開発などが書きやすくなっています。 Dのソースを圧縮して、 'トークン分けされた'状態で保持することも可能です。- ソースの文字セット
ソースファイルがどの文字コードで書かれているのかを調べ、 適切な解析器を呼び出します。 ASCIIかUTF形式が利用できます。 - スクリプト行
先頭の行が #! で始まっていた場合、 その先頭行は無視されます。 - 字句解析
ソースファイルをトークンの列へと分解します。 特殊トークン は他のトークンへと置換されます。 特殊トークン列 はこの段階で処理され、取り除かれます。 - 構文解析
トークンの列から構文木を作ります。 - 意味解析
構文木をたどって、変数を宣言したりシンボルテーブルをロードしたり式に型を割り当てたり します。まとめて言うと、プログラムの意味を決定します。 - 最適化
最適化、プログラムを書き換えて、 意味は同等でもより高速に実行されるバージョンを作ろうとする課程です。 - コード生成
プログラムの意味を実現するために、 目的のアーキテクチャの命令コードが選ばれます。 典型的な出力形式は、リンカへの入力に適した、オブジェクトファイルです。
ソーステキスト
Dのソーステキストは次のフォーマットのいずれかです:- ASCII
- UTF-8
- UTF-16BE
- UTF-16LE
- UTF-32BE
- UTF-32LE
形式 | BOM |
---|---|
UTF-8 | EF BB BF |
UTF-16BE | FE FF |
UTF-16LE | FF FE |
UTF-32BE | 00 00 FE FF |
UTF-32LE | FF FE 00 00 |
ASCII | BOMはつかない |
ソースファイルが BOM で始まらない場合は、 最初の2文字は必ず U0000007F 以下でなければなりません。
二連文字(digraph)や三連文字(trigraph)はDには存在しません。
ソーステキストは、Unicode文字の列へとデコードされ、 解釈されます。 Unicode文字は、以下に分類されます: 空白文字、 行終端、 コメント、 特殊トークン列、 トークン、 そして最後に、ファイル終端。
トークンへ分解する際には、最長一致戦略を用います。つまり、
字句解析器はできるだけ長いトークンを探そうとします。
例えば
>>
は右シフトトークンであって、
2個の不等号トークンとは解釈しません。この規則の例外は、
浮動小数点数リテラルとして読めるトークンに挟まれた .. です。
例えば 1..2 は、.. が先頭の
1 と空白で区切られているかのように解釈されます。
ファイル終端
EndOfFile: physical end of the file \u0000 \u001Aどれかが一番最初に出現した点をソースの終端とします。
行終端
EndOfLine: \u000D \u000A \u000D \u000A EndOfFileバックスラッシュで行を分けることはできません。 1行の文字数に制限はありません。
空白
WhiteSpace: Space Space WhiteSpace Space: \u0020 \u0009 \u000B \u000C
コメント
Comment: /* Characters */ // Characters EndOfLine NestingBlockComment Characters: Character Character Characters NestingBlockComment: /+ NestingBlockCommentCharacters +/ NestingBlockCommentCharacters: NestingBlockCommentCharacter NestingBlockCommentCharacter NestingBlockCommentCharacters NestingBlockCommentCharacter: Character NestingBlockCommentDには三種類のコメントがあります:
- ネストしないブロックコメント
- 行コメント
- ネストできるブロックコメント
文字列とコメントの中身はトークン分けされません。従って、 文字列中に埋め込まれたコメント開始記号ではコメント扱いになりませんし、 コメント内に埋め込まれた引用符では文字列扱いになりません。 "/+" コメントの中の "/+" をのぞき、 コメント中のコメント開始記号も 単純に無視されます。
a = /+ // +/ 1; // 'a = 1;' として解析される a = /+ "+/" +/ 1"; // 'a = " +/ 1";' として解析される a = /+ /* +/ */ 3; // 'a = */ 3;' として解析されるコメントを間に挟むと、トークンは分割されます。例えば
abc/**/def
は2つのトークン abc と def
です。1つの abcdef ではありません。
トークン
Token: Identifier StringLiteral CharacterLiteral IntegerLiteral FloatLiteral Keyword / /= . .. ... & &= && | |= || - -= -- + += ++ < <= << <<= <> <>= > >= >>= >>>= >> >>> ! != !<> !<>= !< !<= !> !>= ( ) [ ] { } ? , ; : $ = == * *= % %= ^ ^= ~ ~=
識別子
Identifier: IdentiferStart IdentiferStart IdentifierChars IdentifierChars: IdentiferChar IdentiferChar IdentifierChars IdentifierStart: _ Letter UniversalAlpha IdentifierChar: IdentiferStart 0 NonZeroDigit識別子はアルファベットか _、または普遍基本文字(Universal Alpha)で始まり、 アルファベット,_,数字,普遍基本文字の列が後ろに続いたものです。 普遍基本文字は ISO/IEC 9899:1999(E) Appendix D. (C99標準です) に (訳注: Universal character names for identifiers として)定義されています。識別子は大文字小文字を区別します。 長さに制限はありません。 __ (2個のアンダースコア)で始まる識別子は処理系側に予約されています。
文字列リテラル
StringLiteral: WysiwygString AlternateWysiwygString DoubleQuotedString EscapeSequence HexString WysiwygString: r" WysiwygCharacters " Postfixopt AlternateWysiwygString: ` WysiwygCharacters ` Postfixopt WysiwygCharacters: WysiwygCharacter WysiwygCharacter WysiwygCharacters WysiwygCharacter: Character EndOfLine DoubleQuotedString: " DoubleQuotedCharacters " Postfixopt DoubleQuotedCharacters: DoubleQuotedCharacter DoubleQuotedCharacter DoubleQuotedCharacters DoubleQuotedCharacter: Character EscapeSequence EndOfLine EscapeSequence: \' \" \? \\ \a \b \f \n \r \t \v \ EndOfFile \x HexDigit HexDigit \ OctalDigit \ OctalDigit OctalDigit \ OctalDigit OctalDigit OctalDigit \u HexDigit HexDigit HexDigit HexDigit \U HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit \& NamedCharacterEntity ; HexString: x" HexStringChars " Postfixopt HexStringChars: HexStringChar HexStringChar HexStringChars HexStringChar: HexDigit WhiteSpace EndOfLine Postfix: c w d
文字列リテラルは、二重引用符かWYSIWYG引用符で囲まれた 文字列やエスケープシーケンス、 16進文字列です。
Wysiwyg 文字列
WYSIWYG文字列は r" と " で囲みます。 r" と " の間の全ての文字は 文字列として扱われます。 行終端文字 は \n 文字1文字となります。 この中ではエスケープシーケンスは使用できません。
r"hello" r"c:\root\foo.exe" r"ab\n" // 4文字 'a', 'b', '\', 'n' からなる文字列
WYSIWYG文字には、バッククォート ` を使った表現もあります。 この ` 文字はキーボードによっては存在しなかったり、 フォントによっては普通の引用符 ' と区別できないことがあります。 このため ` が使用されることはまれですが、" を含む文字列を書くには便利です。
`hello` `c:\root\foo.exe` `ab\n` // 4文字 'a', 'b', '\', 'n' からなる文字列
二重引用符文字列
二重引用符 "" の中では、おなじみの \ を使った記法で エスケープシーケンスを使うことができます。 行終端文字 は \n 文字1文字として扱われます。"hello" "c:\\root\\foo.exe" "ab\n" // 3文字の文字列 'a', 'b', 改行 "ab " // これも3文字の文字列 'a', 'b', 改行
エスケープ文字列
\から始まる文字の並びはエスケープシーケンスになります。 隣り合ったエスケープ文字列は連結されます。
\n 改行文字 \t タブ文字 \" 二重引用符文字 \012 8進表記 \x1A 16進表記 \u1234 wchar文字 \U00101234 dchar文字 \® ® dchar文字 \r\n 復帰改行
未定義のエスケープシーケンスはエラーとなります。 文字列リテラルはUTF文字の組み合わせであると定義されていますが、 8進/16進エスケープシーケンスを用いることで、 任意のバイナリデータを挿入することも可能です。 一方でエスケープシーケンス \u と \U では、 有効な UTF 文字のみが挿入できます。
16進文字列
16進文字列は、16進データを使って文字列リテラルを記述する方法です。 16進データは有効なUTF文字である必要はありません。
x"0A" // "\x0A" と同じ x"00 FBCD 32FD 0A" // "\x00\xFB\xCD\x32\xFD\x0A" と同じ空白や改行文字は無視されるので、 16進データを整形して並べることができます。 16進文字の個数は2の倍数でなくてはなりません。
演算子~でつなげられているか、 あるいは単純に並べて書かれている文字列どうしは結合されます:
"hello " ~ "world" ~ \n // 文字列 'h','e','l','l','o',' ', // 'w','o','r','l','d',改行, となる以下は全て同じ意味です:
"ab" "c" r"ab" r"c" r"a" "bc" "a" ~ "b" ~ "c" \x61"bc"追加の Postfix 文字によって、 文字列リテラルの型を文脈から推論させるのではなく、明示的に指定できます。 これは、あいまいなく型を推論することが不可能なとき、例えば 文字列の型によるオーバーロードがあるときなどに役に立ちます。 postfixと対応する型はそれぞれ:
Postfix | 型 | |
---|---|---|
c | char[ ] | |
w | wchar[ ] | |
d | dchar[ ] |
"hello"c // char[] "hello"w // wchar[] "hello"d // dchar[]
文字列リテラルは読み取り専用です。文字列リテラルへの書き込みは、 未定義動作となります。
文字リテラル
CharacterLiteral: ' SingleQuotedCharacter ' SingleQuotedCharacter: Character EscapeSequence文字リテラルは、1文字分の文字かエスケープシーケンスです。 一重引用符 ' ' でくくられます。
整数リテラル
IntegerLiteral: Integer Integer IntegerSuffix Integer: Decimal Binary Octal Hexadecimal IntegerSuffix: L u U Lu LU uL UL Decimal: 0 NonZeroDigit NonZeroDigit DecimalDigits Binary: 0b BinaryDigits 0B BinaryDigits Octal: 0 OctalDigits Hexadecimal: 0x HexDigits 0X HexDigits NonZeroDigit: 1 2 3 4 5 6 7 8 9 DecimalDigits: DecimalDigit DecimalDigit DecimalDigits DecimalDigit: 0 NonZeroDigit _ BinaryDigits: BinaryDigit BinaryDigit BinaryDigits BinaryDigit: 0 1 _ OctalDigits: OctalDigit OctalDigit OctalDigits OctalDigit: 0 1 2 3 4 5 6 7 _ HexDigits: HexDigit HexDigit HexDigits HexDigit: DecimalDigit a b c d e f A B C D E F _整数は10進,2進,8進,16進のどれかの記法で表記します。
10進整数は、0,1,..,9の並びです。
2進整数は '0b' で始まる0,1の並びです。
8進整数は '0'で始まる0,1,..,7の並びです。
16進整数は、'0x' で始まる 0,1,..,9,A,..,F,a,..,f の並びです。
整数の途中に文字 '_' を入れることができます。 この文字は単に無視されます。 長いリテラルの整形に、例えば1000単位の区切りとしてなどで役に立ちます。
123_456 // 123456 1_2_3_4_5_6_ // 123456整数の後ろに 'L' または 'u' 、あるいはその両方が続くことがあります。
整数の型は次のように決定されます:
10進リテラル | 型 |
---|---|
0 .. 2147483647 | int |
2147483648 .. 9223372036854775807 | long |
10進リテラル, 接尾辞L | 型 |
0L .. 9223372036854775807L | long |
10進リテラル, 接尾辞U | 型 |
0U .. 4294967295U | uint |
4294967296U .. 18446744073709551615U | ulong |
10進リテラル, 接尾辞UL | 型 |
0UL .. 18446744073709551615UL | ulong |
非10進リテラル | 型 |
0x0 .. 0x7FFFFFFF | int |
0x80000000 .. 0xFFFFFFFF | uint |
0x100000000 .. 0x7FFFFFFFFFFFFFFF | long |
0x8000000000000000 .. 0xFFFFFFFFFFFFFFFF | ulong |
非10進リテラル, 接尾辞L | 型 |
0x0L .. 0x7FFFFFFFFFFFFFFFL | long |
0x8000000000000000L .. 0xFFFFFFFFFFFFFFFFL | ulong |
非10進リテラル, 接尾辞U | 型 |
0x0U .. 0xFFFFFFFFU | uint |
0x100000000UL .. 0xFFFFFFFFFFFFFFFFUL | ulong |
非10進リテラル, 接尾辞UL | 型 |
0x0UL .. 0xFFFFFFFFFFFFFFFFUL | ulong |
浮動小数点数リテラル
FloatLiteral: Float Suffix Integer ImaginarySuffix Integer FloatSuffix ImaginarySuffix Integer RealSuffix ImaginarySuffix Float: DecimalFloat HexFloat DecimalFloat: LeadingDecimal . LeadingDecimal . DecimalDigits DecimalDigits . DecimalDigits DecimalExponent . DecimalDigits . DecimalDigits DecimalExponent LeadingDecimal DecimalExponent DecimalExponent e DecimalDigits E DecimalDigits e+ DecimalDigits E+ DecimalDigits e- DecimalDigits E- DecimalDigits HexFloat: HexPrefix HexDigits . HexDigits HexExponent HexPrefix . HexDigits HexExponent HexPrefix HexDigits HexExponent HexPrefix: 0x 0X HexExponent: p DecimalDigits P DecimalDigits p+ DecimalDigits P+ DecimalDigits p- DecimalDigits P- DecimalDigits Suffix: FloatSuffix RealSuffix ImaginarySuffix FloatSuffix ImaginarySuffix RealSuffix ImaginarySuffix FloatSuffix: f F RealSuffix: L ImaginarySuffix: i LeadingDecimal: Decimal 0 DecimalDigits浮動小数点数は、標準Cと同様に、 10進または16進表記が可能です。
16進浮動小数は 0x で始まり、 指数部は p か P のうしろに 2 の指数を表す数を続けたものです。
浮動小数点数リテラルの途中に文字 '_' を入れることができ、 この文字は単に無視されます。 長いリテラルを整形して読みやすくするのに役立ちます。 例えば、1000単位の区切りとしてなど:
123_456.567_8 // 123456.5678 1_2_3_4_5_6_._5_6_7_8 // 123456.5678 1_2_3_4_5_6_._5e-6_ // 123456.5e-6接尾辞のない浮動小数点数はdouble型です。 浮動小数点数には接尾辞 f, F, L のうちどれか一つを付けることができます。 f と F は値がfloat型であることを示し、 L はreal型であることを示します。
接尾辞 i があれば、 ireal (虚数) 型です。
例:
0x1.FFFFFFFFFFFFFp1023 // double.max 0x1p-52 // double.epsilon 1.175494351e-38F // float.min 6.3i // idouble 6.3 6.3fi // ifloat 6.3 6.3Li // ireal 6.3リテラルが型の表現可能な範囲を超えていると、 エラーになります。 リテラルの示す値の下位桁が丸められるのはエラーではありません。
複素数リテラルはトークンではなく、意味解析によって 実数と虚数トークンが組み合わせられます。
4.5 + 6.2i // 複素数
予約語
以下が予約された識別子です:Keyword: abstract alias align asm assert auto body bool break byte case cast catch cdouble cent cfloat char class const continue creal dchar debug default delegate delete deprecated do double else enum export extern false final finally float for foreach function foreach_reverse goto idouble if ifloat import in inout int interface invariant ireal is lazy long macro mixin module new null out override package pragma private protected public real ref return scope short static struct super switch synchronized template this throw true try typedef typeid typeof ubyte ucent uint ulong union unittest ushort version void volatile wchar while with
特殊トークン
特殊トークンは、 以下の表に従って別のトークンへと置換されます:
特殊トークン | 置換後... |
---|---|
__FILE__ | ソースファイル名の文字列リテラル |
__LINE__ | 現在のソース行番号の整数リテラル |
__DATE__ | コンパイルした日にちの文字列リテラル "mmm dd yyyy" |
__TIME__ | コンパイルした時刻の文字列リテラル "hh:mm:ss" |
__TIMESTAMP__ | コンパイルした日時の文字列リテラル "www mmm dd hh:mm:ss yyyy" |
__VENDOR__ | コンパイラベンダ名文字列。例えば "Digital Mars D" |
__VERSION__ | コンパイラのバージョン番号を表す整数。例えば 2001 |
特殊トークン列
特殊トークン列は、トークン列のどの位置にでも登場でき、 字句解析器によって処理されます。 構文解析には影響しません。現在の所、特殊トークン列は #line 一つだけです。
SpecialTokenSequence: # line Integer EndOfLine # line Integer Filespec EndOfLine Filespec: " Characters "これによって、 次の行の行番号は Integer に、 ファイル名は(もしあれば)Filespec に設定されます。 ソースファイル名と行番号は、 エラーメッセージや デバッガ用のシンボルとして使用されています。
例:
int #line 6 "foo\bar" x; // ここがファイル foo\bar の6行目扱いになるバックスラッシュ文字は Filespec 文字列の中では 特別扱いされないことにご注意下さい。