トライグラフとダイグラフを使用するのではなく、両方を理解しようとしています。
私はその投稿を読んで、次のことを理解しました。
- トリグラフの対応する文字への変換は、実際のコンパイルが開始される前に、常にプリプロセッサによって行われます。
- ダイグラフの対応する文字への変換は、コンパイラによって実行されます。
これは本当ですか?
トライグラフとダイグラフを使用するのではなく、両方を理解しようとしています。
私はその投稿を読んで、次のことを理解しました。
これは本当ですか?
Trigraph シーケンスは、プリプロセッサ lexer が文字のストリームを分析してプリプロセッサ トークンを生成する前に、コンパイル プロセスの最初のフェーズで実際に対応する文字に置き換えられます。
次のフェーズでは、エスケープされた改行を処理します。つまり、\
直後に改行が続く のインスタンスで、文字ストリームから削除されます。は、 trigraphの代わりとして最初のフェーズで生成できることに注意してください\
??/
。
次に、レクサーは文字ストリームを分析して、 、 などの前処理トークンを生成します。これは[
、 and と同様に<:
、同じトークンの別のスペルです。したがって、はに置き換えられません。これは、同じトークンを生成する異なる文字シーケンスです。1e1
1E1
<:
[
マクロ展開でプリプロセッサ演算子を使用してトークンを貼り付けることによってトライグラフを生成することはできませんが##
、ダイグラフは可能です。
??/
以下は、このプロセスを説明するための小さなサンプル プログラムです。これには、に展開されるトライグラフの特別な処理が含ま\
れているため、2 行に分割された有向グラフの途中で使用できます。
#include <stdio.h>
#define STR(x) #x
#define xSTR(x) STR(x)
#define glue(a,b) a##b
int main() {
puts(STR(??!));
puts(STR('??!'));
puts(STR("??!"));
puts(STR(<:));
puts(STR('<:'));
puts(STR("<:"));
puts(STR(<\
:));
puts(STR(<??/
:));
puts(STR('<\
:'));
puts(STR("<\
:"));
puts(STR(glue(<,:)));
puts(xSTR(glue(<,:)));
return 0;
}
出力:
chqrlie $ make lexing && ./lexing
clang -O3 -funsigned-char -std=c11 -Weverything -Wwrite-strings -lm -o lexing lexing.c
lexing.c:8:14: warning: trigraph converted to '|' character [-Wtrigraphs]
puts(STR(??!));
^
lexing.c:9:15: warning: trigraph converted to '|' character [-Wtrigraphs]
puts(STR('??!'));
^
lexing.c:10:15: warning: trigraph converted to '|' character [-Wtrigraphs]
puts(STR("??!"));
^
lexing.c:18:15: warning: trigraph converted to '\' character [-Wtrigraphs]
puts(STR(<??/
^
4 warnings generated.
|
'|'
"|"
<:
'<:'
"<:"
<:
<:
'<:'
"<:"
glue(<,:)
<:
ダイグラフは「対応する文字に変換」されません。文字列リテラル"<:"
には、2 つの文字<
と:
(プラス NULL ターミネータ) が含まれます。"??("
トリグラフをサポートするコンパイラがある場合は、文字列と対比してください。
<:
は、 とまったく同じ構文上の意味を持つ単純なトークン[
です。ただし、 に変換されることはありません[
。これを stringify 演算子に渡すと、文字#
列が取得されます"<:"
。