【问题标题】:Good tools for creating a C/C++ parser/analyzer [closed]用于创建 C/C++ 解析器/分析器的好工具 [关闭]
【发布时间】:2009-02-09 00:48:13
【问题描述】:

有哪些好的工具可以快速开始解析和分析 C/C++ 代码?

特别是,我正在寻找处理 C/C++ 预处理器和语言的开源工具。这些工具最好使用 lex/yacc(或 flex/bison)作为语法,不要太复杂。他们应该处理最新的 ANSI C/C++ 定义。

这是我到目前为止发现的,但还没有详细研究它们(想法?):

  • CScope - 老式 C 分析器。不过,似乎没有进行完整的解析。被描述为用于查找 C 函数的美化“grep”。
  • GCC - 每个人都喜欢的开源编译器。非常复杂,但似乎可以做到这一切。有一个用于创建 GCC 扩展的相关项目,名为 GEM,但自 GCC 4.1 (2006) 以来一直没有更新。
  • PUMA - 纯机械手。 (来自页面:“这个项目的目的是 提供用于分析和操作 C/C++ 源代码的类库。为了这 目的 PUMA 提供用于扫描、解析和操作 C/C++ 的类 来源。”)。这看起来很有希望,但自 2001 年以来一直没有更新。显然 PUMA 已并入 AspectC++,但即使是这个项目自 2006 年以来也没有更新。
  • 各种 C/C++ 原始语法。您可以获取 c-c++-grammars-1.2.tar.gz,但自 1997 年以来一直无人维护。通过 Google 搜索可以找到其他基本的 lex/yacc 语法,可以作为起点。
  • 还有其他人吗?

我希望以此为起点,将 C/C++ 源代码翻译成一种新的玩具语言。

谢谢! -马特

(添加 2/9):只是澄清一下:除了 C/C++ 代码本身之外,我还想从预处理器中提取语义信息。我不希望“#define foo 42”消失在整数“42”中,但仍与名称“foo”相关联。不幸的是,这排除了几个首先运行预处理器并且只提供 C/C++ 解析树的解决方案)

【问题讨论】:

  • 马特,我认为那是一种绝望的希望;根据定义,预处理器在进行分析之前对源进行处理。至少旧的管道编译器在解析之前将 prepoc 的源代码放在管道中。通过第一关。也许你可以使用 cpp 嵌入式 cmets?
  • 您可以在源代码上运行您自己的处理器。它将输出一个带注释的源。您需要修改工具用于读取这些注释的 C++ 语法。嘿,涉及到 C++,你知道这并不容易 :)
  • 浏览了 42,000 次?我认为这应该重新开放。如果您同意,请点击上方的“重新打开”。
  • 我认为这个问题应该重新打开。所有“最佳实践相关问题”都标记为离题,但有些可能具有技术层面、客观原因;这不是一个主观的个人问题。

标签: c++ c parsing yacc lex


【解决方案1】:

解析 C++ 非常困难,因为语法是不可判定的。引用Yossi Kreinin

非常复杂的语法

“Outstandingly”应该按字面意思解释,因为所有流行语言都有context-free(或“几乎”无上下文)语法,而 C++ 有undecidable 语法。如果你喜欢编译器和解析器,你可能知道这意味着什么。如果你不喜欢这种事情,有一个simple example 显示解析 C++ 的问题:AA BB(CC); 是对象定义还是函数声明?事实证明,答案很大程度上取决于语句之前的代码——“上下文”。这表明(在直观的层面上)C++ 语法对上下文非常敏感。

