私が勤務している Semantic Designs Inc. は、プログラムの分析と変換のための一般的なインフラストラクチャと、さまざまなプログラミング言語用の特定の分析コンポーネントを組み込んだツールを提供しています。これらをまとめて DMS と呼びます。C++ の場合、DMS には、GCC3、GCC4、ISO14882c1998 (ANSI)、Visual C++ 6.0、およびアンマネージ Visual Studio 2005 C++ のそれぞれについて、統合されたレクサー、プリプロセッサ、パーサー、および名前と型の解決コンポーネントが含まれています。C のさまざまな方言には、制御フロー解析、副作用アナライザー、シンボル依存関係アナライザーもあり、ポインター チェッカー、非アクティブ コード リムーバー、関数プロファイラー、プログラム スライサーなどのツールが実装されています。
名前と型の解決コンポーネントは、完全なシンボル テーブル情報とルックアップ機能を提供するため、識別子への参照を型やその他の宣言情報に簡単に関連付けることができます。この情報は、コンパイラによって取り込まれて使用されるものと似ていますが、抽象構文ツリーと共に、コンポーネントを組み込んだツールによる適応型再利用に適した形式で保持されます。
Semantic Designs は最近、あなたの例のように、ループ宣言のインデックス変数の型に特に関連するカスタム ツールを構築しました。この場合の問題は、-fno-for-scope コンパイラ スイッチを使用する GCC2 コードをアップグレードすることでした。これにより、後の GCC 方言ではサポートされていないループ変数のスコープ解決規則が提供されました。このツールは、ループ変数の宣言を -fno-for-scope スコープ規則を保持する外部コンテキストに移動して、ループを変換する必要がありました。そのような変更が必要でない場合、変更は行われませんでした。
したがって、ツールはループ変数への各参照に関連付けられた型を識別し、スコープをマスキングする場合に区別し、コードを再構築して、GCC3 および GCC4 の名前解決が -fno を使用した GCC2 と同じ意味解釈になるようにする必要がありました。 -スコープ用。これには、各変数参照に関連付けられたシンボル テーブル情報にアクセスできる必要があり、コードが移動された場合は、宣言が移動された変数の型宣言の正しい構文を再構築する必要がありました。DMS C++ の名前および型解決コンポーネントによって提供されるシンボル テーブルおよび識別子参照テーブルには、必要なすべての情報が含まれており、規定の型構文を再構築するためのモジュールにより、正しい新しい型宣言の合成が可能になりました。
たとえば、次の例を考えてみましょう。
// loop variable hides variable in global scope
// will change meaning without -fno-for-scope
// fix: move decl. of cnt before for-loop
// optionally rename globcnt loop variable
float globcnt = 0.0;
int Foo::foo3() {
for (int globcnt = 0; globcnt < 5; globcnt++) {
globalInt += globcnt;
}
globalInt += 2*globcnt + 1;
return 0;
}
GCC2 -fno-for-scope セマンティクスは、GCC3 がループ変数をスコープ外と見なし、グローバル変数への参照を解決する場合でも、ループ外の globcnt への参照がループ変数へのものであることを示します。このツールは、このコードを次のように変換しました。
float globcnt = 0.0;
int Foo::foo3() {
int globcnt = 0;
for (; globcnt < 5; globcnt++) {
globalInt += globcnt;
}
globalInt += 2*globcnt + 1;
return 0;
}
コードが変換されていなければ、GCC4 は常に Foo:foo3 から値 1 を返します。ただし、変換された値は、もともと GCC2 用に設計されたループの反復の影響を受けていたはずです。ツールは、globcnt への最終参照が float 型のグローバル変数ではなく、int 型のローカル変数に対するものであることを認識する必要がありました。これは、シンボル テーブル ルックアップを介して行うことができ、それに応じて動作する必要がありました。
一方、ツールは次のコードで i への参照がループの外側にないことを認識したため、ループ変数の宣言をそのままにしておくことが許容されました (そして優先されました)。
int Foo::foo0() {
for (int i = 0; i < 10; i++) {
globalInt += i*i;
}
return 0;
}