Skip to content

Instantly share code, notes, and snippets.

@sfan5
Last active August 29, 2015 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sfan5/3924c7ac5cf2c0573112 to your computer and use it in GitHub Desktop.
Save sfan5/3924c7ac5cf2c0573112 to your computer and use it in GitHub Desktop.
Brainfuck Interpreter in Rust
use std::error::Error;
use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::io;
use std::env;
fn write_u8<T: io::Write>(mut obj: &mut T, x: u8) {
let mut a: [u8; 1];
a = [x];
obj.write(&a);
}
fn read_u8<T: io::Read>(obj: T) -> u8 {
let a: &mut [u8; 1] = &mut [0];
let mut t;
t = obj.take(1);
t.read(a);
return a[0];
}
fn main() {
let args: Vec<_> = env::args().collect();
if args.len() <= 1 {
println!("Usage: {} <file>", args[0]);
return;
}
let ref arg = args[1];
let mut file = match File::open(arg) {
Err(e) => panic!("Failed to open '{}': {}", arg, e.description()),
Ok(file) => file,
};
let mut prog_s: String = String::new();
match file.read_to_string(&mut prog_s) {
Err(e) => panic!("Failed to read '{}': {}", arg, e.description()),
Ok(a) => a,
};
let prog: &[u8] = prog_s.as_bytes();
let mut stdin = io::stdin();
let mut stdout = io::stdout();
let mut tape: [u8; 16384];
tape = [0; 16384];
let mut i: usize = 0;
let mut p: usize = 0;
let mut parens_bal: i16 = 0;
let mut mode: u8 = 0;
// Mode 0: standard mode, move forward and execute commands
// Mode 1: move forward ignoring the commands and return to mode 0 when the [ ]'s are balanced again
// Mode 2: move backward ignoring the commands and return to mode 0 when the [ ]'s are balanced again
while i < prog_s.len() {
//println!("i={}, mode={}, parens_bal={}, c='{}'", i, mode, parens_bal, prog[i] as char);
if mode == 0 {
match prog[i] as char {
'>' => p += 1,
'<' => p -= 1,
'+' => tape[p] = (tape[p] + 1) % 0xff,
'-' => tape[p] = (tape[p] - 1) % 0xff,
'.' => write_u8(&mut stdout, tape[p]),
',' => tape[p] = read_u8(&mut stdin),
'[' if tape[p] == 0 => {
mode = 1;
parens_bal = 1; // We start after the [ we just matched
},
']' if tape[p] != 0 => {
mode = 2;
parens_bal = 0;
i -= 1; // Start at the ] not the next char
},
_ => {},
}
i += 1;
} else if mode == 1 {
match prog[i] as char {
'[' => parens_bal += 1,
']' => parens_bal -= 1,
_ => {},
}
i += 1;
if parens_bal < 0 {
panic!("Unbalanced parentheses(extranous ]) in '{}' at char {}", arg, i);
} else if parens_bal == 0 {
mode = 0;
}
} else if mode == 2 {
match prog[i] as char {
'[' => parens_bal += 1,
']' => parens_bal -= 1,
_ => {},
}
if parens_bal > 0 {
panic!("Unbalanced parentheses(extranous [) in '{}' at char {}", arg, i);
} else if parens_bal == 0 {
mode = 0;
i += 1; // Start after the matching [
} else {
i -= 1;
}
} else {
panic!("Internal error: mode not 0, 1 or 2");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment