tags:

views:

1093

answers:

11

I'm interested in using something other than the C preprocessor to preprocess my C and Objective-C source code. Are there good alternatives?

An example would be something that allowed one to escape out into a python or perl snippet in the middle of C code, and where the snippet spit out C that is then compiled as normal.

+5  A: 

You might want to consider m4.
http://www.gnu.org/software/m4/

David Poole
To me, m4 feels too much like a science project and not enough like a pre-processor language. Last time I looked, it didn't have a looping construct, but instead had instructions on how to make one using recursion. I took that as a clear signal that the authors were too smart for my own good.
Michael Kohne
looping constructs, like these? [http://www.gnu.org/software/m4/manual/html_node/Forloop.html#Forloop][http://www.gnu.org/software/m4/manual/html_node/Foreach.html#Foreach]
Hasturkun
A: 

I see a 2001 paper introducing a python-like pre-processor http://ray.cg.tuwien.ac.at/rft/Papers/PYM/pym.html. It's not clear that anyone is using it..

Ken
+3  A: 

I've thought about this same problem in the past. Make sure you are OK with the fact that anyone who wants to compile your code will need the new pre-processing tool as well. If you are the only one who will ever work on it, no problem, but if you want to make the code available to others, then you might want to consider whether or not adding a tool requirement is a good idea.

Michael Kohne
I'm definitely not sure I'm okay with it. But I'm interested in looking. :-)
Ken
+3  A: 

Cog isn't exactly a pre-processor, but it does go in-line in the code and generates stuff on the fly.

Michael Kohne
This looks interesting, thank you.
Ken
+1  A: 

The short answer is "no." The preprocessor is so intimately tied to the semantics of C that you can't really remove it, and in fact in some compilers isn't even a separate phase like it used to be in the old days --- compiling Objective C on a Mac just parses the Objective C syntax. So while you could certainly use another macro-processor, like m4, to process your source text before passing it to C, you wouldn't be eliminating the C preprocessor, you'd be adding another step of preprocessing.

But there's a deeper question here: what do you want to gain by eliminating the CPP phase?

Charlie Martin
I agree that he should supplement, not replace, the CPP. However, I disagree that preprocessing is forced by the compiler. At least GCC provides a method for skipping the preprocessing stage.
strager
I don't expect to eliminate the cpp phase - an additional phase is fine. I'm interested in alternatives because cpp is limited and full of pitfalls. No loops, no arrays - anything at all complex is probably just a bad idea in cpp.
Ken
Then I'd be really tempted to use something like Perl and be done with it. M4 will certainly do it -- it's Turing-complete -- but it's covered in hair and unpleasantly arcane. Even compared to perl.
Charlie Martin
If you feed a C sourcefile to perl, it just won't compile. You could instead make a perl script that embeds the C source as more or less one big string that gets printed out, but it'd be ugly.
Ken
Dude, I don't mean feed the C to Perl. Write a Perl script that does templating using a C source file as input. Something like the Template toolkit http://template-toolkit.org/
Charlie Martin
So you're saying I should write my own preprocessor. :-) Yes, that's an option, but I was aware of that one.
Ken
No, I'm saying there are a zillion existing macro processors. Do you actually *have* something you want to do, or are you just saying "the C preprocessor isn't sufficiently wonderful"?
Charlie Martin
+2  A: 

If you're prepared to get your hands dirty with some C++, there's the Wave parser in Boost, which is built using the Spirit recursive descent parser. It's a complete C pre-processor that conforms to all the latest specs for C and C++ (and, by extension, Objective C, AFAICS).

It's highly modular so you can switch your own driver in that could do the extras you want.

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

Phil Nash
A: 

You can use your favourite programming language to build a script/tool to generate source files (.c/.cpp or .h, or whatever). Simply #include them or compile them into your project. It may help to have comments near the #include to identify what/where the tool is and what is generated.

This may not be as handy (or clean) as using a "real" preprocessor, but it would work. Then again, it really depends on your case.

strager
+4  A: 

The idea that you run code, the result of which is then spliced in is called quasiquotation. The code you run is antiquoted.

I know how to solve this problem using Lua. I've used string.gsub with an antiquotation function I wrote myself. I've used shell syntax for the antiquotation. As in the shell the antiquoted code returns a string which is then spliced into the code.

Below prog is the C code with antiquoted text, and antiquote is the antiquotation function. I've used Lua's special string quoting double square brackets to full advantage. In practice you wouldn't do this; you'd put prog in a separate file.

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)

In use, the program looks like this:

: 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");
}
Norman Ramsey
A: 

I'd be interested to see what people come up with. I've tended to do small custom things with preprocessors written in Perl. It's easy to rig up a Makefile that calls the preprocessor. For example, here's a rule to call a program named 'meta' to generate 'file.c' from 'file.c.meta'.

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

I'm doing fun things with 'meta' like generating custom fit C data structures. It's definitely a direction I'd suggest exploring. My hope is to eventually come up with a meta library roughly parallel to C++ templates.

Nathan Kurz
A: 

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.

HUAGHAGUAH
+1  A: 

If you abstract your problem a bit, then you are in fact looking for a templating engine for your code. Just as most websites inserts dynamically generated content in static templates, you want to insert dynamically generated code into your program.

I currently use Jinja2 (Python) for most templating work - I've found it to be very configurable in every way.

Morten Siebuhr