assembler changes & brainf##k compiler lmao
This commit is contained in:
@@ -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),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user