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 log::*;
/// Assembler
@ -9,8 +8,25 @@ pub enum AsmError {
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> {
debug!("Parsing {} as number", input);
if let Ok(n) = input.parse::<Word>() {
return Ok(n);
}
@ -21,7 +37,6 @@ fn parse_num(input: &str) -> Result<Word, AsmError> {
}
fn parse_op(input: &str) -> Result<Word, AsmError> {
debug!("Parsing {} as opcode", input);
let op = match input {
"push" => OpKind::Push,
"pop" => OpKind::Pop,
@ -54,7 +69,7 @@ fn parse_op(input: &str) -> Result<Word, AsmError> {
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 split = input.split_whitespace();
@ -62,7 +77,10 @@ pub fn assemble(input: &str) -> Result<Vec<Word>, AsmError> {
for part in split {
// If just parsed op, next should be num
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 word = (op << 64) | num;
output.push(word);
@ -72,12 +90,18 @@ pub fn assemble(input: &str) -> Result<Vec<Word>, AsmError> {
if let Ok(op) = parse_op(part) {
last = Some(op);
} else {
output.push(parse_num(part)?);
output.push(parse_num(part).map_err(|kind| TaggedAsmError {
kind,
word: part.to_string(),
})?);
}
}
}
if last.is_some() {
Err(AsmError::ExpectedNum)
if let Some(l) = last {
Err(TaggedAsmError {
kind: AsmError::ExpectedNum,
word: l.to_string(),
})
} else {
Ok(output)
}

View file

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

View file

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