I am defining a lexer for a programming language. Part of this involves having a table of keywords and tokens:
#define FOREACH_KEYWORD(V) \
V(And, and) \
V(Else, else) \
V(False, false) \
V(If, if) \
V(Or, or) \
V(True, true)
#define FOREACH_TOKEN(V) \
V(Plus) \
V(Minus) \
V(Times) \
V(Div) \
FOREACH_KEYWORD(V)
These macros are intended to be used like so:
const char *kTokenTypeNames[] = {
#define STR(NAME) #NAME,
FOREACH_TOKEN(STR)
#undef STR
};
// which would ideally expand to
const char *kTokenTypeNames[] = {
"Plus", "Minus", "Times", "Div", "And", "Else", "False", "If", "Or", "True",
};
And the keywords should be included in the token list. The above pseudocode does not work because the two different V
macro parameters have different arities. I would like any macro that has to deal with tokens to only need to take 1 parameter, and any macro that deals with keywords to need to take 2. I'd rather not make everything variadic. I feel like it should be possible to add some interstitial macros to make this combination possible, but I have as of yet not been clever enough to make this happen.
I suppose, in general: I would like to be able to take an X-macro of arity N and reduce it to some M where M is smaller than N.
How can I achieve this?
CodePudding user response:
I'm not sure why you think these two lists should be two instead of one, when one list includes the other. Either make one list or two separate ones.
If you make two separate lists and get rid of FOREACH_KEYWORD(V)
in the FOREACH_TOKEN
list, then you can simply make two separate macro calls:
const char *kTokenTypeNames[] = {
#define STR1(NAME) #NAME,
#define STR2(NAME, dummy) #NAME,
FOREACH_TOKEN1(STR1)
FOREACH_KEYWORD(STR2)
};
CodePudding user response:
Given your specs I think this is what you're looking for.
#define AB_TO_A(A,B) (A)
#define EVAL(...) __VA_ARGS__
#define FOREACH_KEYWORD(V) \
V(And, and) \
V(Else, else) \
V(False, false) \
V(If, if) \
V(Or, or) \
V(True, true)
#define FOREACH_TOKEN(V) \
V(Plus) \
V(Minus) \
V(Times) \
V(Div) \
EVAL(FOREACH_KEYWORD(V AB_TO_A))
const char *kTokenTypeNames[] = {
#define STR(NAME) #NAME,
FOREACH_TOKEN(STR)
#undef STR
};
Coliru demo here.