使用clang AST解析器忽略丢失的标头

N0v*_*ber 6 c++ clang abstract-syntax-tree

我在Windows上,使用MSVC来编译我的项目,但是我需要克服其整洁的AST解析器,这允许我编写一个小代码生成器.
问题是,clang无法解析MSVC头文件(一个众所周知且易于理解的问题).

我尝试了两种选择:

  1. 我包含MSVC头文件夹,解析我的代码中包含的内置头文件会在某些时候导致致命错误,阻止我解析我想要的部分.
  2. 我以前做的只是没有提供任何内置的头文件,并向前声明我需要的类型.它运作良好,不知何故,它不再是最新的Clang.我真的不知道丢失标头上的解析器策略是否发生了变化,但是每次<string>包含类似的内容时都会导致完全失败并且解析得不多.

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

无论如何我可以改变这种行为并使clang继续解析,即使找不到某些标题?

Mar*_*tin 5

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

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

  • 嘿@Martin,我遇到了同样的标题问题,我正在按照本教程创建一个重构工具http://clang.llvm.org/docs/LibASTMatchersTutorial.html 你知道我在哪里或如何可以使用“ClangTool”设置“SetSuppressIncludeNotFoundError”选项? (5认同)
  • @Andrespch 问题有答案吗? (2认同)

Ira*_*ter 0

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

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

我们的DMS 软件再工程工具包及其C++14 前端可以做到这一点。

DMS 提供通用解析、AST 构造/检查/转换/生成以及逆向解析(将 AST 转换回可编译代码),并通过语言定义进行参数化。

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

它可以完全处理棘手的解析情况,包括 C++ 著名的“最令人烦恼的解析”。您可以在从 c++ 代码获取人类可读的 AST中查看解析树。

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'))
    ...
Run Code Online (Sandbox Code Playgroud)

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

        rule rulename if_you_see THIS then replace_by ("-->") THAT
Run Code Online (Sandbox Code Playgroud)

实际的 C++ 规则可能看起来像(这是因为我不知道你的实际代码生成目标而编造的)

     rule replace_abstraction(s: STRING_LITERAL):
      " abstraction_place_holder(\s) "
     ->  " my_DSL_library(\s,17); "
Run Code Online (Sandbox Code Playgroud)

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

编写表面语法转换(在您可以做到的地方)比调用破坏树的过程库(如 Clang,DMS 提供的)要容易得多。

您可以使用 PARLANSE 编写更复杂的元程序,在一个地方应用一些规则,在其他地方应用其他规则,并且如果需要,您可以将源到源转换与直接攻击树的过程转换混合在一起。

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