创建C/C++解析器/分析器的好工具

53
有哪些用于快速开始解析和分析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 年以来就没有维护过了。通过少量的谷歌搜索可以找到其他基本的 lex/yacc 语法,可以作为起点。
  • 还有其他的吗?

我希望将其用作将 C/C++ 源代码翻译成一种新的玩具语言的起点。

谢谢! -Matt

(添加于 2/9):只是一个澄清:我希望从预处理器中提取语义信息,除了 C/C++ 代码本身。我不想让 "#define foo 42" 消失到整数 "42" 中,而是保持与名称 "foo" 相关联。这使得几个运行预处理器后仅提供 C/C++ 解析树的解决方案被排除在外。


马特,我认为这是一个徒劳的希望;预处理器根据定义在分析之前处理源代码。至少旧的管道编译器在解析之前将预处理后的源代码放入管道中。也许你可以使用cpp嵌入式注释? - Charlie Martin
你可以在源代码上运行自己的处理器。它会输出一个带注释的源代码。你需要修改你的工具所使用的C++语法来读取这些注释。嘿,既然涉及到C++,你就知道这不会很容易 :) - Sean McCauliff
2
被浏览了42,000次?我认为这个应该重新开放。如果你同意,请点击上面的“重新开放”。 - Ira Baxter
我认为这个问题应该重新开放。所有“最佳实践相关的问题”都被标记为离题,但有些可能具有技术维度、客观原因;这不是一个主观的、个人的问题。 - tolga
14个回答

37
解析C++非常困难,因为语法是不可判定的。引用Yossi Kreinin的话:
“杰出复杂的语法”。“杰出”应该被字面理解,因为所有流行的语言都有无上下文(或“几乎”无上下文)的语法,而C++具有不可判定的语法。如果你喜欢编译器和解析器,你可能知道这意味着什么。如果你对这种事情不感兴趣,这里有一个简单的例子展示了解析C++的问题: AA BB(CC); 是对象定义还是函数声明?结果取决于语句之前的代码——上下文。这表明(在直觉层面上)C++语法是相当上下文敏感的。

17
像他的许多名言一样,这句话也是错误的。“不可判定”意味着你完全无法知道 A B (C) 的含义。实际上,在上下文中,您可以知道 A、B 和/或 C 是否已定义以及如何定义它们。这使得它变得非常易于判断,只需知道 C 是一种类型还是一个表达式即可。 - MSalters
5
他应该使用"AA * BB(CC)"。这可以是(1)函数声明,(2)对象声明或(3)乘法。 - Richard Corden
7
不要紧。Yossi错误地假设任何文法只要可以被一个两阶段解析器解析,且第二阶段不需要向第一阶段提供反馈,那么它就是可判定的。对于他的第二个论点(无限递归),同样适用。如果一个文法是“不可判定”的,则意味着没有解析器能够检测到递归。 - MSalters
12
Yossi似乎对“不可判定”、“上下文有关”和“歧义”的含义严重困惑。 - jpalecek
1
我来晚了,但这都不重要。人们可以使用GLR或GLL解析器为C++构建解析器,可能会产生一些含有歧义的子树的抽象语法树。这就解决了“解析C ++”的问题。只有在使用弱解析技术时才会变得困难。当然,您需要以某种方式解决任何歧义,例如使用有关符号类型的信息,但您可以稍后解决这个问题,或者您可以在有问题的产生式的语义检查中解决它(后者本质上是GCC在其C ++解析器基于LALR时使用的黑客方法)。 - Ira Baxter
显示剩余11条评论

21

您可以查看clang,它使用llvm进行解析。

现在完全支持C++,链接


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

17

ANTLR 解析器生成器有一个 C/C++ 以及预处理器的 语法。我从未使用过它,所以无法确定它对 C++ 的解析会有多完整。对于解析更简单的语言,ANTLR 在几个场合中都是对我有用的工具。


提到ANTLR的话,我觉得很赞。我之前稍微了解过这个工具,但忘记将其用作lex/yacc的替代品。如果C/C++语法很好,那么这可能会是我最喜欢的选择... - Matt Ball
12
我不知道为什么这个答案现在被接受了,或者最初为什么被接受。据我所知,ANTLR用于C++的语法从未在实践中使用过,而我一直关注这方面的事情。该语法的作者在文档中留下了脚印,说:“它是不完整的,我已经完成了,如果你想修补它,那就可以”。 C++98是一门棘手的语言,C++11更糟糕,然后还有一堆方言(GCC、Microsoft、Sun等)。如果您的解析器不正确,您所拥有的就是无用的东西。然后您需要完全的名称和类型解析才能做任何事情。这里没有关于那方面的内容。 - Ira Baxter

