1. 基本
Brainfuck を理解するには、0
それぞれによって初期化されるセルの無限配列を想像する必要があります。
...[0][0][0][0][0]...
Brainfuck プログラムが開始されると、任意のセルを指します。
...[0][0][*0*][0][0]...
ポインタを右>
に移動すると、ポインタがセル X からセル X+1 に移動します
...[0][0][0][*0*][0]...
セルの値を増やすと、次の+
ようになります。
...[0][0][0][*1*][0]...
セルの値を再度増やすと、次の+
ようになります。
...[0][0][0][*2*][0]...
セルの値を減らすと、次の-
ようになります。
...[0][0][0][*1*][0]...
ポインターを左<
に移動すると、ポインターがセル X からセル X-1 に移動します。
...[0][0][*0*][1][0]...
2.入力
文字を読み取るには、コンマを使用します,
。標準入力から文字を読み取り、その 10 進 ASCII コードを実際のセルに書き込みます。
ASCII テーブルを見てください。たとえば、 の 10 進コードは!
ですが33
、a
は です97
。
さて、BF プログラムのメモリが次のようになっていると想像してみましょう。
...[0][0][*0*][0][0]...
標準入力が を表すと仮定するとa
、コンマ,
演算子を使用すると、BF はa
10 進 ASCII コード97
をメモリに読み込みます。
...[0][0][*97*][0][0]...
一般的にはそのように考えたいと思うでしょうが、実際はもう少し複雑です。真実は、BF は文字ではなくバイト (そのバイトが何であれ) を読み取るということです。例を示しましょう:
Linux では
$ printf ł
プリント:
ł
これは特定のポーランド文字です。この文字は ASCII エンコーディングではエンコードされません。この場合は UTF-8 エンコーディングであるため、以前はコンピューターのメモリで 1 バイト以上を使用していました。16 進数のダンプを作成することでそれを証明できます。
$ printf ł | hd
これは以下を示します:
00000000 c5 82 |..|
ゼロはオフセットされます。82
は 1 番目、c5
は 2 番目のバイトを表しますł
(順番に読み取ります)。|..|
この場合は不可能なグラフ表現です。
ł
1 バイトを読み取る BF プログラムに入力として渡すと、プログラム メモリは次のようになります。
...[0][0][*197*][0][0]...
なぜ197
ですか?10進197
数はc5
16 進数です。おなじみのようですか?もちろん。ł
!の最初のバイトです。
3.出力
.
文字を表示するには、ドットを使用します。実際のセル値を 10 進 ASCII コードのように扱うと仮定して、対応する文字を標準出力に出力します。
さて、BF プログラムのメモリが次のようになっていると想像してみましょう。
...[0][0][*97*][0][0]...
ここでドット (.) 演算子を使用すると、BF は次のように出力します。
a
ASCIIa
の 10 進コードは97
.
たとえば、次のような BF プログラム (97 プラス 2 ドット):
++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++++..
ポイントするセルの値を最大 97 まで増やし、2 回出力します。
ああ
4.ループ
BF では、ループは loop begin[
と loop endで構成されます]
。条件が実際のセル値である C/C++ のようなものだと考えることができます。
以下の BF プログラムをご覧ください。
++[]
++
実際のセル値を 2 回インクリメントします。
...[0][0][*2*][0][0]...
そしての[]
ようなものなwhile(2) {}
ので、無限ループです。
このループを無限にしたくないとしましょう。たとえば、次のことができます。
++[-]
したがって、ループがループするたびに、実際のセル値が減少します。実際のセル値が0
ループ終了になると:
...[0][0][*2*][0][0]... loop starts
...[0][0][*1*][0][0]... after first iteration
...[0][0][*0*][0][0]... after second iteration (loop ends)
有限ループのさらに別の例を考えてみましょう:
++[>]
この例は、ループが開始されたセルでループを終了する必要がないことを示しています。
...[0][0][*2*][0][0]... loop starts
...[0][0][2][*0*][0]... after first iteration (loop ends)
ただし、開始した時点で終了することをお勧めします。なんで ?ループが開始された別のセルを終了する場合、セルポインターがどこにあるかを推測できないためです。正直なところ、この練習により、ブレインファックはブレインファックが少なくなります。