如何在clang抽象语法树的右侧获取整个表达式?

时间:2018-05-15 17:10:58

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

让我们举一个玩具示例,说我在test.cpp文件中有以下代码:

// Store
localStorage.setItem("desire-background", "url-of-background-image");
// Retrieve
document.getElementById("result")
    .style.backgroundImage = localStorage.getItem("desire-background");

我想在除法运算中找到分母的变量名,然后使用clang我使用命令int main() { int gt = 3; int g = 10 / gt; } 得到上述代码的抽象语法树(AST)。我得到以下输出

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

从以上AST的知识和使用clang-query,我使用以下命令得到分母的变量名称

TranslationUnitDecl 0x34f8100 <<invalid sloc>> <invalid sloc>
|-TypedefDecl 0x34f8638 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'
| `-BuiltinType 0x34f8350 '__int128'
|-TypedefDecl 0x34f8698 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'
| `-BuiltinType 0x34f8370 'unsigned __int128'
|-TypedefDecl 0x34f8728 <<invalid sloc>> <invalid sloc> implicit __builtin_ms_va_list 'char *'
| `-PointerType 0x34f86f0 'char *'
|   `-BuiltinType 0x34f8190 'char'
|-TypedefDecl 0x34f8a48 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list 'struct __va_list_tag [1]'
| `-ConstantArrayType 0x34f89f0 'struct __va_list_tag [1]' 1 
|   `-RecordType 0x34f8810 'struct __va_list_tag'
|     `-CXXRecord 0x34f8778 '__va_list_tag'
`-FunctionDecl 0x34f8af0 <test.cpp:1:1, line:5:1> line:1:5 main 'int (void)'
  `-CompoundStmt 0x34f8dc0 <line:2:1, line:5:1>
    |-DeclStmt 0x34f8c98 <line:3:2, col:12>
    | `-VarDecl 0x34f8c18 <col:2, col:11> col:6 used gt 'int' cinit
    |   `-IntegerLiteral 0x34f8c78 <col:11> 'int' 3
    `-DeclStmt 0x34f8da8 <line:4:2, col:17>
      `-VarDecl 0x34f8cc0 <col:2, col:15> col:6 g 'int' cinit
        `-BinaryOperator 0x34f8d80 <col:10, col:15> 'int' '/'
          |-IntegerLiteral 0x34f8d20 <col:10> 'int' 10
          `-ImplicitCastExpr 0x34f8d68 <col:15> 'int' <LValueToRValue>
            `-DeclRefExpr 0x34f8d40 <col:15> 'int' lvalue Var 0x34f8c18 'gt' 'int'

我的输出为

clang-query> match declRefExpr(isExpansionInMainFile(), allOf(hasAncestor(binaryOperator(hasOperatorName("/"))), hasAncestor(declStmt())  ))

现在我们在同一页面上,我有两个问题。

  1. 在上面的玩具示例中,如果我有另一个,则代替10 变量然后我的查询匹配变量(分子和 分母)。如何限制我的clang-query只匹配 变量是除法运算的分母?其他 单词,如何找到右手中存在的变量 二元运算符的一侧&#34; /&#34; ?一个例子是Match #1: /home/clang-llvm/cpp/code/test.cpp:4:15: note: "root" binds here int g = 10 / gt; ^~ 1 match.

  2. 如果我在分母中有一个表达式,而不是变量gt 那我怎么能用clang得到整个表达式呢?换一种说法, 如何获取二进制文件右侧的表达式 运营商&#34; /&#34;在抽象语法树?一个简单的例子可能是 int g = gw / gt;和一个复杂的例子可能是int g = gw / (gt - gw);

  3. 我感谢你在这方面的任何帮助。

1 个答案:

答案 0 :(得分:1)

Clang有一个遍历匹配器“ hasRHS()”,它可以完全满足您的要求。

int main()
{
    int gt = 3;
    int g = 10 / gt;

    int gw, gg, gr, gq;
    int g1 = gw / gt;
    int g2 = gw / (gt-gw);
    int g3 = gw / gt - gw / gr * gg / ( gt - gw ^ 2) + gq;
    return 0;
}

输出:

clang-query> match varDecl(hasDescendant(binaryOperator(hasOperatorName("/"), hasRHS(expr().bind("myExpr")))))

Match #1:
/home/test.cpp:4:18: note: "myExpr" binds here
    int g = 10 / gt;
                 ^~
/home/test.cpp:4:5: note: "root" binds here
    int g = 10 / gt;
    ^~~~~~~~~~~~~~~

Match #2:
/home/test.cpp:7:19: note: "myExpr" binds here
    int g1 = gw / gt;
                  ^~
/home/test.cpp:7:5: note: "root" binds here
    int g1 = gw / gt;
    ^~~~~~~~~~~~~~~~

Match #3:
/home/test.cpp:8:19: note: "myExpr" binds here
    int g2 = gw / (gt-gw);
                  ^~~~~~~
/home/test.cpp:8:5: note: "root" binds here
    int g2 = gw / (gt-gw);
    ^~~~~~~~~~~~~~~~~~~~~

Match #4:
/home/test.cpp:9:19: note: "myExpr" binds here
    int g3 = gw / gt - gw / gr * gg / ( gt - gw ^ 2) + gq;
                  ^~
/home/test.cpp:9:5: note: "root" binds here
    int g3 = gw / gt - gw / gr * gg / ( gt - gw ^ 2) + gq;
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 matches.

“ myExpr”已绑定到您想要的内容。 参考:http://clang.llvm.org/docs/LibASTMatchersReference.html