C预处理器的替换

时间:2008-12-28 20:32:10

标签: objective-c c c-preprocessor

我有兴趣使用 C 预处理器之外的其他东西来预处理我的 C 和Objective-C源代码。有没有好的选择?

一个例子是允许一个人在 C 代码中间逃出一个python或perl片段,并且片段吐出 C ,这是然后正常编译。

13 个答案:

答案 0 :(得分:53)

您可以使用 PHP 作为C预处理器。优点是:

  • 非常类似的语法,因此语法突出显示有效。
  • <??>未在标准C中使用(使用非标准C,唯一被破坏的是返回最小/最大值的旧GCC扩展运算符)
  • 它有丰富的图书馆。
  • 它完成了。
  • 宏的用法非常明确。 (与偷偷摸摸的C预处理器宏相比)

为了认真使用,调试预处理代码需要PHP打印#line指令。

<?php include_once "stdio.h"; ?>

int main()
{
    <?php
        for($i = 0; $i < 20; $i++)
            echo 'printf("%d\n", '.$i.');';
    ?>
}

答案 1 :(得分:10)

Cog并不是一个预处理器,但它确实在代码中内嵌,并在运行中生成内容。

答案 2 :(得分:9)

运行代码,然后将其结果拼接在中的想法称为 quasiquotation 。您运行的代码是反引用

我知道如何使用Lua解决这个问题。我使用了string.gsub我自己写的反引号功能。我已经使用shell语法进行反引号。与在shell中一样,反引号代码返回一个字符串,然后将其拼接到代码中。

prog下面是带反引号文本的C代码,antiquote是反引号函数。我已经使用Lua的特殊字符串引用双方括号来充分利用它。 在实践中你不会这样做;你将prog放在一个单独的文件中。

names = { 'John', 'Paul', 'George', 'Ringo' }

local prog = [===[
#include <stdio.h>

main() {
  $(local out = { }
    for _, n in ipairs(names) do
      table.insert(out, string.format([[  printf("The name is %%s\n", %q);]], n))
    end
    return table.concat(out, '\n  ')
   )
}
]===]


local function antiquote(s)
  local body = s:match '^%$%((.*)%)$'
  return assert(loadstring(body))()
end

prog = prog:gsub('%$%b()', antiquote)
io.stdout:write(prog)

在使用中,程序如下所示:

: nr@curlycoat 1181 ; lua /home/nr/tmp/emit-c.lua
#include <stdio.h>

main() {
    printf("The name is %s\n", "John");
    printf("The name is %s\n", "Paul");
    printf("The name is %s\n", "George");
    printf("The name is %s\n", "Ringo");
}

答案 3 :(得分:7)

您可能需要考虑m4 http://www.gnu.org/software/m4/

答案 4 :(得分:5)

如果您准备好接受一些C ++,那么Boost中的Wave解析器就是使用Spirit递归下降解析器构建的。它是一个完整的C预处理器,符合C和C ++的所有最新规范(以及扩展,Objective C,AFAICS)。

它是高度模块化的,所以你可以切换自己的驱动程序,这可以做你想要的额外功能。

http://www.boost.org/libs/wave/doc/introduction.html

答案 5 :(得分:5)

如果您稍微抽象出问题,那么您实际上正在为您的代码寻找模板引擎。正如大多数网站在静态模板中插入动态生成的内容一样,您希望将动态生成的代码插入到程序中。

我目前使用 Jinja2 (Python)进行大多数模板工作 - 我发现它可以以各种方式进行非常配置。

答案 6 :(得分:5)

当然,标准C预处理器非常有限 我最近做了这样一个工具:https://github.com/d-ash/perlpp

例如这个

<?
    my @types = ('char', 'int', 'long'); 
    foreach (@types) {
?>
        <?= $_ ?> read_<?= uc($_) ?>(<?= $_ ?>* v);
<?  } ?>

变成这个

char read_CHAR(char* v);
int read_INT(int* v);
long read_LONG(long* v);

语法类似于PHP,但它使用Perl代替,并且可以将文本捕获到Perl stings中。

cxw

编辑 - 在@ d-ash的批准下,我也是perlpp的维护者。如果您有任何疑问,请随时给我留言!

答案 7 :(得分:3)

我过去曾想过同样的问题。确保任何想要编译代码的人都需要新的预处理工具。如果你是唯一一个会参与其中的人,没问题,但是如果你想让其他人可以使用这些代码,那么你可能想要考虑是否添加工具要求是一个好主意。

答案 8 :(得分:3)

简短的回答是“不”。预处理器与C的语义密切相关,你无法真正删除它,实际上在某些编译器中甚至不像过去那样单独的阶段---编译目标C Mac只是解析Objective C语法。因此,虽然您可以使用其他宏处理器(如m4)来处理源文本,然后再将其传递给C,但您不会消除 C预处理器,您将添加预处理的另一个步骤。

但是这里有一个更深层次的问题:你想通过消除CPP阶段获得是什么?

答案 9 :(得分:3)

CPP为C代码做了很多重要的事情,你可能不需要重新实现它们。你似乎在寻找的东西可能是一个发出C代码的模板化过程。

Cheetah只是允许您使用python的众多功能之一。还有其他人使用python,还有更多其他语言,但Cheetah因输出不可知而闻名,其中一些模板引擎非常注重HTML / XML。做你的研究。

答案 10 :(得分:1)

我看到2001年的一篇论文介绍了类似python的预处理器http://ray.cg.tuwien.ac.at/rft/Papers/PYM/pym.html。目前尚不清楚是否有人在使用它..

答案 11 :(得分:1)

您可以使用自己喜欢的编程语言来构建脚本/工具来生成源文件(.c / .cpp或.h,或其他)。只需#include他们或将它们编译到您的项目中。在#include附近发表评论可能有助于确定工具的位置和位置以及生成的内容。

这可能不像使用“真正的”预处理器那样方便(或干净),但它可以工作。然后,这真的取决于你的情况。

答案 12 :(得分:1)

我有兴趣看看人们想出了什么。我倾向于用Perl编写的预处理器来做小的自定义事情。装配调用预处理器的Makefile很容易。例如,这里有一个规则来调用名为'meta'的程序从'file.c.meta'生成'file.c'。

% :: %.meta
    meta $< > $@

我正在使用'meta'做有趣的事情,比如生成自定义适合的C数据结构。这绝对是我建议探索的方向。我希望最终能够提出一个与C ++模板大致平行的元库。