*Brainf*ck [#f7d1af24] #contents *はじめに [#o7747c97] なんか、Brainf*ckのページでも作ってみようかなーなんて。~ いっしょに楽しく学びましょう。 *言語の特徴 [#gbc97476] 命令が8つしかない。以下は[[Wikipedia:http://ja.wikipedia.org/wiki/Brainfuck]]からの引用。~ +> ポインタをインクリメントする。ポインタをptrとすると、C言語の「ptr++;」に相当する。 + < ポインタをデクリメントする。C言語の「ptr--;」に相当。 + + ポインタが指す値をインクリメントする。C言語の「(*ptr)++;」に相当。 + - ポインタが指す値をデクリメントする。C言語の「(*ptr)--;」に相当。 + . ポインタが指す値を出力する。C言語の「putchar(*ptr);」に相当。 + , 1バイトを入力してポインタが指す値に代入する。C言語の「*ptr=getchar();」に相当。 + [ ポインタが指す値が0なら、対応する ] までジャンプする。C言語の「while(*ptr){」に相当。 + ] ポインタが指す値が0でないなら、対応する [ にジャンプする。C言語の「}」に相当。 *処理系 [#qc72773f] [[The Brainfuck Archive:http://esoteric.sange.fi/brainfuck/]]の、 impl/compilers/BF2C.c を保存します。~ ~ BF2C.cをCのコンパイラでコンパイルすると、BrainfuckのソースをCのソースに変換してくれるプログラムができあがるので、~ Cに変換されたソースをもう一度Cコンパイラでコンパイルして実行してください。~ こんな感じ。~ ~ program.bf ー(BF2C.exe)→ program.c ー(Cコンパイラ)→ program.exe~ ~ また impl/interp/ 以下にインタープリタもあるようなので、UNIX系OSではそちらを使って #!/usr/bin/bfi などとした方がラクでしょう。 *断り書き [#j7103556] 以下、このコーナーでは「メモリに先頭からa, b, c, d, … と値がはいっており、ポインタは先頭から3番を指している」という状態を、 [a][b][c][d]… ↑ と書くことにします。~ ~ また、メモリのn番目を指したいとき、矢印の横に (n) と表記します。~ 例えば「メモリの99番目から順に e, f, g, h, … と値がはいっており、ポインタは先頭から100番目を指している」という状態を、 …[e][f][g][h]… ↑(100) と表します。~ (追記してくださる方はこのルールに従うか、独自の書き方をする場合はその見方を書いてくださるとありがたいです。) *Hello, World! [#jb4847a8] さて、Wikipediaの[[Hello worldプログラムの一覧:http://ja.wikipedia.org/wiki/Hello_world%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%AE%E4%B8%80%E8%A6%A7]]に、こんなコードが載っております。~ +++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-. ------------.<++++++++.--------.+++.------.--------.>+. これを実行するとたしかに Hello, world! と表示されますが、最初はわけがわからないのでちょっと解説を。~ ~ まず一つ目の +++++++++ ですが、これは次の [ ] ループのためのループ回数の設定です。これを念頭に置いてコードを読むと良く分かります。~ ~ 次に [ がありますが、今ポインタの内容は最初に9まで増やしたので、0ではありません。従って ] までジャンプはせずに、中に入ります。~ そして >++++++++>+++++++++++>+++++<<<- が実行され、メモリの内容は [8][8][11][5][0][0]… ↑ となります。~ ~ [ ] ループはメモリの先頭のが0になるまで(つまり9回)繰り返され、ループが終わった時点でメモリの内容は [0][72][99][45][0][0]… ↑ となります。~ ~ あとは勝手に横から書き換えてみる。 -先ず、"Hello"の出力について。 --右にポインタを移動して72(H の文字コード)を出力。 --もう一度右に移動すると99(c の文字コード)が入っているので文字コードを2足して101(e)を出力。 --7足して108(l)を2回出力。 --3足して111(o)を出力。 -次に、", "の出力について。 --一つ右にポインタを移動すると45(- の文字コード)が入っているので1引いて44(,)を出力。 --12引いて32( (空白))を出力。 -更に、"world"(Worldにあらず)の出力について。 --一つ左にポインタを戻し、8足して119(w)を出力。 --8引いて111(o)を出力。 --3足して114(r)を出力。 --6引いて108(l)を出力。 --8引いて100(d)を出力。 -最後に、"!"(感嘆符)の出力について。 --一つ右にポインタを移動してから1足して、33(!)を出力。 ~ この段階でメモリの内容は [0][72][100][33][0][0]… ↑ となります。 *if構文 [#pc01092f] 続くとか言っておきながら続く気配がないので勝手に横から書いてみる。 入力した文字が「@」かどうか判別する。 >,<++++++++[>--------<-]>>+<[>]>[~~@の場合>>]<<<[~~@ではない場合[-]] では先頭から説明していきます。 >, [0][s][0][0][0] ↑ 仮に入力された文字コードをsとしておきます。一番左のメモリは次に使うので空けています。 <++++++++[>--------<-]> 先ほど空けた一番左のメモリに戻って8を足し0になるまで1を引いて右のメモリから8を引きます。ループが終わり>が実行されると [0][s-64][0][0][0] ↑ となります。 >+< [0][s-64][1][0][0] ↑ [>] sが64(@)の時、s-64=0なので、 [0][0][1][0][0] ↑ なにも起きません。 sが64以外(@ではない)時、s-64≠0なので、 [0][s-64][1][0][0] ↑(4) 結果2つ右にポインタが移動します。 > さらに一つ右に移動するので、 sが64の時 [0][s-64][1][0][0] ↑ sが64以外の時 [0][s-64][1][0][0] ↑(5) ポインタが指す値はs==64?1:0となりました。 [~~@の場合>>] ここで[ ]が来ると、sが64ではない時何も起こらず sが64の時だけ中が実行されます。 文字を出力する、という文を書く場合はメモリの(1)~(5)を弄ったり変更しないように注意してください。[]内の最後に>>を付けてるのはポインタを(5)に移動させる、という意味です。 これは、sが64ではない時、つまり[]内を実行しない場合の結果とポインタが同じ位置に持ってこれるのと、さらに、ポインタ(5)の値は0のはずなのでループを一回に抜けることができます。 [0][s-64][1][0][0] ↑(5) sが64かどうかにかかわらず結果こうなります。 さらに <<< [0][s-64][1][0][0] ↑(1) sが64ではない時、ポインタが指す値は0ではないので [~~@ではない場合[-]] []内を実行できます。C言語等のelse {~~}に相当します。[]内の最後に[-]を付けているのは、ループを抜けるためにメモリの値を0にする、という意味です。ですので場合によっては必要ないかもしれません。 *Brainf*ck系言語 [#z8e76b58] Brainf*ckの性質上、 [ や . などを別の文字列と置き換えることによって、 簡単に別の言語(俺言語)ができてしまう。ここではその一部を紹介しておこう。 -[[プログラミング言語 長門有希:http://not6.blog.shinobi.jp/Entry/103/]] --…,「」および任意の命令区切りを使ってプログラムする言語。 --例えば 「………。…。…。…。…。…。…。…。…。…………。……長門有希」こんな風に。 --でも実態はただの BrainF*ck なのでまともなものはできそうにない。 -[[neko mimi Fu**:http://d.hatena.ne.jp/tokuhirom/20041015/p14]] --ネコミミ!ネコミミモードキス…したくなっちゃった…おにいさま私のしもべーや・く・そ・く・よフルフルフルムーン キスキス…