commit
060e00daff
3 changed files with 162 additions and 0 deletions
@ -0,0 +1,10 @@
|
||||
[package] |
||||
name = "brainfuck" |
||||
version = "0.1.0" |
||||
edition = "2021" |
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
||||
|
||||
[dependencies] |
||||
clap = { version = "3.2.17", features = ["derive"] } |
||||
atty = "0.2.14" |
@ -0,0 +1,149 @@
|
||||
use clap::CommandFactory; |
||||
use clap::Parser; |
||||
use std::io::Write; |
||||
use std::{path::PathBuf, io::{self, Read, BufReader, BufRead}}; |
||||
|
||||
#[derive(Parser, Debug)] |
||||
#[clap(author, version, about, long_about = None)] |
||||
struct Args { |
||||
#[clap(value_parser, value_name = "FILE")] |
||||
file: Option<PathBuf>, |
||||
|
||||
#[clap(short, long, action)] |
||||
interactive: bool, |
||||
|
||||
#[clap(short, long, action)] |
||||
verbose: bool, |
||||
} |
||||
|
||||
fn main() -> Result<(), io::Error> { |
||||
//clap magic
|
||||
let args = Args::parse(); |
||||
let mut cmd = Args::command(); |
||||
|
||||
let mut reader: Box<dyn BufRead> = match &args.file { |
||||
None => { |
||||
if atty::is(atty::Stream::Stdin) && !args.interactive { |
||||
//special case when there is no piped file
|
||||
//and --interactive is not specified
|
||||
//display the help and exit
|
||||
cmd.print_help()?; |
||||
return Ok(()); |
||||
} |
||||
Box::new(BufReader::new(io::stdin())) |
||||
}, |
||||
Some(filepath) => Box::new(BufReader::new(std::fs::File::open(filepath)?)) |
||||
}; |
||||
|
||||
//init
|
||||
let actions = std::collections::HashSet::from(['>', '<', '+', '-', '.', ',', '[', ']']); |
||||
let mut memory = [0_u8; 30000]; |
||||
let mut pointer = 0; |
||||
let mut instructions_str: String = "".into(); |
||||
let mut i = 0; //instructions index
|
||||
|
||||
if args.interactive && args.file.is_some() { |
||||
reader.read_to_string(&mut instructions_str)?; |
||||
reader = Box::new(BufReader::new(io::stdin())); |
||||
} else if !args.interactive { |
||||
reader.read_to_string(&mut instructions_str)?; |
||||
}
|
||||
|
||||
loop { |
||||
//filtering instructions to only contain brainfuck code (optimization)
|
||||
let instructions = instructions_str.chars() |
||||
.filter(|c| actions.contains(c)) |
||||
.collect::<Vec<char>>(); |
||||
|
||||
'reading_instructions: while i < instructions.len() { |
||||
match instructions[i] { |
||||
'>' => pointer += 1, |
||||
'<' => pointer -= 1, |
||||
'+' => memory[pointer] += 1, |
||||
'-' => memory[pointer] -= 1, |
||||
'.' => print!("{}", memory[pointer] as char), |
||||
',' => { |
||||
let mut input = "".into(); |
||||
print!("Enter input (one byte only): "); |
||||
io::stdout().flush()?; |
||||
let mut handle = io::stdin().lock(); |
||||
handle.read_line(&mut input)?; |
||||
|
||||
if input.len() > 0 { |
||||
memory[pointer] = input.chars().nth(0).unwrap() as u8; |
||||
} |
||||
}, |
||||
'[' =>
|
||||
if memory[pointer] == 0 { |
||||
let mut pile = 1; |
||||
while i < instructions.len() && pile != 0 { |
||||
i += 1; |
||||
|
||||
match instructions[i] { |
||||
'[' => pile += 1, |
||||
']' => pile -= 1, |
||||
_ => () |
||||
} |
||||
} |
||||
} |
||||
']' =>
|
||||
if memory[pointer] != 0 { |
||||
let mut pile = 1; |
||||
while i > 0 { |
||||
match instructions[i-1] { |
||||
']' => pile += 1, |
||||
'[' => pile -= 1, |
||||
_ => () |
||||
} |
||||
|
||||
if pile == 0 { break; } |
||||
i -= 1; |
||||
} |
||||
continue 'reading_instructions; |
||||
} |
||||
|
||||
_ => () |
||||
} |
||||
|
||||
i += 1; |
||||
} |
||||
|
||||
if args.verbose || args.interactive { |
||||
print_mem(&memory); |
||||
println!("pointer: {} (0x{:02x})", &pointer, &memory[pointer]); |
||||
println!(); |
||||
} |
||||
|
||||
if !args.interactive { break; } |
||||
|
||||
print!("~ "); |
||||
io::stdout().flush()?; |
||||
reader.read_line(&mut instructions_str)?; |
||||
} |
||||
|
||||
Ok(()) |
||||
} |
||||
|
||||
fn print_mem(memory: &[u8]) { |
||||
let mut i = 0; |
||||
let mut s = String::new(); |
||||
let mut z_counter = 0; |
||||
let z_limit = 3; |
||||
|
||||
while i < memory.len() { |
||||
if memory[i] == 0 { |
||||
z_counter += 1; |
||||
} else { |
||||
z_counter = 0; |
||||
} |
||||
if z_counter == z_limit { |
||||
s += ".. "; |
||||
|
||||
} else if z_counter < z_limit { |
||||
s += &format!("{:02x} ", memory[i]); |
||||
} |
||||
i += 1; |
||||
} |
||||
println!(); |
||||
println!("-- memory (hex) --\n{}", s); |
||||
} |
Loading…
Reference in new issue