【问题标题】:Ignore missing headers with clang AST parser使用 clang AST 解析器忽略丢失的标头
【发布时间】:2016-01-04 18:27:54
【问题描述】:

我在 Windows 上,使用 MSVC 编译我的项目,但我需要 clang 来获得它简洁的 AST 解析器,它允许我编写一个小代码生成器。
问题是,clang 无法解析 MSVC 标头(一个众所周知且可以理解的问题)。

我尝试了两种选择:

  1. 我包含 MSVC 标头文件夹,解析我的代码中包含的内置标头最终会在某些时候导致致命错误,从而阻止我正确解析我想要的部分。
  2. 我之前所做的只是不提供任何内置标头并转发声明我需要的类型。它工作得很好,不知何故它不再与最新的 Clang。我真的不知道缺少标头的解析器策略是否发生了变化,但是每次包含 <string> 之类的内容时都会导致完全失败,并且解析的不多。

我正在使用 python 绑定 (libclang),但如果那里有解决方案,我会考虑切换到 C/C++ API。

我是否可以改变这种行为并让 clang 继续解析,即使某些标头未找到?

【问题讨论】:

  • 您想了解可以解析 MS 标头的解决方案吗?
  • 任何解决方案都可以使这项工作成功!

标签: c++ clang abstract-syntax-tree


【解决方案1】:

忽略由于缺少标头而导致的错误的一种方法是在 ASTFrontendAction 的定义中将 SetSuppressIncludeNotFoundError 设置为 true。下面给出了一个相同的例子。

{
public:
    virtual std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(
        clang::CompilerInstance &Compiler, llvm::StringRef InFile)
    {
        Compiler.getPreprocessor().SetSuppressIncludeNotFoundError(true);
        return std::unique_ptr<clang::ASTConsumer>(
            new CustomASTConsumer(&Compiler.getASTContext()));
    }
};

有关使用 ASTFrontendAction 的完整示例,请访问https://clang.llvm.org/docs/RAVFrontendAction.html

【讨论】:

    【解决方案2】:

    使用 SetSuppressIncludeNotFoundError。我花了一个小时才找到!你可以想象我找到它是多么高兴!

    https://clang.llvm.org/doxygen/classclang_1_1Preprocessor.html#ac7bafe67fc32e41460855b39d20ff6af

    【讨论】:

    • 那太好了,现在我要检查一下这个选项是否暴露在 python 绑定中
    • 嘿@Martin,我遇到了与标题相同的问题,我正在按照本教程创建一个重构工具clang.llvm.org/docs/LibASTMatchersTutorial.html你知道我可以在哪里或如何设置@987654323 @ 选项使用ClangTool?
    • @Andrespch 问题的任何答案?
    【解决方案3】:

    因此,您想要处理使用 MS 标头的 C++ 代码,并且想要访问 AST 以便生成代码。并且 Clang 不会处理 MS 标头。 因此,除非得到彻底的升级,否则 Clang 无法成为答案。

    您要求“任何可以完成这项工作的解决方案”。

    我们的DMS Software Reengineering Tookit 及其C++14 Front End 可以做到这一点。

    DMS 提供通用解析、AST 构造/检查/转换/生成和反向解析(将 AST 转换回可编译代码),由语言定义参数化。

    C++ 前端提供完整的 C++14 解析器、预处理器处理、AST 构造以及全名和类型解析。已经用 GCC 和 MS VS 2013 头文件测试过;我们现在正在使用 2015 头文件进行测试。 (它也处理 MS VS 2013 语法)。

    它完全处理困难的解析情况,包括 C++ 著名的“最令人头疼的解析”。您可以在get human readable AST from c++ code 看到解析树。

    DMS 不提供 Python 绑定,也不提供直接的 C++ 接口。相反,它是一个独立的工具,旨在支持自定义工具的构建(例如,您的“小代码生成器”)。它有自己非常广泛的内部 API 集,用类似于 LISP 的元编程语言 PARLANSE 编码。 DMS 的其他方面通过使用用于词法分析器、语法和转换的 DSL 来管理。见下文。

    请注意:任何可以处理 C++ 的工具都保证是复杂的。 DMS 也相应地复杂,学习使用它需要一段时间,所以你不会立即得到答案。好消息在这里 是有些事情更容易做。您的代码生成问题 很可能是“读取骨架文件,然后用特定于问题的代码替换其中的关键条目”。如果是这种情况,具有以下代码的 DMS 工具(此处为简化演示)可能会解决问题:

        ...
        (= myAST (Registry:ParseFile (. filename)  (. `CppVisualStudio2013') ...)
        (Registry:ApplyTransforms myAST (. `MyTransforms.rsl'))
        (Registry:PrettyPrint myAST (concat filename `.modified'))
        ...
    

    使用 transforms 文件 MyTransforms.rsl 包含概念形式的源到源表面语法(例如 C++ 语法)转换规则

            rule rulename if_you_see THIS then replace_by ("-->") THAT
    

    实际的 C++ 规则可能看起来像(编造这个,因为我没有 了解您的实际代码生成目标)

         rule replace_abstraction(s: STRING_LITERAL):
          " abstraction_place_holder(\s) "
         ->  " my_DSL_library(\s,17); "
    

    上面的 ApplyTransforms 调用将应用所有此文件中的规则,直到不再应用任何规则。

    编写表面语法转换(您可以在其中进行)比调用可破解树的程序库(如 Clang,DMS 提供的程序库)要容易得多。

    您可以使用 PARLANSE 编写更复杂的元程序,在一个地方应用一些规则,在其他地方应用其他规则,如果您愿意,您可以将源到源转换与直接在树上破解的过程转换混合。

    如果您想了解有关转换的更多详细信息,请询问,我会提供链接。

    【讨论】:

      猜你喜欢
      • 2020-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-19
      • 1970-01-01
      • 2018-10-25
      相关资源
      最近更新 更多