组合不同的 arity X-macros
Combine different arity X-macros
我正在为编程语言定义词法分析器。其中一部分涉及 table 个关键字和标记:
#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)
这些宏的用途如下:
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",
};
并且关键字应该包含在标记列表中。上面的伪代码不起作用,因为两个不同的 V
宏参数具有不同的参数。我希望任何必须处理标记的宏只需要采用 1 个参数,而任何处理关键字的宏需要采用 2 个参数。我不想让所有内容都可变。我觉得应该可以添加一些插页式宏来使这种组合成为可能,但我还没有足够聪明地做到这一点。
我想,总的来说:我希望能够采用一个数量为 N 的 X 宏并将其减少到某个 M,其中 M 小于 N。
我怎样才能做到这一点?
当一个列表包含另一个时,我不确定您为什么认为这两个列表应该是两个而不是一个。要么列出一个列表,要么列出两个单独的列表。
如果您创建两个单独的列表并删除 FOREACH_TOKEN
列表中的 FOREACH_KEYWORD(V)
,那么您可以简单地进行两个单独的宏调用:
const char *kTokenTypeNames[] = {
#define STR1(NAME) #NAME,
#define STR2(NAME, dummy) #NAME,
FOREACH_TOKEN1(STR1)
FOREACH_KEYWORD(STR2)
};
根据您的规格,我想这就是您要找的。
#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 演示 here.
我正在为编程语言定义词法分析器。其中一部分涉及 table 个关键字和标记:
#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)
这些宏的用途如下:
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",
};
并且关键字应该包含在标记列表中。上面的伪代码不起作用,因为两个不同的 V
宏参数具有不同的参数。我希望任何必须处理标记的宏只需要采用 1 个参数,而任何处理关键字的宏需要采用 2 个参数。我不想让所有内容都可变。我觉得应该可以添加一些插页式宏来使这种组合成为可能,但我还没有足够聪明地做到这一点。
我想,总的来说:我希望能够采用一个数量为 N 的 X 宏并将其减少到某个 M,其中 M 小于 N。
我怎样才能做到这一点?
当一个列表包含另一个时,我不确定您为什么认为这两个列表应该是两个而不是一个。要么列出一个列表,要么列出两个单独的列表。
如果您创建两个单独的列表并删除 FOREACH_TOKEN
列表中的 FOREACH_KEYWORD(V)
,那么您可以简单地进行两个单独的宏调用:
const char *kTokenTypeNames[] = {
#define STR1(NAME) #NAME,
#define STR2(NAME, dummy) #NAME,
FOREACH_TOKEN1(STR1)
FOREACH_KEYWORD(STR2)
};
根据您的规格,我想这就是您要找的。
#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 演示 here.