4

C ファイルに対して単純な分析を実行したい (fooマクロをINT_TYPE引数として呼び出し、応答を にキャストする場合などint*)、ファイルを前処理したくなく、解析したいだけです (たとえば、正しい行番号が表示されます)。

つまり、私はから取得したい

#include <a.h>

#define FOO(f)

int f() {FOO(1);}

のようなトークンのリスト

<include_directive value="a.h"/>
<macro name="FOO"><param name="f"/><result/></macro>
<function name="f">
    <return>int</return>
    <body>
        <macro_call name="FOO"><param>1</param></macro_call>
    </body>
</function>

インクルードパスなどを設定する必要はありません。

それを行う既存のパーサーはありますか?私が知っているすべてのパーサーは、C が前処理されていると想定しています。マクロと実際のインクルード命令にアクセスしたい。

4

3 に答える 3

1

私たちのCフロントエンドは、プリプロセッサ要素を含むコードを解析できます。これはかなりの程度まで実行でき、それでも使用可能なASTを構築できます。(はい、解析ツリーには正確なファイル/行/列番号情報があります)。

ほとんどのコードを処理できるようにするいくつかの制限があります。これらのいくつかのケースでは、処理できません。多くの場合、同等のコードを提供するソースファイルへの小さな簡単な変更で問題が解決します。

規則と制限の大まかなセットは次のとおりです。

  • #includesと#definesは、宣言またはステートメントが発生する可能性がある場所であればどこでも発生する可能性がありますが、ステートメントの途中では発生しません。これらが問題を引き起こすことはめったにありません。
  • マクロ呼び出しは、関数呼び出しが式で発生する場合に発生する可能性があります。または、ステートメントの代わりにセミコロンなしで表示される可能性があります。整形式でないチャンクにまたがるマクロ呼び出しは適切に処理されません(誰もが驚いていますか?)。後者は時折発生しますが、まれではなく、手動で修正する必要があります。OPの「j(v、oid)*」の例には問題がありますが、これはコードでは非常にまれです。
  • #if ... #endifは、主要な言語の概念(非終端記号)(定数、式、ステートメント、宣言、関数)またはそのようなエンティティのシーケンス、または特定の整形式ではないが一般的に発生するイディオム(ifなど)をラップする必要があります。 (exp){。条件文の各アームには、他のアームと同じ種類の構文構造が含まれている必要があります。#悪い種類のコメントとして使用されるランダムなテキストを折り返すと問題が発生しますが、実際のコメントを作成することでソースで簡単に修正できます。これらの条件が満たされない場合は、多くの場合、#if #elsif #else #endいくつかのトークンを移動して、元のソースコードを変更する必要があります。

私たちの経験では、これらの問題を回避するために、数時間で50,000行のコードベースを修正できます。それは面倒に思えますが(そしてそれはそうです)、代替手段はソースコードをまったく解析できないことです。これは面倒よりもはるかに悪いことです。

また、単なるパーサー以上のものが必要です。解析ツリーの取得に成功した後に何が起こるかを知るには、 「解析後の生活」を参照してください。宣言が埋め込まれているプリプロセッサコンテキストで宣言が記録されるシンボルテーブルを構築するためにいくつかの追加作業を行い、型チェックにプリプロセッサ条件を含めることができるようにしました。

于 2012-05-28T15:56:27.440 に答える
0

このANTLR grammarを見ることができます。ただし、プリプロセッサ トークンのルールを追加する必要があります。

于 2012-05-28T13:01:17.917 に答える
-1

特定の例は、独自の解析を記述し、マクロ展開を無視することで処理できます。

FOO(1)それ自体が関数呼び出しとして解釈できるためです。

ただし、より多くのケースが考慮されると、パーサーははるかに難しくなります。詳細については、 PDF リンクを参照してください。

于 2012-09-08T13:56:48.583 に答える