この記事はたまたま集まった技術&もの作りが好きな人たち Advent Calendar 2019の20日目の記事です。
#はじめに
みなさんこんにちは!プログラミングが大好きな@saba383810です。
私は今までにc言語やc++、Rustなどの言語をやってきたのですがこれらの言語をやる上でいろいろな人に「ポインタが分からんからおしえてくれ。」と言われることが多いです。今回はそんな人たちにポインタを使用した言語を紹介したいと思います。この記事を読んで少しでもおもしろいなと思ってくれればいいな〜〜
注意 : 今回紹介する言語は実用的な言語ではないので趣味のひとつとして楽しんでください!
Brainfuckとは
まず「Brainfuck」とは難解プログラミングの一種でUrban Müllerさんがコンパイラのなるべく小さい言語として考案したプログラミング言語で、コンパイラのサイズは240バイト
とても小さいのです。
さらにチューリング完全なので理論上なんでもできます。理論上は....
またBrainfuckでは文字コードの中でもASCIIコード表を参照して文字を出力していくのでBrainfuckを本気でやろうと思っている人はASCIIコード表をみながらコードを書いていきましょう!!
#言語仕様
まずは以下の表に目を通してください。c言語をやっている人なら右のc言語の例がわかりやすいと思います。
記号 | 説明 | c言語(例) |
---|---|---|
> | ポインタをインクリメントする(ポインタを右に移動) | ptr++; |
< | ポインタをインクリメントする(ポインタを左に移動) | ptr--; |
+ | ポインタの示す値をインクリメントするポインタを | (*ptr)++; |
- | ポインタの示す値をデクリメントする | (*ptr)-- |
. | 現在のポインタを出力 | putchar(*ptr); |
, | 現在のポインタに1バイト分代入する | *ptr=getchar() |
[ | ポインタが指す値が0なら、対応する ] の直後にジャンプする。 | while(*ptr){ |
] | ポインタが指す値が0でないなら、対応する [ | } |
brainfuckでのプログラムは
- ポインタをインクリメントする。
+
- 出力する。
.
- ポインタを右に移動する。
>
の1~3の繰り返しだけでも実は成り立ちます。しかしこれだけの命令でプログラムを書こうとするととてつもない量の+
命令が必要になります。そこで他の文字を使い記述量を減らしていきます。brainfuckってすばらしいでしょ??
言語使用についてもっとくわしいことが知りたいよという方もいるかもしれませんが記述量的に割愛させてもらうのでそういう方はGitHubやwikipediaを覗いてみるといいかも!
実行環境
ここからは実際に手を動かしてやっていきましょう!
まずターミナル上に以下のコマンドを入力してインストールします。
Macの場合
macにHomebrewが入っていないという方はこちらからインストールして以下を入力してください。
$ brew install brainfuck
Linuxの場合
他のディストリビューションを使用している人は各自のパッケージマネージャでbrainfuckをインストールしてください。
ubuntuの例
$ sudo apt-get install bf
インストール完了!!これであなたもbrainfucker!!!
#開発準備
インストールが完了したらまずは作業用ディレクトリをつくりますよね!
私は他のプログラムとのファイルがごちゃごちゃになるのが嫌いなのでディレクトリごとに分けますが「そんなんいらねぇぇ」って方は飛ばしてもらって大丈夫です笑
$ mkdir brainfuck //brainfuck用のディレクトリを作成します。
$ cd brainfuck //brainfuck用ディレクトリに移動
HelloWorld!
プログラムの最初と言えば「HelloWorld!」ですよね!まずはサンプルコードを打ち込んでみましょう。
「なんじゃこりゃ!!」って感じかもしれないですが説明は後ほどするので
作成したディレクトリ上にtest.bf
というファイルを作成し以下のコードを入力!
++++++++++[>+++>+++++++>++++++++++>+++++++++>+++++++++++>++++++++++<<<<<<-]
>>++.>+.+++++++..+++.<<++.>>>---.<.>>++++.<<---.>>>.
Macの場合
$ brainfuck test.bf
Hello World
ubunutuの場合
$ bf test.bf
Hello World
正常に動作すればhelloworld
と表示されたと思います。
macの場合にはbrainfuck
というコマンドですがubuntuなどの場合はbf
なので注意してください。
説明
実行はできたけどよくわからんって人が大半だと思うので少し説明を入れようと思います。
まずはこのGIFを見てください。赤い矢印がポインタのさしている位置で「0」が入っている箱の値がポインタの値です。
このGIFのようにHello
のH
が出したかったらASCIIコード表を参照しポインタの値を72になるまでインクリメントしてあげ、e
,l
,l
,o
も順番に右にシフトしてインクリメントを繰り返し表示してあげればよいのです。
ここまで説明すればもうbrainfuckを書くことができます!しかしこのままでは効率の悪いプログラムになってしまいます。
そこでまだ登場していない[]
で繰り返し処理をしてbrainfuckの文字を短縮してみましょう。!
繰り返し処理
次は以下の表の繰り返し処理について話していきます。
記号 | 説明 | c言語(例) |
---|---|---|
[ | ポインタが指す値が0なら、対応する ] の直後にジャンプする。 | while(*ptr){ |
] | ポインタが指す値が0でないなら、対応する [ | } |
ジャンプすると書いてあるとわかりづらいですね。
実はめちゃくちゃ単純で[
が読まれたタイミングでさしているポインタの値の回数[]
の中を繰り返すという処理になります。試しに以下のプログラムをみてください!
+++[>+<-]>. //3回[]の中を繰り返すので3
++++[>++<-]>. //4回[]の中を繰り返すので8
+++[>+++-<-]>. //3回[]の中を繰り返すので6
注意: 上記のコードはあくまで理解しやすいように噛み砕いて書いたものなので実行しても数字が表示されるわけではありませんm(_ _)m
入出力
次は以下の入力と出力についてやっていきましょう!
記号 | 説明 | c言語(例) |
---|---|---|
. | 現在のポインタを出力 | putchar(*ptr); |
, | 現在のポインタに1バイト分代入する | *ptr=getchar() |
以下のコードは5つの値を入力させ出力するコードです。
,>,>,>,>,<<<<.>.>.>.>.
これは一つずつポインタに値を代入させたあと、最初のポインタに戻り一つずつ出力させています。
これもわかりやすいですよね!
あとは言語仕様をみながら自分で思考錯誤しながらいろいろなプログラムを作ってみてください。
まとめ
ここまでやってきてどうでしたか?
この記事を読んでみなさんのbrainfuckライフの一歩目になってくれていたら嬉しいです。
ここまで読んだくれたあなたは今こう思っているはずです。
『b r a i n f u c k 完 全 に 理 解 し た。』
#参考にしたサイト
- GitHub
https://github.com/fabianishere/brainfuck - wikipedia
https://ja.wikipedia.org/wiki/Brainfuck - braifuckのトレースについてとてもわかりやすく書いてあります。
https://www.narupi.net/2018/12/05/brainfuck/