llvm libtooling 遍历变量,函数,类

背景

由于项目需要,需要解析cpp代码,经调查llvm,clang前端有这样的库可以使用,找到libtooling,功能强大,有完善的文档,于是写一系列的文章介绍libtooling库的使用,

安装llvm

欢迎关注专栏

llvm clang

前置知识

AST是什么:

LLVM Clang AST是指Clang编译器前端生成的抽象语法树(Abstract Syntax Tree)
解析的代码,被表示成树状结构,libtooling从抽象语法树解析
 

使用clang命令输出AST

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

test.cc内容

#include <stdio.h>
void test(int a, int b) {
  int c = a + b -3
}

clang输出

`-FunctionDecl 0x7fc46e075608 <line:2:1, line:4:1> line:2:6 test 'void (int, int)'
  |-ParmVarDecl 0x7fc46e075488 <col:11, col:15> col:15 used a 'int'
  |-ParmVarDecl 0x7fc46e075508 <col:18, col:22> col:22 used b 'int'
  `-CompoundStmt 0x7fc46e075880 <col:25, line:4:1>
    `-DeclStmt 0x7fc46e075868 <line:3:3, col:19>
      `-VarDecl 0x7fc46e075730 <col:3, col:18> col:7 c 'int' cinit
        `-BinaryOperator 0x7fc46e075848 <col:11, col:18> 'int' '-'
          |-BinaryOperator 0x7fc46e075808 <col:11, col:15> 'int' '+'
          | |-ImplicitCastExpr 0x7fc46e0757d8 <col:11> 'int' <LValueToRValue>
          | | `-DeclRefExpr 0x7fc46e075798 <col:11> 'int' lvalue ParmVar 0x7fc46e075488 'a' 'int'
          | `-ImplicitCastExpr 0x7fc46e0757f0 <col:15> 'int' <LValueToRValue>
          |   `-DeclRefExpr 0x7fc46e0757b8 <col:15> 'int' lvalue ParmVar 0x7fc46e075508 'b' 'int'
          `-IntegerLiteral 0x7fc46e075828 <col:18> 'int' 3

其中FunctionDecl就是函数节点,VarDecl是变量节点

其它:关于FrontendAction、ASTConsumer、RecursiveASTVisitor的介绍在这里

https://blog.csdn.net/weixin_43837016/article/details/140134391

代码

以下代码使用libtooling 遍历变量,函数,类等

#include <clang/AST/AST.h>
#include <clang/AST/RecursiveASTVisitor.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Tooling/CommonOptionsParser.h>
#include <clang/ASTMatchers/ASTMatchFinder.h>
#include <clang/Tooling/Tooling.h>

#include <iostream>

using namespace clang;
using namespace clang::tooling;
using namespace clang::ast_matchers;
using namespace llvm;
using namespace std;

const char *toolOverview = "demo";

static cl::OptionCategory optCat("demo Options");

bool checkIfSystem(const Decl *D)
{
    if (!D) {
        return true;
    }
    
    ASTContext & context = D->getASTContext();
    SourceManager &srcMgr = context.getSourceManager();
    SourceLocation srcLoc = D->getLocation();
    
    SourceLocation beginSrcLoc = D->getBeginLoc();
    SourceLocation expansionLoc = srcMgr.getExpansionLoc(beginSrcLoc);
    if (srcMgr.isInSystemHeader(expansionLoc)) {
        return true;
    }

    if (srcMgr.getFileCharacteristic(srcLoc) == SrcMgr::C_System) {
        return true;
    }

    if (srcMgr.getFileCharacteristic(srcLoc) == SrcMgr::C_ExternCSystem) {
        return true;
    }

    return false;
}

class MyVisitor : public RecursiveASTVisitor<MyVisitor> {
public:
    explicit MyVisitor() {}

    bool VisitVarDecl(VarDecl *VD) {
        if (checkIfSystem(VD)) {
            return true;
        }
        std::cout << "Variable name: " << VD->getName().str() << std::endl;

        return true;
    }

    bool VisitFunctionDecl(const FunctionDecl * FD) {
        if (checkIfSystem(FD)) {
            return true;
        }
        std::cout << "FunctionDecl name: " << FD->getName().str() << std::endl;

        return true;
    }

    bool VisitCXXRecordDecl(CXXRecordDecl *CXXRD) {
        if (checkIfSystem(CXXRD)) {
            return true;
        }
        std::cout << "CXXRecordDecl name: " << CXXRD->getName().str() << std::endl;

        return true;
    }
};

class MyConsumer : public ASTConsumer {
    
public:
    explicit MyConsumer(ASTContext *Context) : Context(Context) {}

    void HandleTranslationUnit(ASTContext &Context) override {
        MyVisitor visitor;
        visitor.TraverseDecl(Context.getTranslationUnitDecl());
    }

private:
    ASTContext *Context;
};

class MyAction : public ASTFrontendAction {
public:
    std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, StringRef) override {
        return std::make_unique<MyConsumer>(&CI.getASTContext());

    }

};

int main(int argc, const char *argv[])
{

    auto OptionsParserExpected = CommonOptionsParser::create(argc, argv, optCat, cl::OneOrMore, toolOverview);
    if (!OptionsParserExpected) {
        llvm::errs() << "Failed to parse options: " << toString(OptionsParserExpected.takeError()) << "\n";
        return 1;
    }
    
    CommonOptionsParser &OptionsParser = *OptionsParserExpected;
    ClangTool Tool(OptionsParser.getCompilations(), OptionsParser.getSourcePathList());
    Tool.run(newFrontendActionFactory<MyAction>().get());
    

    return 0;
}

cmake文件:

cmake_minimum_required(VERSION 3.4.3)
project(demo2)
set(CMAKE_CXX_COMPILER "clang++")
find_package(Clang REQUIRED)    
include_directories(${Clang_INCLUDE_DIRS} ${LLVM_MAIN_INCLUDE_DIR})  

add_executable(demo2
demo2.cpp
  )

target_link_libraries(demo2
  PUBLIC
  clangAST
  clangASTMatchers
  clangBasic
  clangFrontend
  clangSerialization
  clangTooling
  )

被解析的cpp代码:

#include <string>
#include <iostream>
using namespace std;

class Test {
public:
	void p() {};
};


int main(int argc, const char *argv[]){
	string s = "abc";
	return 0;
}

打印结果:


CXXRecordDecl name: Test
FunctionDecl name: p
FunctionDecl name: main
Variable name: argc
Variable name: argv
Variable name: s

引用:

Clang AST

  • 16
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LLVM中拓展可变变量的详细过程可以分为以下几个步骤: 1. 定义可变变量 首先,需要定义可变变量。在LLVM中,可以使用全局变量或局部变量来表示可变变量。全局变量可以在整个程序中使用,而局部变量只能在当前函数中使用。在定义可变变量时需要考虑变量型、作用域以及是否可变。 例如,在C++中,可以使用以下代码定义一个全局可变变量: ```c++ int global_var = 0; // 定义一个全局可变变量 ``` 2. 实现变量的代码生成 接下来,需要实现变量的代码生成。在LLVM中,可以使用LLVM IR的全局变量或局部变量来表示可变变量。使用全局变量时,需要使用"global"指令来定义变量。使用局部变量时,需要使用"alloca"指令来分配变量的内存空间。 例如,在LLVM IR中,可以使用以下代码生成一个全局可变变量: ```llvm @global_var = global i32 0 ; 定义一个全局可变变量 ``` 3. 生成可变变量的运行时代码 一旦变量的代码生成实现完成,就需要生成可变变量的运行时代码。在LLVM中,可以使用LLVM提供的运行时库来实现可变变量的内存分配和释放。 例如,在C++中,可以使用以下代码在运行时分配一个局部可变变量的内存空间: ```c++ int *local_var = new int(0); // 在运行时分配一个局部可变变量的内存空间 ``` 在LLVM IR中,可以使用以下代码生成分配内存空间的运行时代码: ```llvm %local_var = alloca i32 ; 分配一个局部可变变量的内存空间 store i32 0, i32* %local_var ; 将0存储到局部可变变量中 ``` 这里使用"alloca"指令分配内存空间,并使用"store"指令将0存储到变量中。 总之,拓展可变变量的过程需要涉及到LLVM前端、LLVM后端以及LLVM的运行时库。在实现过程中需要考虑变量型、作用域、内存分配和释放等方面。需要注意的是,LLVM的代码生成和运行时库的使用都需要遵循LLVM的指令格式和规范。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值