2016-09-15 16 views
1

我試圖寫一個計數以序列特異的元素數量的宏。例如。對於序列(A)(B)(A)我想要得到的計數2 A.
一會兒從https://stackoverflow.com/a/12540675/2525536我結束了這段代碼的辦法:C預處理 - 遞歸條件計算宏觀

#define CAT(x, ...) CAT1(x, __VA_ARGS__) 
#define CAT1(x, ...) CAT2(x, __VA_ARGS__) 
#define CAT2(x, ...) x ## __VA_ARGS__ 

#define EXPAND(...) __VA_ARGS__ 
#define EAT(...) 
#define DEFER(...) __VA_ARGS__ EAT() 
#define OBSTRUCT(...) __VA_ARGS__ DEFER(EAT)() 

#define SIZE(seq) CAT(SIZE_, SIZE_0 seq) 
#define SIZE_0(...) SIZE_1 
#define SIZE_1(...) SIZE_2 
#define SIZE_2(...) SIZE_3 
#define SIZE_3(...) SIZE_4 
#define SIZE_SIZE_0 0 
#define SIZE_SIZE_1 1 
#define SIZE_SIZE_2 2 
#define SIZE_SIZE_3 3 
#define SIZE_SIZE_4 4 

#define GET_FIRST(x) GET_FIRST2(GET_FIRST1 x) 
#define GET_FIRST1(x) x, EAT() 
#define GET_FIRST2(x) GET_FIRST3(x) 
#define GET_FIRST3(x, ...) x 

#define POP_FIRST(x) EAT x 

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

#define CHECK_N(x, n, ...) n 

#define CHECK(...) CHECK_N(__VA_ARGS__, 0,) 
#define CHECK_PROBE(x) x, 1, 

#define NOT(x) CHECK(CAT(NOT_, x)) 
#define NOT_0 ~, 1, 

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

#define BOOL(x) COMPL(NOT(x)) 

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

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

#define WHEN(c) IF(c)(EXPAND, EAT) 

#define INC(x) CAT(INC_, x) 
#define INC_0 1 
#define INC_1 2 
#define INC_2 3 
#define INC_3 4 
#define INC_4 5 

#define DEC(x) CAT(DEC_, x) 
#define DEC_0 0 
#define DEC_1 0 
#define DEC_2 1 
#define DEC_3 2 
#define DEC_4 3 
#define DEC_5 4 

#define COUNT_IF(tpl, data, x) COUNT_IF1(0, SIZE(x), 0, tpl, data, x) 
#define COUNT_IF1(i, n, count, tpl, data, x) \ 
    IF(n) (\ 
     OBSTRUCT(CAT) (\ 
      COUNT_IF3_, \ 
      tpl(i, data, GET_FIRST(x)) \ 
     ) (\ 
      OBSTRUCT(COUNT_IF2)() \ 
       (INC(i), DEC(n), count, tpl, data, POP_FIRST(x)) /* call recursive */ \ 
     ) \ 
     , count \ 
    ) 
#define COUNT_IF2() COUNT_IF1 
#define COUNT_IF3_0 EXPAND 
#define COUNT_IF3_1 INC 

#define A_EQUAL_A(...) 1 
#define A_EQUAL_B(...) 0 
#define COUNT_A(i, data, x) CAT(A_EQUAL_, x)(i) 

EVAL(COUNT_IF(COUNT_A, ~, (A))) 
EVAL(COUNT_IF(COUNT_A, ~, (B))) 
EVAL(COUNT_IF(COUNT_A, ~, (A)(B))) 
EVAL(COUNT_IF(COUNT_A, ~, (B)(A))) 
EVAL(COUNT_IF(COUNT_A, ~, (A)(A))) 
EVAL(COUNT_IF(COUNT_A, ~, (B)(B))) 
EVAL(COUNT_IF(COUNT_A, ~, (A)(B)(A))) 

這工作已經相當不錯了前4個例子,但其他結尾錯誤的宏擴展(INC或EXPAND需要擴展多次)。

原因可能是因爲宏被標記爲藍色C,這就是爲什麼這個工程https://stackoverflow.com/a/11640759/2525536
但我找不到解決方法。
任何想法?

+2

