#[must_use] pub fn build(src: &str) -> String { parse(src).join("\n") } #[must_use] #[expect(clippy::too_many_lines)] pub fn parse(src: &str) -> Vec { let stack = "0x10000"; let acc = "acc"; let rga = "rga"; let bpr = "bpr"; let spr = "spr"; let mut instrs = Vec::::new(); // Define symbols let print_start = "print"; let tokens = lex(src); let mut idstack = Vec::::new(); // set up a stack instrs.push(format!("\tlwi {}, {}", stack, bpr)); instrs.push(format!("\tmov {}, {}", bpr, spr)); // set up the data pointer instrs.push(format!("{}: \t lwi 0x30000, {}", "main", rga)); for (id, tok) in tokens.iter().enumerate() { match tok { BfToken::Inc => { instrs.push(format!("\tinc {}", acc)); } BfToken::Dec => { instrs.push(format!("\tdec {}", acc)); } BfToken::IncPtr => { instrs.push(format!("\tstw {}, {}, 0", acc, rga)); instrs.push(format!("\taddi {}, 4, {}", rga, rga)); instrs.push(format!("\tlwd {}, {}, 0", rga, acc)); } BfToken::DecPtr => { instrs.push(format!("\tstw {}, {}, 0", acc, rga)); instrs.push(format!("\tsubi {}, 4, {}", rga, rga)); instrs.push(format!("\tlwd {}, {}, 0", rga, acc)); } BfToken::Out => { instrs.push(format!("\tpush {}", acc)); instrs.push(format!("\tcall {}", print_start)); instrs.push(format!("\tpop zero")); } BfToken::In => { instrs.push(format!("\tlwd 0x40000, {}, 0", acc)); } BfToken::Forward => { let loop_start = format!("loop_start_{}", id); let loop_end = format!("loop_end_{}", id); idstack.push(id as u32); instrs.push(format!("\tcmp {}, zero", acc)); instrs.push(format!("\tjeq {}, zero", loop_end)); instrs.push(format!("{}: \tnop", loop_start)); } BfToken::Back => { if let Some(start_id) = idstack.pop() { let loop_start = format!("loop_start_{}", start_id); let loop_end = format!("loop_end_{}", start_id); instrs.push(format!("\tcmp {}, zero", acc)); instrs.push(format!("\tjne {}, zero", loop_start)); instrs.push(format!("{}: \tnop", loop_end)); } else { eprintln!("Warning: Unmatched ']' at position {}", id); } } } } instrs.push("\thlt".to_string()); insert_lib(&mut instrs); instrs } fn insert_lib(instrs: &mut Vec) { let bpr = "bpr"; let spr = "spr"; let rg0 = "rg0"; let rg1 = "rg1"; let print_start = "print"; let current = "current"; instrs.push(format!("\tdw {}, 0x20000", current)); instrs.push(format!("{}: \tpush {}", print_start, bpr)); instrs.push(format!("\tmov {}, {}", spr, bpr)); instrs.push(format!("\tlwd {}, {}, 8", bpr, rg0)); instrs.push(format!("\tlwd {}, {}, 0", current, rg1)); instrs.push(format!("\tstb {}, {}, 0", rg0, rg1)); instrs.push(format!("\taddi {}, 1, {}", rg1, rg1)); instrs.push(format!("\tstw {}, {}, 0", rg1, current)); instrs.push(format!("\tmov {}, {}", bpr, spr)); instrs.push(format!("\tpop {}", bpr)); instrs.push("\treturn".to_string()); } enum BfToken { Inc, Dec, IncPtr, DecPtr, Out, In, Forward, Back, } fn lex(src: &str) -> Vec { src.chars() .filter_map(|c| match c { '+' => Some(BfToken::Inc), '-' => Some(BfToken::Dec), '>' => Some(BfToken::IncPtr), '<' => Some(BfToken::DecPtr), '.' => Some(BfToken::Out), ',' => Some(BfToken::In), '[' => Some(BfToken::Forward), ']' => Some(BfToken::Back), _ => None, }) .collect() } fn _create_symbol(id: u32) -> String { format!("label_{}", id) }