how to do two-stage preprocessing of one file

A

andreyvul

What I'm trying to do is have the preprocessor parse one file twice.
The file has three parts, and each is dependent on the previous.
Example (file name is foo.c):
#ifndef ONCE /* first part */
#define D #define
#define ONCE
#include "foo.c"
#endif
#ifdef ONCE /* second part */
D x int
#ifndef TWICE
#define TWICE
#include "foo.c"
#endif
#endif
#ifdef TWICE /* third part */
x y;
#endif

The problem is that the preprocessor just adds the third part to the
second part, but doesn't preprocess the third part in the process.
How do I make my #includes and #ifedefs so that the third part will be
preprocessed?
 
W

Walter Roberson

What I'm trying to do is have the preprocessor parse one file twice.

You cannot do that using the facilities defined by the C preprocessor.

Your particular implementation -probably- offers a way to
preprocess files. For example, on the system I am using at the
moment, the sequence would look something like,

cc -P myfile.c
mv myfile.i myfile_preprocessed.c
cc -o outputfile myfile_preprocessed.c

But it would also not be uncommon on a Unix system for the sequence
to look something closer to

cc -E myfile.c | egrep -v '^#line' > myfile_preprocessed.c
cc -o outfile myfile_preprocessed.c

Many unix C compilers offer some option as in the second example,
to preprocess and send the result to standard output; it may
or may not be necessary in your toolchain to remove #line directives
from the preprocessed output before you can push the file back
through the C parseer.

If you are using one of the Windows compilers... there is probably
some similar option, but probably not named -P or -E .
 
A

andreyvul

You cannot do that using the facilities defined by the C preprocessor.
Oh, I meant _recursively_ preprocess the file twice.
That's why I was asking about proper #include/#ifdef structure, so
that it preprocesses like this:

#block 1
|->#block 2 (via recursive include)
|->#block 3 (via recursive include)

however, it doesn't get to |->#block 3
 
A

Ark Khasin

andreyvul said:
Oh, I meant _recursively_ preprocess the file twice.
That's why I was asking about proper #include/#ifdef structure, so
that it preprocesses like this:

#block 1
|->#block 2 (via recursive include)
|->#block 3 (via recursive include)

however, it doesn't get to |->#block 3
I didn't try it but something along these lines might do it:

#ifndef REC_COUNT
#define REC_COUNT 2
#elif REC_COUNT == 2
#undef REC_COUNT
#define REC_COUNT 1
#elif REC_COUNT == 1
#undef REC_COUNT
#define REC_COUNT 0
#endif
/* Here is the meat */
#if REC_COUNT == 2
/* first iteration */
#elif REC_COUNT == 1
/* second iteration */
#else
/* third and last iteration */
#if REC_COUNT != 0
#include __FILE__
#endif
 
W

Walter Roberson

Oh, I meant _recursively_ preprocess the file twice.

Oh, in that case, let me correct my statement:

The facilities of the C preprocessor are defined in such a way that
you are not guaranteed to be able to do this; if you were able to
get it to work at all, it would be due to implementation-dependant
behaviour.
 
A

andreyvul

andreyvul said:
I didn't try it but something along these lines might do it:

#ifndef REC_COUNT
#define REC_COUNT 2
#elif REC_COUNT == 2
#undef REC_COUNT
#define REC_COUNT 1
#elif REC_COUNT == 1
#undef REC_COUNT
#define REC_COUNT 0
#endif
/* Here is the meat */
#if REC_COUNT == 2
/* first iteration */
#elif REC_COUNT == 1
/* second iteration */
#else
/* third and last iteration */
#if REC_COUNT != 0
#include __FILE__
#endif

Nope, doesn't work.

Great, I have now figured out it is impossible to recursively
preprocess more than one level. Is this supposed to happen per ANSI
specs, or should I go to the cpp newsgroup?
 
A

andreyvul

And I got it to work now:
cc foo.c -E | sed -re '/#[^di]/D' -e /^$/D' | head -7 | cc -x c - -o
foo
Kind of impossible on windows without GnuWin32, msys, or cygwin.
 
A

Ark Khasin

andreyvul said:
Nope, doesn't work.

Great, I have now figured out it is impossible to recursively
preprocess more than one level. Is this supposed to happen per ANSI
specs, or should I go to the cpp newsgroup?
You didn't try hard enough :). The text I posted was not #balanced.
Here's a working example:
------------- iter.c -------------
#include <stdio.h>
int main()
{
#include "iter.h"
return 0;
}
------------- iter.h -------------
#ifndef REC_COUNT
# define REC_COUNT 2
/* first iteration */
puts("first iteration");
#elif REC_COUNT == 2
# undef REC_COUNT
# define REC_COUNT 1
/* second iteration */
puts("second iteration");
#elif REC_COUNT == 1
# undef REC_COUNT
# define REC_COUNT 0
/* third and last iteration */
puts("third and last iteration");
#endif
#if REC_COUNT != 0
# include __FILE__
#endif
------------ output --------------------
first iteration
second iteration
third and last iteration

