Re: Recursive variadic macros

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Nov 6, 2020 at 8:52 PM <newcomer@xxxxxxxxxxxx> wrote:
>
> Consider that I want to write a macro that, for a list of arguments, will
> generate one (or more) lines of code for each argument.  For example
>
>
>
> [code]
>
> #define STATES  S0, WANTDIGIT, DIGIT, REJECTING, ENDNUMBER, WAVEFORM,
> FINISH, ENDOFDATA, OUTPUT_STREAM_ID
>
>
>
> typedef enum { STATES} States;
>
>
>
>
>
> States state = S0;
>
>
>
> void showState()
>
>    {
>
>     #define show1(x, ...) \
>
>     case x: Serial.println(#x); break; \
>
>     __VA_OPT__(show1(__VA_ARGS__))
>
>
>
>     switch(state)
>
>        { /* state */
>
>         show1(STATES);
>
>        } /* state */
>
>     #undef show1
>
>    }
>
> [/code]
>
> What I expect to generate is
>
> [code]
>
>     show1(S0, WANTDIGIT, DIGIT, REJECTING, ENDNUMBER, WAVEFORM, FINISH,
> ENDOFDATA, OUTPUT_STREAM_ID)
>
> [/code]
>
> Which should give me
>
> [code]
>
> void showState()
>    {
>
>      switch(state)
>         { /* state */
>
>           case S0: Serial.println("S0"); break;
>           case WANTDIGIT: Serial.println("WANTDIGIT"); break;
>
>           //..etc.
>
>           case OUTPUT_STREAM_ID: Serial.println("OUTPUT_STREAM_ID"); break;
>
>         } /* state */
>
>    } // showState
>
> [/code]
>
>
>
> What I get, though, is
>
> [code]
>
> C:\Users\admin\OneDrive\Projects\Oscilloscope Tests\PWM_test\PWM_test.ino:
> In function 'void showState()':
>
> PWM_test:39:19: error: expected ':' before ',' token
>
>    39 | #define STATES  S0, WANTDIGIT, DIGIT, REJECTING, ENDNUMBER,
> WAVEFORM, FINISH, ENDOFDATA, OUTPUT_STREAM_ID
>
>       |                   ^
>
> C:\Users\admin\OneDrive\Projects\Oscilloscope
> Tests\PWM_test\PWM_test.ino:48:10: note: in definition of macro 'show1'
>
>    48 |     case x: Serial.println(#x); break; \
>
>       |          ^
>
> C:\Users\admin\OneDrive\Projects\Oscilloscope
> Tests\PWM_test\PWM_test.ino:52:12: note: in expansion of macro 'STATES'
>
>    52 |      show1(STATES);
>
>       |            ^~~~~~
>
> PWM_test:39:19: error: expected primary-expression before ',' token
>
>    39 | #define STATES  S0, WANTDIGIT, DIGIT, REJECTING, ENDNUMBER,
> WAVEFORM, FINISH, ENDOFDATA, OUTPUT_STREAM_ID
>
>       |                   ^
>
> C:\Users\admin\OneDrive\Projects\Oscilloscope
> Tests\PWM_test\PWM_test.ino:48:10: note: in definition of macro 'show1'
>
>    48 |     case x: Serial.println(#x); break; \
>
>       |          ^
>
> C:\Users\admin\OneDrive\Projects\Oscilloscope
> Tests\PWM_test\PWM_test.ino:52:12: note: in expansion of macro 'STATES'
>
>    52 |      show1(STATES);
>
>       |            ^~~~~~
>
> C:\Users\admin\OneDrive\Projects\Oscilloscope
> Tests\PWM_test\PWM_test.ino:50:11: warning: enumeration value 'WANTDIGIT'
> not handled in switch [-Wswitch]
>
>    50 |     switch(state)
>
>       |           ^
>
> C:\Users\admin\OneDrive\Projects\Oscilloscope
> Tests\PWM_test\PWM_test.ino:50:11: warning: enumeration value 'DIGIT' not
> handled in switch [-Wswitch]
>
> C:\Users\admin\OneDrive\Projects\Oscilloscope
> Tests\PWM_test\PWM_test.ino:50:11: warning: enumeration value 'REJECTING'
> not handled in switch [-Wswitch]
>
> C:\Users\admin\OneDrive\Projects\Oscilloscope
> Tests\PWM_test\PWM_test.ino:50:11: warning: enumeration value 'ENDNUMBER'
> not handled in switch [-Wswitch]
>
> C:\Users\admin\OneDrive\Projects\Oscilloscope
> Tests\PWM_test\PWM_test.ino:50:11: warning: enumeration value 'WAVEFORM' not
> handled in switch [-Wswitch]
>
> C:\Users\admin\OneDrive\Projects\Oscilloscope
> Tests\PWM_test\PWM_test.ino:50:11: warning: enumeration value 'FINISH' not
> handled in switch [-Wswitch]
>
> C:\Users\admin\OneDrive\Projects\Oscilloscope
> Tests\PWM_test\PWM_test.ino:50:11: warning: enumeration value 'ENDOFDATA'
> not handled in switch [-Wswitch]
>
> C:\Users\admin\OneDrive\Projects\Oscilloscope
> Tests\PWM_test\PWM_test.ino:50:11: warning: enumeration value
> 'OUTPUT_STREAM_ID' not handled in switch [-Wswitch]
>
> exit status 1
>
> expected ':' before ',' token
>
> [/code]
>
>
>
> What is going wrong here?

While the error can be fixed as follows, the C standard forbids a
recursive macro, and therefore, you must define separate macros as
many as there are levels of a recursion.

#define STATES S0, WANTDIGIT, DIGIT, REJECTING, ENDNUMBER, WAVEFORM,
FINISH, ENDOFDATA, OUTPUT_STREAM_ID

typedef enum { STATES} States;

States state = S0;

void showState()
{

#define show1(x, ...) case x: Serial.println(#x); break;        \
  __VA_OPT__(show1(__VA_ARGS__))
#define expand(fn_to_call, var_to_expand) \
  fn_to_call(var_to_expand)

 switch(state)
   { /* state */

     expand(show1, STATES);

   } /* state */

#undef expand
#undef show1
}

That said, your problem is off-topic for this mailing list because
your problem is a problem about using the C preprocessor, not GCC.
Please ask further questions related to using the C preprocessor
(including techniques to easily define different macros for different
levels of a recursion) in another place to get the best answers
possible.

-- 
Best regards,
Tadeus



[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux