12

嗨,我正在使用 clang 从 c 文件中提取信息。我正在尝试提取宏的值。

例如,我想要值'13'或ast(+(* 3 4)1):

#define SOME_CONSTANT 3*4+1

或从宏函数,我想要一个 ast 例如 (SOME_MACROFUNC (xy) (+ (add4 x) (* y 9))) :

int add4(int q) {return q+4;}
#define SOME_MACROFUNC(x,y) add4(x)+y*9

到目前为止,我已经设法通过“预处理器”类的 macro_begin() 和 macro_end() 函数遍历所有宏。

然后我得到了宏名称,并且从“MacroInfo”类中我能够得到宏是否是函数式的(包括参数名称)。我还可以访问宏中的标记,但我只能获取标记类型,例如:string_literal、标识符、逗号、l_paren、r_paren 等。

所以有两件事:

  1. 我如何访问代币的实际价值,而不仅仅是它们的种类。

  2. 有没有办法从给定令牌的宏中生成 ast?我认为的一种方法是解析我的源代码,然后提取宏,并使用它们的名称,将包括这些宏的代码添加到我的源代码中,然后重新解析它以获得 ast。

例如:

char *tempSOME_CONSTANT = SOME_CONSTANT;    
void tempSOME_MACROFUNC(char *x, char *y) {SOME_MACROFUNC(x,y);}

虽然这种方法看起来真的很hacky,并且可能会遇到不是语句或表达式的宏的问题。

谢谢。

编辑:澄清我主要想要每个宏的扩展主体(直到没有宏,只有非宏标记)。

edit2 解决了一些问题:

如果有人感兴趣,我打算手动扩展宏的主体。

"preprocessor.getSpelling(token)" 获取令牌值。

“preprocessor.getIdentifierTable().get(StringRef(spelling))”获取令牌的 identinfo。

并使用“clang\lib\Lex\PPMacroExpansion.cpp”作为参考。

仍在考虑如何在不重新解析整个源代码树的情况下将其传递给解析器,但这应该不难弄清楚。

感谢 Ira Baxter 的讨论,它帮助我解决了这个问题。

4

2 回答 2

7

我正在做一些非常相似的事情。我使用 clang 前端来收集定义宏的上下文(wrt 类、函数等),然后使用(伪)表达式解析器来确定宏体是否是有效的表达式。最终目标是将宏转换为 C++ 声明。最近,我们收到了一篇被ICSM -2012 接受的论文,解释了我们如何实现这一目标。

用于摆脱宏的工具 - demacrofier- 托管在这里

Ira Baxter 的示例在宏的使用方式上非常有见地。但是,这些宏的百分比非常少 \ref(Ernst 等人对 C 预处理器使用的实证分析)。目前,我更多地关注常见案例。

于 2012-07-13T00:31:19.030 回答
0

一种可能有用也可能没用的技巧是将所有类似函数的宏暂时重新定义为函数。在你的情况下:

#define SOME_MACROFUNC(x,y) add4(x)+y*9

会变成

extern int SOME_MACROFUNC(int x, int y);

然后,您可以通过常规的 AST Matcher 或访问者运行它,并执行您需要的任何处理(包括重构,如果合适)。这不能很好地扩展,但如果宏的数量是众所周知且有限的,它可能是一个可以接受的解决方案。

为了使这个更清晰,您可以创建一个仅由 clang 使用的单独头文件,并确保在运行分析时 clang 首先找到它,这样您就不需要修改原始源库。

于 2017-03-24T03:09:20.113 回答