Non-enum opcodes

This commit is contained in:
Daniel M 2022-02-01 14:28:24 +01:00
parent 85211b127d
commit 307b003e11
2 changed files with 135 additions and 123 deletions

View File

@ -2,50 +2,40 @@ use std::collections::HashMap;
use crate::ast::{Ast, Expr, Stmt, BinOpType};
#[repr(u32)]
#[derive(Debug, Clone, Copy)]
pub enum OP {
Push,
Pop,
Load,
Store,
pub mod op {
type OpSize = u32;
Add,
Subtract,
Multiply,
Divide,
Modulo,
BOr,
BAnd,
BXor,
Shl,
Shr,
Eq,
Neq,
Gt,
Ge,
Lt,
Le,
Jump,
JumpTrue,
JumpFalse,
Value(u32),
Print,
DbgPrint,
pub const PUSH: OpSize = 0;
pub const POP: OpSize = 1;
pub const LOAD: OpSize = 2;
pub const STORE: OpSize = 3;
pub const ADD: OpSize = 4;
pub const SUB: OpSize = 5;
pub const MUL: OpSize = 6;
pub const DIV: OpSize = 7;
pub const MOD: OpSize = 8;
pub const BOR: OpSize = 9;
pub const BAND: OpSize = 10;
pub const BXOR: OpSize = 11;
pub const SHL: OpSize = 12;
pub const SHR: OpSize = 13;
pub const EQ: OpSize = 14;
pub const NEQ: OpSize = 15;
pub const GT: OpSize = 16;
pub const GE: OpSize = 17;
pub const LT: OpSize = 18;
pub const LE: OpSize = 19;
pub const JUMP: OpSize = 20;
pub const JUMP_TRUE: OpSize = 21;
pub const JUMP_FALSE: OpSize = 22;
pub const PRINT: OpSize = 23;
pub const DBG_PRINT: OpSize = 24;
}
#[derive(Debug, Default)]
pub struct Compiler {
ops: Vec<OP>,
global_vars: HashMap<String, u64>,
ops: Vec<u32>,
global_vars: HashMap<String, u16>,
}
impl Compiler {
@ -58,26 +48,30 @@ impl Compiler {
match stmt {
Stmt::Expr(expr) => {
self.compile_expr(expr);
self.ops.push(OP::Pop);
self.ops.push(op::POP);
}
Stmt::Let(name, rhs) => {
let id = self.global_vars.len() as u64;
let id = self.global_vars.len() as u16;
self.global_vars.insert(name.clone(), id);
self.compile_expr(rhs);
self.gen_store(id);
}
Stmt::While(cond, body) => {
let idx_start = self.ops.len();
self.compile_expr(cond);
self.ops.push(OP::JumpFalse);
self.ops.push(op::JUMP_FALSE);
let idx_jmp = self.ops.len();
self.gen_i64(0);
let idx_start = self.ops.len();
self.compile(body);
self.ops.push(OP::Jump);
// check condition before loop jump
self.compile_expr(cond);
self.ops.push(op::JUMP_TRUE);
self.gen_i64(idx_start as i64);
self.overwrite_i64(idx_jmp, self.ops.len() as i64);
@ -86,13 +80,13 @@ impl Compiler {
Stmt::If(cond, if_block, else_block) => {
self.compile_expr(cond);
self.ops.push(OP::JumpFalse);
self.ops.push(op::JUMP_FALSE);
let idx_if = self.ops.len();
self.gen_i64(0);
self.compile(if_block);
self.ops.push(OP::Jump);
self.ops.push(op::JUMP);
let idx_else = self.ops.len();
self.gen_i64(0);
@ -105,24 +99,24 @@ impl Compiler {
},
Stmt::DbgPrint(expr) => {
self.compile_expr(expr);
self.ops.push(OP::DbgPrint);
self.ops.push(op::DBG_PRINT);
}
Stmt::Print(expr) => {
self.compile_expr(expr);
self.ops.push(OP::Print);
self.ops.push(op::PRINT);
}
}
}
}
pub fn into_ops(self) -> Vec<OP> {
pub fn into_ops(self) -> Vec<u32> {
self.ops
}
pub fn compile_expr(&mut self, expr: &Expr) {
match expr {
Expr::I64(val) => {
self.ops.push(OP::Push);
self.ops.push(op::PUSH);
self.gen_i64(*val)
}
Expr::Ident(name) => {
@ -155,48 +149,48 @@ impl Compiler {
self.compile_expr(rhs);
match bo {
BinOpType::Add => self.ops.push(OP::Add),
BinOpType::Sub => self.ops.push(OP::Subtract),
BinOpType::Mul => self.ops.push(OP::Multiply),
BinOpType::Div => self.ops.push(OP::Divide),
BinOpType::Mod => self.ops.push(OP::Modulo),
BinOpType::BOr => self.ops.push(OP::BOr),
BinOpType::BAnd => self.ops.push(OP::BAnd),
BinOpType::BXor => self.ops.push(OP::BXor),
BinOpType::Shl => self.ops.push(OP::Shl),
BinOpType::Shr => self.ops.push(OP::Shr),
BinOpType::Equ => self.ops.push(OP::Eq),
BinOpType::Neq => self.ops.push(OP::Neq),
BinOpType::Gt => self.ops.push(OP::Gt),
BinOpType::Ge => self.ops.push(OP::Ge),
BinOpType::Lt => self.ops.push(OP::Lt),
BinOpType::Le => self.ops.push(OP::Le),
BinOpType::Add => self.ops.push(op::ADD),
BinOpType::Sub => self.ops.push(op::SUB),
BinOpType::Mul => self.ops.push(op::MUL),
BinOpType::Div => self.ops.push(op::DIV),
BinOpType::Mod => self.ops.push(op::MOD),
BinOpType::BOr => self.ops.push(op::BOR),
BinOpType::BAnd => self.ops.push(op::BAND),
BinOpType::BXor => self.ops.push(op::BXOR),
BinOpType::Shl => self.ops.push(op::SHL),
BinOpType::Shr => self.ops.push(op::SHR),
BinOpType::Equ => self.ops.push(op::EQ),
BinOpType::Neq => self.ops.push(op::NEQ),
BinOpType::Gt => self.ops.push(op::GT),
BinOpType::Ge => self.ops.push(op::GE),
BinOpType::Lt => self.ops.push(op::LT),
BinOpType::Le => self.ops.push(op::LE),
BinOpType::Assign => unreachable!(),
}
}
fn gen_i64(&mut self, val: i64) {
self.ops.push(OP::Value((val & u32::MAX as i64) as u32));
self.ops.push(OP::Value((val >> 32) as u32));
self.ops.push((val & u32::MAX as i64) as u32);
self.ops.push((val >> 32) as u32);
}
fn overwrite_i64(&mut self, idx: usize, val: i64) {
self.ops[idx] = OP::Value((val & u32::MAX as i64) as u32);
self.ops[idx+1] = OP::Value((val >> 32) as u32);
self.ops[idx] = (val & u32::MAX as i64) as u32;
self.ops[idx+1] = (val >> 32) as u32;
}
fn gen_load(&mut self, addr: u64) {
self.ops.push(OP::Load);
self.gen_i64(addr as i64)
fn gen_load(&mut self, addr: u16) {
self.ops.push(op::LOAD | (addr << 8) as u32);
// self.gen_i64(addr as i64)
}
fn gen_store(&mut self, addr: u64) {
self.ops.push(OP::Store);
self.gen_i64(addr as i64)
fn gen_store(&mut self, addr: u16) {
self.ops.push(op::STORE | (addr << 8) as u32);
// self.gen_i64(addr as i64)
}
}
pub fn compile(ast: &Ast) -> Vec<OP> {
pub fn compile(ast: &Ast) -> Vec<u32> {
let mut compiler = Compiler::new();
compiler.compile(ast);
compiler.into_ops()

110
src/vm.rs
View File

@ -1,8 +1,8 @@
use crate::{bytecode::OP, interpreter::Value};
use crate::{bytecode::op::*, interpreter::Value};
#[derive(Debug, Default)]
pub struct Vm {
prog: Vec<OP>,
prog: Vec<u32>,
ip: usize,
stack: Vec<Value>,
@ -10,8 +10,21 @@ pub struct Vm {
heap: Vec<Value>,
}
macro_rules! binop_stack {
($self:ident, $op:tt) => {
{
let rhs = $self.stack.pop().unwrap();
let lhs = $self.stack.last_mut().unwrap();
match (lhs, rhs) {
(Value::I64(lhs), Value::I64(rhs)) => *lhs = *lhs $op rhs,
_ => panic!("Invalid data for add"),
}
}
};
}
impl Vm {
pub fn new(prog: Vec<OP>) -> Self {
pub fn new(prog: Vec<u32>) -> Self {
Self {
prog,
..Default::default()
@ -22,16 +35,17 @@ impl Vm {
while let Some(op) = self.prog.get(self.ip).copied() {
self.ip += 1;
match op {
OP::Push => {
match op & 0xff {
PUSH => {
let val = self.read_i64();
self.stack.push(Value::I64(val));
}
OP::Pop => {
POP => {
self.stack.pop();
}
OP::Load => {
let addr = self.read_i64() as usize;
LOAD => {
// let addr = self.read_i64() as usize;
let addr = (op >> 8) as usize;
if let Some(val) = self.heap.get(addr) {
self.stack.push(val.clone());
@ -39,26 +53,28 @@ impl Vm {
panic!("Trying to load from uninitialized heap");
}
}
OP::Store => {
STORE => {
let val = self
.stack
.pop()
.expect("Trying to pop value from stack for storing");
let addr = self.read_i64() as usize;
// let addr = self.read_i64() as usize;
let addr = (op >> 8) as usize;
if self.heap.len() == addr {
self.heap.push(val);
} else {
self.heap[addr] = val;
}
}
OP::Print => {
PRINT => {
let val = self
.stack
.pop()
.expect("Trying to pop value from stack for printing");
print!("{}", val);
}
OP::DbgPrint => {
DBG_PRINT => {
let val = self
.stack
.pop()
@ -66,94 +82,96 @@ impl Vm {
print!("{:?}", val);
}
OP::Add => {
let vals = self.pop2_i64();
self.stack.push(Value::I64(vals.0 + vals.1))
ADD => {
binop_stack!(self, +);
// self.stack.push(Value::I64(vals.0 + vals.1))
}
OP::Subtract => {
let vals = self.pop2_i64();
self.stack.push(Value::I64(vals.0 - vals.1))
SUB => {
binop_stack!(self, -);
// let vals = self.pop2_i64();
// self.stack.push(Value::I64(vals.0 - vals.1))
}
OP::Multiply => {
let vals = self.pop2_i64();
self.stack.push(Value::I64(vals.0 * vals.1))
MUL => {
binop_stack!(self, *);
// let vals = self.pop2_i64();
// self.stack.push(Value::I64(vals.0 * vals.1))
}
OP::Divide => {
let vals = self.pop2_i64();
self.stack.push(Value::I64(vals.0 / vals.1))
DIV => {
binop_stack!(self, /);
// let vals = self.pop2_i64();
// self.stack.push(Value::I64(vals.0 / vals.1))
}
OP::Modulo => {
let vals = self.pop2_i64();
self.stack.push(Value::I64(vals.0 % vals.1))
MOD => {
binop_stack!(self, %);
// let vals = self.pop2_i64();
// self.stack.push(Value::I64(vals.0 % vals.1))
}
OP::Eq => {
EQ => {
let vals = self.pop2_i64();
self.stack
.push(Value::I64(if vals.0 == vals.1 { 1 } else { 0 }))
}
OP::Neq => {
NEQ => {
let vals = self.pop2_i64();
self.stack
.push(Value::I64(if vals.0 != vals.1 { 1 } else { 0 }))
}
OP::Gt => {
GT => {
let vals = self.pop2_i64();
self.stack
.push(Value::I64(if vals.0 > vals.1 { 1 } else { 0 }))
}
OP::Ge => {
GE => {
let vals = self.pop2_i64();
self.stack
.push(Value::I64(if vals.0 >= vals.1 { 1 } else { 0 }))
}
OP::Lt => {
LT => {
let vals = self.pop2_i64();
self.stack
.push(Value::I64(if vals.0 < vals.1 { 1 } else { 0 }))
}
OP::Le => {
LE => {
let vals = self.pop2_i64();
self.stack
.push(Value::I64(if vals.0 <= vals.1 { 1 } else { 0 }))
}
OP::BOr => {
BOR => {
let vals = self.pop2_i64();
self.stack.push(Value::I64(vals.0 | vals.1))
}
OP::BAnd => {
BAND => {
let vals = self.pop2_i64();
self.stack.push(Value::I64(vals.0 & vals.1))
}
OP::BXor => {
BXOR => {
let vals = self.pop2_i64();
self.stack.push(Value::I64(vals.0 ^ vals.1))
}
OP::Shl => {
SHL => {
let vals = self.pop2_i64();
self.stack.push(Value::I64(vals.0 << vals.1))
}
OP::Shr => {
SHR => {
let vals = self.pop2_i64();
self.stack.push(Value::I64(vals.0 >> vals.1))
}
OP::Value(_) => {
panic!("This is not an instruction, but data. This should never be evaluated")
}
OP::Jump => {
JUMP => {
self.ip = self.read_i64() as usize;
}
OP::JumpTrue => {
JUMP_TRUE => {
let jmp_target = self.read_i64() as usize;
if !matches!(self.stack.pop(), Some(Value::I64(0))) {
self.ip = jmp_target;
}
}
OP::JumpFalse => {
JUMP_FALSE => {
let jmp_target = self.read_i64() as usize;
if matches!(self.stack.pop(), Some(Value::I64(0))) {
self.ip = jmp_target;
}
}
_ => panic!("Invalid opcode")
}
}
}
@ -168,7 +186,7 @@ impl Vm {
}
fn read_i64(&mut self) -> i64 {
let mut val = if let Some(OP::Value(val)) = self.prog.get(self.ip).copied() {
let mut val = if let Some(val) = self.prog.get(self.ip).copied() {
val
} else {
panic!("Expected Value as next OP")
@ -176,7 +194,7 @@ impl Vm {
self.ip += 1;
val |= (if let Some(OP::Value(val)) = self.prog.get(self.ip).copied() {
val |= (if let Some(val) = self.prog.get(self.ip).copied() {
val
} else {
panic!("Expected Value as next OP")