12

我想要一个命令行工具来从 C 或 C++ 源文件中提取定义或声明(typedef、结构、枚举、变量或函数)。替换现有定义/声明的方法也很方便(在通过用户提交的脚本转换提取的定义之后)。是否有这样的通用工具可用,或者是否有这种工具的合理近似?

编写脚本的能力和与用户创建的脚本或程序挂钩的能力在这里很重要,尽管我在学术上也对 GUI 程序感到好奇。Unix/Linux 阵营的开源解决方案是首选(尽管我也对 Windows 和 OS X 工具感到好奇)。主要语言兴趣是 C 和 C++,但更通用的解决方案会更好(我认为我们不需要超精确的解析功能来查找、提取和替换程序源文件中的定义)。

示例用例(额外 - 对于好奇的头脑):

  1. 给定这些类型的深度嵌套struct的 s 和变量(数组)初始化,假设需要通过添加或重新排序字段或以更易读的格式重写变量/数组定义来更改结构定义,而不会引入人工导致的错误。这将通过提取旧的初始化,然后使用脚本/程序编写新的初始化来替换旧的初始化来工作。
  2. 为了实现代码浏览工具 - 提取定义。
  3. 装饰性代码生成(例如记录函数条目/返回)。
  4. 脚本代码结构(例如,提取这个和那个东西并放在不同的地方而不做任何更改 - 版本控制提交注释可以记录执行此操作的命令,以使其明显且可验证,没有任何更改)。

替代问题:如果有一个工具可以告诉定义的位置(开始和结束行就足够了 - 我们甚至可以假设我们感兴趣的所有定义/声明都在它们自己的行中),那么它只是一个简单的练习编写程序的手指灵巧度

  1. 提取定义,
  2. 替换定义,甚至
  3. 提取定义,运行由命令行选项(或编辑器)指定的程序以

    • stdin从(或从临时文件)接收所需的提取定义,
    • 执行转换(编辑),以及
    • 将新定义输出到stdout(或将它们保存到给定的临时文件)

    由正在执行的程序替换。

因此,主要的、更具挑战性的问题将是找到定义的开始和结束行。

关于标签的注意事项:code-generation比本来更准确的标签,code-transformation但它不存在。

4

3 回答 3

4

我们的DMS 软件再造工具包正在努力成为您想要的工具。但它正在推动最先进的技术,并不是一种必杀技工具。做真正有趣的工作就足够了。

DMS 为解析、分析和转换源代码提供了通用工具。

它使用显式语法来定义语言(例如 C 和 C++);语法驱动构建抽象语法树(AST)的解析器。各种分析原语提供 a) 设施 [“属性语法”ATG] 用于沿着树状信息流路径收集信息,这些路径与 AST 的形状很好地匹配,b) 符号定义映射的符号使用构造 [“符号表”] , c)使用 ATG 提取的事实进行控制和数据流分析,d) 范围分析,e) 局部和全局点分析。这些原始分析器可用于组合来自 AST 的事实,以得出关于由 AST 表示的代码的结论(例如,“此语句修改这些变量”)。语言前端将语法和特定于语言的分析器打包在一个可重用的包中。DMS 具有针对各种语言的不同深度和成熟度的语言前端。

[编辑 6/27:C 和 C++ 前端支持 C 和 C++ 的特定方言:ANSIC、C99、GCC3/4 C、MS Visual C、ANSI C++98、ANSI C++11、GCC3/4 C++,MS Visual C++ 2005/2008/2010。如果你想准确分析代码,你应该使用“正确”的方言来处理你的代码。]

但“分析”不是重点。分析的目的是推动变革。DMS 提供了额外的支持以在程序上修改 AST,通过以语言的表面语法编写的源到源重写规则来修改 AST (均以某些选择的分析结果为条件),或对程序集和源到组集进行分组-源代码一起重写以进行复合,复杂的重写,可以进行大量代码更改,例如重新架构等。转换 AST 后,它们可用于在相应的前端重新生成(“漂亮”)语法正确的代码-结束语言/方言。[通过分段修改一种语言的 AST 直到你有另一种语言的 AST,你可以构建翻译器,但这并不像这句话所暗示的那么容易]。

这一切都在很大程度上起作用,但仍然受到某些语言复杂性的阻碍。对于 C 和 C++,一个著名的复杂性是预处理器。通过任意编辑程序文本,预处理器条件可以使源代码无法被任何类似于标准解析技术的东西解析。DMS 的 C 和 C++ 前端在一定程度上改善了这一点,并且可以使用结构良好的预处理器指令解析代码,包括一些大多数人不会称之为结构化但通常会发生的奇怪情况:

   #IF  cond
        if (abc)  {
   #ELSE
        if (def)  {
   #ENDIF

我们在使用预处理器条件的任意位置解析代码方面取得了有趣的进展。但是一旦你这样做了,现在你所有的分析器突然不得不考虑预处理器条件,我们突然都在人们没有真正访问过的编译器的地盘上。

DMS 已被用于在大型 C++ 程序中进行重大架构转变,从非 CORBA 样式转换为具有大量代码改组的 CORBA 样式,以沿任意控制流路径提取代码以生成现有 C 代码的 SOW 样式 API,在大型 C 程序中插入工具以检测指针错误等。[它已应用于许多其他语言的其他任务]。

根据我们自己的经验,它仍然很难使用。在我们看来,这与民主是所有其他政府制度中最糟糕的制度是同一意义上的。YMMV。该网站有很多 DMS 衍生工具和讨论。

事实上,它已被用于提取函数(SOW 练习比这更通用)和插入函数(这是检测的一般情况)。

像 GCC-XML 这样的工具是 DMS 功能的影子。GCC-XML 解析、构建符号表并转储数据声明(不是代码),但它不能进行任何代码更改。Clang更好;它将 C 和 C++ 解析为 AST,可以对 LLVM 中间表示进行分析,并具有某种机制,用于将待应用的补丁吐出到受所需树更改启发的源文本。我不知道 Clang 是否可以进行大规模的代码转换,尤其是那些转换的结果再次转换的情况(如何修改树以获取延迟的文本补丁?)。DMS 可以整天这样做,并且可以为除 C 和 C++ 之外的许多语言执行此操作,并且可以针对它所知道的任意混合语言执行此操作。

在条件语句的预处理器问题得到解决之前,分析/转换 C 和 C++ 代码并不容易。我们只有凭借绝对的意志力和使用我们可以构建的最强大的工具才能在这些语言上成功完成这些任务。(Java 不存在这些问题,而 DMS 相应地更擅长分析/转换它)。

冒着狂妄自大的严重风险,我相信 DMS 是用于通用分析和转换的最佳工具。作为它的架构师,我将其视为我的长期工作,以使其更强大地完成这项任务。

于 2012-06-27T03:42:53.213 回答
3

您可能会考虑将GCC-XML作为开发工具的基础,就像您正在谈论的那样。我已经将它与pygccxml结合使用来自动提取深度嵌套的结构成员。它不会让你的工作变得轻而易举,但你肯定会比其他情况更好。

我还听到其他人提到clang作为编写此类工具的基础,但我自己没有机会深入研究它。

于 2012-06-27T02:49:50.483 回答
2

你可以看看Clang。他们有非平凡的源代码处理库。

于 2012-06-27T04:26:53.503 回答