43

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

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

4

13 回答 13

63

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

  • 非常相似的语法,所以语法高亮有效。
  • <?并且?>不在标准 C 中使用(对于非标准 C,唯一被破坏的是返回 min/max 的旧 GCC 扩展运算符)
  • 它有丰富的图书馆。
  • 图灵完成了。
  • 宏的使用非常明确。(与偷偷摸摸的 C 预处理器宏相比)

但是,如果要认真使用,则需要让 PHP 打印 #line 指令来调试预处理代码。

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

int main()
{
    <?php
        for($i = 0; $i < 20; $i++)
            echo 'printf("%d\n", '.$i.');';
    ?>
}
于 2013-04-27T19:28:03.723 回答
10

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

于 2008-12-28T20:34:16.907 回答
10

Cog并不完全是一个预处理器,但它确实在代码中嵌入并动态生成内容。

于 2008-12-28T20:55:03.573 回答
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");
}
于 2008-12-29T02:23:01.540 回答
6

当然,标准的 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 字符串中。

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

于 2013-02-22T15:24:26.853 回答
5

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

我目前使用Jinja2 (Python) 进行大多数模板工作——我发现它在各个方面都非常可配置。

于 2009-07-28T16:50:06.067 回答
5

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

它是高度模块化的,因此您可以切换您自己的驱动程序,以实现您想要的额外功能。

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

于 2008-12-28T20:58:54.453 回答
3

CPP does many important things for C code that you probably don't need re-implemented. What you seem to be looking for instead may be a templating process that emits C code.

Cheetah is just one of many that allows you to use python. There are others that use python and still more in other languages, but Cheetah is known for being output-agnostic where some templating engines are very heavily geared towards HTML/XML. Do your research.

于 2008-12-29T15:20:26.463 回答
3

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

于 2008-12-28T20:53:56.650 回答
3

最简洁的答案是不。” 预处理器与 C 的语义密切相关,以至于您无法真正删除它,事实上,在某些编译器中,它甚至不像过去那样是一个单独的阶段 --- 在Mac 只解析 Objective C 语法。因此,虽然您当然可以使用另一个宏处理器,如 m4,在将源文本传递给 C 之前对其进行处理,但您不会取消C 预处理器,而是添加另一个预处理步骤。

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

于 2008-12-28T20:56:20.200 回答
2

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

这可能不像使用“真正的”预处理器那样方便(或干净),但它会起作用。再说一次,这真的取决于你的情况。

于 2008-12-28T21:14:44.610 回答
1

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

于 2008-12-28T20:36:16.217 回答
1

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

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

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

于 2008-12-29T06:28:43.790 回答