library now

This commit is contained in:
voidNUL 2024-02-25 07:20:44 -06:00
parent cf59d6f88c
commit dd9a0c6f4e
5 changed files with 107 additions and 50 deletions

7
Cargo.lock generated Normal file
View file

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "forte"
version = "0.1.0"

11
demo.asm Normal file
View file

@ -0,0 +1,11 @@
fun 0
push 2 15 30
dif 5
ret 0
fun 1
push 2 16 4
dif 1
call 0
add 1
exe 0

View file

@ -1,5 +1,4 @@
use crate::{OpKind, Word}; use crate::{OpKind, Word};
use log::*;
/// Assembler /// Assembler
@ -9,8 +8,25 @@ pub enum AsmError {
InvalidOp, InvalidOp,
} }
#[derive(Debug, Clone)]
pub struct TaggedAsmError {
kind: AsmError,
word: String,
}
impl std::fmt::Display for TaggedAsmError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[Assembler] Error parsing token: ")?;
match self.kind {
AsmError::ExpectedNum => {
write!(f, "Expected number, found {}", self.word)
},
AsmError::InvalidOp => write!(f, "Expected opcode, found {}", self.word),
}
}
}
fn parse_num(input: &str) -> Result<Word, AsmError> { fn parse_num(input: &str) -> Result<Word, AsmError> {
debug!("Parsing {} as number", input);
if let Ok(n) = input.parse::<Word>() { if let Ok(n) = input.parse::<Word>() {
return Ok(n); return Ok(n);
} }
@ -21,7 +37,6 @@ fn parse_num(input: &str) -> Result<Word, AsmError> {
} }
fn parse_op(input: &str) -> Result<Word, AsmError> { fn parse_op(input: &str) -> Result<Word, AsmError> {
debug!("Parsing {} as opcode", input);
let op = match input { let op = match input {
"push" => OpKind::Push, "push" => OpKind::Push,
"pop" => OpKind::Pop, "pop" => OpKind::Pop,
@ -54,7 +69,7 @@ fn parse_op(input: &str) -> Result<Word, AsmError> {
Ok(op as Word) Ok(op as Word)
} }
pub fn assemble(input: &str) -> Result<Vec<Word>, AsmError> { pub fn assemble(input: &str) -> Result<Vec<Word>, TaggedAsmError> {
let mut last: Option<Word> = None; let mut last: Option<Word> = None;
let split = input.split_whitespace(); let split = input.split_whitespace();
@ -62,7 +77,10 @@ pub fn assemble(input: &str) -> Result<Vec<Word>, AsmError> {
for part in split { for part in split {
// If just parsed op, next should be num // If just parsed op, next should be num
if last.is_some() { if last.is_some() {
let num = parse_num(part)?; let num = parse_num(part).map_err(|kind| TaggedAsmError {
kind,
word: part.to_string(),
})?;
let op = last.take().unwrap(); let op = last.take().unwrap();
let word = (op << 64) | num; let word = (op << 64) | num;
output.push(word); output.push(word);
@ -72,12 +90,18 @@ pub fn assemble(input: &str) -> Result<Vec<Word>, AsmError> {
if let Ok(op) = parse_op(part) { if let Ok(op) = parse_op(part) {
last = Some(op); last = Some(op);
} else { } else {
output.push(parse_num(part)?); output.push(parse_num(part).map_err(|kind| TaggedAsmError {
kind,
word: part.to_string(),
})?);
} }
} }
} }
if last.is_some() { if let Some(l) = last {
Err(AsmError::ExpectedNum) Err(TaggedAsmError {
kind: AsmError::ExpectedNum,
word: l.to_string(),
})
} else { } else {
Ok(output) Ok(output)
} }

View file

@ -5,7 +5,6 @@ mod util;
use op::*; use op::*;
use util::*; use util::*;
use log::*;
pub type Byte = u32; pub type Byte = u32;
pub type Word = u128; pub type Word = u128;
@ -19,6 +18,7 @@ pub struct Machine {
ip: Word, ip: Word,
ebp: Word, ebp: Word,
phase: Phase, phase: Phase,
pub log: String,
pub cstack: Vec<Word>, pub cstack: Vec<Word>,
pub pstack: Vec<Word>, pub pstack: Vec<Word>,
pub fstack: Vec<Word>, pub fstack: Vec<Word>,
@ -32,6 +32,7 @@ impl Machine {
ip: 0, ip: 0,
ebp: 0, ebp: 0,
phase: Phase::Warmup, phase: Phase::Warmup,
log: "".to_string(),
cstack: vec![], cstack: vec![],
pstack: vec![], pstack: vec![],
fstack: vec![], fstack: vec![],
@ -108,18 +109,15 @@ impl Machine {
let word = self let word = self
.instructions .instructions
.get(self.ip as usize) .get(self.ip as usize)
.expect("Ran out of instructions"); .ok_or(Error::NoExec)?;
let instr: Op = match word.try_into() { let instr: Op = match word.try_into() {
Ok(i) => i, Ok(i) => i,
Err(_) => { Err(_) => return Err(Error::IllegalOp),
error!("Invalid opcode: {:#x}", word);
panic!()
},
}; };
debug!( self.log.push_str(&format!(
"[{:?}]{}: {:?} {}", "[{:?}] {}: {:?} {}\n",
self.phase, self.ip, instr.kind, instr.var self.phase, self.ip, instr.kind, instr.var,
); ));
self.ip += 1; self.ip += 1;
match self.phase { match self.phase {
Phase::Warmup => self.step_warmup(instr), Phase::Warmup => self.step_warmup(instr),
@ -135,7 +133,10 @@ impl Machine {
Some(n) => n, Some(n) => n,
None => return Err(Error::StackUnderflow), None => return Err(Error::StackUnderflow),
}; };
debug!("{}: _ {}", self.ip, num); self.log.push_str(&format!(
"[Recital] {}: {} added to stack\n",
self.ip, num
));
self.pstack.push(*num); self.pstack.push(*num);
self.ip += 1; self.ip += 1;
} }
@ -329,9 +330,9 @@ impl Machine {
} }
}, },
OpKind::Exe => { OpKind::Exe => {
// Ignore in execution // Successfully reached end of main!
self.phase = Phase::Recital; self.phase = Phase::Recital;
// TODO: Maybe break program here? return Err(Error::EndReached);
}, },
OpKind::Sto => { OpKind::Sto => {
@ -348,7 +349,10 @@ impl Machine {
}, },
_ => {}, _ => {},
}; };
debug!("{:?}", self.pstack);
self
.log
.push_str(&format!("[STACK]: {:?}\n", self.pstack));
Ok(()) Ok(())
} }
@ -362,6 +366,11 @@ impl Machine {
None => return Err(Error::StackUnderflow), None => return Err(Error::StackUnderflow),
} }
}, },
OpKind::Push => {
for _ in 0..instr.var {
self.ip += 1;
}
},
_ => {}, _ => {},
} }
Ok(()) Ok(())
@ -373,35 +382,39 @@ impl Machine {
} }
Ok(()) Ok(())
} }
pub fn run(&mut self) -> String {
loop {
match self.step() {
Ok(_) => {},
Err(e) => {
if e == Error::EndReached {
self
.log
.push_str(&format!("[BRAVO] Final stack: {:?}\n", self.pstack))
} else {
self.log.push_str(&format!("[CLAM] {}\n", e))
}
return self.log.clone();
},
}
}
}
}
pub fn interpret(program: &str) -> String {
let mut m = Machine::new();
let program = match asm::assemble(program) {
Ok(p) => p,
Err(e) => return format!("{}", e),
};
m.read(program);
let s = m.run();
s
} }
fn main() { fn main() {
flexi_logger::Logger::try_with_str("rh24") let p = include_str!("../demo.asm");
.unwrap() let s = interpret(&p);
.start() println!("{s}");
.unwrap();
let mut m = Machine::new();
// let program = vec![
// //
// Op::new(OpKind::Fun, 0),
// Op::new(OpKind::Push, 2),
// 15,
// 30,
// Op::new(OpKind::Dif, 1),
// Op::new(OpKind::Ret, 0),
// Op::new(OpKind::Fun, 0),
// Op::new(OpKind::Push, 2),
// 16,
// 4,
// Op::new(OpKind::Dif, 1),
// Op::new(OpKind::Call, 0),
// Op::new(OpKind::Add, 1),
// Op::new(OpKind::Exe, 0),
// ];
let program = include_str!("./../demo.asm");
let program = asm::assemble(program).unwrap();
m.read(program);
m.steps(32).unwrap();
println!("RESULT = {:?}", m.pstack);
} }

View file

@ -17,6 +17,7 @@ pub enum Error {
ReadOob, ReadOob,
BadCall, BadCall,
NoExec, NoExec,
IllegalOp,
EndReached, EndReached,
} }
@ -28,6 +29,7 @@ impl Display for Error {
Self::StackUnbalanced => write!(f, "Stack Unbalanced"), Self::StackUnbalanced => write!(f, "Stack Unbalanced"),
Self::WriteOob => write!(f, "Memory write out of bounds"), Self::WriteOob => write!(f, "Memory write out of bounds"),
Self::ReadOob => write!(f, "Memory read out of bounds"), Self::ReadOob => write!(f, "Memory read out of bounds"),
Self::IllegalOp => write!(f, "Illegal instruction reached"),
Self::BadCall => { Self::BadCall => {
write!(f, "Attempted to call function which does not exist") write!(f, "Attempted to call function which does not exist")
}, },