Standard C-macro scripting
Hans Petter Selasky
hselasky at c2i.net
Tue Dec 13 16:04:39 PST 2005
On Tuesday 13 December 2005 20:48, John Baldwin wrote:
> On Tuesday 13 December 2005 01:36 pm, Hans Petter Selasky wrote:
> > Hi,
> >
> > ...
> >
> > What do you think about using C-macros like a scripting language?
>
> Honestly, I think I've now been scarred for life. :-/ I think that this
> stuff would be so obscure that no one else would be able to help with
> maintenace.
Macros are easy. It is just concat, stringify and expand. Maybe you have to
think more about it before you get it. I am probably too used to it.
What is the alternative? An Awk script would require a lot more code and it
cannot be called from a C-program when it is compiling.
Consider the following: One has some "enums" and wants to declare these and
make a debugging table at the same time. The problem is that at some time one
adds another "enum" and then the debugging table is out of sync. Using an
Awk/Perl/XXX script to keep things in sync would be overkill.
If one makes some standard macros that do standard transforms, then people
will not get confused. I have started out to standardise this, for example
one macro to make enums, MAKE_ENUM, and another to make tables of different
kinds, MAKE_TABLE. There might be room for improvement.
#define _MAKE_ENUM(enum,value,arg...) \
enum value, \
/**/
#define MAKE_ENUM(macro,end...) \
enum { macro(_MAKE_ENUM) end } \
/**/
#define __MAKE_TABLE(a...) a /* double pass to expand all macros */
#define _MAKE_TABLE(a...) (a), /* add comma */
#define MAKE_TABLE(m,field,p,a...) m##_##field p = \
{ __MAKE_TABLE(m(m##_##field _MAKE_TABLE)) a }
What the macros above do, is not difficult to understand at all. It is bare
simple.
Here is the definition of some enum series:
#define MY_ENUMS_DEFAULT_DRIVER_DESC(enum,val,desc) desc
#define MY_ENUMS(m)\
m(MY_ENUM_UNKNOWN ,,"unknown")\
m(MY_ENUM_YYY ,,"yyy ...")\
m(MY_ENUM_DAIC ,,"zzz ...")\
/**/
Here is the declaration:
MAKE_ENUM(MY_ENUMS,
N_MY_ENUMS);
Here is the debugging table:
static const char * const
MAKE_TABLE(MY_ENUMS,DEFAULT_DRIVER_DESC,[]);
Because the "MAKE_ENUM" macro only use the two first arguments passed to "m"
in "MY_ENUMS", the other arguments can be used for other purpose, and one can
list more information:
Here is a real example of a state machine:
#define L3_STATES(m)/* \
m(----------------,,--------,-------------,-------------------------,------)*\
m( ,,timeout , timeout , , q931 )*\
m( state ,,delay , state , desc , conv.)*\
m(----------------,,--------,-------------,-------------------------,------)*/
\
m( ST_L3_U0 ,, 0/*hz*/, ST_L3_U0 , "Null" , 0x00 )\
\
m( ST_L3_OUTGOING ,, 8/*hz*/, ST_L3_U0 , "Outgoing initialized" , 0x00 )\
m( ST_L3_U1 ,, 8/*hz*/, ST_L3_U0 , "Outgoing setup (U1)" , 0x01 )\
m( ST_L3_U2 ,,16/*hz*/, ST_L3_U0 , "Outgoing setup (U2)" , 0x02 )\
m( ST_L3_U2_ACK ,,16/*hz*/, ST_L3_U0 , "Outgoing setup (U2)" , 0x02 )\
m( ST_L3_U3 ,, 8/*hz*/, ST_L3_U3_TO , "Outgoing proceeding" , 0x03 )\
m( ST_L3_U3_TO ,, 4/*hz*/, ST_L3_U0 , "Outgoing proceeding" , 0x03 )\
\
m( ST_L3_U4 ,, 8/*hz*/, ST_L3_U4_TO , "Outgoing delivered" , 0x04 )\
m( ST_L3_U4_TO ,, 4/*hz*/, ST_L3_U0 , "Outgoing delivered" , 0x04 )\
\
m( ST_L3_INCOMING ,, 8/*hz*/, ST_L3_U0 , "Incoming initialized" , 0x00 )\
m( ST_L3_IN_ACK ,,16/*hz*/, ST_L3_U0 , "Incoming initialized" , 0x19 )\
m( ST_L3_U6 ,, 8/*hz*/, ST_L3_U0 , "Incoming present" , 0x06 )\
m( ST_L3_U7 ,, 8/*hz*/, ST_L3_U7_TO , "Incoming alerted" , 0x07 )\
m( ST_L3_U7_TO ,, 4/*hz*/, ST_L3_U0 , "Incoming alerted" , 0x07 )\
m( ST_L3_U8 ,, 4/*hz*/, ST_L3_U0 , "Incoming connecting" , 0x08 )\
\
m( ST_L3_UA ,, 8/*hz*/, ST_L3_UA_TO , "Active" , 0x0A )\
m( ST_L3_UA_TO ,, 4/*hz*/, ST_L3_U0 , "Active" , 0x0A )\
\
m( ST_L3_UC ,, 8/*hz*/, ST_L3_UC_TO , "Disconnected" , 0x0C )\
m( ST_L3_UC_TO ,, 4/*hz*/, ST_L3_U0 , "Disconnected" , 0x0C )\
/**/
Isn't the state-machine above easy to edit and understand ?
What is wrong about that?
And how would you solve it?
--HPS
More information about the freebsd-hackers
mailing list