【问题标题】:gcc for parsing code用于解析代码的 gcc
【发布时间】:2011-11-15 23:48:03
【问题描述】:

我想知道如何使用 GCC 作为库来为我的程序解析 C/C++/Java/Objective C/Ada 代码。 我想绕过预处理并为用户编写的所有函数加上前缀 My。 就像这样Print(); 变成MyPrint(); 我也希望用变量来做这个。

【问题讨论】:

  • 这是一个相当大的要求。你试过什么?您面临哪些具体问题?您是否阅读过 gcc 链上的手册页(因为没有预处理等)?此外,预处理可能不是让代码在程序内部工作所需的唯一步骤。你到底想做什么?
  • 我尝试过使用 clang 但我永远无法编译它。我:不擅长削皮。什么是 gcc 链?我想跳过预处理,因为我不想要文件中的标题或宏。基本上我要做的是用前缀重命名函数和变量。
  • 啊,我是说gcc工具链。这确实是一个比我应该使用的更广泛的术语。我应该只是说 gcc 手册页,也许链接手册页取决于你在做什么。
  • Mooing Duck 你是说你可以使用 Lua 进行 c++ 解析吗?我不知道Lua,但如果它有效,我会学习它。我也阅读了 GCC 手册页
  • 通常当有人想要包含 GCC 时,他们只是想为他们的项目制作附加组件,而使用脚本语言要容易得多。如果您的目标是更改源代码,那么您需要与 GCC 交互。

标签: c++ c parsing gcc


【解决方案1】:

你可以看这里:
http://codesynthesis.com/~boris/blog/2010/05/03/parsing-cxx-with-gcc-plugin-part-1/

这是关于如何使用 gcc 插件接口解析 C++ 代码的描述。其他语言应以相同方式处理。

你也可以试试 mozilla 的猪肉:
https://wiki.mozilla.org/Pork

当我尝试它(猪肉)时,我花了一个小时左右来修复编译问题,但后来 我可以这样写脚本:

rewrite SyncPrimitiveUpgrade {
  type PRLock* => Mutex*
  call PR_NewLock() => new Mutex()
  call PR_Lock(lock) => lock->Lock()
  call PR_Unlock(lock) => lock->Unlock()
  call PR_DestroyLock(lock) => delete lock
}

所以它找到了所有类型的 PRLock 并用 Mutex 重新标记它,它还搜索函数调用 喜欢 PR_NewLock 并将其替换为“新互斥锁”。

【讨论】:

  • 我现在正在使用这个,我的代码编译有问题,也许我的系统太新了。
  • 或者你的系统太旧了。 gcc 的插件支持是在 gcc 4.5 中引入的,所以如果你的 gcc 版本
  • 我的系统是 Ubuntu 11.10,带有 gcc gcc-3.3 gcc-3.4 gcc-4.0 gcc-4.2 gcc-4.3 gcc-4.4 gcc-4.5 gcc-4.6
  • @Taylor :您对那些具体有什么问题?
  • Awesome pork 示例——没有什么比拥有工作代码更好的了。
【解决方案2】:

您可能希望研究sparse C 解析器。它理解很多 C(Linux 内核源代码中使用的所有 C,这是合法 ANSI-C 和 GNU-C 扩展的一个相当好的子集)并提供一些示例编译器后端来提供类似 lint 的静态用于类型检查的分析工具。

虽然代码看起来非常干净和彻底,但您的任务可能通过另一种机制更容易完成——sparse 源代码中包含的用于演示编译器的example.c 有 1955 行长。

【讨论】:

  • sparse 看起来不错,但它并不支持 C++。
  • 当然没有 Java/Objective C/Ada。 :) 它是 C 并且只有 C。
  • 正如 Taylor 所说,sparse 看起来不错,但该 wiki 上的下载链接或 git repo 链接似乎都不起作用:|
  • @Necrolis:试试git clone git://git.kernel.org/pub/scm/devel/sparse/sparse.git——它在几个小时前对我有用。
【解决方案3】:

对于 C,您无法可靠地做到这一点。如果您跳过预处理,您将 - 通常 - 没有要解析的有效 C 代码。例如

#define FOO
#define BAR
#define BAZ

FOO void BAR qux BAZ(void) { }

