特定节点上的AST匹配器 [英] AST matcher on a specific node

查看:230
本文介绍了特定节点上的AST匹配器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了一个AST匹配器来查找特定的类型语句。在匹配的节点中,我计算了该节点的邻居同级。现在,我需要在邻居节点上运行匹配器,以验证它们是否满足我的条件。
lang声AST匹配器将整个树节点一一匹配。我想对特定节点运行匹配器,如果该节点符合我的条件,则返回true。
这可能吗?

解决方案

我建议实现自己的匹配器,该匹配器将封装查找邻居节点和将它们与其他匹配器进行匹配。



我整理了以下匹配器作为如何完成此操作的示例:

 使用clang :: ast_matchers :: internal :: Matcher; 
constexpr auto AVERAGE_NUMBER_OF_NESTED_MATCHERS = 3;
使用Matchers =
llvm :: SmallVector< Matcher< clang :: Stmt> ;、 AVERAGE_NUMBER_OF_NESTED_MATCHERS> ;;


clang :: Stmt * getNeighbor(const clang :: Stmt& Node,clang :: ASTContext& Context){
//这是我对此的幼稚实现方法,您可以轻松地将自己的
自动设置为Parents = Context.getParents(Node);
if(Parents.size()!= 1){
返回nullptr;
}

//在处理语句时,假设邻居-是封闭的复合语句中的下一个
//语句。
if(auto * Parent = Parents [0] .get< clang :: CompoundStmt>()){
auto Neighbor = std :: adjacent_find(
Parent-> body_begin(), Parent-> body_end(),
[& Node](const auto * Top,const auto * Bottom){return Top ==& Node;});

if(Neighbor!= Parent-> body_end()){
return * std :: next(Neighbor);
}
}

返回nullptr;
}

AST_MATCHER_P(clang :: Stmt,neighbors,Matchers,NestedMatchers){
//节点是当前测试的节点
const clang :: Stmt * CurrentNode =& Node;

//我们的目标是迭代给定的匹配器,并将当前节点
//与第一个匹配器进行匹配。
//
//接下来,我们计划检查下一个
//匹配器是否与上一个节点的邻居/兄弟匹配。
for(auto NestedMatcher:NestedMatchers){
//这就是调用匹配器测试一个节点的方式。
//
//注意:它使用Finder和Builder,因此最好从
//在匹配器中进行操作,并免费获得
if(CurrentNode = = nullptr或
而不是NestedMatcher.matches(* CurrentNode,Finder,Builder)){
返回false;
}

// //您可以放置​​自己的查找邻居/同级对象的实现。
CurrentNode = getNeighbor(* CurrentNode,Finder-> getASTContext());
}

返回true;
}

我希望摘要中的注释涵盖此匹配器背后的主要思想。



演示



匹配器:

  neighbors({declStmt()。bind( first),forStmt()。bind( second),
returnStmt()。bind(第三)})

代码段:



< pre class = lang-cpp prettyprint-override> int foo(){
int x = 42;
int y = 10;
for(; x> y; --x){
}
返回x;
}

输出:

 第一:
DeclStmt 0x4c683e0
`-VarDecl 0x4c68360用y'int'cinit
`-IntegerLiteral 0x4c683c0'int'10