16

根据您的问题,GCCXML可能是您的答案。基本上,它使用GCC解析源代码,然后提供易于理解的解析树XML。使用GCCXML,您只需一次解决所有问题。


1
由于它实际上并不转储模板(只转储模板实例化),因此它在某种程度上严重缺乏,特别是在导致大多数解析问题的一个领域。例如,在模板内部查看关键字“typename”。 - MSalters
1
这是一个非常好的链接和建议,但在我的情况下并不完全适用,因为我需要从预处理器中提取语义信息。 GCCXML 是在预处理操作完成后对结果树进行操作的。此外,看起来这个项目最近没有更新。 - Matt Ball
1
gccxml现在相当老了(2004年!)。希望他们能更新它! - Nick

14

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

不支持C ++,尽管这比C要难得多。


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


8
请看一下doxygen的工作方式,完整源代码可用且基于flex。
一个误导性的候选者是GOLD,它是一个免费的Windows解析器工具包,专门用于创建翻译器。他们支持的语言列表是指可以实现解析器的语言,而不是支持的解析语法列表。
他们只有C和C#的语法,没有C++。

我希望使用非Windows平台(Mac、Linux或Solaris),但我确实有一个Windows系统。我以前使用过Doxygen,并想更深入地了解它的内部结构。 - Matt Ball
我的理解是Gold是一个LALR解析器生成器。但它不能解析C ++。 - Ira Baxter
该死,你是对的。他们的“支持语言”列表是指可以调用解析器的语言,而不是可解析的语言。 - Andy Dent

7

解析C++是一个非常复杂的挑战

有Boost / Spirit框架,几年前他们尝试实现了C ++解析器的想法,但它还远未完成

完全和正确地解析ISO C ++远非易事,事实上有许多相关努力。但这是一项本质上复杂的工作,不容易完成,除非重写完整的编译器前端,理解所有C ++ 预处理器。Spirit团队提供了一个名为“wave”的预处理器实现。

话虽如此,您可能需要查看猪肉/猪叫声(基于elsa),它是一个专门用于源代码转换目的的C ++解析器工具包,Mozilla项目正在使用它进行大规模静态源代码分析和自动化代码重写,最有趣的部分是它不仅支持大多数C ++,而且还支持预处理器本身!

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

个人而言,我会检查Mozilla使用的基于elsa的猪肉/猪叫声套件,除此之外,FSF现已批准了使用运行时库许可证的gcc插件的工作,因此我假设一旦人们可以使用二进制插件轻松利用基于gcc的C ++解析器进行这种目的,事情将会迅速改变。

因此,简而言之:如果您有钱:EDG,如果您需要免费/开源的东西现在:否则/猪叫声相当有前途,如果您有时间,您可能需要为项目使用gcc。

只针对C代码的另一个选项是cscout


有关 Elsa 的更多详细信息,请参见此处的其他答案。 - Ira Baxter

6
C++的语法有点充满争议。有一个好的Lambda主题关于它的讨论,但要点是C++语法可能需要任意多的前瞻。对于我想象中你可能在做的事情,我会考虑入侵Gnu CC或Splint。特别是,Gnu CC将语言生成部分分开得非常彻底,因此您最好构建一个新的g++后端。

很高兴收到你的来信,Charlie,而且还在这么随意的地方!我的主要动机是C++很复杂,很难进行静态分析并在编辑时提供代码感知。我想要一种新的语言,它易于分析,但与C++同构等效。 - Matt Ball
1
你不会得到“易于分析”和“同构于C ++”。无论其语法如何,C ++ 都很难分析。你能期望的最好的情况是为 C++ 自身提供一些分析工具。 - Ira Baxter

4
实际上,PUMA和AspectC++仍在积极维护和更新。我正在考虑使用AspectC++,并对缺乏更新感到困惑。我给作者发了电子邮件,他说AspectC++和PUMA仍在开发中。您可以通过SVNhttps://svn.aspectc.org/repos/获取源代码,或者您可以在http://akut.aspectc.org获得常规二进制版本。像很多优秀的C++项目一样,作者没有时间维护网页。如果你有全职工作和生活,这是很有道理的。

3

要是想要更加易懂的东西,可以考虑使用 Tiny-CSmall C 这样的编程语言。


谢谢提供这些链接!这些项目肯定会帮助我们快速创建解析器。 - Matt Ball
不,这甚至都不接近。 - Ira Baxter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接