8

@encodeディレクティブは、渡されたデータ型のさまざまな要素のコード化された型記述子であるconstchar*を返します。例は次のとおりです。

struct test
{ int ti ;
  char tc ;
} ;

printf( "%s", @encode(struct test) ) ;
// returns "{test=ic}"

sizeof()を使用してプリミティブ型を判別することができました。完全なオブジェクトの場合は、クラスメソッドを使用してイントロスペクションを実行できます。

しかし、不透明な構造体の各要素をどのように決定しますか?

4

3 に答える 3

15

@Lotharsの答えは「冷笑的」かもしれませんが、残念ながら、それはマークにかなり近いです。のようなものを実装する@encode()には、型情報を抽出するための本格的なパーサーが必要です。まあ、少なくとも「些細な」@encode()ステートメント以外の何か(すなわち@encode(char *))については。最近のコンパイラには、通常、2つまたは3つの主要コンポーネントがあります。

  • フロントエンド。
  • 中間端(一部のコンパイラーの場合)。
  • バックエンド。

フロントエンドはすべてのソースコードを解析する必要があり、基本的にソースコードテキストを内部の「マシンで使用可能な」形式に変換します。

バックエンドは、内部の「マシンで使用可能な」フォームを実行可能コードに変換します。

「中間エンド」を持つコンパイラは、通常、いくつかのニーズのためにそうします。それらは、おそらく完全に異なる言語で構成される複数の「フロントエンド」をサポートします。もう1つの理由は、最適化を単純化することです。すべての最適化パスは、同じ中間表現で機能します。gccコンパイラスイートは、「3ステージ」コンパイラの一例です 。llvm「中間およびバックエンド」ステージコンパイラと見なすことができます。「低レベル仮想マシン」は中間表現であり、すべての最適化はこの形式で行われます。 llvmまた、最後の1秒までこの中間表現に保持することができます。これにより、「リンク時間の最適化」が可能になります。コンパイラは実際にはclang「フロントエンド」ですllvm

したがって、@encode()「既存の」コンパイラに機能を追加したい場合は、おそらく「ソースからソースへ」の「コンパイラ/プリプロセッサ」として機能を追加する必要があります。これが元のObjective-CおよびC++コンパイラの記述方法でした。入力ソーステキストを解析して「プレーンC」に変換し、標準のCコンパイラにフィードしました。これを行うにはいくつかの方法があります。

あなた自身を転がしてください

  • yaccおよびを使用しlexて、ANSI-Cパーサーをまとめます。文法が必要です-ANSIC文法(Yacc)は良いスタートです。実は、はっきり言って、私が言うときyacc、私は本当に バイソンとを意味しflexます。また、大まかに言って、他のさまざまyacclexCベースのツール:レモンdparserなど...
  • の疑似クローンであるYappまたはEYappで使用perlします。おそらく、Cベースと比較して、アイデアをすばやくプロトタイピングするのに適しています。結局のところ、正規表現、連想配列、メモリ管理なしなどです。yaccperlyacclexperl
  • Antlrを使用してパーサーを構築します。私はこのツールチェーンの経験はありませんが、Java開発者向けのもう1つの「コンパイラコンパイラ」ツールです。自由に利用できるCおよびObjective-Cの文法が利用できるようです。

別のツールをハックする

注:これらのツールを使用して追加などを行う個人的な経験はありません@encode()が、大きな助けになると思います。

  • CIL-このツールの個人的な経験はありませんが、Cソースコードを解析してから「何かをする」ために設計されています。ドキュメントから収集できるものから、このツールを使用すると、必要なタイプ情報を抽出できるはずです。
  • スパース-一見の価値がありますが、確かではありません。
  • clang-この目的には使用していませんが、目標の1つは、この種のものだけを「簡単にハッキング可能」にすることでした。特に(そして繰り返しますが、個人的な経験はありません)、すべての構文解析の「重労働」を行い、「興味深い」部分に集中できるようにします。この場合、コンテキストと構文に依存する型情報を抽出し、それを次のように変換します。プレーンなC文字列に。
  • gccプラグイン-プラグインはgcc4.5(コンパイラの現在のアルファ/ベータバージョン)機能であり、コンパイラに簡単に接続して、必要な型情報を抽出できるようにすることができます。プラグインアーキテクチャがこの種のことを可能にするかどうかはわかりません。

その他

  • Coccinelle-「後で見る」ために最近これをブックマークしました。この「かもしれない」はあなたが望むことをすることができるかもしれません、そして「かもしれない」は多くの努力なしでそれをすることができるかもしれません。
  • MetaC-最近これもブックマークしました。これがどれほど役立つかわかりません。
  • mygcc-「かもしれない」あなたが望むことをする。それは興味深いアイデアですが、あなたが望むものに直接適用することはできません。Webページから:「Mygccを使用すると、プログラマーは構文、制御フロー、およびデータフロー情報を考慮した独自のチェックを追加できます。」

リンク。

  • CocoaDevObjective-C解析-一見の価値があります。レクサーと文法へのリンクがいくつかあります。

ボーナスリンク#1を編集します。

@Lotharは彼のコメントで良い点を述べています。実は含めるつもりだったlccのですが、途中で迷子になってしまったようです。

  • lcc - lccCコンパイラ。これは、少なくともソースコードサイズの点で特に小さいCコンパイラです。また、私が強くお勧めする本もあります。
  • tcc - tccCコンパイラ。教育学的ではありませんlccが、それでも一見の価値があります。
  • poc - pocObjective-Cコンパイラ。これは「ソースからソースへ」のObjective-Cコンパイラです。Objective-Cのソースコードを解析してCのソースコードを出力し、それを渡しgccます(通常はgcc)。で利用できないObjective-C拡張機能/機能がいくつかありますgcc。間違いなく一見の価値があります。
于 2010-02-14T01:47:52.527 に答える
4

これを実装するには、最初にANSI Cコンパイラを実装してから、実装固有のプラグマと関数を追加します。

はい、私はこれが冷笑的な答えであることを知っており、反対票を受け入れます。

于 2010-02-13T11:18:21.370 に答える
2

これを行う1つの方法は、型定義のソースコードを読み取り、@encode...を対応する文字列リテラルに置き換えるプリプロセッサを作成することです。

プログラムがでコンパイルされている場合の別のアプローチは、-g実行時にプログラムのデバッグ情報から型定義を読み取る関数を作成するか、gdbまたは別のプログラムを使用してそれを読み取り、必要に応じて再フォーマットすることです。このgdb ptypeコマンドを使用して、特定のタイプの定義を印刷できます(または、それが不十分な場合はmaint print type、必要以上の情報を印刷することもできます)。

プラグインをサポートするコンパイラ(GCC 4.5など)を使用している場合は、このためのコンパイラプラグインを作成することも可能です。プラグインは、コンパイラがすでに解析した型情報を利用できます。明らかに、このアプローチは非常にコンパイラ固有です。

于 2010-02-12T23:23:42.100 に答える