From 1298f5bd10d751fc34a934077f48a8e363aa5e91 Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Wed, 28 Sep 2011 00:25:38 +0200 Subject: digital/avr/common/preproc: add preprocessor loops --- digital/avr/common/preproc.h | 146 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 144 insertions(+), 2 deletions(-) (limited to 'digital/avr/common/preproc.h') diff --git a/digital/avr/common/preproc.h b/digital/avr/common/preproc.h index a1cebe93..4ed18fc8 100644 --- a/digital/avr/common/preproc.h +++ b/digital/avr/common/preproc.h @@ -29,6 +29,17 @@ * * To run tests, give it to cpp -DPREPROC_TEST. */ + +#ifdef PREPROC_TEST +#define empty_list +#define empty_list_comma +#define one_item_list a +#define one_item_list_comma ,a +#define two_items_list a, b +#define two_items_list_comma ,a ,b +#define ten_items_list a, b, c, d, e, f, g, h, i, j +#endif + /** Count the number of macro arguments. */ #define PREPROC_NARG(args...) \ PREPROC_NARG_ (dummy, ## args) @@ -53,15 +64,15 @@ N, ...) N #ifdef PREPROC_TEST -#define a 1, 2, 3, 4 NARG: 0: PREPROC_NARG () 1: PREPROC_NARG (1) 2: PREPROC_NARG (1, 2) 3: PREPROC_NARG (1, 2, 3) - 4: PREPROC_NARG (a) + 10: PREPROC_NARG (ten_items_list) 63: PREPROC_NARG (,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, \ ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,) +#undef a #endif /** Paste arguments together. Macro arguments are completely macro-expanded @@ -114,4 +125,135 @@ NARG_CALL: three which are 11, 22 and 33: PREPROC_NARG_CALL (macro_, 11, 22, 33) #endif +/** Reverse a list (maximum of 10 elements). + * For example, PREPROC_LIST_REVERSE(a, b, c) will expand to c, b, a. */ +#define PREPROC_LIST_REVERSE(args...) \ + PREPROC_NARG_CALL (PREPROC_LIST_REVERSE_, ## args) +#define PREPROC_LIST_REVERSE_0() +#define PREPROC_LIST_REVERSE_1(arg) arg +#define PREPROC_LIST_REVERSE_2(arg, args...) \ + PREPROC_LIST_REVERSE_1(args), arg +/* Boring details... {{{ */ +#define PREPROC_LIST_REVERSE_3(arg, args...) \ + PREPROC_LIST_REVERSE_2(args), arg +#define PREPROC_LIST_REVERSE_4(arg, args...) \ + PREPROC_LIST_REVERSE_3(args), arg +#define PREPROC_LIST_REVERSE_5(arg, args...) \ + PREPROC_LIST_REVERSE_4(args), arg +#define PREPROC_LIST_REVERSE_6(arg, args...) \ + PREPROC_LIST_REVERSE_5(args), arg +#define PREPROC_LIST_REVERSE_7(arg, args...) \ + PREPROC_LIST_REVERSE_6(args), arg +#define PREPROC_LIST_REVERSE_8(arg, args...) \ + PREPROC_LIST_REVERSE_7(args), arg +#define PREPROC_LIST_REVERSE_9(arg, args...) \ + PREPROC_LIST_REVERSE_8(args), arg +#define PREPROC_LIST_REVERSE_10(arg, args...) \ + PREPROC_LIST_REVERSE_9(args), arg +/* }}} */ + +#ifdef PREPROC_TEST +PREPROC_LIST_REVERSE: + : PREPROC_LIST_REVERSE (empty_list) + a: PREPROC_LIST_REVERSE (one_item_list) + b, a: PREPROC_LIST_REVERSE (two_items_list) + j, i, h, g, f, e, d, c, b, a: PREPROC_LIST_REVERSE (ten_items_list) +#endif + +/** Call a macro for every argument (maximum of 10). + * For example, PREPROC_FOR(macro, a, b, c) will expand to macro(a) macro(b) + * macro(c). */ +/* First step needed to expand macro which can contain commas. */ +#define PREPROC_FOR(macro, args...) \ + PREPROC_FOR_ (macro, ## args) +#define PREPROC_FOR_(macro, args...) \ + PREPROC_PASTE (PREPROC_FOR_, PREPROC_NARG (args)) (macro, args) +#define PREPROC_FOR_0(macro, dummy_arg) +#define PREPROC_FOR_1(macro, arg) macro (arg) +#define PREPROC_FOR_2(macro, arg, args...) \ + macro (arg) PREPROC_FOR_1 (macro, args) +/* Boring details... {{{ */ +#define PREPROC_FOR_3(macro, arg, args...) \ + macro (arg) PREPROC_FOR_2 (macro, args) +#define PREPROC_FOR_4(macro, arg, args...) \ + macro (arg) PREPROC_FOR_3 (macro, args) +#define PREPROC_FOR_5(macro, arg, args...) \ + macro (arg) PREPROC_FOR_4 (macro, args) +#define PREPROC_FOR_6(macro, arg, args...) \ + macro (arg) PREPROC_FOR_5 (macro, args) +#define PREPROC_FOR_7(macro, arg, args...) \ + macro (arg) PREPROC_FOR_6 (macro, args) +#define PREPROC_FOR_8(macro, arg, args...) \ + macro (arg) PREPROC_FOR_7 (macro, args) +#define PREPROC_FOR_9(macro, arg, args...) \ + macro (arg) PREPROC_FOR_8 (macro, args) +#define PREPROC_FOR_10(macro, arg, args...) \ + macro (arg) PREPROC_FOR_9 (macro, args) +/* }}} */ + +#ifdef PREPROC_TEST +#define macro(arg) +PREPROC_FOR: + : PREPROC_FOR (macro) + : PREPROC_FOR (macro, empty_list) + : PREPROC_FOR (macro, one_item_list) + : PREPROC_FOR (macro, two_items_list) + : PREPROC_FOR (macro, ten_items_list) +If first comma is included in the list: + : PREPROC_FOR (macro empty_list_comma) + : PREPROC_FOR (macro one_item_list_comma) + : PREPROC_FOR (macro two_items_list_comma) +#undef macro +#endif + +/** Call a macro for every arguments (maximum of 10) with an argument index. + * For example, PREPROC_FOR_ENUM(macro, a, b, c) will expand to macro(0, a) + * macro(1, b) macro(2, c). */ +/* First step needed to expand macro which can contain commas. */ +#define PREPROC_FOR_ENUM(macro, args...) \ + PREPROC_FOR_ENUM_ (macro, ## args) +/* Second step needed to expand args. */ +#define PREPROC_FOR_ENUM_(macro, args...) \ + PREPROC_FOR_ENUM__ (macro, PREPROC_NARG (args), PREPROC_LIST_REVERSE (args)) +#define PREPROC_FOR_ENUM__(macro, nargs, args...) \ + PREPROC_PASTE (PREPROC_FOR_ENUM_, nargs) (macro, args) +#define PREPROC_FOR_ENUM_0(macro, dummy_arg) +#define PREPROC_FOR_ENUM_1(macro, arg) macro (0, arg) +#define PREPROC_FOR_ENUM_2(macro, arg, args...) \ + PREPROC_FOR_ENUM_1 (macro, args) macro (1, arg) +/* Boring details... {{{ */ +#define PREPROC_FOR_ENUM_3(macro, arg, args...) \ + PREPROC_FOR_ENUM_2 (macro, args) macro (2, arg) +#define PREPROC_FOR_ENUM_4(macro, arg, args...) \ + PREPROC_FOR_ENUM_3 (macro, args) macro (3, arg) +#define PREPROC_FOR_ENUM_5(macro, arg, args...) \ + PREPROC_FOR_ENUM_4 (macro, args) macro (4, arg) +#define PREPROC_FOR_ENUM_6(macro, arg, args...) \ + PREPROC_FOR_ENUM_5 (macro, args) macro (5, arg) +#define PREPROC_FOR_ENUM_7(macro, arg, args...) \ + PREPROC_FOR_ENUM_6 (macro, args) macro (6, arg) +#define PREPROC_FOR_ENUM_8(macro, arg, args...) \ + PREPROC_FOR_ENUM_7 (macro, args) macro (7, arg) +#define PREPROC_FOR_ENUM_9(macro, arg, args...) \ + PREPROC_FOR_ENUM_8 (macro, args) macro (8, arg) +#define PREPROC_FOR_ENUM_10(macro, arg, args...) \ + PREPROC_FOR_ENUM_9 (macro, args) macro (9, arg) +/* }}} */ + +#ifdef PREPROC_TEST +#define macro(index, arg) +PREPROC_FOR_ENUM: + : PREPROC_FOR_ENUM (macro) + : PREPROC_FOR_ENUM (macro, empty_list) + <0, a>: PREPROC_FOR_ENUM (macro, one_item_list) + <0, a> <1, b>: PREPROC_FOR_ENUM (macro, two_items_list) + <0, a> <1, b> <2, c> <3, d> <4, e> <5, f> <6, g> <7, h> <8, i> <9, j>: + PREPROC_FOR_ENUM (macro, ten_items_list) +If first comma is included in the list: + : PREPROC_FOR_ENUM (macro empty_list_comma) + <0, a>: PREPROC_FOR_ENUM (macro one_item_list_comma) + <0, a> <1, b>: PREPROC_FOR_ENUM (macro two_items_list_comma) +#undef macro +#endif + #endif /* preproc_h */ -- cgit v1.2.3