自定义gcc预处理器

时间:2010-08-23 08:33:43

标签: gcc c-preprocessor

你能给我一个编写自定义gcc预处理器的例子吗?

我的目标是用适当的CRC32计算值替换SID(“foo”)相似的宏。对于任何其他宏,我想使用标准的cpp预处理器。

看起来可以使用-no-integrated-cpp -B选项实现此目标,但是我找不到任何简单的使用示例。

2 个答案:

答案 0 :(得分:21)

警告:危险和丑陋的黑客攻击。现在闭上眼睛您可以通过将'-no-integrated-cpp'和'-B'开关添加到gcc命令行来挂钩您自己的预处理器。 '-no-integrated-cpp'表示gcc在使用其内部搜索路径之前会在'-B'路径中搜索其预处理器。如果使用'-E'选项调用'cc1','cc1plus'或'cc1obj'程序(这些是C,C ++和Objective-c编译器),则可以识别预处理程序的调用。当您看到此选项时,您可以进行自己的预处理。当没有'-E'选项时,将所有参数传递给原始程序。当有这样的选项时,您可以进行自己的预处理,并将操纵的文件传递给原始编译器。

看起来像这样:

> cat cc1
#!/bin/sh

echo "My own special preprocessor -- $@"

/usr/lib/gcc/i486-linux-gnu/4.3/cc1 $@
exit $?

> chmod 755 cc1
> gcc -no-integrated-cpp -B$PWD x.c
My own special preprocessor -- -E -quiet x.c -mtune=generic -o /tmp/cc68tIbc.i
My own special preprocessor -- -fpreprocessed /tmp/cc68tIbc.i -quiet -dumpbase x.c -mtune=generic -auxbase x -o /tmp/cc0WGHdh.s

此示例调用原始预处理器,但会打印其他消息和参数。您可以使用自己的预处理器替换脚本。

糟糕的黑客已经结束了。你现在可以睁开眼睛了。

答案 1 :(得分:2)

一种方法是在编译之前使用program transformation system来“重写”只是 SID宏调用到你想要的东西,剩下的预处理器处理剩下的就是编译器本身。

我们的DMS Software Reengineering Toolkit就是这样一个系统,可以应用于多种语言,包括C,特别是GCC 2/3/4系列编译器。

要使用DMS实现此想法,您将使用其C front end运行DMS 编译步骤之前的源代码。 DMS可以解析代码而无需扩展预处理程序指令,build 表示它的抽象语法树,对AST进行转换,然后将结果吐出为可编译的C文本。

您将使用的特定转换规则是:

rule replace_SID_invocation(s:STRING):expression->expression
          = "SID(\s)" -> ComputeCRC32(s);

其中ComputeCRC32是自定义代码,可以执行它所说的内容。 (DMS包括CRC32实现,因此自定义代码非常短。

DMS对于这项任务来说是一件很重要的事情。您可以使用PERL来实现非常相似的东西。与PERL(或其他一些字符串匹配/替换黑客)的区别在于以下风险:a)它可能会在您想要替换的地方找到模式,例如。

  ... QSID("foo")... // this isn't a SID invocation

您可以通过仔细编码模式匹配来修复,b)无法匹配在令人惊讶的情况下发现的SID调用:

  ...   SID  ( /* master login id */  "Joel" )  ... // need to account for formatting and whitespace

和c)无法处理文字字符串本身中出现的各种转义字符:

  ...   SID("f\no\072") ...  // need to handle all of GCC's weird escapes

DMS的C前端为您处理所有逃脱;上面的ComputeCRC32函数会看到包含实际目标字符的字符串,而不是您在源代码中看到的原始文本。

所以这真的是你是否关心暗角情况,或者你认为你可能需要做更多特殊处理。

考虑到你描述这个问题的方式,我会非常想要首先走Perl路线并简单地取缔这些有趣的案例。如果你不能这样做,那么大锤子就有意义了。