Brainfuck


[外]の表記がついた項目は外部ページへリンクしています。

8つの命令語


命令語一覧

BFで使用する命令は以下の8種類のみで構成されます。

  1. + ポインタが指す値をインクリメントする
  2. - ポインタが指す値をデクリメントする
  3. > ポインタをインクリメントする
  4. < ポインタをデクリメントする
  5. [ ポインタが指す値が0なら、対応する ] の直後までジャンプする
  6. ] ポインタが指す値が0でないなら、対応する [ にジャンプする
  7. .(ドット) ポインタが指す値を出力する(asciiコードで出力)
  8. ,(コンマ) 1バイトを入力してポインタが指す値に代入する

+ と - の動作

動作の対象はポインタで指定されている配列の要素値です。以下の表の状態だと配列[0]がポインタで指定されているので、 配列[0]の要素値に対してインクリメントしたり、デクリメントしたりします。

表の赤い箇所が現在の変更対象
配列 01234567829999
配列の要素値 0000000000
ポインタ位置

一度インクリメントまたはデクリメントする度に指定された要素値は数値が1だけ増減します。 なので上記の状態から++とすると以下のように値が+2されて配列[0]に2が格納されます。

配列 01234567829999
配列の要素値 2000000000
ポインタ位置

尚、配列の要素値の範囲は0〜255でマイナス値はありません。要素値が0の場合に-(デクリメント)すると配列の要素に入る値は255になり、255の場合に+(インクリメント)すると配列の要素に入る値は0となる。

>  と < の動作

動作の対象はポインタ(配列への指標)です。ポインタをインクリメントまたはデクリメントして、ポインタを左右に移動させます。

表の赤い箇所が現在の変更対象
配列 01234567829999
配列の要素値 0000000000
ポインタ位置

上記の状態から>>とポインタをインクリメントさせると、変更対象の要素値は以下のようになります。

配列 01234567829999
配列の要素値 0000000000
ポインタ位置

尚、ポインタの範囲は0〜n(処理系に依存する)でマイナス値はありません。………無いはず。 ポインタ位置が0の場合にデクリメントするとポインタはnに設定されます。 逆もまた然りでn位置でインクリメントするとポインタは0となる。

.(ドット) と ,(コンマ) の動作

.(ドット)はポインタで指定されている配列の要素値をASCIIコードとして画面に出力し、,(コンマ)はキーボードからの入力をASCIIコードとしてポインタで指定されている配列に格納します。

そりだけ?うん、そりだけ。

単純な機能しか備えていないので.(ドット)はOutput、,(コンマ)はInputくらいの知識で問題ありません。

[ と ] の動作

[ ]は対で使われる繰り返し構文です。Cとして表すならwhile(*ptr){ }です。基本的に繰り返し構文には繰り返し回数を制御するカウンタが必要なので、[ ]の前でカウンタ用の値を格納しておくのが一般的な使い方です。
VxWorksやSymbian OS等のRTOSはこの条件に当てはまりません。

以下のコードを例に処理の動きを追ってみます。尚、配列名はstrとします。

+++[->+++++++++++++++++<]>.

まぁ簡単に解説すると、最初の「+++」でstr[0]に3が格納されます。このstr[0]に格納された値を繰り返し処理制御用のカウンタとして扱います。

次に「 [ 」に入りますが現在参照しているstr[0]の値は3なので対応する「 ] 」に飛ばす中の処理を行います。そして「-」でstr[0]の値がデクリメントされ2に。

※現在の状態
配列str 01234567829999
配列の要素値 2000000000
ポインタ位置

次に。(赤色のコードから)
+++[->+++++++++++++++++<]>.

「>」でポインタをインクリメントするのでstr[1]の要素値に「+++++++++++++++++」を格納する。「+」の数は17なのでstr[1] = 17となる。次の「<」で参照ポインタをstr[0]に戻し、「 ] 」で判定。値は2なのでループを抜けずに対応する「 [ 」に飛ぶ。

これをstr[0] = 0になるまで続けます。

※現在の状態
配列str 01234567829999
配列の要素値 03400000000
ポインタ位置

次に。(赤色のコードから)
+++[->+++++++++++++++++<]>.

赤色コードの一つ前の「-」を処理した時点でstr[0]の値が0になりました。さて、このまま処理を続けます。また「>」でポインタをずらし、str[1]に17を足すとstr[1] = 51になりました。次に「<」でポインタを戻し「 ] 」で判定します。

str[0]の値は0なのでそのまま処理を抜けて後は残った「>」「.(ドット)」を処理してプログラムは終了です。

※最終的な状態
配列str 01234567829999
配列の要素値 05100000000
ポインタ位置


コードの最後の「.(ドット)」でstr[1]の要素値を出力します。10進数の51は16進数で0x33です。 0x33をASCIIコード表と照らし合わせてみましょう。文字の「3」が対応しているはずです。 なのでこのプログラムは文字の「3」を出力するプログラムということになります。 内部処理としては3x17の計算をしただけの単純なプログラムです。

命令語が全て記号なのでコードの可読性は低く見えるかもしれませんが、 結局やっていることは単純な命令を順番に処理しているだけでしたね。

また[ ]は何重にもネストさせることはできるんですが、 逆にコードが長くなる可能性があるので使用には注意した方が良いでしょう。