Ever wished, you had C enums as similar powerful as Java enums? cppviz aims in this direction.
For example, write in your C code
#include "cppviz.h"
#define PLANET_DATA(_,__,___, T, A, E) \
T(_,__,___, int , char * , int ) \
A(_,__,___, id , name , radius ) \
/*----------------------------------------------*/ \
E(_,__,___, MERCURY , "Mercury" , 2439 ) \
E(_,__,___, VENUS , "Venus" , 6051 ) \
E(_,__,___, EARTH , "Earth" , 6378 )
ENUM(PLANET);
Then the ENUM macro at the end lets the preprocessor create the following source
typedef enum _e_PLANET {
PLANET_MERCURY,
PLANET_VENUS,
PLANET_EARTH,
} PLANET;
How many planets are there in the enum? Find out with
COUNT(PLANET);
which gives
(0 + 1 + 1 + 1);
which is ... ehm ... kind of right :-) Well, if you can count it, you can iterate through it!
FOREACH(PLANET, planet) {
printf("%d\n", (int) planet);
}
From this, the preprocessor will create
for (PLANET planet = (PLANET) 0; planet < (0 + 1 + 1 + 1); planet = (PLANET) (((int) planet) + 1)) {
printf("%d\n", (int) planet);
}
printing each planets ordinal. Nice, but nicer would be to have the attributes of each planet at hand, right?
To grab display name and radius, just add
ATTRIBUTE(PLANET, 2); /* for the "name" attribute */
ATTRIBUTE(PLANET, 3); /* for the "radius" attribute */
resulting in two arrays
char * PLANET_name[] = {
"Mercury",
"Venus",
"Earth",
};
int PLANET_radius[] = {
2439,
6051,
6378,
};
Want to have the ENUM NAMES of each of the planets, too? Get them with
NAMES(PLANET);
and this will create the array
const char * PLANET_element_name[] = {
"MERCURY",
"VENUS",
"EARTH",
};
Finally, you can apply a planet-specific landing procedure with
SWITCH(PLANET, planet, landing_procedure(x, y));
which will turn into
switch (planet) {
case PLANET_MERCURY:
PLANET_MERCURY_landing_procedure(x, y);
break;
case PLANET_VENUS:
PLANET_VENUS_landing_procedure(x, y);
break;
case PLANET_EARTH:
PLANET_EARTH_landing_procedure(x, y);
break;
default:
break;
};
Well, the specific landing functions/macros you will have to write for yourself :-)
Finally, a translation for a complete example. First, the source code
/* Include the magick. */
#include "cppviz.h"
/* and some other stuff */
#include <stdio.h>
/*
Create the data table for planets. The table name has to end
with "_DATA", everything before "_DATA" will be the main name,
here "PLANET". Sorry for the crude underscore parameters ...
*/
#define PLANET_DATA(_,__,___, T, A, E) \
T(_,__,___, int , char * , int ) \
A(_,__,___, id , name , radius ) \
/*----------------------------------------------*/ \
E(_,__,___, MERCURY , "Mercury" , 2439 ) \
E(_,__,___, VENUS , "Venus" , 6051 ) \
E(_,__,___, EARTH , "Earth" , 6378 )
/* Now, create the enum, simple as that! */
ENUM(PLANET);
/* We want to access the planets attributes, name and radius. Simple as that! */
ATTRIBUTE(PLANET, 2);
ATTRIBUTE(PLANET, 3);
/* We also want the enum ELEMENT NAMES of all planets, simple as that! */
NAMES(PLANET);
/* The landing procedures, one for each planet. Your job to fill them ... */
void PLANET_MERCURY_landing_procedure(int x, int y) { /* ... */ }
void PLANET_VENUS_landing_procedure(int x, int y) { /* ... */ }
void PLANET_EARTH_landing_procedure(int x, int y) { /* ... */ }
/* Let the spaceship roll! */
int main() {
/* Some totally relevant x, y coordinates. */
int x, y;
/* Print stuff for each planet, simple as that! */
FOREACH(PLANET, planet) {
printf("%s %s %d\n", PLANET_element_name[planet], PLANET_name[planet], PLANET_radius[planet]);
}
/* Perform the planet specific landing procedure. */
/* Yes, simple as that! */
PLANET planet;
/* ... */
SWITCH(PLANET, planet, landing_procedure(x, y));
}
and the result is
typedef enum _e_PLANET { PLANET_MERCURY, PLANET_VENUS, PLANET_EARTH, } PLANET;
char * PLANET_name[] = { "Mercury", "Venus", "Earth", };
int PLANET_radius[] = { 2439, 6051, 6378, };
const char * PLANET_element_name[] = { "MERCURY", "VENUS", "EARTH", };
void PLANET_MERCURY_landing_procedure(int x, int y) { }
void PLANET_VENUS_landing_procedure(int x, int y) { }
void PLANET_EARTH_landing_procedure(int x, int y) { }
int main() {
int x, y;
for (PLANET planet = (PLANET) 0; (int) planet < (0 + 1 + 1 + 1); planet = (PLANET) (((int) planet) + 1)) {
printf("%s %s %d\n", PLANET_element_name[planet], PLANET_name[planet], PLANET_radius[planet]);
}
PLANET planet;
switch (planet) {
case PLANET_MERCURY:
PLANET_MERCURY_landing_procedure(x, y);
break;
case PLANET_VENUS:
PLANET_VENUS_landing_procedure(x, y);
break;
case PLANET_EARTH:
PLANET_EARTH_landing_procedure(x, y);
break;
default:
break;
};
}
You guessed it, some conventions are called for.
Thats about it, have fun!
Georg
GCC-tested!