Cerate the base yoooo 🥰💙

This commit is contained in:
Anas Elgarhy 2022-10-07 21:54:49 +02:00
parent ac4932fc62
commit 67667d9cb9
5 changed files with 181 additions and 14 deletions

View file

@ -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,
}

View file

@ -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,
}
}
}

View file

@ -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
View 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
View file

@ -0,0 +1 @@
>+++++++++[<++++ ++++>-]<.>++++++++[<++++>-]<+.>+++++++++[<-------->-]<.