#include <stdio.h>

#define CAT_(a, ...) a ## __VA_ARGS__
#define CAT(...) CAT_(__VA_ARGS__)

#define EAT(...)
#define EXPAND(...) __VA_ARGS__
#define IIF(c) CAT(IIF_, c)
#define IIF_1(...) __VA_ARGS__ EAT
#define IIF_0(...) EXPAND

#define COMPL(x) CAT(COMPL_, x)
#define COMPL_1 0
#define COMPL_0 1

#define CHECK_N(x, n, ...) n
#define CHECK(...) CHECK_(__VA_ARGS__)
#define CHECK_(...) CHECK_N(__VA_ARGS__, 0)
#define PROBE(x) x, 1

#define IS_EMPTY(x) BOOL(CHECK(CAT(IS_EMPTY_, x)()))
#define IS_EMPTY_()   PROBE(~)

#define NOT(x) CHECK(CAT(NOT_, x))
#define NOT_0 PROBE(~)
#define BOOL(x) COMPL(NOT(x))

#define IF(c) IIF(BOOL(c))
#define UNLESS(c) IF(c)()

#define EMPTY()
#define DEFER(id) id EMPTY()
#define OBSTRUCT(id) id DEFER(EMPTY)()

#define  EVAL(...) EVAL1(EVAL1(EVAL1(EVAL1(__VA_ARGS__))))
#define EVAL1(...) EVAL2(EVAL2(EVAL2(EVAL2(__VA_ARGS__))))
#define EVAL2(...) EVAL3(EVAL3(EVAL3(EVAL3(__VA_ARGS__))))
#define EVAL3(...) EVAL4(EVAL4(EVAL4(EVAL4(__VA_ARGS__))))
#define EVAL4(...) EVAL5(EVAL5(EVAL5(EVAL5(__VA_ARGS__))))
#define EVAL5(...) __VA_ARGS__

#define FOREACH(macro, x, ...) \
  UNLESS(IS_EMPTY(x))( \
    macro(x) \
    OBSTRUCT(FOREACH_INDIRECT)()(macro, __VA_ARGS__) \
  )

#define FOREACH_INDIRECT(...) FOREACH

#define QUOTE(...) QUOTE_(__VA_ARGS__)
#define QUOTE_(...) #__VA_ARGS__

#define ENUM_ARR_ELEM(x) , QUOTE(x)
#define ENUM(tag, first, ...) \
    enum tag {first, __VA_ARGS__}; \
    char *CAT(tag, _names)[] = {QUOTE(first)EVAL(FOREACH(ENUM_ARR_ELEM, __VA_ARGS__))}; \
    static char *CAT(tag, _to_str) (int x) \
    { \
        return x > sizeof(CAT(tag, _names)) / sizeof(char*) ? QUOTE(!!!UNKNOWN tag!!!) : CAT(tag, _names)[x]; \
    }

ENUM(crap,
    shit,
    fuck,
    dick,
    ass,
    turd,
    fart
)

int main()
{
    puts(crap_to_str(shit));
    puts(crap_to_str(666));
    return 0;
}