我不禁懷疑,如果C預處理器是這​​個工作,不管它是正確的工具。這感覺就像一個[XY問題](http://mywiki.wooledge.org/XyProblem)。 –

+0

當然這是另一個問題的一部分。如果序列最終包含特定的元素/標記,我想應用一個宏。在我看來,最短的方法是計算該令牌的出現次數,並對0進行測試。 – user2525536

+0

我必須在這裏同意Jonathan Leffler。解決方法是實現一個合格的代碼生成器,因爲C預處理器不是。即使你成功地實現了這些,代碼也是難以管理的,SO並不是真正的混淆代碼藝術性的問答場所。 – 2016-09-16 08:22:05

回答

1

正如我已經收到了有關使用C預處理這個任務有些評論是不處理這個問題,我還是打算走這條路,不僅最大限度地減少代碼依賴一個適當的方式,但也做出最好的出什麼C在我的代碼中提供(這可能並不明顯)。
有這個說我找到了原因宏不正確,也擴大的方式,使預處理器正確做這個任務。
的問題是該宏產生從外部(第一元件)等INC(EXPAND(INC(0)))的構建體向內側(最後一個元素)。預處理器試圖解決這個問題,而總是隻知道所有的值直到當前的level /元素。這變成了類似INC(COUNT_IF1(...))的事情,在這一點上預處理器開始替代INC
的處理,這是使預處理從內部延伸宏觀到外面的正確方法。
簡化了代碼有點給出了這樣的解決方案:

#define CAT(x, ...) CAT1(x, __VA_ARGS__) 
#define CAT1(x, ...) CAT2(x, __VA_ARGS__) 
#define CAT2(x, ...) x ## __VA_ARGS__ 

#define EXPAND(...) __VA_ARGS__ 
#define EAT(...) 
#define DEFER(...) __VA_ARGS__ EAT() 
#define OBSTRUCT(...) __VA_ARGS__ DEFER(EAT)() 

#define SIZE(seq) CAT(SIZE_, SIZE_0 seq) 
#define SIZE_0(...) SIZE_1 
#define SIZE_1(...) SIZE_2 
#define SIZE_2(...) SIZE_3 
#define SIZE_3(...) SIZE_4 
#define SIZE_SIZE_0 0 
#define SIZE_SIZE_1 1 
#define SIZE_SIZE_2 2 
#define SIZE_SIZE_3 3 
#define SIZE_SIZE_4 4 

#define GET_FIRST(x) GET_FIRST2(GET_FIRST1 x) 
#define GET_FIRST1(x) x, EAT() 
#define GET_FIRST2(x) GET_FIRST3(x) 
#define GET_FIRST3(x, ...) x 

#define POP_FIRST(x) EAT x 

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

#define CHECK_N(x, n, ...) n 

#define CHECK(...) CHECK_N(__VA_ARGS__, 0,) 
#define CHECK_PROBE(x) x, 1, 

#define NOT(x) CHECK(CAT(NOT_, x)) 
#define NOT_0 ~, 1, 

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

#define BOOL(x) COMPL(NOT(x)) 

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

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

#define WHEN(c) IF(c)(EXPAND, EAT) 

#define INC(x) CAT(INC_, x) 
#define INC_0 1 
#define INC_1 2 
#define INC_2 3 
#define INC_3 4 
#define INC_4 5 

#define DEC(x) CAT(DEC_, x) 
#define DEC_0 0 
#define DEC_1 0 
#define DEC_2 1 
#define DEC_3 2 
#define DEC_4 3 
#define DEC_5 4 

#define IS_PAREN(x) CHECK(IS_PARENT1 x) 
#define IS_PARENT1(...) CHECK_PROBE(~) 

#define IS_COMPARABLE(x) IS_PAREN(CAT(COMPARE_, x)(())) 

#define BITAND(lhs, rhs) CAT(CAT(CAT(BITAND_, lhs), _), rhs) 
#define BITAND_0_0 0 
#define BITAND_0_1 0 
#define BITAND_1_0 0 
#define BITAND_1_1 1 

#define NOT_EQUAL(lhs, rhs) \ 
    IIF(BITAND(IS_COMPARABLE(lhs), IS_COMPARABLE(rhs)))(\ 
     NOT_EQUAL_HELPER, \ 
     1 NULL \ 
    )(lhs, rhs) 
#define NOT_EQUAL_HELPER(lhs, rhs) IS_PAREN(\ 
     CAT(COMPARE_, lhs)(CAT(COMPARE_, rhs))(()) \ 
    ) 

#define EQUAL(lhs, rhs) COMPL(NOT_EQUAL(lhs, rhs)) 

#define COUNT_IF(match, x) COUNT_IF1(SIZE(x), match, 0, x) 
#define COUNT_IF1(n, match, count, x) \ 
    IF(n) (\ 
     OBSTRUCT(COUNT_IF2)()(\ 
      DEC(n), \ 
      match, \ 
      IF(match(GET_FIRST(x)))(INC, EXPAND)(count), POP_FIRST(x) \ 
     ) /* call recursive */ \ 
     , count \ 
    ) 
#define COUNT_IF2() COUNT_IF1 

#define COMPARE_A(x) x 
#define EQUAL_A(x) EQUAL(x, A) 


EVAL(COUNT_IF(EQUAL_A, (A))) 
EVAL(COUNT_IF(EQUAL_A, (B))) 
EVAL(COUNT_IF(EQUAL_A, (A)(B))) 
EVAL(COUNT_IF(EQUAL_A, (B)(A))) 
EVAL(COUNT_IF(EQUAL_A, (A)(A))) 
EVAL(COUNT_IF(EQUAL_A, (B)(B))) 
EVAL(COUNT_IF(EQUAL_A, (A)(B)(A)(A))) 

P.S:一個11行的宏仍然在我看來很簡單的複雜性和可維護性方面來處理。