Created
July 5, 2019 12:57
-
-
Save WarpspeedSCP/038672749c3f7bc0d939cf1c2a72929b to your computer and use it in GitHub Desktop.
A brainfuck interpreter in rust. Takes input from stdin.
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::env::args; | |
use std::io::{stdin, Read, BufRead}; | |
use std::u8; | |
use std::fmt::{self, Display}; | |
struct BFVM { | |
data: Box<u8>, | |
instr_data: Vec<u8>, | |
loop_stack: u32, | |
data_ptr: usize, | |
instr_ptr: usize, | |
run: bool, | |
} | |
impl fmt::Display for BFVM { | |
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
write!(f, "data: {:#?}\ndata ptr: {}\ninstruction ptr: {}\nloop stack: {}", &self.data[..10], self.data_ptr, self.instr_ptr, self.loop_stack) | |
} | |
} | |
impl BFVM { | |
pub fn new(program: String) -> Self { | |
BFVM { | |
data: box![0u8 ; 0x1000], | |
instr_data: program.into_bytes(), | |
data_ptr: 0, | |
instr_ptr: 0, | |
loop_stack: 0, | |
run: true, | |
} | |
} | |
pub fn step(&mut self, input: &mut std::io::StdinLock) { | |
if self.instr_ptr == self.instr_data.len() - 1 { | |
println!("\nreached end of program."); | |
self.run = false; | |
return; | |
} | |
match self.instr_data[self.instr_ptr] as char { | |
'>' => { | |
self.data_ptr = (self.data_ptr + 1) % self.data.len(); | |
}, | |
'<' => { | |
if self.data_ptr > 0 { | |
self.data_ptr -= 1; | |
} else { | |
self.data_ptr = self.data.len() - 1; | |
} | |
}, | |
'+' => { | |
self.data[self.data_ptr] = self.data[self.data_ptr].overflowing_add(1).0; | |
}, | |
'-' => { | |
self.data[self.data_ptr] = self.data[self.data_ptr].overflowing_sub(1).0; | |
}, | |
'.' => { | |
if self.data[self.data_ptr].is_ascii_whitespace() || !self.data[self.data_ptr].is_ascii_control() { | |
print!("{}", self.data[self.data_ptr] as char); | |
} else { | |
println!("{}", self.data[self.data_ptr]); | |
}// | |
}, | |
',' => { | |
match input.read_exact(&mut self.data[self.data_ptr..self.data_ptr + 1]) { | |
Ok(_) => {}, | |
Err(w) => println!("{:#?}", w) | |
} | |
}, | |
'[' => { | |
self.loop_stack += 1; | |
if self.data[self.data_ptr] == 0 { | |
let curr_stack = self.loop_stack; | |
while self.instr_ptr < self.instr_data.len() && self.loop_stack >= curr_stack { | |
self.instr_ptr += 1; | |
match self.instr_data[self.instr_ptr] as char { | |
'[' => { | |
self.loop_stack += 1; | |
}, | |
']' => { | |
self.loop_stack -= 1 | |
}, | |
'\0' => panic!(), | |
_ => {} | |
}; | |
} | |
} | |
}, | |
']' => { | |
if self.data[self.data_ptr] > 0 { | |
let curr_stack = self.loop_stack; | |
while self.instr_ptr > 0 && self.loop_stack >= curr_stack { | |
self.instr_ptr -= 1; | |
match self.instr_data[self.instr_ptr] as char { | |
'[' => { | |
self.loop_stack -= 1; | |
}, | |
']' => { | |
self.loop_stack += 1 | |
}, | |
_ => {} | |
}; | |
} | |
self.loop_stack += 1; | |
} else { | |
self.loop_stack -= 1; | |
} | |
}, | |
_ => {} | |
}; | |
self.instr_ptr += 1; | |
} | |
} | |
fn main() { | |
let std_in = stdin(); | |
let mut input = std_in.lock(); | |
let mut strng = String::new(); | |
input.read_line(&mut strng).unwrap(); | |
let mut vm = BFVM::new(strng); | |
while vm.run { | |
vm.step(&mut input); | |
} | |
} | |
// borrowed hello world | |
//++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++. | |
// Print 3 1's and 3 0's | |
// +.>+.>+.[-.<] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment