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)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(author, about, long_about = None, version)]
|
#[command(author, about, long_about = None, version)]
|
||||||
|
@ -7,9 +7,22 @@ pub struct Args {
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
pub verbose: bool,
|
pub verbose: bool,
|
||||||
/// The brainfuck source code file to run (if not will be entered in REPL mode)
|
/// 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>,
|
pub source: Option<String>,
|
||||||
|
#[arg(short, long, default_value = None)]
|
||||||
|
pub features: Option<Vec<Feature>>,
|
||||||
/// The brainfuck array size
|
/// The brainfuck array size
|
||||||
#[arg(short, long, default_value = "30000")]
|
#[arg(short, long, default_value = "30000")]
|
||||||
pub array_size: usize,
|
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 arguments;
|
||||||
mod interpreter;
|
mod interpreter;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
extern crate pretty_env_logger;
|
extern crate pretty_env_logger;
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
|
|
||||||
use arguments::Args;
|
use arguments::Args;
|
||||||
|
use utils::;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
pretty_env_logger::init();
|
pretty_env_logger::init();
|
||||||
|
@ -18,23 +20,47 @@ fn main() {
|
||||||
info!("Verbose mode enabled");
|
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 {
|
match args.source {
|
||||||
Some(source) => {
|
Some(source) => {
|
||||||
info!("Running brainfuck source code from file: {}", source);
|
info!("Running brainfuck source code from file: {}", source);
|
||||||
interpreter::run(
|
interpreter.run(None)
|
||||||
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
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
info!("Entering REPL mode");
|
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