Another tricky c++ preprocessor question

I want to set up a macro which #defines identifiers to sequentially higher integers.

For instance:

COUNTINGMACRO(DEAD_STATE)
COUNTINGMACRO(ALIVE_STATE)
COUNTINGMACRO(HAPPY_STATE)
COUNTINGMACRO(SAD_STATE)

will have the same result as
#define DEAD_STATE 0
#define ALIVE_STATE 1
#define HAPPY_STATE 2
#define SAD_STATE 3

(And yes, I would normally use an enum, but this is a special case.)

Thoughts? Is this even possible?

thanks

Oh, and if it helps, I have control over how the preprocessor is called, since this is actually being used for a scripting language. So I could, potentially, call the preprocessor multiple times if that would help.

(I think I have a solution that would work if I ran the preprocessor twice and could figure out how to make a macro resolve with line feeds in it.)

No can do. You can’t invoke macros inside another macro.

…of course, you don’t necessarily want to have a #define in there, you just want the same effect. I don’t know if you can get the preprocessor to run twice, but mutli-line macros are easy.


#define FOO( a, b ) \
	{ \
		foo(a); \
		foo(b); \
	}


You don’t necessarily need to enclose the whole thing in brackets, but it’s a good practice. Otherwise, you may start finding really weird errors.

Just out of curiosity, why can’t you use an enum?

Your macro will resolve to { foo(a); foo(b); } all on one line. the \ means “treat what’s on the next line as if it’s on this line”.
I can’t use an enum because enums are not part of the preprocessor, they’re part of the actual compiler. And I’m just using the preprocessor to provide macro support for a scripting language, which has its own syntax and compiler. I can add support for this feature directly into the scripting language, but that’s hard, whereas getting the preprocessor to do it for me should be easy.

The fact that I can run the preprocessor twice if I need to gets me partially around that.

Here’s what I tried first:



#define NEXT_COUNTER 0

 #define TEST_COUNTER(foo) \
#define foo NEXT_COUNTER \
#undef NEXT_COUNTER \
#define NEXT_COUNTER foo + 1


If I run this through the preprocessor twice, it ALMOST works. Except that instead of resolving to



#define foo NEXT_COUNTER
#undef NEXT_COUNTER
#define NEXCOUNTER foo + 1


it resolves to



#define foo NEXT_COUNTER #undef NEXT_COUNTER #define NEXCOUNTER foo + 1


I think you’re pretty much stuck if you want to use the standard preprocessor. You can always try writing your own…

There might also be something you can do with templates to get the effect you want, but I’m not 100% sure on that.

You know, the template approach might have some merit. I need to think about it some more cause the syntax gets ugly as sin. Take a look at Wikipedia’s article on template metaprogramming and see if you’re inspired to do something.

Since C++ is AFAIK backwards compatible with ANSI (or K&R for that matter), how about using enum instead?


#include <stdlib.h>
#include <stdio.h>

enum {DEAD_STATE,
      ALIVE_STATE,
      HAPPY_STATE,
      SAD_STATE};

void main(void)
{
  printf("DEAD is %d
"
         "ALIVE is %d
"
         "HAPPY is %d
"
         "SAD is %d
",
         DEAD_STATE,
         ALIVE_STATE,
         HAPPY_STATE,
         SAD_STATE);
}

This yields the output:

And for your obfuscation pleasure, you can do it with a macro, just with the enum hidden behind the scenes:


#include <stdlib.h>
#include <stdio.h>

#define TABSTART enum{
#define TABEND ENDTAB};
#define PSEUDOCOUNTINGMACRO(v) v,

TABSTART
PSEUDOCOUNTINGMACRO(DEAD_STATE)
PSEUDOCOUNTINGMACRO(ALIVE_STATE)
PSEUDOCOUNTINGMACRO(HAPPY_STATE)
PSEUDOCOUNTINGMACRO(SAD_STATE)
TABEND

void main(void)
{
  printf("DEAD is %d
"
         "ALIVE is %d
"
         "HAPPY is %d
"
         "SAD is %d
",
         DEAD_STATE,
         ALIVE_STATE,
         HAPPY_STATE,
         SAD_STATE);
}

Sadly, that won’t work for two reasons:
(1) I’m not actually compiling C or C++ code, I’m just using the preprocessor. And enums are a feature of the language, not the preprocessor.

