2011-12-08 39 views
2

我想构建一个解析并列出头文件内容的程序。到目前为止,这么好,我发现它很容易解析和列出我编写的头文件,但是当我开始解析跨平台API头时,事情变得混乱。解析不规则的C++原型

我目前的做法是相当简单的,这里是解析以下功能的伪代码示例:

void foo(int a); 

void is a type, so we are dealing with instancing a type 
foo is the name of that type 
foo is followed by brackets, meaning it is a function of type void named foo 
    int is a type... 
    a is the name of that type instance 
foo is a function of type void that takes one parameter of type int named a 

然而,当我进入更大和更复杂的头,我偶然发现有些不规则的原型,包括宏和上帝知道什么。举例:

GLAPI void APIENTRY glEvalCoord1d(GLdouble u); 

GLAPI和APIENTRY是平台相关的宏。我的简单解析方案会破坏哪种类型,因为它期望对象的名称遵循其类型。这两个宏恰好转换为__stdcall,__declspec(dllimport)或extern,但理论上它们可能意味着什么,在编译之前它们的含义不清楚。

如何编写我的解析器,以便它可以处理这种情况,而不会感到困惑?宏本身是在早期阶段定义的,所以解析器可以意识到GLAPI和APIENTRY是宏,因此它们可以简单地被忽略,这是要走的路吗?自然地,这只是众多不规则之处的变体之一,解析器可能偶然发现通过不同的头文件进行解析,所以任何有关如何处理任何“合法”头文件内容解析的通用技术都是受欢迎的。

+0

不,我不需要任何建议。干杯,但。 –

+0

我很抱歉,有一个感叹号“需要建议!”但由于某种原因,该网站将其更改为?甚至在我编辑我的帖子后,它仍然把一个问号...奇怪,但我假设,因为我发布了一个问题,问号是默认的...让我猜,你试图编辑它,并失败了? ? :) – dtech

+0

哈,你是对的..它确实似乎重写了尾随感叹号。 –

回答

1

在解析之前没有任何真正的选择来扩展宏,至少如果你想处理与微软相同复杂度的头文件,或者任何其他与编译器系统相关的头文件已经存在10次年或以上。

未经处理的源代码不是C;它只是没有经过处理的源代码。这些宏(以及令人惊讶的预处理器条件并未提及)可以以任意而又非常复杂的方式编辑这个API。除非您也处理#includes,否则您通常无法知道所使用的宏或扩展的条件。

你可以让GCC为你做预处理器扩展,然后解析它。这将是最接近 的最简单方法。

这仍然留下解析真正的C代码的问题,具有所有的声明的复杂性,以及片段中的含糊不清等问题T X;其中语句的含义取决于T的声明。要准确解析标题,您需要一个完整的C语法分析器。

我们的C Front End可以做完整的预处理,或者你可以调用它的模式,其中一些宏展开,有些不是。通过调整这个集合,你经常分析这样的头文件,而不会泄露每个宏。预处理器条件要困难得多,因为它们可能发生在不方便(非结构化)的地方。

0

如果你想要的只是函数的名字和签名,那么简单的搜索和替换宏就足够了。

但是,您需要检查宏是否包含关键字(如返回值)。这可能是通过剥离每个关键字的宏定义来实现的,因为它们是被定义的,但是跟踪它们并使用简单的预处理器将是必要的。

与平台相关的关键字(如__declspec__attribute__)的语法非常有限,并且只有少数几个,因此可以特别删除这些关键字。

您可能想要看看doxygen如何处理这个问题,因为它几乎完全符合您的需求并处理宏。它允许根据定义扩展宏列表,以及应扩展为自定义值的宏列表。您可以调整它以将__declspec(x)扩展为空,并且默认情况下将所有其他扩展为其定义的值。

这当然不是万无一失的,但搜索和替换是关于您将获得的最简单的功能解决方案。您需要遵循标准的C++预处理器规则,这些规则不是非常复杂,需要额外的宏(const,declspec等)去除额外的属性,并解析最终的结果。