b8abbfd02f
frontend/backend distinction or use of standard model)
136 lines
4.1 KiB
Rust
136 lines
4.1 KiB
Rust
#[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<String> {
|
|
let stack = "0x10000";
|
|
let acc = "acc";
|
|
let rga = "rga";
|
|
|
|
let bpr = "bpr";
|
|
let spr = "spr";
|
|
let mut instrs = Vec::<String>::new();
|
|
|
|
// Define symbols
|
|
let print_start = "print";
|
|
|
|
let tokens = lex(src);
|
|
|
|
let mut idstack = Vec::<u32>::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<String>) {
|
|
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<BfToken> {
|
|
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)
|
|
}
|