aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2022-04-07 22:07:39 -0700
committerKaz Kylheku <kaz@kylheku.com>2022-04-07 22:07:39 -0700
commit768e1ae91c76af878dbbd93833ad49ae98da6260 (patch)
treea697790e2e263837e426a1b9310782358f1c0a3f
parent3c3991533abf3d32606f11016cfaf94aa0a85235 (diff)
downloadcppawk-768e1ae91c76af878dbbd93833ad49ae98da6260.tar.gz
cppawk-768e1ae91c76af878dbbd93833ad49ae98da6260.tar.bz2
cppawk-768e1ae91c76af878dbbd93833ad49ae98da6260.zip
narg: new variexpand macro.
-rw-r--r--cppawk-include/narg-priv.h98
-rw-r--r--cppawk-include/narg.h9
-rw-r--r--cppawk-narg.189
-rw-r--r--testcases-narg13
4 files changed, 199 insertions, 10 deletions
diff --git a/cppawk-include/narg-priv.h b/cppawk-include/narg-priv.h
index 73a00b1..2cacdaf 100644
--- a/cppawk-include/narg-priv.h
+++ b/cppawk-include/narg-priv.h
@@ -152,6 +152,101 @@
a24, a25, a26, a27, a28, a29, a30, a31, a32) \
mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1), a2), a3), a4), a5), a6), a7), a8), a9), a10), a11), a12), a13), a14), a15), a16), a17), a18), a19), a20), a21), a22), a23), a24), a25), a26), a27), a28), a29), a30), a31), a32)
+#define __repi_1(mac1, mac2, a1) \
+ mac1(a1, 1)
+#define __repi_2(mac1, mac2, a1, a2) \
+ mac2(mac1(a1, 1), a2, 2)
+#define __repi_3(mac1, mac2, a1, a2, a3) \
+ mac2(mac2(mac1(a1, 1), a2, 2), a3, 3)
+#define __repi_4(mac1, mac2, a1, a2, a3, a4) \
+ mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4)
+#define __repi_5(mac1, mac2, a1, a2, a3, a4, a5) \
+ mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5)
+#define __repi_6(mac1, mac2, a1, a2, a3, a4, a5, a6) \
+ mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6)
+#define __repi_7(mac1, mac2, a1, a2, a3, a4, a5, a6, a7) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7)
+#define __repi_8(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8)
+#define __repi_9(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8, a9) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8), a9, 9)
+#define __repi_10(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8), a9, 9), a10, 10)
+#define __repi_11(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8), a9, 9), a10, 10), a11, 11)
+#define __repi_12(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
+ a12) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8), a9, 9), a10, 10), a11, 11), a12, 12)
+#define __repi_13(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
+ a12, a13) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8), a9, 9), a10, 10), a11, 11), a12, 12), a13, 13)
+#define __repi_14(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
+ a12, a13, a14) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8), a9, 9), a10, 10), a11, 11), a12, 12), a13, 13), a14, 14)
+#define __repi_15(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
+ a12, a13, a14, a15) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8), a9, 9), a10, 10), a11, 11), a12, 12), a13, 13), a14, 14), a15, 15)
+#define __repi_16(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
+ a12, a13, a14, a15, a16) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8), a9, 9), a10, 10), a11, 11), a12, 12), a13, 13), a14, 14), a15, 15), a16, 16)
+#define __repi_17(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
+ a12, a13, a14, a15, a16, a17) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8), a9, 9), a10, 10), a11, 11), a12, 12), a13, 13), a14, 14), a15, 15), a16, 16), a17, 17)
+#define __repi_18(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
+ a12, a13, a14, a15, a16, a17, a18) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8), a9, 9), a10, 10), a11, 11), a12, 12), a13, 13), a14, 14), a15, 15), a16, 16), a17, 17), a18, 18)
+#define __repi_19(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
+ a12, a13, a14, a15, a16, a17, a18, a19) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8), a9, 9), a10, 10), a11, 11), a12, 12), a13, 13), a14, 14), a15, 15), a16, 16), a17, 17), a18, 18), a19, 19)
+#define __repi_20(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
+ a12, a13, a14, a15, a16, a17, a18, a19, a20) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8), a9, 9), a10, 10), a11, 11), a12, 12), a13, 13), a14, 14), a15, 15), a16, 16), a17, 17), a18, 18), a19, 19), a20, 20)
+#define __repi_21(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
+ a12, a13, a14, a15, a16, a17, a18, a19, a20, a21) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8), a9, 9), a10, 10), a11, 11), a12, 12), a13, 13), a14, 14), a15, 15), a16, 16), a17, 17), a18, 18), a19, 19), a20, 20), a21, 21)
+#define __repi_22(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
+ a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8), a9, 9), a10, 10), a11, 11), a12, 12), a13, 13), a14, 14), a15, 15), a16, 16), a17, 17), a18, 18), a19, 19), a20, 20), a21, 21), a22, 22)
+#define __repi_23(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
+ a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8), a9, 9), a10, 10), a11, 11), a12, 12), a13, 13), a14, 14), a15, 15), a16, 16), a17, 17), a18, 18), a19, 19), a20, 20), a21, 21), a22, 22), a23, 23)
+#define __repi_24(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
+ a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, \
+ a24) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8), a9, 9), a10, 10), a11, 11), a12, 12), a13, 13), a14, 14), a15, 15), a16, 16), a17, 17), a18, 18), a19, 19), a20, 20), a21, 21), a22, 22), a23, 23), a24, 24)
+#define __repi_25(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
+ a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, \
+ a24, a25) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8), a9, 9), a10, 10), a11, 11), a12, 12), a13, 13), a14, 14), a15, 15), a16, 16), a17, 17), a18, 18), a19, 19), a20, 20), a21, 21), a22, 22), a23, 23), a24, 24), a25, 25)
+#define __repi_26(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
+ a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, \
+ a24, a25, a26) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8), a9, 9), a10, 10), a11, 11), a12, 12), a13, 13), a14, 14), a15, 15), a16, 16), a17, 17), a18, 18), a19, 19), a20, 20), a21, 21), a22, 22), a23, 23), a24, 24), a25, 25), a26, 26)
+#define __repi_27(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
+ a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, \
+ a24, a25, a26, a27) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8), a9, 9), a10, 10), a11, 11), a12, 12), a13, 13), a14, 14), a15, 15), a16, 16), a17, 17), a18, 18), a19, 19), a20, 20), a21, 21), a22, 22), a23, 23), a24, 24), a25, 25), a26, 26), a27, 27)
+#define __repi_28(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
+ a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, \
+ a24, a25, a26, a27, a28) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8), a9, 9), a10, 10), a11, 11), a12, 12), a13, 13), a14, 14), a15, 15), a16, 16), a17, 17), a18, 18), a19, 19), a20, 20), a21, 21), a22, 22), a23, 23), a24, 24), a25, 25), a26, 26), a27, 27), a28, 28)
+#define __repi_29(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
+ a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, \
+ a24, a25, a26, a27, a28, a29) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8), a9, 9), a10, 10), a11, 11), a12, 12), a13, 13), a14, 14), a15, 15), a16, 16), a17, 17), a18, 18), a19, 19), a20, 20), a21, 21), a22, 22), a23, 23), a24, 24), a25, 25), a26, 26), a27, 27), a28, 28), a29, 29)
+#define __repi_30(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
+ a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, \
+ a24, a25, a26, a27, a28, a29, a30) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8), a9, 9), a10, 10), a11, 11), a12, 12), a13, 13), a14, 14), a15, 15), a16, 16), a17, 17), a18, 18), a19, 19), a20, 20), a21, 21), a22, 22), a23, 23), a24, 24), a25, 25), a26, 26), a27, 27), a28, 28), a29, 29), a30, 30)
+#define __repi_31(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
+ a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, \
+ a24, a25, a26, a27, a28, a29, a30, a31) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8), a9, 9), a10, 10), a11, 11), a12, 12), a13, 13), a14, 14), a15, 15), a16, 16), a17, 17), a18, 18), a19, 19), a20, 20), a21, 21), a22, 22), a23, 23), a24, 24), a25, 25), a26, 26), a27, 27), a28, 28), a29, 29), a30, 30), a31, 31)
+#define __repi_32(mac1, mac2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
+ a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, \
+ a24, a25, a26, a27, a28, a29, a30, a31, a32) \
+ mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac2(mac1(a1, 1), a2, 2), a3, 3), a4, 4), a5, 5), a6, 6), a7, 7), a8, 8), a9, 9), a10, 10), a11, 11), a12, 12), a13, 13), a14, 14), a15, 15), a16, 16), a17, 17), a18, 18), a19, 19), a20, 20), a21, 21), a22, 22), a23, 23), a24, 24), a25, 25), a26, 26), a27, 27), a28, 28), a29, 29), a30, 30), a31, 31), a32, 32)
+
#define __varexpand(mac1, mac2, ...) \
__xcat(__repn_, __narg(__VA_ARGS__)) (mac1, mac2, __VA_ARGS__)
@@ -168,4 +263,7 @@
#define __va_args(...) __VA_ARGS__
#define __splice(args) __va_args args
+#define __variexpand(mac1, mac2, ...) \
+ __xcat(__repi_, __narg(__VA_ARGS__)) (mac1, mac2, __VA_ARGS__)
+
#endif
diff --git a/cppawk-include/narg.h b/cppawk-include/narg.h
index 3419a24..b5a6aa5 100644
--- a/cppawk-include/narg.h
+++ b/cppawk-include/narg.h
@@ -32,9 +32,10 @@
#include "narg-priv.h"
#endif
-#define narg(...) __narg(__VA_ARGS__)
-#define varexpand(first, rest, ...) __varexpand(first, rest, __VA_ARGS__)
-#define revarg(...) __revarg(__VA_ARGS__)
-#define splice(args) __splice(args)
+#define narg(...) __narg(__VA_ARGS__)
+#define varexpand(first, rest, ...) __varexpand(first, rest, __VA_ARGS__)
+#define variexpand(first, rest, ...) __variexpand(first, rest, __VA_ARGS__)
+#define revarg(...) __revarg(__VA_ARGS__)
+#define splice(args) __splice(args)
#endif
diff --git a/cppawk-narg.1 b/cppawk-narg.1
index 985ea1c..3c1d8a3 100644
--- a/cppawk-narg.1
+++ b/cppawk-narg.1
@@ -11,6 +11,7 @@
#define narg(...P)
#define splice(\fIargs\fP)
#define varexpand(\fIfirst_mac\fP, \fIrest_mac\fP, ...)
+ #define variexpand(\fIfirst_mac\fP, \fIrest_mac\fP, ...)
#define revarg(...)
.ft R
@@ -150,18 +151,27 @@ some overflow detection up to 48 arguments, followed by unspecified behavior
for 49 or more arguments.
.IP \fBvarexpand\fR
-The most complex macro in the
+The most complex macros in the
.I <narg.h>
-header is
-.BR varexpand .
+header are
+.B varexpand
+and
+.BR variexpand .
-This macro is used for writing variadic macros with complex expansions,
+These macros are used for writing variadic macros with complex expansions,
using a compact specification.
The
.B varexpand
macro uses "higher order macro" programming: it has arguments which are
-themselves macros. To understand
+themselves macros.
+The
+.B variexpand
+macro is a variation on this, explained after a complete description of
+.B varexpand
+is given.
+
+To understand
.B varexpand
it helps to understand the Lisp
.B reduce
@@ -283,7 +293,7 @@ Example:
macro which generates a left-associative nested expression, like this:
.ft B
- rlist(\fI1\fP) \fI->\fP cons(\fI1\fP, Inil)
+ rlist(\fI1\fP) \fI->\fP cons(\fI1\fP, nil)
rlist(\fI1\fP, \fI2\fP) \fI->\fP cons(\fI2\fP, cons(\fI1\fP, nil))
rlist(\fI1\fP, \fI2\fP, \fI3\fP) -> cons(\fI3\fP, cons(\fI2\fP, cons(\fI1\fP, nil)))
.ft R
@@ -313,6 +323,73 @@ macro to reverse the arguments:
#define list(...) rlist(revarg(__VA_ARG__))
.ft R
+.IP \fBvariexpand\fB
+The
+.B variexpand
+macro is very similar to
+.BR varexpand .
+The difference is that
+.B varexpand
+passes an extra argument to both of the
+.B first_mac
+and
+.BR rest_mac
+macros. This argument is a decimal integer token indicating the master argument
+position being expanded.
+
+For instance, suppose we wish to have a macro with the following properties:
+
+.ft B
+ series(\fIa\fP) \fI->\fP \fIa1\fP
+ series(\fIa\fP, \fIb\fP) \fI->\fP \fIa1\fP + \fIb2\fP
+ series(\fIa\fP, \fIb\fP, \fIc\fP) \fI->\fP \fIa1\fP + \fIb2\fP + \fIc3\fP
+.ft R
+
+Note that the numbers do not appear as arguments. The
+.B variexpand
+macro will supply them:
+
+.ft B
+ #define series_first(\fIx\fP, \fIi\fP) \fIx\fP ## \fIi\fP
+ #define series_next(\fIprev\fP, \fIx\fP, \fIi\fP) \fIprev\fP + \fIx\fP ## \fIi\fP
+ #define series(...) variexpand(\fIseries_first\fP, \fIseries_next\fP, \e
+ __VA_ARGS__)
+.ft R
+
+Here,
+.B series_first
+is always called with
+.I i " ="
+1, and
+.B series_next
+is called with
+.I i
+taking on the values 2, 3, ... .
+The value of
+.I i
+indicates the one-based argument position of
+.I x
+in the
+.B series
+macro.
+
+One use for this is the generation of better temporary variables.
+The C preprocessor doesn't have a facility for generating temporary
+variable names. An unsatisfactory substitute is the use of some private
+namespace prefix like
+.B __x
+pasted together with the expansion of the
+.B __LINE__
+macro. However, macros can occur in the same line of code, or
+as arguments of a larger multi-line macro during the expansion of which
+.B __LINE__
+is pinned to the same value. If a large, multi-clause macro is based on
+.BR variexpand ,
+it can pass the argument number to its child clauses, which can combine
+it with
+.B __LINE__
+and a prefix to generate unique variables.
+
.SH BUGS
As noted in the DESCRIPTION, the
.BR narg ,
diff --git a/testcases-narg b/testcases-narg
index 9f8f55c..97baac1 100644
--- a/testcases-narg
+++ b/testcases-narg
@@ -70,3 +70,16 @@ done
echo okay
:
okay
+--
+7:
+$cppawk '
+#include <narg.h>
+#define first(x, i) x ## i
+#define rest(prev, x, i) prev : x ## i
+#define colonize(...) [variexpand(first, rest, __VA_ARGS__)]
+#define str(x) #x
+#define xstr(x) str(x)
+#define scolonize(...) xstr(colonize(__VA_ARGS__))
+BEGIN { print scolonize(a), scolonize(a, b), scolonize(a, b, c) }'
+:
+[a1] [a1 : b2] [a1 : b2 : c3]