Files
rbfckr/src/machine.rs

117 lines
3.1 KiB
Rust

use std::io::{BufReader, BufWriter, Read, Write};
#[derive(Debug)]
pub enum InstructionType {
Increment,
Decrement,
Leftshift,
Rightshift,
PutChar,
GetChar,
JumpIfZero,
JumpIfNotZero,
}
#[derive(Debug)]
pub struct Instruction {
pub itype: InstructionType,
pub argument: usize,
}
pub struct Machine<'a> {
ip: usize,
mp: usize,
buf: [u8; 1],
memory: [u32; 50000],
code: Vec<Instruction>,
input: &'a mut BufReader<Box<dyn Read>>,
output: &'a mut BufWriter<Box<dyn Write>>,
}
impl<'a> Machine<'a> {
pub fn new(code: Vec<Instruction>, input: &'a mut BufReader<Box<dyn Read>>, output: &'a mut BufWriter<Box<dyn Write>>) -> Self {
Machine {
ip: 0,
mp: 0,
buf: [0; 1],
memory: [0; 50000],
code,
input,
output,
}
}
pub fn execute(&mut self){
// prevent ip from getting out of bounds
while self.ip < self.code.len() {
// get current instruction
let instruction = &self.code[self.ip];
// match type and execute
match instruction.itype {
InstructionType::Increment => {
self.memory[self.mp] += instruction.argument as u32
}
InstructionType::Decrement => {
self.memory[self.mp] -= instruction.argument as u32
}
InstructionType::Leftshift => {
self.mp += instruction.argument
}
InstructionType::Rightshift => {
self.mp -= instruction.argument
}
InstructionType::PutChar => {
for _ in 0..instruction.argument {
self.put_char()
}
}
InstructionType::GetChar => {
for _ in 0..instruction.argument {
self.get_char()
}
}
InstructionType::JumpIfZero => {
if self.memory[self.mp] == 0 {
self.ip = instruction.argument;
continue;
}
}
InstructionType::JumpIfNotZero => {
if self.memory[self.mp] != 0 {
self.ip = instruction.argument;
continue;
}
}
}
}
}
pub fn get_char(&mut self){
let byte_input = match self.input.read(&mut self.buf) {
Ok(byte_input) => byte_input,
Err(e) => panic!(e),
};
if byte_input != 1 {
panic!("input read error")
}
self.memory[self.mp] = self.buf[0] as u32;
}
pub fn put_char(&mut self){
self.buf[0] = self.memory[self.mp] as u8;
let byte_write = match self.output.write(&self.buf) {
Ok(byte_write) => byte_write,
Err(e) => panic!(e),
};
if byte_write != 1 {
panic!("output write error")
}
self.output.flush();
}
}