(2) More importantly, these macros need to be scattered throughout other things, not all sequential, ie:



COUNTINGMACRO(DEAD)
deadStateThing1
deadStateThing2

COUNTINGMACRO(ALIVE)
happyFunAliveThing(blah blah blah)

COUNTINGMACRO(HAPPY)


etc.

What exactly are you trying to do with this, anyway? There may be a more appropriate solution out there.

As I said, I’ve written a scripting language for the game I’m working on, which is basically fully written and working. However, I’ve just gotten a request to add a new features which allow all the parts of a side mission to be encapsulated together.

Syntactically, I’d like the designers (who use the language) to do something like this:



BEGIN_SIDE_MISSION(happyMission)

SIDE_MISSION_STATE(TALK_TO_BOB)
//stuff in here relating to TALK_TO_BOB
SIDE_MISSION_STATE(DRINK_A_SODA)
//stuff in here relating to DRINK_A_SODE
END_SIDE_MISSION


It’s important that TALK_TO_BOB and DRINK_A_SODA be #defined, so that later on, language commands can do thinks like IF GETVAR(happyMission_STATE) == DRINK_A_SODA. It’s also important that they be unique and, ideally, sequential.

The more of this work I can get the preprocessor to do for me, the happier I am. The simpler the syntax is (ie, the side missions states defined as they are used, not initially listed in some different place that can get out of sync), the happier the designers are.

Since you control how the pre-processor is called, why not something like this?


cpp input_file | perl script.pl | cpp > output_file 

The first cpp parses all the #includes and #defines
The perl (or other language) script replaces COUNTINGMACRO(x) with #define x
The second cpp takes care of all the #define x

If you don’t have #includes in your input file, you can simply use


perl script.pl input_file | cpp > output_file 

The perl script can be a simple one-liner run on the command line. e.g if the input_file is


COUNTINGMACRO(DEAD_STATE)
COUNTINGMACRO(ALIVE_STATE)
COUNTINGMACRO(HAPPY_STATE)

int x1 DEAD_STATE;
int x2 ALIVE_STATE;
int x3 HAPPY_STATE;


Then


perl -ne 'if(/COUNTINGMACRO\(([A-Z_]+)\)/) {printf "#define $1 %i
", $counter++} else {print;}' input_file 


results in


#define DEAD_STATE 0
#define ALIVE_STATE 1
#define HAPPY_STATE 2

int x1 DEAD_STATE;
int x2 ALIVE_STATE;
int x3 HAPPY_STATE;



and the following


perl -ne 'if(/COUNTINGMACRO\(([A-Z_]+)\)/) {printf "#define $1 %i
", $counter++} else {print;}' input_file | cpp > output_file


results in



int x1 0 ;
int x2 1 ;
int x3 2 ;


That’s actually almost precisely the approach I think I’m going to have to take… 3 passes. Once through the preprocessor to handle #include files and simple #defines, once through a custom-written preprocessor to expand “special” macros, and then again through the preprocessor to process any #defines generated by the special macros.

Of course, I don’t know Perl, so will have to just write the middle step preprocessor in C++ or something

What about this?


#define SIDE_MISSION_STATE(x) static int x

The values of the various states wouldn’t necessarily be unique (in fact, they’d all be 0), but their addresses would be unique. They may or may not be sequential depending on your compiler.

You can use the one-liner I showed above, replacing COUNTINGMACRO with whatever macro name you want to use.

Writing this in C++ would be a nightmare, I think.

Actually, if you’re really hung up on using the values, you can try this:


#define SIDE_MISSION_STATE(x) const static int x = (int) &x;

Again, that’s a C++ thing, not a C++ preprocessor thing.

There might be something similar and tricky that could be done with the LINE macro, but it wouldn’t end up generating things that were sequential.

I don’t understand the distinction you’re making. Why won’t that work?

If the statics are all in the same file and no variables are declared in between, your compiler will probably line them up sequentially. I’m 95% sure of that, but of course you’d want to check. In that case, they’d differ by sizeof(int) rather than 1, but you can correct for that easily.

Because the preprocessor won’t touch any of that at all. It will just leave it unchanged. The only things the preprocessor does (in general) are:
-remove comments
-expand macros
-include files

My scripting language uses the preprocessor because all three of those things are generally useful for any language. But once the preprocessor has run, my compiler takes over, and C++ is out the window.