使用clang AST解析器

时间:2015-10-07 13:34:57

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

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

我尝试了两个选项:

  1. 我包含MSVC头文件夹,解析我的代码中包含的内置头文件会在某些时候导致致命错误,导致我无法正确解析我想要的部分。
  2. 我之前所做的只是不提供任何内置标题,并向前声明我需要的类型。它运作良好,不知何故,它不再是最新的Clang。我真的不知道丢失标头上的解析器策略是否发生了变化,但是每次包含<string>之类的内容都会导致完全失败并且解析得不多。
  3. 我正在使用python绑定(libclang),但如果有解决方案,我会考虑切换到C / C ++ API。

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

3 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:0)

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

你要求&#34;任何可以使这项工作的解决方案&#34;。

我们的DMS Software Reengineering Tookit及其C++14 Front End可以执行此操作。

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

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

它完全处理棘手的解析案例,包括C ++着名的#34;最令人烦恼的解析&#34;。您可以在get human readable AST from c++ code处看到解析树。

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

提醒一句:任何可以处理C ++的工具都是复杂的。 DMS相对复杂,学习使用它需要一段时间,因此您无法获得即时答案。这里的好消息 是有些事情更容易做。你的代码生成问题 很可能&#34;读取一个框架文件,然后用特定于问题的代码替换其中的关键条目&#34;。如果是这种情况,带有以下代码的DMS工具(此处为简化表示)可能会起到作用:

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

使用转换文件 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编写更复杂的元程序,以便在一个地方应用某些规则,在其他地方应用其他规则,并且可以将源到源转换与直接在树中直接攻击的过程转换混合(如果需要)。

如果您想了解有关变换的详细信息,请询问并提供链接。

答案 2 :(得分:0)

忽略由于缺少标头而导致的错误的一种方法是在 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