Cerate the base yoooo 🥰💙
This commit is contained in:
parent
ac4932fc62
commit
67667d9cb9
5 changed files with 181 additions and 14 deletions
|
@ -1,4 +1,4 @@
|
|||
use clap::{arg, Parser};
|
||||
use clap::{arg, Parser, ValueEnum};
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, about, long_about = None, version)]
|
||||
|
@ -7,9 +7,22 @@ pub struct Args {
|
|||
#[arg(short, long)]
|
||||
pub verbose: bool,
|
||||
/// The brainfuck source code file to run (if not will be entered in REPL mode)
|
||||
#[arg(short, long, default_value = None)]
|
||||
#[arg(default_value = None)]
|
||||
pub source: Option<String>,
|
||||
#[arg(short, long, default_value = None)]
|
||||
pub features: Option<Vec<Feature>>,
|
||||
/// The brainfuck array size
|
||||
#[arg(short, long, default_value = "30000")]
|
||||
pub array_size: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Copy, Clone, ValueEnum)]
|
||||
pub enum Feature {
|
||||
/// If the value is you want decrement the value and the value is 0, set the value to 255, otherwise decrement the value.
|
||||
/// If the value is you want increment the value and the value is 255, set the value to 0, otherwise increment the value.
|
||||
ReverseCounter,
|
||||
/// If the pointer at the end of the array, set the pointer to 0, otherwise increment the pointer.
|
||||
/// If the pointer at the beginning of the array, set the pointer to the end of the array, otherwise decrement the pointer.
|
||||
ReversePointer,
|
||||
|
||||
}
|
|
@ -1,3 +1,112 @@
|
|||
pub fn run(bf_code: String, bf_arr_size: usize) {
|
||||
use std::io::{Read, Write};
|
||||
use std::usize;
|
||||
use crate::arguments;
|
||||
|
||||
pub struct Interpreter {
|
||||
pub array: Vec<u8>,
|
||||
pub pointer: usize,
|
||||
pub array_size: usize,
|
||||
pub bf_code: String,
|
||||
pub brackets: Vec<BfCommand>,
|
||||
pub features: Vec<arguments::Feature>,
|
||||
}
|
||||
impl Interpreter {
|
||||
pub fn new(array_size: usize,
|
||||
bf_code: Option<String>,
|
||||
features: Vec<arguments::Feature>) -> Self {
|
||||
Self {
|
||||
array: vec![0; array_size],
|
||||
pointer: 0,
|
||||
array_size,
|
||||
bf_code: bf_code.unwrap_or_else(|| String::new()),
|
||||
brackets: Vec::new(),
|
||||
features,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(&mut self, bf_code: Option<String>) {
|
||||
let mut cells = vec![0u8; bf_arr_size];
|
||||
let mut ptr = 0;
|
||||
let mut brackets = vec![];
|
||||
|
||||
for (i, ch) in bf_code.chars().enumerate() {
|
||||
trace!("Current character: {}", ch);
|
||||
trace!("Current pointer: {}", ptr);
|
||||
trace!("Current cell: {}", cells[ptr]);
|
||||
|
||||
match BfCommand::from_char(ch, i) {
|
||||
Some(cmd) => {
|
||||
trace!("Executing command: {:?}", cmd);
|
||||
match cmd {
|
||||
BfCommand::IncPtr => {
|
||||
if ptr == bf_arr_size - 1 {
|
||||
eprintln!("Error: pointer out of bounds");
|
||||
} else {
|
||||
ptr += 1;
|
||||
}
|
||||
},
|
||||
BfCommand::DecPtr => ptr -= 1,
|
||||
BfCommand::IncVal => {
|
||||
cells[ptr] += 1
|
||||
},
|
||||
BfCommand::DecVal => cells[ptr] -= 1,
|
||||
BfCommand::Print => {
|
||||
trace!("Printing value: {}", cells[ptr]);
|
||||
println!("{}", cells[ptr]);
|
||||
std::io::stdout().flush().unwrap();
|
||||
},
|
||||
BfCommand::Read => cells[ptr] = std::io::stdin()
|
||||
.bytes().next().unwrap().unwrap() as u8,
|
||||
BfCommand::LoopStart(index) => brackets.push(cmd),
|
||||
BfCommand::LoopEnd => {
|
||||
if cells[ptr] != 0 {
|
||||
let i = brackets
|
||||
.iter()
|
||||
.map(|cmd| match cmd {
|
||||
BfCommand::LoopStart(index) => *index,
|
||||
_ => unreachable!()
|
||||
})
|
||||
.last();
|
||||
brackets.truncate(i);
|
||||
ptr = index;
|
||||
} else {
|
||||
brackets.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
None => {
|
||||
trace!("Ignoring character: {}", ch);
|
||||
} // Ignore unknown characters
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum BfCommand {
|
||||
IncPtr,
|
||||
DecPtr,
|
||||
IncVal,
|
||||
DecVal,
|
||||
Print,
|
||||
Read,
|
||||
LoopStart(usize),
|
||||
LoopEnd,
|
||||
}
|
||||
|
||||
impl BfCommand {
|
||||
fn from_char(c: char, index: usize) -> Option<BfCommand> {
|
||||
match c {
|
||||
'>' => Some(BfCommand::IncPtr),
|
||||
'<' => Some(BfCommand::DecPtr),
|
||||
'+' => Some(BfCommand::IncVal),
|
||||
'-' => Some(BfCommand::DecVal),
|
||||
'.' => Some(BfCommand::Print),
|
||||
',' => Some(BfCommand::Read),
|
||||
'[' => Some(BfCommand::LoopStart(index)),
|
||||
']' => Some(BfCommand::LoopEnd),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
48
src/main.rs
48
src/main.rs
|
@ -1,11 +1,13 @@
|
|||
mod arguments;
|
||||
mod interpreter;
|
||||
mod utils;
|
||||
|
||||
use clap::Parser;
|
||||
extern crate pretty_env_logger;
|
||||
#[macro_use] extern crate log;
|
||||
|
||||
use arguments::Args;
|
||||
use utils::;
|
||||
|
||||
fn main() {
|
||||
pretty_env_logger::init();
|
||||
|
@ -18,23 +20,47 @@ fn main() {
|
|||
info!("Verbose mode enabled");
|
||||
}
|
||||
|
||||
info!("Initializing interpreter");
|
||||
let mut interpreter = interpreter::Interpreter::new(
|
||||
args.array_size,
|
||||
urils::read_brainfuck_code_if_any(args.source),
|
||||
args.features.unwrap_or_else(|| vec![]));
|
||||
|
||||
match args.source {
|
||||
Some(source) => {
|
||||
info!("Running brainfuck source code from file: {}", source);
|
||||
interpreter::run(
|
||||
match std::fs::read_to_string(source) {
|
||||
Ok(source) => source,
|
||||
Err(e) => {
|
||||
error!("Failed to read source code file: {}", e);
|
||||
eprintln!("Failed to read source code file: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
},
|
||||
args.array_size
|
||||
)
|
||||
interpreter.run(None)
|
||||
},
|
||||
None => {
|
||||
info!("Entering REPL mode");
|
||||
println!("Welcome to the brainfuck REPL mode! :)");
|
||||
println!("Enter your brainfuck code and press enter to run it.");
|
||||
println!("Enter !fuck to exit :D");
|
||||
println!("Enter !help fuck to get more help");
|
||||
|
||||
loop {
|
||||
let mut input = String::new();
|
||||
std::io::stdin().read_line(&mut input).unwrap();
|
||||
if input.starts_with("!") {
|
||||
match input.trim() {
|
||||
"!fuck" => {
|
||||
println!("Bye bye :D");
|
||||
break;
|
||||
},
|
||||
"!help" => {
|
||||
println!("!fuck: exit the REPL mode");
|
||||
println!("!array, !a: print the current array");
|
||||
println!("!array_size, !as: print the current array size");
|
||||
println!("!pointer, !p: print the current pointer value");
|
||||
println!("!history: print the history of the commands");
|
||||
println!("!help: show this fu*king help message");
|
||||
},
|
||||
_ => println!("Unknown command: {}, type !help to show the help", input.trim())
|
||||
}
|
||||
} else {
|
||||
interpreter.run(Some(input));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
18
src/utils.rs
Normal file
18
src/utils.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
fn read_brainfuck_code_if_any(source: Option<String>) -> Option<String> {
|
||||
match source {
|
||||
Some(source) => {
|
||||
info!("Reading brainfuck source code from file: {}", source);
|
||||
match std::fs::read_to_string(source) {
|
||||
Ok(source) => Some(source),
|
||||
Err(e) => {
|
||||
error!("Failed to read source code file: {}", e);
|
||||
eprintln!("Failed to read source code file: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
},
|
||||
None => {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
1
test_code/print_hi.bf
Normal file
1
test_code/print_hi.bf
Normal file
|
@ -0,0 +1 @@
|
|||
>+++++++++[<++++ ++++>-]<.>++++++++[<++++>-]<+.>+++++++++[<-------->-]<.
|
Loading…
Reference in a new issue