~tmpod/brainfucc

025a886ec78f63108793c46f5131abcacce2dd80 — tmpod 1 year, 5 months ago c1289aa
Tidy up code and prepare for LC3 backend
3 files changed, 54 insertions(+), 56 deletions(-)

M src/compiler.rs
M src/interpreter.rs
M src/main.rs
M src/compiler.rs => src/compiler.rs +49 -52
@@ 17,70 17,67 @@ pub enum BrainfuckInstruction {
}

#[derive(Debug)]
pub struct CompiledBrainfuck {
pub struct BrainfuckIR {
    pub name: Option<String>,
    pub instructions: Vec<BrainfuckInstruction>,
    pub jumps: HashMap<usize, usize>,
    pub comments: String,
}

pub fn compile_into_tuple(
    source: &str,
) -> (Vec<BrainfuckInstruction>, HashMap<usize, usize>, String) {
    let mut instructions = Vec::new();
    let mut jumps = HashMap::new();
    let mut jump_stack = Vec::new();
    let mut comments = String::new();
impl BrainfuckIR {
    pub fn parse(source: &str) -> Self {
        use BrainfuckInstruction::*;

    for c in source.chars() {
        let inst = match c {
            '<' => BrainfuckInstruction::RGT,
            '>' => BrainfuckInstruction::LFT,
            '+' => BrainfuckInstruction::INC,
            '-' => BrainfuckInstruction::DEC,
            '.' => BrainfuckInstruction::OUT,
            ',' => BrainfuckInstruction::INP,
            '[' => {
                jump_stack.push(instructions.len());
                BrainfuckInstruction::JMP
            }
            ']' => {
                let open = jump_stack.pop().unwrap();
                jumps.insert(open, instructions.len());
                jumps.insert(instructions.len(), open);
                BrainfuckInstruction::RET
            }
            _ => {
                comments.push(c);
        let mut instructions = Vec::new();
        let mut jumps = HashMap::new();
        let mut jump_stack = Vec::new();
        let mut comments = String::new();

        for c in source.chars() {
            let inst = match c {
                '<' => RGT,
                '>' => LFT,
                '+' => INC,
                '-' => DEC,
                '.' => OUT,
                ',' => INP,
                '[' => {
                    jump_stack.push(instructions.len());
                    JMP
                }
                ']' => {
                    let open = jump_stack.pop().expect("Closing bracket with no opening");
                    jumps.insert(open, instructions.len());
                    jumps.insert(instructions.len(), open);
                    RET
                }
                _ => {
                    comments.push(c);
                    continue;
                }
            };

            // Tiny optimization I suppose
            if let Some(BrainfuckInstruction::INP) = instructions.last() {
                continue;
            }
        };
        instructions.push(inst);
    }

    (instructions, jumps, comments)
}
            instructions.push(inst);
        }

pub fn compile(source: &str) -> CompiledBrainfuck {
    let compiled = compile_into_tuple(source);
    CompiledBrainfuck {
        name: Option::None,
        instructions: compiled.0,
        jumps: compiled.1,
        comments: compiled.2,
        BrainfuckIR {
            name: None,
            instructions,
            jumps,
            comments,
        }
    }
}

pub fn compile_from_string(source: String) -> CompiledBrainfuck {
    compile(source.as_str())
}

pub fn compile_named(source: &str, name: &str) -> CompiledBrainfuck {
    let compiled = compile_into_tuple(source.into());
    CompiledBrainfuck {
        name: Option::Some(name.into()),
        instructions: compiled.0,
        jumps: compiled.1,
        comments: compiled.2,
    pub fn parse_named(source: &str, name: &str) -> Self {
        let ir = Self::parse(source);
        BrainfuckIR {
            name: Some(name.to_string()),
            ..ir
        }
    }
}

M src/interpreter.rs => src/interpreter.rs +3 -3
@@ 1,7 1,7 @@
use std::io::Read;

use crate::compiler::Word;
use crate::compiler::{BrainfuckInstruction, CompiledBrainfuck};
use crate::compiler::{BrainfuckIR, BrainfuckInstruction};

const DEFAULT_TAPE_SIZE: usize = 30_000;



@@ 9,7 9,7 @@ type InputHook = fn() -> Word;
type OutputHook = fn(Word) -> ();

pub fn execute(
    compiled: CompiledBrainfuck,
    compiled: BrainfuckIR,
    tape_size: usize,
    input_hook: InputHook,
    output_hook: OutputHook,


@@ 78,7 78,7 @@ pub fn default_output_hook(out: u8) {
    print!("{}", out as char);
}

pub fn execute_default(compiled: CompiledBrainfuck) {
pub fn execute_default(compiled: BrainfuckIR) {
    execute(
        compiled,
        DEFAULT_TAPE_SIZE,

M src/main.rs => src/main.rs +2 -1
@@ 6,13 6,14 @@ use std::io::Read;
mod cli;
mod compiler;
mod interpreter;
mod lc3;

fn main() -> Result<(), Box<dyn Error>> {
    let mut src_file = File::open(env::args().skip(1).next().expect("Missing source filename"))?;
    let mut src = String::new();
    src_file.read_to_string(&mut src).unwrap();

    let compiled = crate::compiler::compile_from_string(src);
    let compiled = crate::compiler::BrainfuckIR::parse(src.as_str());
    eprintln!("Compiled: {:?}", compiled);
    crate::interpreter::execute_default(compiled);