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.)
…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.
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.
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.
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:
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.
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;
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
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.
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.