tags:

views:

808

answers:

12

The Wikipedia entry for the C Preprocessor states:

The language of preprocessor directives is agnostic to the grammar of C, so the C preprocessor can also be used independently to process other types of files.

How can this be done? Any examples or techniques?

EDIT: Yes, I'm mostly interested in macro processing. Even though it's probably not advisable or maintainable it would still be useful to know what's possible.

A: 

You could implement the C preprocessor in the compiler for another language.

You could use it to preprocess any sort of text file, but there's much better things for that purpose.

David Thornley
+1  A: 

Usually you can invoke the C compiler with an option to preprocess only (and ignore any #line statements). Take this as a simple example:

<?php
function foo()
{
#ifdef DEBUG
    echo "Some debug info.";
#endif
    echo "Foo!";
}

foo();

We define a PHP source file with preprocess statements. We can then preprocess it (gcc can do this, too):

cl -nologo -EP foo.php > foo2.php

Since DEBUG is not the defined the first echo is stripped. Plus here is that lines beginning with # are comments in PHP so you don't have to preprocess them for a "debug" build.

Edit: Since you asked about macros. This works fine too and could be used to generate boilerplate code etc.

gix
are people really doing this sort of things?
Geo
@Geo, yes they are. Perl has (or used to have) a command-line option to run the perl script through CPP before letting the parser at it, for instance. If all you need is some #ifdef handling to turn blocks of code on and off or #include to share source lines, cpp is actually a pretty good choice of tool.
RBerteig
+1  A: 

Many C compilers have a flag that tells them to only preprocess. With gcc it's the -E flag. eg:

$ gcc -E -                 
#define FOO foo
bar FOO baz

will output:

# 1 "<stdin>"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "<stdin>"

bar foo baz

With other C compilers you'll have to check the manuals to see how to swithc to preprocess-only mode.

Laurence Gonsalves
You might wanna have your example actually do something.
dborba
Heh. Good point. Fixed.
Laurence Gonsalves
A: 

Basically what it's saying is that preprocessors have nothing to do with C syntax. They are basically simple parsers that follow a set of rules. So you could use preprocessors kind of like you'd use sed or awk for some silly tasks. Don't ask me why you'd ever want to do it though.

For example, on a text file:

#define pi 3.141

pi is not an irrational number.

Then you run the preprocessor & you'd get.

3.141 is not an irrational number.

dborba
+2  A: 

For example, Assembler. While many assemblers have their own way to #include headers and #define macros, it can be useful to use the C preprocessor for this. GNU make, for example, has implicit rules for turning *.S files into *.s files by running the preprocessor ('cpp'), before feeding the *.s file to the GNU assembler ('as').

DevSolar
Although depending on the case of a single letter of the file name was a poor design choice there... where I've done the equivalent thing in other projects, I've used .asm or .src for the "real" source code, and the standard .s for the code emitted by cpp. Unfortunately there are many developers (even using Gnu tools) that live on file systems that can't distinguish names by case alone. NTFS defaults to be case preserving, but not case sensitive, for instance.
RBerteig
I didn't say it was a *smart* choice. ;-)
DevSolar
Actually GNU Make doesn't run it through the C preprocessor (at least not directly), it runs it through the C compiler `$(CC)`, this method works on case sensitive file systems as it doesn't require two files similarly named.
Joe D
@Joe D: Wrong on both accounts. The implicit make rule is "to make N.s from N.S", and the call is `$(CPP) $(CPPFLAGS)`. (GNU make manual, Catalogue of Implicit Rules.)
DevSolar
+1  A: 

Using Microsoft's compiler, I think (I just looked it up, haven't tested it) that it's the /P compiler option.

Other compilers presumably have similar options (or, for some compilers the preprocessor might actually be a different executable, which is usually run implicitly by the compiler but which you can also run explicitly separately).

ChrisW
+1  A: 

Assuming you're using GCC, You can take any plain old text file, regardless of its contents, and run:

gcc -E filename

Any preprocessor directives in the file will be processed by the preprocessor and GCC will then exit.

The point is that it doesn't matter what the actual content of the text file is, since all the preprocessor cares about is its own directives.

Jeff L
+1  A: 

Yes, it can be done by parsing your own language through the gcc preprocessor (e.g. 'gcc -E').

We have done this on my job with our our, specific language. It has quite some advantages:

  • You can use C's include statements (#include) which is very powerful
  • You can use your #ifdef constructions
  • You can define Constants (#define MAGIC_NUMBER 42) or macro functions (#define min(x,y) ( (x( < (y) ? (x) : (y))

... and the other things in the c processor.

HOWEVER, you also inherit the unsafe C constructions, and having a preprocessor not integrated with your main language is the cause of it. Think about the minimum macro and doing something like :

a = 2;
b = 3;

c = min(a--, b--);

Just think what value a and b will have after the min function?

Same is true about the non-typed constants that you introduce

See the Safer C book for details.

Roalt
+1  A: 

I have heard of people using the C pre-processor on Ada code. Ada has no preprocessor, so you have to do something like that if you want to preprocess your code.

However, it was a concious design decision not to give it one, so doing this is very un-Ada. I wouldn't suggest anyone do this.

T.E.D.
+1  A: 

A while ago I did some work on a project that used imake for makefile generation. As I recall, it was basically the c preprocessor syntax to generate the make files.

Caleb Huitt - cjhuitt
+9  A: 

You can call CPP directly:

cpp <file>

Rather than calling it through gcc:

gcc -E filename

Have you considered dabbling with a more flexible macro processing language, like m4 for instance?

kjfletch
+1 for the reference to `m4`. This has traditionally been the preprocessor of choice for complex tasks; CPP is very primitive by comparison.
ephemient
You can't really have "fun" with CPP. m4 on the other hand is a minefield of enjoyment; just have to get over the initial hump of pain.
kjfletch
m4 does look interesting, thanks to everyone who's mentioned that.
Just make sure you don't use m4 macros in standard C/C++ code, or the coder coming after you will hate your guts for it. ;-)
DevSolar
A: 

The C preprocessor can also be invoked by the Glasgow Haskell Compiler (GHC) prior to compiling Haskell code, by passing the -cpp flag.

Stephan202