2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

clang で AST を JSON で dump するメモ

Last updated at Posted at 2021-06-06

背景

C/C++ コードから関数定義を抜き出したり, ちょっとした source-to-source translation とかしたい.

libclang(clang-index?)の python binding などもありますが, メソッド調べるとかめんどいです.

clang そのものに AST を JSON でダンプする機能があります!

ast-dump

-ast-dump=json で JSON でダンプできます. (xml もあるよ)

-ast-dump オプションは Clang 固有のため, Clang 専用コンパイルフラグである -Xclang を先につけます.
もしくは, 条件によっては -cc1(clang そのもの?を呼び出す) でもよいです.

-fsyntax-only で構文処理だけするようにします(実際にコンパイルを行わない)

$ clang -Xclang -ast-dump=json -fsyntax-only test.c
$ clang -cc1 -ast-dump=json -fsyntax-only test.c

あとは python で読むなりして JSON 処理すればいけます!
JSON viewer 使って構成をチェックするとよいでしょう.

スクリプト例

JSON を python で処理する例です.

def eval_expr(expr):
    s = ""

    if expr['kind'] == 'ConstantExpr':
        inner = expr['inner']
        assert len(inner) == 1

        s += eval_expr(inner[0])

    elif expr['kind'] == 'UnaryOperator':
        opcode = expr['opcode']

        assert len(expr['inner']) == 1
        assert opcode == '-'

        s += "{}{}".format(opcode, eval_expr(expr['inner'][0]))

    elif expr['kind'] == 'IntegerLiteral':

        s += expr['value']

    elif expr['kind'] == 'BinaryOperator':
        assert len(expr['inner']) == 2

        opcode = expr['opcode']

        s += "{} {} {}".format(eval_expr(expr['inner'][0]), opcode, eval_expr(expr['inner'][1]))

    else:
        print("eval_expr: TODO:", expr)
        raise

    return s

制約

プリプロセッサ

#define とかのプリプロセッサ関連の情報はダンプされません. プリプロセッサ情報とかも欲しい場合はなにかほかの手を考える必要があります. AST 情報吐いてくれそうな C preprocessor を探してみるとか.

libclang では pp-trace https://clang.llvm.org/extra/pp-trace.html がありこれを何やら活用する手もありそうです.

システムヘッダのファイル名はトラックされない場合がある?

AST はプリプロセス後のソースで生成されます.

たとえば cublas_v2.h を処理すると FP_NAN(math.h で定義) の EnumDecl が生成されますが, これに対応するソースファイル情報(math.h)は出てこないです.
以下のように, includedFrom で cuComplex.h は残っていますが, math.h はないです.

    {
      "id": "0xe21268",
      "kind": "EnumDecl",

...
            "end": {
              "spellingLoc": {
                "offset": 25890,
                "line": 856,
                "col": 17,
                "tokLen": 1,
                "includedFrom": {
                  "file": "/usr/local/cuda/include/cuComplex.h"
                }
              },
              "expansionLoc": {
                "offset": 25898,
                "line": 857,
                "col": 7,
                "tokLen": 6,
                "includedFrom": {
                  "file": "/usr/local/cuda/include/cuComplex.h"
                }
              }
            }
          },
          "name": "FP_NAN",
          "type": {
            "qualType": "int"
          },

...

システムヘッダの場合はうまくトラックされないようです.

ただ, TypedefDecl など一部はうまくトラックしてくれるようです.
 

関数ポインタの typedef

typedef の定義が関数ポインタの場合, ほかの typedef と切り分けが面倒かもです.

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?