wrote interpreter source code
This commit is contained in:
+96
-2
@@ -1,3 +1,97 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
use anyhow::Result;
|
||||
use anyhow::anyhow;
|
||||
use std::collections::HashMap;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::fs;
|
||||
fn clean_code(code: &str) -> Vec<char> {
|
||||
let vec: Vec<char> = code.chars().collect();
|
||||
let clean = vec
|
||||
.into_iter()
|
||||
.filter(|b| "+-<>,.[]".contains(*b))
|
||||
.collect();
|
||||
clean
|
||||
}
|
||||
fn precompute_jump_table(code: &[char]) -> Result<HashMap<usize, usize>> {
|
||||
let mut jump_table = HashMap::new();
|
||||
let mut stack = Vec::new();
|
||||
for (i, &char) in code.iter().enumerate() {
|
||||
if char == '[' {
|
||||
stack.push(i);
|
||||
} else if char == ']' {
|
||||
match stack.pop() {
|
||||
Some(start_index) => {
|
||||
jump_table.insert(start_index, i);
|
||||
jump_table.insert(i, start_index);
|
||||
}
|
||||
None => {
|
||||
return Err(anyhow!("miss matching closing brackets at index {}", i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !stack.is_empty() {
|
||||
return Err(anyhow!("open brackets unclosed"));
|
||||
}
|
||||
Ok(jump_table)
|
||||
}
|
||||
fn execute(raw_code: &str) -> Result<()> {
|
||||
let clean = clean_code(raw_code);
|
||||
let jump_table = precompute_jump_table(&clean)?;
|
||||
let mut tape: [u8; 30000] = [0; 30000];
|
||||
let mut data_ptr: usize = 0;
|
||||
let mut exec_ptr: usize = 0;
|
||||
while exec_ptr < clean.len() {
|
||||
let cmd = clean[exec_ptr];
|
||||
match cmd {
|
||||
'+' => {
|
||||
tape[data_ptr] = tape[data_ptr].wrapping_add(1);
|
||||
}
|
||||
'-' => {
|
||||
tape[data_ptr] = tape[data_ptr].wrapping_sub(1);
|
||||
}
|
||||
'>' => {
|
||||
data_ptr += 1;
|
||||
if data_ptr > 29999 {
|
||||
data_ptr = 0;
|
||||
}
|
||||
}
|
||||
'<' => {
|
||||
if data_ptr == 0 {
|
||||
data_ptr = 29999;
|
||||
}
|
||||
else {
|
||||
data_ptr -= 1;
|
||||
}
|
||||
}
|
||||
',' => {
|
||||
let mut buf = [0; 1];
|
||||
if io::stdin().read_exact(&mut buf).is_ok() {
|
||||
tape[data_ptr] = buf[0];
|
||||
}
|
||||
}
|
||||
'.' => {
|
||||
print!("{}", tape[data_ptr] as char);
|
||||
let _ = io::stdout().flush();
|
||||
}
|
||||
'[' => {
|
||||
if tape[data_ptr] == 0 {
|
||||
exec_ptr = *jump_table.get(&exec_ptr).unwrap();
|
||||
}
|
||||
}
|
||||
']' => {
|
||||
if tape[data_ptr] != 0 {
|
||||
exec_ptr = *jump_table.get(&exec_ptr).unwrap();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
exec_ptr += 1;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn main() -> Result<()> {
|
||||
let code_path = std::env::args().nth(1).ok_or_else(|| anyhow!("Usage: bf <path to file.bf>"))?;
|
||||
let code = fs::read_to_string(&code_path)?;
|
||||
execute(&code)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user