mirror of
https://github.com/Noratrieb/crapderive.git
synced 2026-01-14 16:45:08 +01:00
interpret
This commit is contained in:
parent
86f7d33c13
commit
25e794f779
3 changed files with 171 additions and 3 deletions
165
src/interpret.rs
Normal file
165
src/interpret.rs
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
//!
|
||||
//! The interpreter is little endian
|
||||
//!
|
||||
//! ```text
|
||||
//! | 0 | 1 | 2 | 3
|
||||
//! ---------------
|
||||
//! 1 0 0 0
|
||||
//! --------------
|
||||
//! Decimal 1
|
||||
//! ```
|
||||
|
||||
use logos::Span;
|
||||
|
||||
use crate::{
|
||||
error::Result,
|
||||
ir::{Place, Register, Stmt, Value},
|
||||
};
|
||||
|
||||
impl Register {
|
||||
fn as_index(self) -> usize {
|
||||
self.0.into()
|
||||
}
|
||||
}
|
||||
|
||||
struct InterpretCtx {
|
||||
memory: Vec<u8>,
|
||||
registers: [u64; 16],
|
||||
flag: bool,
|
||||
stmts: Vec<Stmt>,
|
||||
spans: Vec<Span>,
|
||||
ip: usize,
|
||||
}
|
||||
|
||||
impl InterpretCtx {
|
||||
fn interpret(&mut self) -> Result<()> {
|
||||
let stmt_i = self.ip;
|
||||
while stmt_i < self.stmts.len() {
|
||||
self.ip += 1;
|
||||
self.interpret_stmt(stmt_i)?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn interpret_stmt(&mut self, stmt_i: usize) -> Result<()> {
|
||||
let stmt = &self.stmts[stmt_i];
|
||||
match stmt {
|
||||
Stmt::Mov { from, to } => {
|
||||
let value = self.read_value(from);
|
||||
self.write_place(to, value);
|
||||
}
|
||||
Stmt::Add { to, value } => {
|
||||
let old = self.read_place(to);
|
||||
let value = self.read_value(value);
|
||||
let new = old.wrapping_add(value);
|
||||
self.write_place(to, new);
|
||||
}
|
||||
Stmt::Sub { to, value } => {
|
||||
let old = self.read_place(to);
|
||||
let value = self.read_value(value);
|
||||
let new = old.wrapping_sub(value);
|
||||
self.write_place(to, new);
|
||||
}
|
||||
Stmt::Mul { to, value } => {
|
||||
let old = self.read_place(to);
|
||||
let value = self.read_value(value);
|
||||
let new = old.wrapping_mul(value);
|
||||
self.write_place(to, new);
|
||||
}
|
||||
Stmt::Div { to, value } => {
|
||||
let old = self.read_place(to);
|
||||
let value = self.read_value(value);
|
||||
let new = old.wrapping_div(value);
|
||||
self.write_place(to, new);
|
||||
}
|
||||
Stmt::Jmp { to } => {
|
||||
let index = to.index;
|
||||
self.ip = index;
|
||||
}
|
||||
Stmt::Cmp { lhs, rhs } => {
|
||||
let lhs = self.read_value(lhs);
|
||||
let rhs = self.read_value(rhs);
|
||||
self.flag = lhs == rhs;
|
||||
}
|
||||
Stmt::Je { to } => {
|
||||
let index = to.index;
|
||||
if self.flag {
|
||||
self.ip = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_value(&self, value: &Value) -> u64 {
|
||||
match value {
|
||||
Value::Literal(n) => *n,
|
||||
Value::Place(place) => self.read_place(place),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_place(&self, place: &Place) -> u64 {
|
||||
match place {
|
||||
Place::Register(reg) => self.registers[reg.as_index()],
|
||||
Place::AddrRegister(reg) => {
|
||||
let addr = self.registers[reg.as_index()] as usize;
|
||||
self.read_addr(addr)
|
||||
}
|
||||
Place::AddrLiteral(addr) => {
|
||||
let addr = *addr as usize;
|
||||
self.read_addr(addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn write_place(&mut self, place: &Place, value: u64) {
|
||||
match place {
|
||||
Place::Register(reg) => {
|
||||
let r = &mut self.registers[reg.as_index()];
|
||||
*r = value;
|
||||
}
|
||||
Place::AddrRegister(reg) => {
|
||||
let addr = self.registers[reg.as_index()] as usize;
|
||||
self.write_addr(addr, value);
|
||||
}
|
||||
Place::AddrLiteral(addr) => {
|
||||
let addr = *addr as usize;
|
||||
self.write_addr(addr, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_addr(&self, addr: usize) -> u64 {
|
||||
u64::from_le_bytes([
|
||||
self.memory[addr],
|
||||
self.memory[addr + 1],
|
||||
self.memory[addr + 2],
|
||||
self.memory[addr + 3],
|
||||
self.memory[addr + 4],
|
||||
self.memory[addr + 5],
|
||||
self.memory[addr + 6],
|
||||
self.memory[addr + 7],
|
||||
])
|
||||
}
|
||||
|
||||
fn write_addr(&mut self, addr: usize, value: u64) {
|
||||
assert!(addr + 7 < self.memory.len());
|
||||
let bytes = value.to_le_bytes();
|
||||
for i in 0..8 {
|
||||
self.memory[addr + i] = bytes[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn interpret(stmts: Vec<Stmt>, spans: Vec<Span>) -> Result<()> {
|
||||
let mut ctx = InterpretCtx {
|
||||
memory: vec![0; 100_000],
|
||||
registers: [0; 16],
|
||||
flag: false,
|
||||
stmts,
|
||||
spans,
|
||||
ip: 0,
|
||||
};
|
||||
|
||||
ctx.interpret()
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ use crate::{
|
|||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy, DebugPls)]
|
||||
pub struct Register(u8);
|
||||
pub struct Register(pub u8);
|
||||
|
||||
#[derive(Debug, Clone, Copy, DebugPls)]
|
||||
pub enum Place {
|
||||
|
|
@ -30,7 +30,7 @@ pub enum Value {
|
|||
|
||||
#[derive(Debug, Clone, Copy, DebugPls)]
|
||||
pub struct Location {
|
||||
index: usize,
|
||||
pub index: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, DebugPls)]
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use std::{io, process};
|
|||
use crate::error::CompilerError;
|
||||
|
||||
mod error;
|
||||
mod interpret;
|
||||
mod ir;
|
||||
mod parser;
|
||||
|
||||
|
|
@ -13,7 +14,9 @@ fn main() -> Result<(), io::Error> {
|
|||
let ast = result.unwrap_or_else(|e| report_and_exit(&file, e));
|
||||
dbg_pls::color!(&ast);
|
||||
let stmts = ir::compile(ast.into_iter()).unwrap_or_else(|e| report_and_exit(&file, e));
|
||||
dbg_pls::color!(stmts.0);
|
||||
dbg_pls::color!(&stmts.0);
|
||||
|
||||
interpret::interpret(stmts.0, stmts.1).unwrap_or_else(|e| report_and_exit(&file, e));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue