assembler changes & brainf##k compiler lmao

This commit is contained in:
2025-06-22 03:51:16 +01:00
parent 528ceddade
commit 9c56258c48
10 changed files with 731 additions and 154 deletions
+298
View File
@@ -0,0 +1,298 @@
use std::{
fs,
path::{self, Path},
};
use common::prelude::{Instruction, Register};
use crate::{
assembler::{
Module, Node, Opcode, Symbol, Token, codegen, create_sections, expand_pseudo_ops,
resolve_symbols,
},
node,
};
pub fn build(src: &Path) -> Vec<Instruction> {
let src = fs::read_to_string(src).unwrap();
let mut nodes = parse(src);
// we need to expand pseudoinstructions etc now
nodes = expand_pseudo_ops(nodes, 0).unwrap();
create_sections(&mut nodes).unwrap();
for n in nodes.iter() {
println!("{}", n);
}
resolve_symbols(&mut nodes).unwrap();
codegen(nodes).unwrap()
}
pub fn parse(src: String) -> Vec<Node> {
let stack = Token::Immediate(0x10000);
let acc = Token::Register(Register::Acc);
let rga = Token::Register(Register::Rga);
let bpr = Token::Register(Register::Bpr);
let spr = Token::Register(Register::Spr);
let mut nodes = Vec::<Node>::new();
// Define symbols
let print_start = Symbol {
name: "print".to_string(),
module: Module::Resolved(0),
};
let tokens = lex(src);
let mut id = 0;
let mut idstack = Vec::<u32>::new();
nodes.extend(vec![
// set up a stack
node!(None, Opcode::Lwi, stack, bpr),
node!(None, Opcode::Mov, bpr, spr),
// set up the data pointer
node!(
Some(Symbol {
name: "main".to_string(),
module: Module::Resolved(0)
}),
Opcode::Lwi,
Token::Immediate(0x30000),
rga
),
]);
for (id, tok) in tokens.iter().enumerate() {
match tok {
BfToken::Inc => {
// inc acc
nodes.extend(vec![node!(None, Opcode::Inc, acc)]);
}
BfToken::Dec => {
// dec acc
nodes.extend(vec![node!(None, Opcode::Dec, acc)]);
}
BfToken::IncPtr => {
// stb acc, rga
// add rga, 4
// ldb rga, acc
nodes.extend(vec![
node!(None, Opcode::Stw, acc, rga, 0),
node!(None, Opcode::AddI, rga, 4, rga),
node!(None, Opcode::Ldw, rga, acc, 0),
]);
}
BfToken::DecPtr => {
// stb acc, rga
// sub rga, 4
// ldb rga, acc
nodes.extend(vec![
node!(None, Opcode::Stw, acc, rga, 0),
node!(None, Opcode::SubI, rga, 4, rga),
node!(None, Opcode::Ldw, rga, acc, 0),
]);
}
BfToken::Out => {
// push rga
// call print
// pop zero
nodes.extend(vec![
node!(None, Opcode::Push, acc),
node!(None, Opcode::Call, Token::Symbol(print_start.clone())),
node!(None, Opcode::Pop, Token::Register(Register::Zero)),
]);
}
BfToken::In => {
// Read a byte from input and store it at the current data pointer
// Assuming we have an input function mapped to a specific memory location or I/O port
nodes.extend(vec![
// Read input (assuming input is mapped to memory address 0x40000)
node!(None, Opcode::Ldw, Token::Immediate(0x40000), acc, 0),
// Store the input byte at the current data pointer
]);
}
BfToken::Forward => {
// Start of loop [
let loop_start = format!("loop_start_{}", id);
let loop_end = format!("loop_end_{}", id);
// Push the current position for the matching ]
idstack.push(id as u32);
// Load current cell value and check if zero
nodes.extend(vec![
// Compare with zero
node!(None, Opcode::Cmp, acc, Token::Register(Register::Zero)),
// If zero, jump to end of loop
node!(
None,
Opcode::Jeq,
Token::Symbol(Symbol {
name: loop_end,
module: Module::Resolved(0),
}),
Token::Register(Register::Zero)
),
]);
// Add label for loop start
nodes.push(node!(
Some(Symbol {
name: loop_start,
module: Module::Resolved(0),
}),
Opcode::Nop
));
}
BfToken::Back => {
// End of loop ]
if let Some(start_id) = idstack.pop() {
let loop_start = format!("loop_start_{}", start_id);
let loop_end = format!("loop_end_{}", start_id);
// Jump back to the start of the loop
nodes.extend(vec![
// Compare with zero
node!(None, Opcode::Cmp, acc, Token::Register(Register::Zero)),
// If not zero, jump back to start of loop
node!(
None,
Opcode::Jne,
Token::Symbol(Symbol {
name: loop_start,
module: Module::Resolved(0),
}),
Token::Register(Register::Zero)
),
// Add label for loop end
node!(
Some(Symbol {
name: loop_end,
module: Module::Resolved(0),
}),
Opcode::Nop
),
]);
} else {
// Unmatched closing bracket - could add error handling here
eprintln!("Warning: Unmatched ']' at position {}", id);
}
}
}
}
nodes.push(node!(None, Opcode::Hlt));
insert_lib(&mut nodes);
nodes
}
fn insert_lib(nodes: &mut Vec<Node>) {
let bpr = Token::Register(Register::Bpr);
let spr = Token::Register(Register::Spr);
let rg0 = Token::Register(Register::Rg0);
let rg1 = Token::Register(Register::Rg1);
let print_start = Symbol {
name: "print".to_string(),
module: Module::Resolved(0),
};
let current = Symbol {
name: "current".to_string(),
module: Module::Resolved(0),
};
// set up the program framework.
nodes.extend(vec![
// set display to 0x20000
node!(
None,
Opcode::Dw,
Token::Symbol(current.clone()),
Token::Immediate(0x20000)
),
// print function
// initialisation
node!(Some(print_start.clone()), Opcode::Push, bpr.clone()),
node!(None, Opcode::Mov, spr.clone(), bpr.clone()),
// function body
node!(
None,
Opcode::Ldw,
bpr.clone(),
rg0.clone(),
Token::Immediate(8)
),
node!(
None,
Opcode::Ldw,
Token::Symbol(current.clone()), // Load address of current
rg1.clone(),
Token::Immediate(0)
),
node!(
None,
Opcode::Stb,
rg0.clone(),
rg1.clone(),
Token::Immediate(0)
),
node!(
None,
Opcode::AddI,
rg1.clone(),
Token::Immediate(1),
rg1.clone()
),
// function return according to spec.
node!(
None,
Opcode::Stw,
rg1.clone(),
Token::Symbol(current.clone()), // Store back to current
Token::Immediate(0)
),
node!(None, Opcode::Mov, bpr.clone(), spr.clone()),
node!(None, Opcode::Pop, bpr.clone()),
node!(None, Opcode::Return),
]);
}
enum BfToken {
Inc,
Dec,
IncPtr,
DecPtr,
Out,
In,
Forward,
Back,
}
fn lex(src: String) -> 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) -> Symbol {
Symbol {
name: format!("label_{}", id),
module: Module::Resolved(0),
}
}