recursive variadic macros

A

Andrey Vul

How do I make a recursive variadic macro, with the condition that the
recursion ends when only one argument remains?
The code so far is:
#define Tchain(sc1,...) case sc1 : Tchain(__VA_ARGS__) return

later on, in a switch(),
Tchain(1,2,3,4,5) 6;

Which expands to
case 1 : (Tchain(2,3,4,5)) return 6;

How do I construct the macro so that the expansion would be
case 1 : case 2 : case 3 : case 4 : case 5 : return 6;
?
 
B

Ben Pfaff

Andrey Vul said:
How do I make a recursive variadic macro, with the condition that the
recursion ends when only one argument remains?

Macros can't recurse, so you can't.
 
A

Andrey Vul

Macros can't recurse, so you can't.
So the following:
#define x(y) x(y+1)
, when expanded, will return:
x(y+1)
as opposed to a stack overflow from the preprocessor?

So variadics aren't as powerful as I thought...
 
F

Franken Sense

In Dread Ink, the Grave Hand of Ben Pfaff Did Inscribe:
Macros can't recurse, so you can't.

That's what I thought!
--
Frank

I once asked the most fabulous couple I know, Madonna and Guy Ritchie, how
they kept things fresh despite having been married for almost seven months.
'It's a job, Al,' Guy told me. 'We work at it every day.'
~~ Al Franken,
 
J

James Kuyper

Andrey said:
How do I make a recursive variadic macro, with the condition that the
recursion ends when only one argument remains?
The code so far is:
#define Tchain(sc1,...) case sc1 : Tchain(__VA_ARGS__) return

later on, in a switch(),
Tchain(1,2,3,4,5) 6;

Which expands to
case 1 : (Tchain(2,3,4,5)) return 6;

How do I construct the macro so that the expansion would be
case 1 : case 2 : case 3 : case 4 : case 5 : return 6;
?

The fundamental problem is that after the in initial replacement of a
macro with it's definition, 6.10.3.4 says:

"1 ...the resulting preprocessing token sequence is rescanned, along
with all subsequent preprocessing tokens of the source file, for more
macro names to replace.
2 If the name of the macro being replaced is found during this scan of
the replacement list (not including the rest of the source file’s
preprocessing tokens), it is not replaced."

Thus, macros cannot be recursive.
 
L

luserXtrog

How do I make a recursive variadic macro, with the condition that the
recursion ends when only one argument remains?
The code so far is:
#define Tchain(sc1,...) case sc1 : Tchain(__VA_ARGS__) return

later on, in a switch(),
Tchain(1,2,3,4,5) 6;

Which expands to
case 1 : (Tchain(2,3,4,5)) return 6;

How do I construct the macro so that the expansion would be
case 1 : case 2 : case 3 : case 4 : case 5 : return 6;
?

The only workaround I've found for this sort of thing is a lot
of different macros for each number of arguments. This should
show the idea; each argument gets decorated with a big O and
called as a function:

#define O(x) O ## x
#define ps(x) O(x)();
#define ps2(x,y) ps(x) ps(y)
#define ps3(x,y,z) ps2(x,y) ps(z)
#define ps4(a,b,c,d) ps3(a,b,c) ps(d) //:)
#define ps5(a,b,c,d,e) ps4(a,b,c,d) ps(e)
#define ps6(a,b,c,d,e,f) ps5(a,b,c,d,e) ps(f)
#define ps7(a,b,c,d,e,f,g) ps6(a,b,c,d,e,f) ps(g)
#define ps8(a,b,c,d,e,f,g,h) ps7(a,b,c,d,e,f,g) ps(h)

It's a little tiresome counting the arguments to use the correct
macro; but if used a lot, it does save a little typing.

hth
 
L

luserXtrog

That can be solved, at least. Google Google Groups for "PP_NARG". It
evaluates to a decimal string of the number of arguments, which you can use
to dynamically call the appropriate macro. C99 compliant. The above case
could be refactored to something like:

#define ps_(M, ...) M(__VA_ARGS__)
#define ps(...)     ps_(XPASTE(ps, PP_NARG(__VA_ARGS__)), __VA_ARGS__)

I've used this technique before, mostly recently here:

       http://monkeymail.org/archives/libevent-users/2009-April/001590.html

I didn't realize it when I posted that code, but the pre-processor output of
a single invocation of the event_delegate macro generates well over a
megabyte of output! Doesn't seem to slow down compilation, though, and it's
all ultimately constant folded (using gcc-specific builtins).

Awesome. So you can do something like this:

#define Paste(a,b) a ## b
#define XPASTE(a,b) Paste(a,b)

#define c1(a) case a:
#define c2(a,b) c1(a) c1(b)
#define c3(a,b,c) c1(a) c2(b,c)
#define c4(a,b,c,d) c1(a) c3(b,c,d)
#define c_(M, ...) M(__VA_ARGS__)
#define cases(...) c_(XPASTE(c, PP_NARG(__VA_ARGS__)), __VA_ARGS__)

cases(3,4,5,6)


which produces
case 3: case 4: case 5: case 6:
 
L

luserXtrog

PP_NARGS doesn't seem to be documented in the GNU cpp manual.  I
wonder if there's a listing somewhere of preprocessors where
it's implemented.  It's not in my copy of C99, so I assume
that while compliant, its not required.  It definitely seems
like a useful extension, though

I thought that somewhat related was the way that some
preprocessors (like ctpp, (see the .sig, please excuse the
shameless plug)) and GNU cpp, handle quoting and pasting of
__VA_ARGS__ in a replacement list - as an extension,
#__VA_ARGS__ would seem to imply that the statement wants
the entire list to be quoted, but more on topic for this
discussion might be a notation that quotes each member of
__VA_ARGS__, and how to determine how a prepressor might
DTRT for all cases, without munging entire macros.

It's not a builtin. You'd've had to Google Google Groups as
William Ahern advises upthread.

For the lazy, here's the link

http://groups.google.com/group/comp...707dbc8b98?lnk=gst&q=PP_NARG#ccd52d707dbc8b98

For the really lazy, here's the macro

/*
* The PP_NARG macro evaluates to the number of arguments that have
been
* passed to it.
*
* Laurent Deniau, "__VA_NARG__," 17 January 2006, <comp.std.c> (29
November 2007).
*/
#define PP_NARG(...) PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#define PP_NARG_(...) PP_ARG_N(__VA_ARGS__)

#define PP_ARG_N( \
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63,N,...) N

#define PP_RSEQ_N() \
63,62,61,60, \
59,58,57,56,55,54,53,52,51,50, \
49,48,47,46,45,44,43,42,41,40, \
39,38,37,36,35,34,33,32,31,30, \
29,28,27,26,25,24,23,22,21,20, \
19,18,17,16,15,14,13,12,11,10, \
9,8,7,6,5,4,3,2,1,0
 
L

luserXtrog

Awesome. So you can do something like this:

#define Paste(a,b) a ## b
#define XPASTE(a,b) Paste(a,b)

#define c1(a) case a:
#define c2(a,b) c1(a) c1(b)
#define c3(a,b,c) c1(a) c2(b,c)
#define c4(a,b,c,d) c1(a) c3(b,c,d)
#define c_(M, ...) M(__VA_ARGS__)
#define cases(...) c_(XPASTE(c, PP_NARG(__VA_ARGS__)), __VA_ARGS__)

cases(3,4,5,6)

which produces
case 3: case 4: case 5: case 6:

Does anyone have a macro to expand 3,6 to the sequence 3,4,5,6?
This could be the long-awaited cases(range(a,b)) label!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top