From owner-freebsd-hackers@FreeBSD.ORG Thu Dec 15 09:31:11 2005 Return-Path: X-Original-To: freebsd-hackers@freebsd.org Delivered-To: freebsd-hackers@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 72B3F16A41F; Thu, 15 Dec 2005 09:31:11 +0000 (GMT) (envelope-from PeterJeremy@optushome.com.au) Received: from mail05.syd.optusnet.com.au (mail05.syd.optusnet.com.au [211.29.132.186]) by mx1.FreeBSD.org (Postfix) with ESMTP id 61C9E43D5C; Thu, 15 Dec 2005 09:31:08 +0000 (GMT) (envelope-from PeterJeremy@optushome.com.au) Received: from cirb503493.alcatel.com.au (c220-239-19-236.belrs4.nsw.optusnet.com.au [220.239.19.236]) by mail05.syd.optusnet.com.au (8.12.11/8.12.11) with ESMTP id jBF9V0dv000987 (version=TLSv1/SSLv3 cipher=EDH-RSA-DES-CBC3-SHA bits=168 verify=NO); Thu, 15 Dec 2005 20:31:01 +1100 Received: from cirb503493.alcatel.com.au (localhost.alcatel.com.au [127.0.0.1]) by cirb503493.alcatel.com.au (8.12.10/8.12.10) with ESMTP id jBF9V0Hh081120; Thu, 15 Dec 2005 20:31:00 +1100 (EST) (envelope-from pjeremy@cirb503493.alcatel.com.au) Received: (from pjeremy@localhost) by cirb503493.alcatel.com.au (8.12.10/8.12.9/Submit) id jBF9UxJk081119; Thu, 15 Dec 2005 20:30:59 +1100 (EST) (envelope-from pjeremy) Date: Thu, 15 Dec 2005 20:30:59 +1100 From: Peter Jeremy To: Hans Petter Selasky Message-ID: <20051215093059.GL77268@cirb503493.alcatel.com.au> References: <200512131936.11640.hselasky@c2i.net> <200512131448.22599.jhb@freebsd.org> <200512140105.46945.hselasky@c2i.net> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <200512140105.46945.hselasky@c2i.net> User-Agent: Mutt/1.4.2.1i X-PGP-Key: http://members.optusnet.com.au/peterjeremy/pubkey.asc Cc: freebsd-hackers@freebsd.org Subject: Re: Standard C-macro scripting X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 15 Dec 2005 09:31:11 -0000 On Wed, 2005-Dec-14 01:05:45 +0100, Hans Petter Selasky wrote: >On Tuesday 13 December 2005 20:48, John Baldwin wrote: >> 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. I tend to agree. >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. When you have nested macros and have to work out what is stringified at each level of expansion, it can get very difficult to follow. >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. The approach I use (borrowed from gcc) is multiple includes. To take your enum example: ========== foo.def =================== m(MY_ENUM_UNKNOWN ,,"unknown") m(MY_ENUM_YYY ,,"yyy ...") m(MY_ENUM_DAIC ,,"zzz ...") ========== foo.c ===================== enum MY_ENUM { #define m(a,b,c) a b, #include "foo.def" #undef m }; static const char * const MY_ENUMS_DEFAULT_DRIVER_DESC[] = { #define m(a,b,c) c, #include "foo.def" #undef m }; ========== EOF ====================== Personally, I think this is far easier to understand - a single macro which is redefined to have a number of simple macro expansions rather than seven macros with carefully organised nesting to ensure correct stringification. I agree that this requires re-reading the definition file but it will be cached after the first pass so this isn't particularly expensive. You also have the advantage that the data (foo.def) doesn't have to be a single statement so you can (more easily) embed comments or other preprocessor directives. gcc uses this for various *.def files, redefining macros to suit requirements. As a real (cut-down) example from an interpreter I'm maintaining (in reality optab.h has 146 entries with 5 different opX_XX() macros): =============== optab.h ================== opd_dd(ex_add, ADD, "add",) /* 2 A+B */ opd_d( ex_plus, PLUS, "plus",) /* 3 +B */ opd_dd(ex_sub, SUB, "sub",) /* 4 A-B */ opd_d( ex_minus, MINUS, "minus",) /* 5 -B */ opd_dd(ex_pwr, PWR, "pwr",) /* 16 A*B */ opd_d( ex_exp, EXP, "exp",) /* 17 *B */ opd_dd(ex_comb, COMB, "comb",) /* 22 A!B */ opd_d( ex_fac, FAC, "fac",) /* 23 !B */ #undef opd_d #undef opd_dd =========== opt_codes.h ============ enum OpCode { #define opd_d(a,b,c,d) b, #define opd_dd(a,b,c,d) b, #include "optab.h" OPT_MAX /* largest opt-code */ }; =============== optable.c ============== const pfd_d exop2[] = { #define opd_d(a,b,c,d) a, #define opd_dd(a,b,c,d) ex_botch2, #include "optab.h" }; const pfd_dd exop3[] = { #define opd_d(a,b,c,d) ex_botch3, #define opd_dd(a,b,c,d) a, #include "optab.h" }; const char *opname[] = { #define opd_d(a,b,c,d) c, #define opd_dd(a,b,c,d) c, #include "optab.h" }; =============== main.h ============== #define opd_d(a,b,c,d) data a(data) d; #define opd_dd(a,b,c,d) data a(data, data) d; #include "optab.h" ========== EOF ====================== >Here is a real example of a state machine: > >#define L3_STATES(m)/* \ ... >m( ST_L3_UC_TO ,, 4/*hz*/, ST_L3_U0 , "Disconnected" , 0x0C )\ >/**/ > >Isn't the state-machine above easy to edit and understand ? It looks the same as my definitions file (modulo a backslash on each line and not having it in a separate file). >What is wrong about that? The complexity of the macros you need to expand it. There's also no scope for conditional inclusion (what if you wanted a single state machine description to conditionally compile for several protocol variants). >And how would you solve it? See above. -- Peter Jeremy