MSVCでもCPPでFizzBuzzしてみた

[前回の記事](http://qiita.com/alucky0707/items/3599cdcf973382df978b)でC言語のプリプロセッサでFizzBuzzする方法を書いたのですが、GCCとかでしか動かなくてちょっとアレだなぁ、と思ったので __がんばって__ MSVCとかTCCとかでも動くようにしてみました。
__がんばって__ ってところがポイントです。がんばったんです！

##で、どんなコードになったの？

こんなコードになりました。

```c:fizzbuzz.c
#include "counter.h"

#ifndef FIZZBUZZ_MAX
#  define FIZZBUZZ_MAX 100
#endif

#if   COUNTER % 15 == 0
FizzBuzz
#elif COUNTER % 3  == 0
Fizz
#elif COUNTER % 5  == 0
Buzz
#else
COUNTER
#endif

#if COUNTER < FIZZBUZZ_MAX
#  include __FILE__
#endif
```

このコード自体は前回の`__INCLUDE_LEVEL__`を使ったものとそう変わらないような気がします。
しかし、このコードでは`__INCLUDE_LEVEL__`の代わりに`COUNTER`というマクロが使われています。

この`COUNTER`というマクロはもちろん、コンパイラによって組み込まれたものではなく、僕が定義したものです。そして、その定義は`counter.h`の中にあります。
この`counter.h`に秘密がありそうですね。

##`counter.h`。あるいはCPPで状態を扱うということ

前回の記事で「CPPでは変数のようにマクロの更新ができない」と書きました。
それはつまり、

```c
#define COUNTER 0
```

というマクロがあったとして、

```c
#define COUNTER (COUNTER + 1)
```

のようにもう一度定義しなおしても、展開結果は‘(COUNTER + 1)‘のようになってしまう、ということです。
しかも、仮に`(0 + 1)`と展開されたとしても、CPPではそこからさらに計算を行なって`1`という数値にしてくれるわけではないので、とてもFizzBuzzの出力には使えそうにありません。

前回の記事ではタウンページよろしく「そんなときに`__INCLUDE_LEVEL__`が便利なんですよ」と言ったわけなのですが、今回は`__INCLUDE_LEVEL__`の無い環境でも動くようにしなければいけないので、使うことはできません。

そこでどのようにするのかと言うと‥‥。

###「御託はいいからさっさとコードを見せろ！」

はい。

いやまあ、言う程すごいことはしてないんですよ。
強いて言えばちょっとがんばっただけです。

それでは`counter.h`のコード。

```c:counter.h
#ifndef COUNTER_H_
#define COUNTER_H_

/*    1の位の値 */
#define COUNTER_VALUE_1 0
/*   10の位の値 */
#define COUNTER_VALUE_2 0
/*  100の位の値 */
#define COUNTER_VALUE_3 0
/* 1000の位の値 */
#define COUNTER_VALUE_4 0

#define COUNTER 0

/* 引数として与えられたものを、展開してから結合するマクロ */
#define JOIN1(x) x
#define JOIN2(x, y) JOIN2_(x, y)
#define JOIN2_(x, y) x ## y
#define JOIN3(x, y, z) JOIN3_(x, y, z)
#define JOIN3_(x, y, z) x ## y ## z
#define JOIN4(x, y, z, w) JOIN4_(x, y, z, w)
#define JOIN4_(x, y, z, w) x ## y ## z ## w

#endif /* COUNTER_H_ */

/*  1の位から処理 */
#if   COUNTER_VALUE_1 == 0
#  undef COUNTER_VALUE_1
#  define COUNTER_VALUE_1 1
#elif COUNTER_VALUE_1 == 1
#  undef COUNTER_VALUE_1
#  define COUNTER_VALUE_1 2
#elif COUNTER_VALUE_1 == 2
#  undef COUNTER_VALUE_1
#  define COUNTER_VALUE_1 3
#elif COUNTER_VALUE_1 == 3
#  undef COUNTER_VALUE_1
#  define COUNTER_VALUE_1 4
#elif COUNTER_VALUE_1 == 4
#  undef COUNTER_VALUE_1
#  define COUNTER_VALUE_1 5
#elif COUNTER_VALUE_1 == 5
#  undef COUNTER_VALUE_1
#  define COUNTER_VALUE_1 6
#elif COUNTER_VALUE_1 == 6
#  undef COUNTER_VALUE_1
#  define COUNTER_VALUE_1 7
#elif COUNTER_VALUE_1 == 7
#  undef COUNTER_VALUE_1
#  define COUNTER_VALUE_1 8
#elif COUNTER_VALUE_1 == 8
#  undef COUNTER_VALUE_1
#  define COUNTER_VALUE_1 9
#elif COUNTER_VALUE_1 == 9
#  undef COUNTER_VALUE_1
/* 10位に繰り上がる場合 */
#  define COUNTER_VALUE_1 0
#  if   COUNTER_VALUE_2 == 0
#    undef COUNTER_VALUE_2
#    define COUNTER_VALUE_2 1
#  elif COUNTER_VALUE_2 == 1
#    undef COUNTER_VALUE_2
#    define COUNTER_VALUE_2 2
#  elif COUNTER_VALUE_2 == 2
#    undef COUNTER_VALUE_2
#    define COUNTER_VALUE_2 3
#  elif COUNTER_VALUE_2 == 3
#    undef COUNTER_VALUE_2
#    define COUNTER_VALUE_2 4
#  elif COUNTER_VALUE_2 == 4
#    undef COUNTER_VALUE_2
#    define COUNTER_VALUE_2 5
#  elif COUNTER_VALUE_2 == 5
#    undef COUNTER_VALUE_2
#    define COUNTER_VALUE_2 6
#  elif COUNTER_VALUE_2 == 6
#    undef COUNTER_VALUE_2
#    define COUNTER_VALUE_2 7
#  elif COUNTER_VALUE_2 == 7
#    undef COUNTER_VALUE_2
#    define COUNTER_VALUE_2 8
#  elif COUNTER_VALUE_2 == 8
#    undef COUNTER_VALUE_2
#    define COUNTER_VALUE_2 9
#  elif COUNTER_VALUE_2 == 9
#    undef COUNTER_VALUE_2
#    define COUNTER_VALUE_2 0
/* 100の位に繰り上がる場合 */
#    if   COUNTER_VALUE_3 == 0
#      undef COUNTER_VALUE_3
#      define COUNTER_VALUE_3 1
#    elif COUNTER_VALUE_3 == 1
#      undef COUNTER_VALUE_3
#      define COUNTER_VALUE_3 2
#    elif COUNTER_VALUE_3 == 2
#      undef COUNTER_VALUE_3
#      define COUNTER_VALUE_3 3
#    elif COUNTER_VALUE_3 == 3
#      undef COUNTER_VALUE_3
#      define COUNTER_VALUE_3 4
#    elif COUNTER_VALUE_3 == 4
#      undef COUNTER_VALUE_3
#      define COUNTER_VALUE_3 5
#    elif COUNTER_VALUE_3 == 5
#      undef COUNTER_VALUE_3
#      define COUNTER_VALUE_3 6
#    elif COUNTER_VALUE_3 == 6
#      undef COUNTER_VALUE_3
#      define COUNTER_VALUE_3 7
#    elif COUNTER_VALUE_3 == 7
#      undef COUNTER_VALUE_3
#      define COUNTER_VALUE_3 8
#    elif COUNTER_VALUE_3 == 8
#      undef COUNTER_VALUE_3
#      define COUNTER_VALUE_3 9
#    elif COUNTER_VALUE_3 == 9
#      undef COUNTER_VALUE_3
#      define COUNTER_VALUE_3 0
/* さすがに1000の位まで対応しなくていいよね？ */
#      define COUNTER_VALUE_4 1
#    endif
#  endif
#endif

/* 桁の数に合わせて結合するようにする */
#if   COUNTER_VALUE_2 == 0 && COUNTER_VALUE_3 == 0 && COUNTER_VALUE_4 == 0
#  undef COUNTER
#  define COUNTER JOIN1(COUNTER_VALUE_1)
#elif COUNTER_VALUE_3 == 0 && COUNTER_VALUE_4 == 0
#  undef COUNTER
#  define COUNTER JOIN2(COUNTER_VALUE_2, COUNTER_VALUE_1)
#elif COUNTER_VALUE_4 == 0
#  undef COUNTER
#  define COUNTER JOIN3(COUNTER_VALUE_3, COUNTER_VALUE_2, COUNTER_VALUE_1)
#else
#  undef COUNTER
#  define COUNTER JOIN4(COUNTER_VALUE_4, COUNTER_VALUE_3, COUNTER_VALUE_2, COUNTER_VALUE_1)
#endif
```

長いです。
しかも、長いわりに中身がないという、プログラマの三大美徳にひっかかりそうものになっています。

読めば分かりますが、展開結果に`COUNTER`が出てこないようにするためと計算の無いCPPのために、10進数に数値を分解してインクリメントを自力で実装しています。
状態を表現するのが難しいCPPとはいえ、何だかとても残念なコードなのでした。

##MSVCでの実行

Visual Studio立ち上げるの面倒だったので、`cl`コマンドの使えるプロンプトを起動して、`fizzbuzz.c`と`counter.h`の保存されたディレクトリに移動して、

```
$ cl /EP fizzbuzz.c | grep -v -e "#" -v -e "^$"
```

でFizzBuzzが見れます。ちなみにMSVCでは`#include`の深さが1024までいけるっぽいので、

```
$ cl /EP /DFIZZBUZZ_MAX=1000 fizzbuzz.c | grep -v -e "#" -v -e "^$"
```

のようにして、1000までFizzBuzzできます。

MSVCたんいじめるの楽しい！ ✌(’ω’✌ )三✌(’ω’)✌三( ✌’ω’)✌

また、TCCでは再帰のレベルが32までしかサポートされてないっぽいので、

```
$ tcc -E -w -DFIZZBUZZ_MAX=30 fizzbuzz.c | grep -v -e "#" -v -e "^ $" -v -e "^$"
```

とするといいかと思います。

##最後に

コンパイラいじめダメゼッタイ