翻訳フェーズ
From cppreference.com
Cソースファイルは、次のフェーズがこの厳密な順序で実行されるかのように、コンパイラによって処理されます。実際の], 実装では、動作が同じである限り、これらのアクションを組み合わせたり、異なる方法で処理したりする場合があります。
目次 |
[編集] フェーズ 1
1) ソースコードファイル(通常はUTF-8などのマルチバイトエンコーディングのテキストファイル)の個々のバイトは、実装定義の方法で、*ソース文字セット*の文字にマッピングされます。特に、OS依存の行末インジケータは改行文字に置き換えられます。
- ソース文字セットは、次の96文字からなるシングルバイトサブセットとして*基本ソース文字セット*を含むマルチバイト文字セットです。
a) 5つの空白文字(スペース、水平タブ、垂直タブ、フォームフィード、改行)
b) '0'から'9'までの10個の数字
c) 'a'から'z'、および'A'から'Z'までの52文字のアルファベット
d) 29個の句読点文字: _ { } [ ] # ( ) < > % : ; . ? * + - / ^ & | ~ ! = , \ " '
2) トリグラフシーケンスは、対応するシングル文字表現に置き換えられます。(C23まで)
[編集] フェーズ 2
1) バックスラッシュが行末(改行文字の直後)にある場合、バックスラッシュと改行の両方が削除され、2つの物理行が1つの論理行に結合されます。これは単一パス操作です。2つのバックスラッシュで終わり、その後に空行がある行は、3行を1つに結合しません。
このコードを実行
#include <stdio.h> #define PUTS p\ u\ t\ s /* Line splicing is in phase 2 while macros * are tokenized in phase 3 and expanded in phase 4, * so the above is equivalent to #define PUTS puts */ int main(void) { /* Use line splicing to call puts */ PUT\ S\ ("Output ends here\\ 0Not printed" /* After line splicing, the remaining backslash * escapes the 0, ending the string early. */ ); }
2) このステップの後(元々改行がなかったか、バックスラッシュで終わっていたかに関わらず)、空でないソースファイルが改行文字で終わっていない場合、動作は未定義です。
[編集] フェーズ 3
1) ソースファイルは、コメント、空白文字(スペース、水平タブ、改行、垂直タブ、フォームフィード)のシーケンス、および*プリプロセッサートークン*に分解されます。プリプロセッサートークンは以下のとおりです。
a) ヘッダー名: <stdio.h> または "myfile.h"
b) 識別子
c) プリプロセッサ番号。これは整数定数と浮動小数点定数をカバーしますが、1..E+3.foo や 0JBK のような無効なトークンもカバーします。
e) 演算子および区切り文字、例: +、<<=、<%、または ##。
f) 他のどのカテゴリにも当てはまらない、個々の非空白文字
2) 各コメントは1つのスペース文字に置き換えられます。
3) 改行は保持され、改行以外の空白シーケンスが単一のスペース文字に折りたたまれるかどうかは実装定義です。
入力が指定された文字までプリプロセッサートークンに解析された場合、次のプリプロセッサートークンは、通常、プリプロセッサートークンを構成できる最長の文字シーケンスとして取得されます。これは、後続の分析が失敗する原因となる場合でも同様です。これは一般に*最大マッチャー*として知られています。
int foo = 1; // int bar = 0xE+foo; // error: invalid preprocessing number 0xE+foo int bar = 0xE/*Comment expands to a space*/+foo; // OK: 0xE + foo int baz = 0xE + foo; // OK: 0xE + foo int pub = bar+++baz; // OK: bar++ + baz int ham = bar++-++baz; // OK: bar++ - ++baz // int qux = bar+++++baz; // error: bar++ ++ +baz, not bar++ + ++baz int qux = bar+++/*Saving comment*/++baz; // OK: bar++ + ++baz
最大マッチャー規則の唯一の例外は次のとおりです。
- ヘッダー名プリプロセッサートークンは、 #include ディレクティブ内、または #embed ディレクティブ内(C23以降)、__has_includeおよび__has_embed式内(C23以降)、および #pragma ディレクティブ内の実装定義の場所でのみ形成されます。
#define MACRO_1 1 #define MACRO_2 2 #define MACRO_3 3 #define MACRO_EXPR (MACRO_1 <MACRO_2> MACRO_3) // OK: <MACRO_2> is not a header-name
[編集] フェーズ 4
1) プリプロセッサが実行されます。
2) #include ディレクティブで導入された各ファイルは、再帰的にフェーズ1からフェーズ4まで処理されます。
3) このフェーズの終わりに、すべてのプリプロセッサディレクティブがソースから削除されます。
[編集] フェーズ 5
1) 文字定数および文字列リテラル内のすべての文字とエスケープシーケンスは、*ソース文字セット*から*実行文字セット*に変換されます(これは、フェーズ1でリストされた*基本ソース文字セット*の96文字すべてがシングルバイト表現を持つ限り、UTF-8のようなマルチバイト文字セットである可能性があります)。エスケープシーケンスで指定された文字が実行文字セットのメンバーでない場合、結果は実装定義ですが、ヌル(ワイド)文字ではないことが保証されています。
注: この段階で実行される変換は、一部の実装ではコマンドラインオプションで制御できます。gccおよびclangは、ソース文字セットのエンコーディングを指定するために-finput-charsetを、文字列リテラルおよび文字定数の実行文字セットのエンコーディングを指定するために-fexec-charsetおよび-fwide-exec-charsetを使用します(エンコーディングプレフィックスがないもの(C11以降)。
[編集] フェーズ 6
隣接する文字列リテラルが連結されます。
[編集] フェーズ 7
コンパイルが行われます。トークンは構文的および意味的に解析され、翻訳単位として変換されます。
[編集] フェーズ 8
リンクが行われます。外部参照を満たすために必要な翻訳単位とライブラリコンポーネントが、実行環境(OS)で実行するために必要な情報を含むプログラムイメージに収集されます。
[編集] 参考文献
- C23標準 (ISO/IEC 9899:2024)
- 5.1.1.2 翻訳フェーズ (p: TBD)
- 5.2.1 文字セット (p: TBD)
- 6.4 字句要素 (p: TBD)
- C17標準 (ISO/IEC 9899:2018)
- 5.1.1.2 翻訳フェーズ (p: 9-10)
- 5.2.1 文字セット (p: 17)
- 6.4 字句要素 (p: 41-54)
- C11標準 (ISO/IEC 9899:2011)
- 5.1.1.2 翻訳フェーズ (p: 10-11)
- 5.2.1 文字セット (p: 22-24)
- 6.4 字句要素 (p: 57-75)
- C99標準 (ISO/IEC 9899:1999)
- 5.1.1.2 翻訳フェーズ (p: 9-10)
- 5.2.1 文字セット (p: 17-19)
- 6.4 字句要素 (p: 49-66)
- C89/C90標準 (ISO/IEC 9899:1990)
- 2.1.1.2 翻訳フェーズ
- 2.2.1 文字セット
- 3.1 字句要素
[編集] 関連項目
| C++ドキュメント(*翻訳フェーズ*について)
|