来源操纵

时间:2011-08-15 00:26:13

标签: c parsing linux-kernel clang

我需要在Linux内核中进行一些源到源操作。我试图用clang来达到这个目的,但是有一个问题。 Clang对源代码进行预处理,即宏和包含扩展。这导致clang有时会在Linux内核方面产生破碎的C代码。我不能手动维护所有更改,因为我希望每个文件有数千个更改。

我尝试过ANTLR,但可用的公共语法不完整,不适合Linux内核等项目。

所以我的问题如下。有没有办法在不预处理的情况下对C代码执行源到源操作?

假设下面的代码。

#define AAA 1
void f1(int a){
    if(a == AAA)
        printf("hello");
}

在应用源到源操作后,我想得到这个

#define AAA 1
void f1(int a){
    if(functionCall(a == AAA))
        printf("hello");
}
但是,例如,Clang生成的代码不符合我的要求,即它扩展了宏AAA

#define AAA 1
void f1(int a){
    if(functionCall(a == 1))
        printf("hello");
}

我希望我足够清楚。

修改

以上代码只是一个例子。我想要做的源到源操作不受if()语句替换的限制,而是在表达式前插入一元运算符,用其正值或负值替换算术表达式等。

解决方案

我找到了一个解决方案。我使用gcc来生成预处理的源代码,然后应用Clang。然后我对宏扩展没有任何问题,包括,因为那个工作是由gcc完成的。谢谢你的答案!

5 个答案:

答案 0 :(得分:4)

您可以考虑http://coccinelle.lip6.fr/:它提供了一个很好的语义修补框架。

答案 1 :(得分:2)

一个想法是替换所有出现的

if(a == AAA)

if(functionCall(a == AAA))

您可以使用例如sed工具轻松完成此操作。

如果要更换有限的模式集合,可以编写一个sed脚本来执行替换。

这会解决您的问题吗?

答案 2 :(得分:0)

处理预处理器是将转换应用于C(和C ++)代码时最困难的问题之一。

我们的DMS Software Reengineering Toolkit及其C Front End相对接近这一点。 DMS可以解析C源代码,保留大多数预处理器条件,宏定义和使用。

它通过在“结构良好”的位置允许预处理器操作来实现。示例:允许声明或语句发生的#defines,宏调用和条件作为语言中许多非终结符的替换(例如,函数头,表达式,语句,声明)以及人们通常放置的许多非结构化位置他们(例如,#if fooif(...){#endif)。它解析源代码和预处理器指令,就好像它们是一种语言(它们是,它的名称为“C”)的一部分,并构建相应的AST,它们可以被转换并使用捕获的预处理器指令正确地重新生成。 [这个级别的能力完美地处理了OP的例子。]

某些指令的位置很差(在语法意义上,例如,跨语言的多个片段,以及“你必须开玩笑”的可理解性)。这些DMS通过扩展它们来处理,并由高级工程师提供一些指导(“总是扩展这个宏”)。一种不太令人满意的方法是将非结构化预处理器条件/宏调用手动转换为结构化调用;这有点痛苦,但比人们预期的更可行,因为坏情况的发生频率远远低于好情况。

为了做得更好,需要考虑预处理器条件的符号表和流分析,并捕获所有预处理器条件。我们已经用DMS做了一些实验工作来捕获符号表中的条件声明(似乎工作正常),我们刚开始为后者开发一个方案。

不容易变绿。

答案 3 :(得分:0)

Clang保留有关原始源代码的非常准确的信息。

最值得注意的是,SourceManager能够判断给定的令牌是从宏扩展还是按原样编写,而Chandler Caruth最近实现了宏诊断,它能够显示实际的宏扩展堆栈(at追溯的各个阶段)追溯到实际的书面代码(3.0)。

因此,可以使用生成的AST,然后重写源代码,其所有宏仍然存在。您几乎必须查询每个节点以了解它是否来自宏扩展,如果它确实检索了扩展的原始代码,但似乎仍然可能。

  • Clang中有一个重写器模块
  • 您可以在宏诊断堆栈上挖掘Chandler的代码

所以我猜你应该拥有所有你需要的东西:)(希望如此,因为我将无法提供更多帮助:p)

答案 4 :(得分:0)

我建议采用Rose框架。 Source可在github上找到。