Jayendra Parmar
Jayendra Parmar

Reputation: 774

building a clang AST programmatically

I am writing a transpiler which can translate the source language to C++. I am using flex, bison, and clang-AST for this purpose. I will start with an empty AST and with each semantic action in parsing I will add nodes to the clang-AST.

The problem is that I can't find a way to build the AST programmatically. Let say I want to generate an AST for the following code without RecursiveASTVisitor(because my source language is not C++)

#include <iostream>

int main()
{
  std::cout << "Hello World " << std::endl;

  return 0;
}

So the corresponding code which can generate the AST should look like this

#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;
}

The code mentioned above is not a working code and looking at the docs of llvm or clang is PITA can anybody help me out who has done any similar work?

Upvotes: 3

Views: 2179

Answers (1)

Andreas ZUERCHER
Andreas ZUERCHER

Reputation: 902

  • There is writing clang's AST from scratch as clang itself does, not with an API but with its internal functions; conceivably you could go that route but suffer churn in the nonpublic not-API functions that you'd be using. It is not clear that your intended purpose needs the bleeding edge of freshness of the AST-authoring functions that clang itself needs for developing C++20 and C++2b and onward.
  • But then there is the refactoring API, as mentioned in Clang: write a function's AST from original file to a new file but your intended purpose isn't refactoring per se, but you can contort your thinking a tad to utilize the relatively-stable refactoring API within clang to build up the AST that you seek as “refactoring” from nothingness/scratch.

Also many commenters are deriding the usage of clang's AST as a data-structure. They would eschew clang's AST to “emit source code”, but to emit nontrivial source code one must re-invent your own AST. Why bother reinventing the C++-AST wheel? Just build up clang's AST via the refactoring API instead of designing an AST of your own volition from scratch. Then as the final step after all of your “refactorings” of your intended transpilation have completed, read the generated C++ source code back out from the clang AST by traversing it with a visitor.

Upvotes: 2

Related Questions