解析器应该如何在不进行预处理的情况下识别这是 qux 的函数定义?

【讨论】:

  • 我的意思是我想跳过预处理,我不希望宏被扩展并且我不希望最终代码中的标题。
【解决方案4】:

首先,GCC 不是一个库,也不是一个整体(与 LLVM 相比)。

为什么(即为什么)要解析 C、C++、Ada 源代码?

我会考虑(假设是 GCC 4.6 版本)扩展 GCC 通过用 C 编写的插件,或者最好使用 MELT,一种高级域特定语言扩展 GCC(免责声明:我是 MELT 的主要作者)。

但是使用 GCC 作为库根本不现实。

我真的认为,对于您想要实现的目标,MELT 是正确的工具。但是,它的记录很差。请使用gcc-melt@googlegroups.com 列表提问。

请注意,扩展 GCC 确实需要一些工作(可能超过一周),因为您需要部分了解 GCC 内部表示。

【讨论】:

    【解决方案5】:

    我们的DMS Software Reengineering Toolkit 可以解析各种方言的 C、C++、Java 和 Ada 代码(目前不是 Objective C),并对代码进行转换。 DMS 的C and C++ 前端包含一个预处理器,因此您可以在解析之前进行预处理。

    我可能不明白你想做什么,因为用“My....”前缀重命名每个函数和(全局?)变量似乎很奇怪。但是你可以通过一些 DMS 规则来做到这一点(GCC3 用户函数重命名的粗略草图:

    domain C~GCC3.
    
    rule rewrite_function_names(t: type_designator, i: IDENTIFIER, p: parameter_list, s: statements):
          function_header->functionheader
    "\t \i(\p) { \s } " -> "\t \renamed\(\i\) (\p) { \s }" ;
    

    还有一个辅助函数“重命名”,它接受一个包含标识符的树节点,并返回一个具有重命名标识符的树节点。

    因为 DMS 模式只匹配解析树,所以您不会得到任何误报。

    您需要一些额外的模式来处理每种语言中各种不同的语法情况(例如,对于 C,“void”返回类型,因为“void”不是语法中的类型指示符,以及全局变量声明) ,以及不同语言的不同规则(Ada的语法和C的不一样)。

    这对你的任务来说似乎是个大锤,但如果你真的坚持以一种可靠的方式为各种语言做这件事,似乎很难避免为所有这些语言获得合适的解析器的问题。 (如果你真的要对所有这些语言都这样做,可以教 DMS 处理 ObjectiveC,就像我们教它处理其他语言一样)。

    您的替代方案是某种字符串破解解决方案,它可能在 95% 的时间都有效。如果你能接受,那么 Perl 或类似的东西可能是你的答案。

    【讨论】:

    • 看起来不错的解决方案,但它看起来是专有软件。我现在没有钱购买软件,而且我也不会使用其他我会使用它的 Windows。
    【解决方案6】:

    忘记 GCC,它是作为编译器的解析器,而不是分析解析器,你最好使用 libclang 之类的东西,clang 的 C 接口,它可以处理 C 和 C++

    【讨论】:

    • 几个 GCC 插件能够做一些分析,所以我认为它可能是一个相关的工具。
    • Basile:问题是它们是插件,clang 是作为分析器和解析器从头开始构建的,虽然我认为插件会减少工具链的长度,但我建议使用 LLVM +这些天在 GCC 上铿锵作响
    • 作为一个编译器插件可以被视为一个决定性的优势:插件完全在编译器内部工作,所以准确地看到编译器看到的内容以及编译器的工作原理。此外,使用编译器插件比一些外部工具的破坏性更小:您基本上只需将一系列参数添加到您的 makefile 的 CFLAGS 或 CXXFLAGS 中。
    • 我尝试过使用 libclang,但是我遇到了很多问题,我通过教程和其他东西并且永远无法获得任何代码来编译 stackoverflow.com/questions/7921676/… 所以我决定使用 gcc/clang/ANTLR 3一种应该工作的方式。
    猜你喜欢
    • 2012-03-18
    • 1970-01-01
    • 2011-03-16
    • 2010-11-20
    • 2017-09-22
    • 1970-01-01
    相关资源
    最近更新 更多