如何在clang中从AST中排除标题?

时间:2015-01-20 14:58:32

标签: c++ clang abstract-syntax-tree

我正在使用clang生成AST。我有以下文件(lambda.cpp)来解析:

#include <iostream>

void my_lambda()
{
    auto lambda = [](auto x, auto y) {return x + y;};
    std::cout << "fabricati diem"; 
}

我正在使用以下命令解析它:

clang -Xclang -ast-dump -fsyntax-only lambda.cpp

问题是clang还解析了标题内容。结果,我有相当大的(~3000行)文件与无用(对我来说)的内容。

生成AST时如何排除标题?

3 个答案:

答案 0 :(得分:15)

clang-check可能对此事有用,clang-check选项-ast-dump-filter=<string>记录如下

  

-ast转储滤波器= LT;串GT; - 与-ast-dump或-ast-print一起使用仅转储/打印在a中具有某个子字符串的AST声明节点   合格的名字。使用-ast-list列出所有可过滤的声明节点   名。

clang-check在示例代码(lambda.cpp)上使用-ast-dump-filter=my_lambda运行时

#include <iostream>

void my_lambda()
{
    auto lambda = [](auto x, auto y) {return x + y;};
    std::cout << "fabricati diem"; 
}

它只转储匹配的声明节点FunctionDecl my_lambda 'void (void)'

这是命令行参数和输出中的几行。

$ clang-check -extra-arg=-std=c++1y -ast-dump -ast-dump-filter=my_lambda lambda.cpp --

FunctionDecl 0x2ddf630 <lambda.cpp:3:1, line:7:1> line:3:6 my_lambda 'void (void)'
`-CompoundStmt 0x2de1558 <line:4:1, line:7:1>
  |-DeclStmt 0x2de0960 <line:5:9, col:57>

答案 1 :(得分:2)

使用-ast-dump-filter过滤特定标识符即可。但是如果你想从一个文件中的所有标识符

中得到什么呢?

我提出了以下解决方案:

在包含后添加一行可识别的行:

#include <iostream>
int XX_MARKER_XX = 123234; // marker line for ast-dump
void my_lambda()
...

然后用

转储ast
clang-check -extra-arg=-std=c++1y -ast-dump lambda.cpp > ast.txt

您可以使用XX_MARKER_XX轻松剪切sed之前的所有内容:

cat ast.txt | sed -n '/XX_MARKER_XX/,$p'  | less

仍然很多,但对于更大的文件更有用。

答案 2 :(得分:1)

这是C ++的一个问题,而不是clang:C ++中没有文件,只有编译单元。当你#include一个文件时,你将所有文件中的定义(递归地)包含在你的编译单元中,并且没有办法区分它们(它是标准期望编译器做的事情)。

想象一下不同的场景:

/////////////////////////////
// headertmp.h
#if defined(A)
    struct Foo {
        int bar;
    };
#elif defined(B)
    struct Foo {
        short bar;
    };
#endif

/////////////////////////////
// foobar.cpp
#ifndef A
# define B
#endif

#include "headertmp.h"

void foobar(Foo foo) {
    // do stuff to foo.bar
}

你的foobar.cpp声明了一个名为Foo的结构和一个名为foobar的函数,但headertmp.h本身并没有定义任何Foo,除非AB已定义。只有在foobar的编译单元中,两者结合在一起才能理解headertmp.h

如果您对编译单元中的声明子集感兴趣,则必须直接从生成的AST中提取必要的信息(类似于链接器将不同的编译单元链接在一起时必须执行的操作)。当然,您可以在解析器提取的任何元数据上过滤此编译单元的AST。