zoukankan      html  css  js  c++  java
  • Clang Preprocessor 类的创建

    参考:

    Create a working compiler with the LLVM framework, Part 2

    How to parse C programs with Clang: A tutorial

    [Clang,libClang] exercise1 : FileManager

    注意:此篇笔记各类之构造函数源码来自 llvm/clang doxygen 5.0.0 svn,与现行版本(此时为 3.9.1)有一定出入,其中主要是现行版本有些参数是 llvm::IntrusiveRefCntPtr(llvm 实现的 smart pointer)而不是 std::shared_ptr

    一、Preprocessor 的构造函数

    前端由许多部分组成,其中第一部分通常是一个 lexer,clang 中 Preprocessor 类是 lexer 的 main interface。出于性能考虑,clang 没有独立的预处理器程序,而是在 lexing 的过程中进行预处理。

    Preprocessor 的构造函数如下所示:

     1 Preprocessor::Preprocessor(
     2         std::shared_ptr<PreprocessorOptions>    PPOpts, // constructor: PreprocessorOptions()
     3         DiagnosticsEngine&                      diags,  
     4         LangOptions&                            opts,   // constructor: LangOptions()
     5                                                         // Keep track of the various options that can be enabled,
     6                                                         // which controls the dialect of C or C++ that is accepted
     7         SourceManager&                          SM,
     8         HeaderSearch&                           Headers,
     9         ModuleLoader&                           TheModuleLoader,
    10         IdentifierInfoLookup*                   IILookup = nullptr,
    11         bool                                    OwnsHeaderSearch = false,
    12         TranslationUnitKind                     TUKind = TU_Complete 
    13         )    
    Preprocessor 的构造函数 

     DiagnosticsEngine : 用来给用户报告错误和警告信息。构造函数如下:

    1 DiagnosticsEngine::DiagnosticsEngine(
    2         IntrusiveRefCntPtr<DiagnosticIDs>   Diags,        // constructor: DiagnosticIDs()
    3                                                           // used for handling and querying diagnostic IDs
    4         DiagnosticOptions*                  DiagOpts,     // constructor: DiagnosticOptions()
    5                                                           // Options for controlling the compiler diagnostics engine
    6         DiagnosticConsumer*                 client = nullptr,
    7         bool                                ShouldOwnClient = true
    8         )
    DiagnosticsEngine 的构造函数

    其中 DiagnosticConsumer 是一个抽象接口,由前端的 clients 实现,用来 formats and prints fully processed diagnostics。clang 内置一个 TextDiagnosticsConsumer 类,将错误和警告信息写到 console 上,clang binary 用的 DiagnosticConsumer 也是这个类。TextDiagnosticsConsumer 的构造函数如下:

    1 TextDiagnosticPrinter::TextDiagnosticPrinter(
    2         raw_ostream&        os,        // llvm::outs() returns a reference to a raw_ostream for standard output
    3         DiagnosticOptions*  diags,
    4         bool                OwnsOutputStream = false  // within destructor:(OS is the member, initialized with os) 
    5                                                       // if (OwnsOutputStream) delete &OS
    6         )
    TextDiagnosticPrinter 的构造函数

     SourceManager :handles loading and caching of source files into memory。构造函数如下:

    1 SourceManager::SourceManager(vim 
    2         DiagnosticsEngine&  Diag,
    3         FileManager&        FileMgr,
    4         bool                UserFilesAreVolatile = false
    5         )
    SourceManager 的构造函数

      FileManager :实现了对文件系统查找、文件系统缓存、目录查找管理的支持。构造函数如下:

    1 FileManager::FileManager(
    2         const FileSystemOptions&            FileSystemOpts,  // use default constructor
    3         IntrusiveRefCntPtr<vfs::FileSystem> FS = nullptr
    4         )
    FileManager 的构造函数

      HeaderSearch :Encapsulates the information needed to find the file referenced by a #include or #include_next, (sub-)framework lookup, etc。构造函数如下:

    1 HeaderSearch::HeaderSearch(
    2         std::shared_ptr<HeaderSearchOptions>    HSOpts,  // constructor: HeaderSearchOptions::HeaderSearchOptions(StringRef _Sysroot = "/")
    3         SourceManager&                          SourceMgr,
    4         DiagnosticsEngine&                      Diags,
    5         const LangOptions&                      LangOpts,
    6         const TargetInfo*                       Target
    7         )
    HeaderSearch 的构造函数

     TargetInfo :Exposes information about the current target。 其构造函数为 protected,因此需要调用工厂函数 static TargetInfo* TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags, const std::shared_ptr<TargetOptions>& Opts) ,其中 TargetOptions 类包含 target 的相关信息,如 CPU、ABI 等。类中有一个属性 Triple 用以定义 target 的架构。Triple 是一个 string,形如 i386-apple-darwin,通过 llvm::sys::getDefaultTargetTriple() 可以获得编译 llvm 的机器的 host triple。

    ModuleLoader:描述了 module loader 的抽象接口。Module loader 负责解析一个 module name(如“std”),将其与实际的 module file 联系起来,并加载该 module。CompilerInstance 便是一个实现了该接口的 module loader。

    二、通过 CompilerInstance 创建 Preprocessor

    比起手写 Preprocessor,CompilerInstance 更加实用一些。CompilerInstance 主要有两个作用:(1)管理运行编译器所必须的各个对象,如 preprocessor、target information、AST context 等;(2)提供创建和操作常用 Clang 对象的有用方法。下面是其类定义的一部分:

     1 class CompilerInstance : public ModuleLoader {
     2     /// The options used in this compiler instance.
     3     std::shared_ptr<CompilerInvocation> Invocation;
     4     /// The diagnostics engine instance.
     5     IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics;
     6     /// The target being compiled for.
     7     IntrusiveRefCntPtr<TargetInfo> Target;
     8     /// The file manager.
     9     IntrusiveRefCntPtr<FileManager> FileMgr;
    10     /// The source manager.
    11     IntrusiveRefCntPtr<SourceManager> SourceMgr;
    12     /// The preprocessor.
    13     std::shared_ptr<Preprocessor> PP;
    14     /// The AST context.
    15     IntrusiveRefCntPtr<ASTContext> Context;
    16     /// An optional sema source that will be attached to sema.
    17     IntrusiveRefCntPtr<ExternalSemaSource> ExternalSemaSrc;
    18     /// The AST consumer.
    19     std::unique_ptr<ASTConsumer> Consumer;
    20     /// The semantic analysis object.
    21     std::unique_ptr<Sema> TheSema;
    22     /// ...
    23 };
    CompilerInstance 类定义的一部分

     下列代码通过 CompilerInstance 来创建 Preprocessor:

     1 #include <memory>
     2  
     3  #include "clang/Basic/LangOptions.h"
     4  #include "clang/Basic/TargetInfo.h"
     5  #include "clang/Frontend/CompilerInstance.h"
     6  
     7  int main() {
     8      clang::CompilerInstance ci; 
     9  
    10      ci.createDiagnostics();
    11  
    12      std::shared_ptr<clang::TargetOptions> pTargetOptions =
    13          std::make_shared<clang::TargetOptions>();
    14      pTargetOptions->Triple = llvm::sys::getDefaultTargetTriple();
    15      clang::TargetInfo *pTargetInfo =
    16          clang::TargetInfo::CreateTargetInfo(ci.getDiagnostics(), pTargetOptions);
    17      ci.setTarget(pTargetInfo);
    18  
    19      ci.createFileManager();
    20      ci.createSourceManager(ci.getFileManager());
    21      ci.createPreprocessor(clang::TU_Complete);
    22  
    23      return 0;
    24  }
    Use CompilerInstance to construct Preprocessor

    首先创建 DiagnosticsEngine(通过 createDiagnostics()),然后创建并设置 TargetInfo,然后依次创建 FileManager(通过 createFileManager()),SourceManager(通过 createSourceManager (FileManager &FileMgr)),最后创建 Preprocessor(createPreprocessor(TranslationUnitKind))。

    三、FileManager 与 SourceManager

     FileManager:

  • 相关阅读:
    ZOJ 1002 Fire Net
    Uva 12889 One-Two-Three
    URAL 1881 Long problem statement
    URAL 1880 Psych Up's Eigenvalues
    URAL 1877 Bicycle Codes
    URAL 1876 Centipede's Morning
    URAL 1873. GOV Chronicles
    Uva 839 Not so Mobile
    Uva 679 Dropping Balls
    An ac a day,keep wa away
  • 原文地址:https://www.cnblogs.com/jerrywossion/p/6429855.html
Copyright © 2011-2022 走看看