2016-09-15 4 views
1

시퀀스의 특정 요소 수를 계산하는 매크로를 작성하려고합니다. 예 : 순서 (A) (B) (A)에 대해 나는 A.의 수를 2 싶어
지금은이 코드와 끝까지 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))) 

을 첫 번째 네 가지 예제는 다른 매크로 이름 확장 (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는 코드를 모호하게 만드는 예술성에 대한 Q & A의 장소가 아닙니다. –

답변

1

이 작업을 위해 C 전 처리기를 사용하는 것에 대한 몇 가지 의견은 이미이 문제를 처리하는 적절한 방법이 아니므로이 방법으로 코드 종속성을 최소화 할뿐만 아니라 C를 최대한 활용할 것입니다. 내 코드에 제공됩니다 (여기서는 분명하지 않을 수 있음).
매크로가 올바르게 확장되지 않는 이유와 전처리 기가 올바르게이 작업을 수행하는 방법을 알았습니다.
매크로는 외부 (첫 번째 요소)에서 내부 (마지막 요소)까지 INC(EXPAND(INC(0)))과 같은 구조를 생성했습니다. 전처리 기는 현재 레벨/요소까지 항상 모든 값을 알고있는 동안이 문제를 해결하려고했습니다. 이것은 예를 들어 INC을 대체하기 시작한 전 처리기에서 INC(COUNT_IF1(...))과 같은 것으로 바뀌 었습니다.
올바른 처리 방법은 전처리 기가 내부에서 외부로 매크로를 확장하도록하는 것입니다.

#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 개 라인의 매크로는 여전히 복잡성과 유지 보수의 관점에서 처리하기 위해 나에게 간단한데 : 코드를 조금 단순화
이 솔루션을 제공합니다.