.... which also disproves a claim of a nearby post that it's impossible.
In fact, you can do recursion of any fixed depth this way.
Unless of course I misunderstood what you were trying to achieve.
 
A

andreyvul

You didn't try hard enough :). The text I posted was not #balanced.
Here's a working example:
------------- iter.c -------------
#include <stdio.h>
int main()
{
#include "iter.h"
return 0;}

------------- iter.h -------------
#ifndef REC_COUNT
# define REC_COUNT 2
/* first iteration */
puts("first iteration");
#elif REC_COUNT == 2
# undef REC_COUNT
# define REC_COUNT 1
/* second iteration */
puts("second iteration");
#elif REC_COUNT == 1
# undef REC_COUNT
# define REC_COUNT 0
/* third and last iteration */
puts("third and last iteration");
#endif
#if REC_COUNT != 0
# include __FILE__
#endif
------------ output --------------------
first iteration
second iteration
third and last iteration

... which also disproves a claim of a nearby post that it's impossible.
In fact, you can do recursion of any fixed depth this way.
Unless of course I misunderstood what you were trying to achieve.

What if you had a macro in the third iteration that was to be expanded
by the previous iterations?
 
A

andreyvul

You didn't try hard enough :). The text I posted was not #balanced.
Here's a working example:
------------- iter.c -------------
#include <stdio.h>
int main()
{
#include "iter.h"
return 0;}

------------- iter.h -------------
#ifndef REC_COUNT
# define REC_COUNT 2
/* first iteration */
puts("first iteration");
#elif REC_COUNT == 2
# undef REC_COUNT
# define REC_COUNT 1
/* second iteration */
puts("second iteration");
#elif REC_COUNT == 1
# undef REC_COUNT
# define REC_COUNT 0
/* third and last iteration */
puts("third and last iteration");
#endif
#if REC_COUNT != 0
# include __FILE__
#endif
------------ output --------------------
first iteration
second iteration
third and last iteration

... which also disproves a claim of a nearby post that it's impossible.
In fact, you can do recursion of any fixed depth this way.
Unless of course I misunderstood what you were trying to achieve.

What if you have a macro in the third iteration that needs expanding
in the second iteration, which needs expanding in the first iteration?
*That* was what I was trying to do.
 
A

andreyvul

Here's an example of what I mean:
#ifndef REC
#define REC 2
#define d #define
#define i include
#elif REC == 2
#undef REC
#define REC 1
i <stdio.h>
d p(a) puts(a)
d q(a) int a
d Q main
d r(a) char**a
#elif REC == 1
#undef REC
#define REC 0
q(Q)(q(c), r(v)){p("Hello, World!\n");return 0;}
#endif
#if REC != 0
#include __FILE__
#endif

Should produce:
[stdio.h]
int main(int c, char**v){puts("Hello, World!\n"); return 0;}
 
A

Ark Khasin

andreyvul said:
Here's an example of what I mean:
#ifndef REC
#define REC 2
#define d #define
#define i include
#elif REC == 2
#undef REC
#define REC 1
i <stdio.h>
d p(a) puts(a)
d q(a) int a
d Q main
d r(a) char**a
#elif REC == 1
#undef REC
#define REC 0
q(Q)(q(c), r(v)){p("Hello, World!\n");return 0;}
#endif
#if REC != 0
#include __FILE__
#endif

Should produce:
[stdio.h]
int main(int c, char**v){puts("Hello, World!\n"); return 0;}
THAT you should not even attempt to do. It's a tad late to find quotes
from the standard, but basically:
- # in a context of macro definition means STRINGIZE when applied to a
macro argument; I doubt other uses are meaningful or valid
- you cannot (re)define preprocessor directives
So it is not valid C.

This is what you are doing:
- You deliberately take a bad (i.e. invalid) C-like source,
- You massage it to automatically produce a valid C source and run with it.
If that's what you want, you can use an arbitrary pair of source
language style and a corresponding preprocessor utility; that has
nothing to do with C.

YOU CAN, however, process your file in every which way you like, as you
demonstrated in this thread. Attempting to coerce a C compiler to do
preprocessing is not a terribly good idea. I'd suggest to use a
standalone PP that gives you some guarantees of what it outputs. (Google
them C preprocessors.) Or use a specific compiler you know suits your needs.
Keep in mind that:
- the compiler is under no obligation to produce preprocessor output.
- if the compiler does produce PP output, it may turn bad source into a
perfectly good source; I used to have a vivid example of that around
#define SLASH /
something /SLASH alleged comment
but I lost it. Basically, PP found a token /, then a token SLASH which
it expanded to / and output //. It compiles as start of comment (a
single token //) but in the original source they were, effectively, two
/ tokens. One might argue that PP should have produced / / but then
again, the compiler owes me nothing in that department.

If my hunch is correct and all you are trying to do is to obfuscate your
code, there are better ways of doing so.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top