【讨论】:

  • 他的很多引述,这个也是错误的。 “不可判定”是指你无法完全说出什么是 A B (C);方法。实际上,通过上下文,您可以知道之前是否以及如何定义 A、B 和/或 C。这使得它可以简单地确定。您只需要知道 C 是类型还是表达式。
  • 他应该使用“AA * BB(CC)”。这可以是 (1) 函数声明,(2) 对象声明或 (3) 乘法。
  • 没关系。 Yossi 假设(不正确地)要可判定,任何语法都必须可以由两阶段解析器解析,而无需从第二阶段反馈到第一阶段。对于他的第二个论点(无限递归),同样适用。 “不可判定”意味着没有解析器可以检测到递归
  • Yossi 似乎对 undecidablecontext-sensitiveambiguous 的含义感到非常困惑。
  • @Adam Rosenfield:我同意这个定义;但是,这意味着您的命题“如果不使用语义信息,就不可能确定给定的 XXX 程序在语法上是否有效”对于任何需要声明变量的语言(即 C、C++、Pascal、Perl、Java 等)都是正确的。
【解决方案2】:

你可以看看clang使用llvm进行解析。

现在完全支持 C++ link

【讨论】:

  • 更新:“Clang 目前实现了所有 ISO C++ 1998 标准(包括 ISO C++ 2003 标准中解决的缺陷),除了 'export'(已从 C++'0x 草案中删除)并被认为是生产质量的 C++ 编译器”日期:2011-07-27 clang.llvm.org/cxx_status.html
【解决方案3】:

ANTLR 解析器生成器具有用于 C/C++ 的 grammar 以及预处理器。我从来没有使用过它,所以我不能说它对 C++ 的解析有多完整。 ANTLR 本身在很多场合对我来说都是一个有用的工具,用于解析更简单的语言。

【讨论】:

  • Mod up 提到了 ANTLR。不久前我看过这个,但忘记了将它用作 lex/yacc 的替代品。如果C/C++语法不错,这可能是我最喜欢的路径……
  • 我不知道为什么这是现在被接受的答案,或者为什么它最初被接受。据我所知,C++ 的 ANTLR 语法从未在实践中使用过,并且我一直在跟踪这样的事情。该语法的作者在文档中留下了足迹,说:“它不完整,我已经完成了,如果你愿意,你可以修补它”。 C++98 是一门难学的语言,而 C++11 更差,还有一堆方言(GCC,Microsoft,Sun,...)。如果您没有正确的解析器,那么您所拥有的只是无用的。然后你需要全名和类型解析来做任何事情。这里没有什么。
【解决方案4】:

根据您的问题GCCXML 可能是您的答案。 基本上,它使用 GCC 解析源代码,然后为您提供易于理解的解析树 XML。 使用 GCCXML,您一劳永逸。

【讨论】:

  • 因为它实际上并不转储模板(仅模板实例化),所以它非常缺乏,尤其是在导致大多数解析问题的领域。参见例如模板中的关键字“typename”。
  • 这是一个非常好的链接和建议,但在我的特殊情况下,它并不能很好地工作,因为我需要从预处理器中提取语义信息。完成预处理魔术后,GCCXML 对生成的树进行操作。另外,这个项目最近好像没有更新。
  • gccxml 现在已经很老了(2004 年!)。希望他们能更新它!
【解决方案5】:

pycparser 是用 Python 编写的完整的 C (C99) 解析器。它有一个完全可配置的 AST 后端,因此它被用作您可能需要的任何类型语言处理的基础。

但不支持 C++。诚然,它比 C 难很多


更新(2012 年):毫无疑问,此时的答案是 Clang - 它是模块化的,支持完整的 C++(具有许多 C++-11 特性)并且具有相对友好的代码库。它还有一个用于绑定高级语言的 C API(即for Python)。

【讨论】:

    【解决方案6】:

    看看doxygen 是如何工作的,完整的源代码是可用的,它是基于 flex 的。

    GOLD 是一个误导性的候选对象,它是一个免费的基于 Windows 的解析器工具包,专门用于创建翻译器。他们支持的语言列表指的是可以实现解析器的语言,而不是支持的解析语法列表。

    他们只有 C 和 C# 的语法,没有 C++。

    【讨论】:

    • 我希望使用非 Windows 平台(Mac、Linux 或 Solaris),但我确实有 Windows 系统。我以前用过 Doxygen,想深入了解一下。
    • 我的理解是Gold是一个LALR解析器生成器。那不会解析 C++。
    • 该死,你是对的。他们的“支持的语言”列表是关于可以调用解析器的语言,而不是可解析的语言。
    【解决方案7】:

    Parsing C++ is a very complex challenge.

    有 Boost/Spirit 框架,几年前他们做了play with the idea of implementing a C++ parser,但现在是far from complete

    完全正确地解析 ISO C++ 绝非易事,而且实际上有很多相关的努力。但这是一项固有的复杂工作,如果不重写理解所有 C++ 预处理器的完整编译器前端,则不容易完成。 Spirit 人员提供了一个名为“wave”的预处理器实现。

    也就是说,您可能想看看 pork/oink(基于 elsa),这是一个 C++ 解析器工具包,专门用于源代码转换目的,Mozilla 项目正在使用它来做大规模静态源代码分析和自动代码重写,最有趣的是它不仅支持大部分C++,还支持预处理器本身!

    另一方面,确实有一个专有的解决方案可用:EDG 前端,它几乎可以用于所有与 C++ 相关的工作。

    就个人而言,我会查看 Mozilla 使用的基于 elsa 的猪肉/oink 套件,除此之外,FSF 现在已批准使用运行时库许可证在 gcc plugins 上的工作,因此我假设事情一旦人们可以使用二进制插件轻松利用基于 gcc 的 C++ 解析器来实现此类目的,就会发生迅速变化。

    所以,简而言之:如果你有钱:EDG,如果你需要一些免费/开源的东西现在:else/oink 是相当有前途的,如果你有时间,你可能想要为您的项目使用 gcc。

    另一个仅适用于 C 代码的选项是 cscout

    【讨论】:

    • 在此处查看其他答案以了解有关 Elsa 的更多详细信息。
    【解决方案8】:

    C++ 的语法是出了名的多毛。有a good thread at Lambda about it,,但要点是 C++ 语法可能需要任意多的前瞻。

    对于我想你可能正在做的事情,我会考虑破解 Gnu CC 或 Splint。特别是 Gnu CC 确实将语言生成部分非常彻底地分离出来,因此您最好构建一个新的 g++ 后端。

    【讨论】:

    • 很高兴收到您的来信,查理,在这样一个随机的地方!我的主要动机是 C++ 很复杂,很难在编辑时进行静态分析和提供代码感。我想要一种易于分析但同构等同于 C++ 的新语言
    • 你不会得到“易于分析”和“与 C++ 同构”。 C++ 无论其语法如何,都很难分析。您可以期望的最好的结果是某种针对 C++ 本身的分析工具。
    【解决方案9】:

    实际上,PUMA 和 AspectC++ 仍然在积极维护和更新。我正在研究使用 AspectC++ 并且想知道自己缺乏更新。我给作者发了电子邮件,他说 AspectC++ 和 PUMA 仍在开发中。您可以通过 SVN https://svn.aspectc.org/repos/ 获取源代码,或者您可以在 http://akut.aspectc.org 获取常规二进制构建。和现在很多优秀的c++项目一样,作者没有时间跟上网页维护。如果你有一份全职工作和生活,那是有道理的。

    【讨论】:

      【解决方案10】:

      Elsa 在 C++ 解析方面胜过我所知道的一切,即使它不是 100% 兼容的。我是一个粉丝。有一个模块可以打印出 C++,所以这可能是您的玩具项目的一个很好的起点。

      【讨论】:

      • 感谢您的链接!我去看看……
      • 当我在我的 C++ 文件上尝试它并停止说这没有实现或类似的东西时。
      • 这些工具根据网站上的日期显示,最后一次更新是在 2005 年;作者声称“尝试解析 C++03 规范定义的 C++(如)”。这取决于其他东西来进行预处理。
      • Ira,今天我毫无疑问地推荐 clang。 2009 年还不够好。
      【解决方案11】:

      请参阅我们的C++ Front End 对于功能齐全的 C++ 解析器:构建 AST、符号表、命名 和类型分辨率。您甚至可以解析和保留预处理器 指令。 C++ 前端构建在我们的DMS Software Reengineering Toolkit 之上,它允许您使用该信息执行任意操作 使用源到源转换来更改源代码。

      DMS 是实现此类转换器的理想引擎。

      话虽如此,我认为您想象中的任务没有多大意义;我不 看到尝试替换 C++ 的巨大价值,你会发现构建 一个完整的翻译需要大量的工作,尤其是如果您的 target 是一种“玩具”语言。而且可能没什么意义 使用健壮的解析器解析 C++,如果它的唯一目的是产生 C++ 的同构版本,更易于解析(等等,我们假设 已经是一个强大的 C++ 了!)。

      2012 年 5 月编辑:DMS 的 C++ 前端现在处理 GCC3/GCC4/C++11、Microsoft VisualC 2005/2010。稳健。

      2015 年 2 月编辑:现在处理 GCC 和 MS 方言中的 C++14。

      2015 年 8 月编辑:现在在统一的树中解析和捕获代码和预处理器指令。

      2020 年 5 月编辑:过去几年一直在做 C++17。 C++20 正在开发中。

      【讨论】:

      • 重复另一个问题来源的答案stackoverflow.com/questions/792454/… 用于推广商业软件的插件....
      • 重复类问题:“我怎样才能(轻松)构建复杂的语言处理器?” a) 你不能,b) 这个引擎的设计目的是让这件事变得尽可能简单(我没说简单)。
      • 引用 OP:In particular, I'm looking for open source tools - DMS 是开源的吗?
      • DMS 不是开源的,即使您不知道这一点,SO 批准的短语“我们的 XXXX”也清楚地表明了这一点。像其他人在这里所做的那样,我没有看到解决开源工具的任何意义。在 OP 的预期任务中,他们几乎完全失败了,所以他不得不寻找其他地方,例如商业。我们是我所知道的唯一可以满足他需求的商业(或实际上任何类型)工具,包括能够捕获预处理器指令,因此恕我直言,答案是相关的。
      • 第二,虽然我的回答指出了 OP 唯一真正的解决方案之一,但我的回答更多地关注他的意图和期望的结果。他实际上不会构建替代方案 a) 因为他没有精力去做,b) 因为它没有机会取代真正的 C++。 [是的,这个回复有点晚了,但莫顿的评论让我很困扰。]
      【解决方案12】:

      tiny-CSmall C 这样更容易理解的东西怎么样

      【讨论】:

      • 感谢您的链接!这些项目肯定会帮助您快速开始创建解析器
      • 不,这甚至不会接近。
      【解决方案13】:

      不久前,我尝试编写一个工具来自动为 c 文件生成单元测试。

      为了进行预处理,我将文件放入 GCC。输出很难看,但您可以轻松地从预处理文件中追踪原始代码的位置。但为了您的需要,您可能还需要其他东西。

      我使用Metre 作为 C 解析器的基础。它是开源的,使用 lex 和 yacc。这使得在不完全了解 lex 和 yacc 的情况下很容易在短时间内启动和运行。

      我还编写了一个 C 应用程序,因为 lex 和 yacc 解决方案无法帮助我跨函数跟踪功能并一次性解析整个函数的结构。它在短时间内变得无法维护并被放弃。

      【讨论】:

        【解决方案14】:

        如何使用像 GNU 的 CFlow 这样的工具,它可以分析代码并生成调用图图表,这是 opengroup(手册页)对 cflow 的看法。 GNU版cflow自带源码,也开源了...

        希望这会有所帮助, 最好的祝福, 汤姆。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-09-10
          • 1970-01-01
          • 2011-12-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-07
          • 1970-01-01
          相关资源
          最近更新 更多