解析不规则的c++原型
Parsing irregular c++ prototypes
我正在尝试构建一个解析和列出头文件内容的程序。到目前为止,一切顺利,我发现很容易解析和列出我编写的头文件,但是当我开始解析跨平台API头文件时,事情变得混乱了。
我目前的方法相当简单,下面是解析以下函数的伪代码示例:
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是宏,因此可以简单地忽略它们,这是正确的方法吗?当然,这只是解析器在解析不同头文件时可能遇到的许多不规则变化之一,因此,任何处理解析任何"合法"头文件内容的通用技术都是受欢迎的。
在解析之前没有任何真正的替代方法可以扩展宏,至少如果您希望处理头文件具有与Microsoft相同的复杂性,或者与已经存在了10年或更长时间的编译器系统相关的任何其他头文件。
未预处理的源代码不是C;它只是未经预处理的源代码。宏(和你惊讶地没有提到的预预处理条件)可以以不是任意的但非常复杂的方式编辑明显的源代码。除非您也处理#include,否则您通常无法知道使用了什么宏,或者扩展了什么条件。
您可以让GCC为您做预处理器扩展,然后解析它。那就太远了这是最简单的方法
这仍然留下了解析实际C代码的问题,包括声明器的所有复杂性,以及片段(如 tx;)中的歧义,其中语句的含义取决于T的声明。要准确解析头文件,需要一个完整的C解析器。
我们的C前端可以做完整的预处理,或者你可以调用一种模式,在这种模式下,一些宏被展开,一些宏不被展开。通过调优此集,您通常可以解析这些头文件,而无需展开每个宏。预处理器条件要困难得多,因为它们可能出现在不方便的(非结构化的)地方。
如果您想要的只是函数的名称和签名,那么对宏进行简单的搜索和替换就足够了。
但是,您需要检查宏是否包含关键字(如返回值)。这可以通过在定义关键字时剥离每个关键字的宏定义来实现,但是跟踪它们并使用简单的预处理器是必要的。
与平台相关的关键字,如__declspec
和__attribute__
,语法非常有限,而且只有少数几个,因此可以专门删除它们。
你可能想看看氧是如何处理这个的,因为它几乎完全是你想要的,并且处理宏。它允许按定义展开宏列表,也允许将宏列表扩展为自定义值。您可以将__declspec(x)
扩展为零,并将所有其他扩展为默认的定义值。
这当然不是万无一失的,但是搜索和替换是你能得到的最简单的功能解决方案。您需要遵循标准的c++预处理器规则,这并不是非常复杂,使用额外的宏(const、declspec等)来剥离额外的属性,并解析最终结果。
- 函数向量_指针有不同的原型,我可以构建一个吗
- 功能原型的目的
- getline() 的原型/库是什么;
- 具有enable_if外部类原型的模板类构造函数定义
- 函数如何通知用户它基于函数原型抛出异常?
- 在C++中包含原型文件的正确方法是什么?
- 在函数中拥有函数原型的目的是什么?
- 什么..(省略号)作为函数原型中唯一的函数参数,C++?
- 是否可以使用 libclang python 解析 cpp 文件中没有标头的函数原型
- 如果原型是本地的,则使用流 I/O C++类型约束将失败
- 如何进行原型消息交叉引用?
- 有没有办法在C++编译时更改函数原型?
- 省略函数原型中的返回类型
- 在 linux 原因上运行自定义原型插件
- 为什么以及如何使用原型设计模式
- 您是否必须随项目一起交付原型文件?
- 如何在C++中遍历谷歌原型地图?
- 错误:'EM::EM(...)' 的原型与类 'EM' 中的任何原型都不匹配
- 功能原型,没有定义
- 如何使用 "using" 关键字定义函数原型/签名