秒:
ForStmt 0x4c684d0
|-<<< NULL>>>
|-<<< NULL>>>
| -BinaryOperator 0x4c68468‘_Bool’’>’
| | -ImplicitCastExpr 0x4c68438‘int’< LValueToRValue>
| | `-DeclRefExpr 0x4c683f8'int'左值Var 0x4c682b0'x''int'
| `-ImplicitCastExpr 0x4c68450‘int’< LValueToRValue>
| `-DeclRefExpr 0x4c68418‘int’左值Var 0x4c68360‘y’’int’
| -UnaryOperator 0x4c684a8‘int’左值前缀’-’
| `-DeclRefExpr 0x4c68488'int'左值Var 0x4c682b0'x''int'
`-CompoundStmt 0x4c684c0

第三名:
ReturnStmt 0x4c68540
`-ImplicitCastExpr 0x4c68528'int '< LValueToRValue>
`-DeclRefExpr 0x4c68508'int'左值Var 0x4c682b0'x''int'

I希望能回答您的问题!


I wrote a AST matcher for finding specific type statements. In the matched nodes I calculated the neighbor siblings of that node. Now I need to run matcher on the neighbor nodes to verify they satisfies my condition or not. The clang AST matcher matches the whole tree node one by one. I want to run matcher against a particular node and return true if the node matches my required condition. Is this possible?

解决方案

I suggest to implement your own matcher that will encapsulate the logic of finding neighbor nodes and matching them against other matchers.

I've put together the following matcher as an example of how that can be done:

using clang::ast_matchers::internal::Matcher;
constexpr auto AVERAGE_NUMBER_OF_NESTED_MATCHERS = 3;
using Matchers =
    llvm::SmallVector<Matcher<clang::Stmt>, AVERAGE_NUMBER_OF_NESTED_MATCHERS>;


clang::Stmt *getNeighbor(const clang::Stmt &Node, clang::ASTContext &Context) {
  // It is my naive implementation of this method, you can easily put your own
  auto Parents = Context.getParents(Node);
  if (Parents.size() != 1) {
    return nullptr;
  }

  // As we deal with statements, let's assume that neighbor - is the next
  // statement in the enclosing compound statement.
  if (auto *Parent = Parents[0].get<clang::CompoundStmt>()) {
    auto Neighbor = std::adjacent_find(
        Parent->body_begin(), Parent->body_end(),
        [&Node](const auto *Top, const auto *Bottom) { return Top == &Node; });

    if (Neighbor != Parent->body_end()) {
      return *std::next(Neighbor);
    }
  }

  return nullptr;
}

AST_MATCHER_P(clang::Stmt, neighbors, Matchers, NestedMatchers) {
  // Node is the current tested node
  const clang::Stmt *CurrentNode = &Node;

  // Our goal is to iterate over the given matchers and match the current node
  // with the first matcher.
  //
  // Further on, we plan on checking whether the next
  // matcher matches the neighbor/sibling of the previous node.
  for (auto NestedMatcher : NestedMatchers) {
    // This is how one can call a matcher to test one node.
    //
    // NOTE: it uses Finder and Builder, so it's better to do it from
    //       inside of a matcher and get those for free
    if (CurrentNode == nullptr or
        not NestedMatcher.matches(*CurrentNode, Finder, Builder)) {
      return false;
    }

    // Here you can put your own implementation of finding neighbor/sibling
    CurrentNode = getNeighbor(*CurrentNode, Finder->getASTContext());
  }

  return true;
}

I hope that the comments within the snippet cover the main ideas behind this matcher.

Demo

Matcher:

neighbors({declStmt().bind("first"), forStmt().bind("second"),
           returnStmt().bind("third")})

Code snippet:

int foo() {
  int x = 42;
  int y = 10;
  for (; x > y; --x) {
  }
  return x;
}

Output:

first:
DeclStmt 0x4c683e0
`-VarDecl 0x4c68360  used y 'int' cinit
  `-IntegerLiteral 0x4c683c0 'int' 10

second:
ForStmt 0x4c684d0
|-<<<NULL>>>
|-<<<NULL>>>
|-BinaryOperator 0x4c68468 '_Bool' '>'
| |-ImplicitCastExpr 0x4c68438 'int' <LValueToRValue>
| | `-DeclRefExpr 0x4c683f8 'int' lvalue Var 0x4c682b0 'x' 'int'
| `-ImplicitCastExpr 0x4c68450 'int' <LValueToRValue>
|   `-DeclRefExpr 0x4c68418 'int' lvalue Var 0x4c68360 'y' 'int'
|-UnaryOperator 0x4c684a8 'int' lvalue prefix '--'
| `-DeclRefExpr 0x4c68488 'int' lvalue Var 0x4c682b0 'x' 'int'
`-CompoundStmt 0x4c684c0

third:
ReturnStmt 0x4c68540
`-ImplicitCastExpr 0x4c68528 'int' <LValueToRValue>
  `-DeclRefExpr 0x4c68508 'int' lvalue Var 0x4c682b0 'x' 'int'

I hope that answers your question!

这篇关于特定节点上的AST匹配器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