rustの練習がてらbrainf*ckを実装してみた
簡単すぎて練習にならなかったのは内緒
use std::env;
use std::io;
use std::io::Read;
use std::u16;
use std::char;
fn main() {
let mut args = env::args();
if args.len() != 2 {
println!("usage: <expr>");
}
else {
brainfuck(args.nth(1).unwrap());
}
}
fn brainfuck(text: String) {
let bytes = text.as_bytes(); // 扱いやすいように[u8]へ変換
let mut pos: usize = 0; // プログラムの位置
let mut pointer: usize = 0; // brainfuckが保持するポインタ
let mut values: [u32; u16::MAX as usize] = [0; u16::MAX as usize]; // brainfuckが保持する配列
while pos < bytes.len() {
match bytes[pos] {
// ポインタをインクリメント
b'>' => {
pointer += 1;
},
// ポインタをデクリメント
b'<' => {
if pointer > 0 {
pointer -= 1;
}
},
// ポインタが指す値をインクリメント
b'+' => {
values[pointer] += 1;
},
// ポインタが指す値をデクリメントする
b'-' => {
values[pointer] -= 1;
},
// ポインタが指す値を出力に書き出す
b'.' => {
if let Some(c) = char::from_u32(values[pointer]) {
print!("{}", c);
}
else {
print!("?");
}
}
// 入力から1バイト読み込んで、ポインタが指す先に代入する
b',' => {
values[pointer] = io::stdin().bytes().nth(0).unwrap().unwrap() as u32;
}
// ポインタが指す値が0なら、対応する ] の直後にジャンプする
b'[' => {
if values[pointer] == 0 {
let mut level = 0; // ネストした[]に対応するために使用
let mut p = pos;
loop {
p += 1;
if bytes[p] == b'[' {
level += 1;
}
else if bytes[p] == b']' {
if level == 0 {
pos = p;
break;
}
else {
level -= 1;
}
}
}
}
},
// ポインタが指す値が0でないなら、対応する [ の直後にジャンプする
b']' => {
if values[pointer] != 0 {
let mut level = 0; // ネストした[]に対応するために使用
let mut p = pos;
loop {
p -= 1;
if bytes[p] == b']' {
level += 1;
}
else if bytes[p] == b'[' {
if level == 0 {
pos = p;
break;
}
else {
level -= 1;
}
}
}
}
},
// それ以外はエラー
b => {
println!("brainfuck unexpect {}", b);
break;
}
}
// プログラムを進める
pos += 1;
}
}
Hello, world!
ちゃんと動いたよ!よかったね!
cargo run '+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.------------.<++++++++.--------.+++.------.--------.>+.'
Hello, world!