pub type VM_Word = i64; #[derive(Clone, Copy, Debug)] #[repr(u64)] pub enum VM_Instruction { Nop, Jmp, Call, Branch, Ret, Lit, Dup, Drop, Swap, Rot, Fetch, Store, Accept, Emit, Add, //Sub, Mul, Div, Rem, Addf,//Subf, Mulf, Divf BitwiseNot, } pub struct VM { pub data_stack: Vec< VM_Word >, pub call_stack: Vec< VM_Word >, pub inst_ptr: VM_Word, pub memory: Vec< VM_Word >, } impl VM { pub fn new(memsize: usize) -> Self { VM { data_stack: Vec::new(), call_stack: Vec::new(), inst_ptr: 0, memory: vec![0; memsize] } } pub fn execute(&mut self, entry: VM_Word) { self.inst_ptr = entry; while self.execute_step() {} } pub fn execute_step(&mut self) -> bool { // fetch instruction from memory let inst = unsafe { std::mem::transmute(self.memory[ self.inst_ptr as usize ]) }; self.inst_ptr += 1; // decode instruction & load immediate if neccesary let mut imm : VM_Word = 0; match inst { VM_Instruction::Jmp | VM_Instruction::Call | VM_Instruction::Branch | VM_Instruction::Lit => { imm = self.memory[ self.inst_ptr as usize ]; self.inst_ptr += 1; } _ => {} } // execute instruction self.execute_instruction( inst, imm ) } pub fn execute_instruction(&mut self, inst: VM_Instruction, imm: VM_Word) -> bool { // eprintln!("execute {:?}, {}", inst, imm); match inst { VM_Instruction::Nop => {} VM_Instruction::Lit => { self.data_stack.push( imm ); } VM_Instruction::Jmp => { self.inst_ptr += imm; } VM_Instruction::Call => { self.call_stack.push( self.inst_ptr ); self.inst_ptr = imm; } VM_Instruction::Branch => { if self.data_stack.pop().expect("branch expects val") == 0 { //self.call_stack.push( self.inst_ptr ); self.inst_ptr += imm; } } VM_Instruction::Ret => { if let Some(target) = self.call_stack.pop() { self.inst_ptr = target; } else { return false; } } VM_Instruction::Fetch => { let addr = self.data_stack.pop().expect("fetch requries addr"); let val = self.memory[ addr as usize ]; self.data_stack.push(val); } VM_Instruction::Store => { let addr = self.data_stack.pop().expect("store requires addr"); let val = self.data_stack.pop().expect("store requires val"); self.memory[ addr as usize ] = val; } VM_Instruction::Accept => { // todo: read word from stdin self.data_stack.push(0); } VM_Instruction::Emit => { let val = char::from(self.data_stack.pop().expect("emit expects value") as u8); print!("{}", val); } VM_Instruction::Dup => { self.data_stack.push( *self.data_stack.last().expect("dup expect val") ); } VM_Instruction::Drop => { self.data_stack.pop().expect("drop expects value"); } VM_Instruction::Swap => { let a = self.data_stack.pop().expect("swap expects value"); let b = self.data_stack.pop().expect("swap expects value"); self.data_stack.push(a); self.data_stack.push(b); } VM_Instruction::Rot => { let a = self.data_stack.pop().expect("rot expects value"); let b = self.data_stack.pop().expect("rot expects value"); let c = self.data_stack.pop().expect("rot expects value"); self.data_stack.push(a); self.data_stack.push(c); self.data_stack.push(b); } VM_Instruction::Add => { let a = self.data_stack.pop().expect("add expects value"); let b = self.data_stack.pop().expect("add expects value"); self.data_stack.push( a + b ); } VM_Instruction::Addf => { let a = self.data_stack.pop().expect("addf expects value"); let af : f64 = unsafe{ std::mem::transmute(a) }; let b = self.data_stack.pop().expect("addf expects value"); let bf : f64 = unsafe{ std::mem::transmute(a) }; let cf = af + bf; let c : i64 = unsafe{ std::mem::transmute(cf) }; self.data_stack.push(c); } VM_Instruction::BitwiseNot => { let a = self.data_stack.pop().expect("bitwise not expects value"); self.data_stack.push( !a ); } } true } }