mirror of
https://github.com/Noratrieb/brainfuck.git
synced 2026-01-16 06:15:02 +01:00
rename a bunch of stuff
This commit is contained in:
parent
ddf2686049
commit
5fc5c49dff
10 changed files with 252 additions and 215 deletions
139
rust2/src/lir/interpreter.rs
Normal file
139
rust2/src/lir/interpreter.rs
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
use std::{
|
||||
io::{Read, Write},
|
||||
num::Wrapping,
|
||||
};
|
||||
|
||||
use crate::lir::{Lir, Stmt};
|
||||
|
||||
const MEM_SIZE: usize = 32_000;
|
||||
|
||||
type Memory = [Wrapping<u8>; MEM_SIZE];
|
||||
|
||||
// `repr(C)` to make sure rustc never reorders the fields weirdly
|
||||
// maybe useless, but seems to give tiny wins
|
||||
#[repr(C)]
|
||||
struct Interpreter<'c, W, R, P> {
|
||||
code: &'c Lir<'c>,
|
||||
profile_collector: P,
|
||||
ip: usize,
|
||||
ptr: usize,
|
||||
mem: Memory,
|
||||
stdout: W,
|
||||
stdin: R,
|
||||
}
|
||||
|
||||
pub fn run<W, R, P>(code: &Lir<'_>, stdout: W, stdin: R, profile_collector: P)
|
||||
where
|
||||
W: Write,
|
||||
R: Read,
|
||||
P: FnMut(usize),
|
||||
{
|
||||
let mut interpreter = Interpreter {
|
||||
code,
|
||||
ip: 0,
|
||||
ptr: 0,
|
||||
stdout,
|
||||
stdin,
|
||||
mem: [Wrapping(0u8); MEM_SIZE],
|
||||
profile_collector,
|
||||
};
|
||||
|
||||
// SAFETY: `Lir` can only be produced by the `crate::lir` module, which is trusted to not
|
||||
// produce out of bounds jumps and put the `End` at the end
|
||||
unsafe {
|
||||
interpreter.execute();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'c, W: Write, R: Read, P> Interpreter<'c, W, R, P>
|
||||
where
|
||||
P: FnMut(usize),
|
||||
{
|
||||
unsafe fn execute(&mut self) {
|
||||
let stmts = self.code.stmts();
|
||||
loop {
|
||||
// SAFETY: If the code ends with an `End` and there are no out of bounds jumps,
|
||||
// `self.ip` will never be out of bounds
|
||||
// Removing this bounds check speeds up execution by about 40%
|
||||
debug_assert!(self.ip < stmts.len());
|
||||
let instr = unsafe { *stmts.get_unchecked(self.ip) };
|
||||
self.ip += 1;
|
||||
match instr {
|
||||
Stmt::Add(n) => {
|
||||
*self.elem_mut() += n;
|
||||
}
|
||||
Stmt::Sub(n) => {
|
||||
*self.elem_mut() -= n;
|
||||
}
|
||||
Stmt::AddOffset { offset, n } => *self.elem_mut_offset(offset) += n,
|
||||
Stmt::SubOffset { offset, n } => *self.elem_mut_offset(offset) -= n,
|
||||
Stmt::MoveAddTo { offset } => {
|
||||
let value = self.elem();
|
||||
*self.elem_mut() = Wrapping(0);
|
||||
*self.elem_mut_offset(offset) += value;
|
||||
}
|
||||
Stmt::Right(n) => {
|
||||
self.ptr += n as usize;
|
||||
if self.ptr >= MEM_SIZE {
|
||||
self.ptr = 0;
|
||||
}
|
||||
}
|
||||
Stmt::Left(n) => {
|
||||
if self.ptr < n as usize {
|
||||
let diff = n as usize - self.ptr;
|
||||
self.ptr = MEM_SIZE - 1 - diff;
|
||||
} else {
|
||||
self.ptr -= n as usize;
|
||||
}
|
||||
}
|
||||
Stmt::Out => {
|
||||
let char = self.elem() as char;
|
||||
write!(self.stdout, "{char}").unwrap();
|
||||
self.stdout.flush().unwrap();
|
||||
}
|
||||
Stmt::In => {
|
||||
let mut buf = [0; 1];
|
||||
self.stdin.read_exact(&mut buf).unwrap();
|
||||
*self.elem_mut() = Wrapping(buf[0]);
|
||||
}
|
||||
Stmt::SetN(n) => {
|
||||
*self.elem_mut() = Wrapping(n);
|
||||
}
|
||||
Stmt::JmpIfZero(pos) => {
|
||||
if self.elem() == 0 {
|
||||
self.ip = pos as usize;
|
||||
}
|
||||
}
|
||||
Stmt::JmpIfNonZero(pos) => {
|
||||
if self.elem() != 0 {
|
||||
self.ip = pos as usize;
|
||||
}
|
||||
}
|
||||
Stmt::End => break,
|
||||
}
|
||||
|
||||
// this should be a no-op if `profile_collector` is does nothing
|
||||
(self.profile_collector)(self.ip);
|
||||
}
|
||||
}
|
||||
|
||||
fn elem_mut_offset(&mut self, offset: i32) -> &mut Wrapping<u8> {
|
||||
let ptr = self.ptr as isize;
|
||||
let offset = offset as isize;
|
||||
// SAFETY: `self.ptr` is never out of bounds
|
||||
debug_assert!(self.ptr < self.mem.len());
|
||||
unsafe { self.mem.get_unchecked_mut((ptr + offset) as usize) }
|
||||
}
|
||||
|
||||
fn elem_mut(&mut self) -> &mut Wrapping<u8> {
|
||||
// SAFETY: `self.ptr` is never out of bounds
|
||||
debug_assert!(self.ptr < self.mem.len());
|
||||
unsafe { self.mem.get_unchecked_mut(self.ptr) }
|
||||
}
|
||||
|
||||
fn elem(&self) -> u8 {
|
||||
// SAFETY: `self.ptr` is never out of bounds
|
||||
debug_assert!(self.ptr < self.mem.len());
|
||||
unsafe { self.mem.get_unchecked(self.ptr).0 }
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue