library now
This commit is contained in:
parent
cf59d6f88c
commit
dd9a0c6f4e
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal 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
11
demo.asm
Normal 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
|
40
src/asm.rs
40
src/asm.rs
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
|
@ -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")
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue