2. AST生成

AST的生成发生在clang::ParseAST函数中,该函数由ASTFrontendAction::ExecuteAction调用。ParseAST函数流程图如下所示:

img

从图中可以看出,词法分析、语法分析和语义分析都开始于Parser类。在编译过程中首先创建Parser类,并检查其中的词法分析器、语法分析器、以及语义分析相关设置是否完备。然后进行初始化操作,在初始化的时候Parser会读入源码的第一个字符并进行解析。之后以是否到达文件末尾作为判断条件对整个源码文件进行完整解析并生成相应的抽象语法树,随后会调用ASTConsumer::HandleTranslationUnit回调函数,该函数是虚函数,通过Sema::getASTConsumer得到实际的Consumer,这里Sema是ParseAST函数的输入参数。这个函数是用户自定义,用来在解析完一个翻译单元的时候执行相同的处理。

ParseAST函数中的主要过程如下:

C++
void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {

 ...

 if (HaveLexer) {

  llvm::TimeTraceScope TimeScope("Frontend", StringRef(""));

  P.Initialize();  // 词法分析和预处理



  Parser::DeclGroupPtrTy ADecl;



  for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl); !AtEOF;

     AtEOF = P.ParseTopLevelDecl(ADecl)) { // 语义分析

   // If we got a null return and something was parsed, ignore it.  This

   // is due to a top-level semicolon, an action override, or a parse error

   // skipping something.

   if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))

    return;

  }

 }



 // Process any TopLevelDecls generated by #pragma weak.

 for (Decl *D : S.WeakTopLevelDecls())

  Consumer->HandleTopLevelDecl(DeclGroupRef(D));



 Consumer->HandleTranslationUnit(S.getASTContext());

...

}