Date: Wed, 14 Dec 2005 01:05:45 +0100 From: Hans Petter Selasky <hselasky@c2i.net> To: John Baldwin <jhb@freebsd.org> Cc: freebsd-hackers@freebsd.org Subject: Re: Standard C-macro scripting Message-ID: <200512140105.46945.hselasky@c2i.net> In-Reply-To: <200512131448.22599.jhb@freebsd.org> References: <200512131936.11640.hselasky@c2i.net> <200512131448.22599.jhb@freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200512140105.46945.hselasky>