组合不同的 arity X-macro

Combine different arity X-macros

提问人:tekknolagi 提问时间:12/14/2021 最后编辑:Jonathan Lefflertekknolagi 更新时间:8/23/2022 访问量:102

问:

我正在为编程语言定义词法分析器。其中一部分涉及包含关键字和标记的表:

#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",
};

关键字应包含在令牌列表中。上面的伪代码不起作用,因为两个不同的宏参数具有不同的 arities。我希望任何必须处理标记的宏只需要取 1 个参数,而任何处理关键字的宏都需要取 2 个参数。我宁愿不要让一切都变得多变。我觉得应该可以添加一些插页式宏来使这种组合成为可能,但到目前为止,我还不够聪明,无法做到这一点。V

我想,总的来说:我希望能够获取 arity N 的 X 宏并将其简化为一些 M,其中 M 小于 N。

我怎样才能做到这一点?

C-预处理器 X-宏

评论

1赞 user3386109 12/14/2021
目前尚不清楚预期的输出是什么。换句话说,假设存在一些完全符合您要求的功能,那么它究竟会做什么?VV
0赞 tekknolagi 12/14/2021
可以是任何东西 - 我会用示例使用进行修改
0赞 user3386109 12/14/2021
我认为你所需要的只是#define STR(NAME, ...) #NAME,
0赞 tekknolagi 12/14/2021
这并不能解决内部问题,是吗?FOREACH_KEYWORDFOREACH_TOKEN
1赞 Yunnosch 12/14/2021
请显示您希望在所示示例中看到的预处理器扩展输出。即手动写下你想要成为你正在尝试的结果。这将有助于猜测你的目标是什么。请提供所需的输出,而不是只是试图再次解释它。

答:

4赞 Lundin 12/14/2021 #1

我不确定为什么你认为这两个列表应该是两个而不是一个,当一个列表包含另一个列表时。要么列出一个清单,要么列出两个单独的清单。

如果您创建两个单独的列表并删除列表中的 delete,那么您可以简单地进行两个单独的宏调用:FOREACH_KEYWORD(V)FOREACH_TOKEN

const char *kTokenTypeNames[] = {
#define STR1(NAME) #NAME,
#define STR2(NAME, dummy) #NAME,
  FOREACH_TOKEN1(STR1)
  FOREACH_KEYWORD(STR2)
};
2赞 H Walters 12/14/2021 #2

鉴于您的规格,我认为这就是您要找的。

#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 演示在这里