以编程方式构建一个叮当作响的AST

building a clang AST programmatically

本文关键字:一个 叮当作响 AST 编程 方式 构建      更新时间:2023-10-16

我正在编写一个可以将源语言翻译成C++的transiler。为此,我使用flex、bison和clang AST。我将从一个空的AST开始,在解析中的每个语义操作中,我将向clang AST添加节点。

问题是我找不到一种以编程方式构建AST的方法。假设我想在没有递归ASTVisitor的情况下为以下代码生成一个AST(因为我的源语言不是C++)

#include <iostream>
int main()
{
std::cout << "Hello World " << std::endl;
return 0;
}

因此,可以生成AST的相应代码应该看起来像这个

#include "clang/AST/ASTContext.h"
int main(int argc, const char **argv)
{
//Create an empty context
clang::ASTContext *context = new clang::ASTContext(NULL, NULL, NULL, NULL, NULL);
//Declare a main function
clang::FunctionDecl *FD = clang::FunctionDecl::Create(Context, "main");
//Declare params
std::vector<clang::ParmVarDecl*> NewParamInfo;
NewParamInfo.push_back(clang::ParmVarDecl::Create(Context, FD, "argc"));
NewParamInfo.push_back(clang::ParmVarDecl::Create(Context, FD, "argv"));
//set params to function
FD->setParams(ArrayRef<clang::ParmVarDecl*>(NewParamInfo));
//Declare a compund stament
clang::CompoundStmt *CS = new (Context) clang::CompoundStmt(clang::SourceLocation());
//Declare a Statement to print
clang::Stmt *S = new (Context) clang::ReturnStmt("std::cout << "Hello World " << std::endl;");
//Add print statement to compund statement
CS->setStmts(Context, S, 1);
//Add compund statement to body of function
FD->setBody(CS);
return 0;
}

上面提到的代码不是一个工作代码,看看llvm或clang的文档是PITA,有人能帮我做过类似的工作吗?

  • 像clang本身一样从头开始编写clang的AST,不是用API,而是用它的内部函数;可以想象的是,你可以走这条路,但在你将要使用的非公开的非API函数中会遭受混乱。目前尚不清楚您的预期目的是否需要clang本身开发C++20和C++2b及以后版本所需的AST创作功能的新鲜感
  • 但是还有重构API,正如Clang中提到的:编写一个函数';将AST从原始文件转换为新文件,但您的预期目的并不是重构本身,但您可以稍微扭曲您的想法,利用clang中相对稳定的重构API来构建您所寻求的AST,即从零/零开始的"重构">

许多评论者也在嘲笑clang的AST作为数据结构的使用。他们会避开clang的AST来"发出源代码",但要发出非平凡的源代码,必须重新发明自己的AST。为什么要重新发明C++-AST轮子?只需通过重构API构建clang的AST,而不是根据自己的意愿从头开始设计AST。然后,作为完成所有预期编译的"重构"后的最后一步,通过与访问者一起遍历,从clang AST中读取生成的C++源代码。