【问题标题】:Combine different arity X-macros结合不同的arity X宏
【发布时间】:2022-01-17 10:54:09
【问题描述】:

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

#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 宏参数有不同的arities。我希望任何必须处理标记的宏只需要采用 1 个参数,而任何处理关键字的宏都需要采用 2。我宁愿不要让所有内容都可变。我觉得应该可以添加一些插页式宏来实现这种组合,但我还没有足够聪明来实现这一点。

我想,一般来说:我希望能够采用 N 的 X 宏并将其减少到某个 M,其中 M 小于 N。

我怎样才能做到这一点?

【问题讨论】:

  • 不清楚预期的输出是什么。换句话说,假设存在一些 V 完全符合您的要求,那么 V 究竟会做什么?
  • 可以是任何东西——我会修改一个示例使用
  • 我想你只需要#define STR(NAME, ...) #NAME,
  • 这不能解决FOREACH_TOKEN 中的FOREACH_KEYWORD,是吗?
  • 请为所示示例显示您希望看到的预处理器扩展输出。 IE。手动编写您想要的结果。这将有助于猜测你的目标是什么。请提供所需的输出,而不是仅仅试图再次解释它。

标签: c macros c-preprocessor


【解决方案1】:

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

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

const char *kTokenTypeNames[] = {
#define STR1(NAME) #NAME,
#define STR2(NAME, dummy) #NAME,
  FOREACH_TOKEN1(STR1)
  FOREACH_KEYWORD(STR2)
};

【讨论】:

    【解决方案2】:

    鉴于您的规格,我认为这就是您正在寻找的。​​p>

    #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.

    【讨论】:

    • 这是完美的解决方案——谢谢。
    猜你喜欢
    • 1970-01-01
    • 2015-08-18
    • 1970-01-01
    • 2016-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多