Last active
August 29, 2015 14:05
-
-
Save sfan5/3924c7ac5cf2c0573112 to your computer and use it in GitHub Desktop.
Brainfuck Interpreter in Rust
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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