Crates.io | bfcore |
lib.rs | bfcore |
version | 0.2.0 |
source | src |
created_at | 2019-08-13 23:33:15.28037 |
updated_at | 2019-08-14 01:59:06.820826 |
description | An interpreter for BrainF*ck without std or alloc |
homepage | https://github.com/adam-mcdaniel/bfcore |
repository | https://github.com/adam-mcdaniel/bfcore |
max_upload_size | |
id | 156629 |
size | 15,006 |
An interpreter for BrainF*ck without std or alloc.
Now you can run brainf*ck on any hardware you want. This library doesn't even require a memory allocator!
Here's the smallest example of how you'd run brainf*ck using bfcore.
extern crate bfcore;
use bfcore::{Interpreter, Input, Output};
#[derive(Default)]
struct In; impl Input for In {}
#[derive(Default)]
struct Out; impl Output for Out {}
fn main() {
Interpreter::new(
"+[----->+++<]>+.---.+++++++..+++.",
&mut In::default(),
&mut Out::default()
).run();
}
That doesn't really show you much, though.
Let me be more clear.
extern crate bfcore;
use bfcore::{Interpreter, Input, Output};
#[derive(Default)]
struct In;
impl Input for In {
fn input(&mut self) -> char {
// When the interpreter needs user input, return EOF, or '\0'
'\0'
}
}
#[derive(Default)]
struct Out;
impl Output for Out {
fn output(&mut self, ch: char) {
// When the interpreter wants to output, print the output character
print!("{}", ch);
}
}
fn main() {
Interpreter::new(
"+[----->+++<]>+.---.+++++++..+++.",
&mut In::default(),
&mut Out::default()
).run();
}
The Input
trait allows you to provide input to the interpreter, and the Output
trait allows it to output to where ever you'd like.
You can also have the input and output objects maintain states, like a buffer.
extern crate bfcore;
use bfcore::{Input, Interpreter, Output};
use std::io::stdin;
/// Captures input from commandline as needed.
#[derive(Default)]
struct MyInput { buffer: String }
impl Input for MyInput {
fn input(&mut self) -> char {
// Only get user input if we've run out of characters in our buffer
if self.buffer.is_empty() {
stdin()
.read_line(&mut self.buffer)
.expect("Did not enter a correct string");
}
let result = self.buffer.chars().nth(0);
if !self.buffer.is_empty() {
self.buffer = self.buffer[1..].to_string();
}
match result {
Some(ch) => ch,
None => 0 as char,
}
}
}
#[derive(Default)]
struct MyOutput;
impl Output for MyOutput {
fn output(&mut self, ch: char) {
print!("{}", ch);
}
}
fn main() {
// Create an interpreter with a program that prints hello world
// Give it instances of our input and output structs
Interpreter::new(
r#"+[----->+++<]>+.---.+++++++..+++."#,
&mut MyInput::default(),
&mut MyOutput::default()
).run(); // Run the interpreter
}
I don't have an example of this, but you could even use outputting non-printable characters to change the states of the input and output objects to do different things. You could have them switch between writing to files or to the screen by outputing special characters to switch modes, and more.