#Brainf*ckとは
以下の命令によって動く言語です。
>
ポインタをインクリメントする。ポインタをptrとすると、C言語の「ptr++;
」に相当する。<
ポインタをデクリメントする。C言語の「ptr--;
」に相当。+
ポインタが指す値をインクリメントする。C言語の「(*ptr)++;
」に相当。-
ポインタが指す値をデクリメントする。C言語の「(*ptr)--;
」に相当。.
ポインタが指す値を出力に書き出す。C言語の「putchar(*ptr);
」に相当。,
入力から1バイト読み込んで、ポインタが指す先に代入する。C言語の「*ptr=getchar();
」に相当。[
ポインタが指す値が0なら、対応する]
の直後にジャンプする。C言語の「while(*ptr){
」に相当。]
ポインタが指す値が0でないなら、対応する[
(の直後[1])にジャンプする。C言語の「}
」に相当[2]。
(引用: Wikipedia Brainfuck)
使用する命令が8個しかないのが非常に特徴的ですね。
では、実装していきましょう。
#ソースコード(Visual C++)
Source.cpp
#include <cstdio>
#include <cstdint>
#include <string>
int main(int argc, char *argv[])
{
//ファイルが指定されていない時のエラー処理
if (argc != 2) {
std::printf("開くファイルを指定してください。\n");
return -1;
}
//ファイルが開けない時のエラー処理
std::FILE *fp = nullptr;
if (fopen_s(&fp, argv[1], "r")) {
std::printf("ファイルを開くことが出来ません。\n");
return -1;
}
//コードを読み取って格納
char read_char;
std::string code{};
while ((read_char = std::fgetc(fp)) != EOF) {
code.push_back(read_char);
}
std::fclose(fp);
//コードを処理
constexpr std::size_t buffer_size = 30000;
char buffer[buffer_size]{};
std::size_t buffer_ptr = 0;
std::int_fast32_t loop = 0;
const std::size_t code_len = code.size();
for (std::size_t code_ptr = 0; code_ptr < code_len; ++code_ptr) {
switch (code[code_ptr]) {
case '>':++buffer_ptr; break;
case '<':--buffer_ptr; break;
case '+':++buffer[buffer_ptr]; break;
case '-':--buffer[buffer_ptr]; break;
case '.':std::putchar(buffer[buffer_ptr]); break;
case ',':buffer[buffer_ptr] = std::getchar(); break;
case '[':
if (buffer[buffer_ptr] != 0) break;
for (++code_ptr; loop > 0 || code[code_ptr] != ']'; ++code_ptr) {
if (code[code_ptr] == '[') ++loop;
if (code[code_ptr] == ']') --loop;
}
break;
case ']':
if (buffer[buffer_ptr] == 0) break;
for (--code_ptr; loop > 0 || code[code_ptr] != '['; --code_ptr) {
if (code[code_ptr] == ']') ++loop;
if (code[code_ptr] == '[') --loop;
}
--code_ptr;
break;
}
}
return 0;
}
#ソースコード(その他 C++)
Source.cpp
#include <cstdio>
#include <cstdint>
#include <string>
int main(int argc, char *argv[])
{
//ファイルが指定されていない時のエラー処理
if (argc != 2) {
std::printf("開くファイルを指定してください。\n");
return -1;
}
//ファイルが開けない時のエラー処理
std::FILE *fp = nullptr;
if ((fp = std::fopen(argv[1], "r")) == nullptr) {
std::printf("ファイルを開くことが出来ません。\n");
return -1;
}
//コードを読み取って格納
char read_char;
std::string code{};
while ((read_char = std::fgetc(fp)) != EOF) {
code.push_back(read_char);
}
std::fclose(fp);
//コードを処理
constexpr std::size_t buffer_size = 30000;
char buffer[buffer_size]{};
std::size_t buffer_ptr = 0;
std::int_fast32_t loop = 0;
const std::size_t code_len = code.size();
for (std::size_t code_ptr = 0; code_ptr < code_len; ++code_ptr) {
switch (code[code_ptr]) {
case '>':++buffer_ptr; break;
case '<':--buffer_ptr; break;
case '+':++buffer[buffer_ptr]; break;
case '-':--buffer[buffer_ptr]; break;
case '.':std::putchar(buffer[buffer_ptr]); break;
case ',':buffer[buffer_ptr] = std::getchar(); break;
case '[':
if (buffer[buffer_ptr] != 0) break;
for (++code_ptr; loop > 0 || code[code_ptr] != ']'; ++code_ptr) {
if (code[code_ptr] == '[') ++loop;
if (code[code_ptr] == ']') --loop;
}
break;
case ']':
if (buffer[buffer_ptr] == 0) break;
for (--code_ptr; loop > 0 || code[code_ptr] != '['; --code_ptr) {
if (code[code_ptr] == ']') ++loop;
if (code[code_ptr] == '[') --loop;
}
--code_ptr;
break;
}
}
return 0;
}
#出力
h.bf
+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.
------------.<++++++++.--------.+++.------.--------.>+.
出力
$ brainc.exe h.bf
Hello, World!
#他言語での実装
コンパイラ・インタプリタ、ともに載せています。
Rust >> brainf*ck
Javascript >> シラミ騒動で Brainf**k
D言語 >> D言語でBrainf
C# >> Brainf*ck .NET
Ruby >> Brainfck | RubyでBrainfckのコードを生成する
Ruby >> brainf*ckを書いてみた
JavaScript >> Node.jsでPEG.jsでBrainf*ck
C >> c言語でBrainf*ckインタプリタ
D >> D言語でBrainf*ckコンパイル時コンパイラを作ろう
JavaScript >> JavaScriptでBrainF*ckインタプリタを実装する
解説 >> 今すぐBrainf*ckを始めるべき10の理由
##ソースコードのライセンス
These codes are licensed under CC0.
ソースコードは自由に使用してください。