mirror of
https://github.com/Noratrieb/crapderive.git
synced 2026-01-15 00:55:06 +01:00
mob
This commit is contained in:
parent
ce7deb7dc6
commit
f9a3d93558
5 changed files with 108 additions and 27 deletions
10
README.md
10
README.md
|
|
@ -60,6 +60,12 @@ A location is a location in the VM code. It must contain a symbol with the label
|
||||||
|
|
||||||
Mov moves the `value` `B` to the `place` `A`.
|
Mov moves the `value` `B` to the `place` `A`.
|
||||||
|
|
||||||
|
### Movb
|
||||||
|
|
||||||
|
`movb A, B`
|
||||||
|
|
||||||
|
Mov moves the `value` `B` to the `place` `A`. Only a single byte is written.
|
||||||
|
|
||||||
### Add
|
### Add
|
||||||
|
|
||||||
`add A, B`
|
`add A, B`
|
||||||
|
|
@ -131,5 +137,5 @@ The interrupt 0 exits the program. The exit code is passed in `r0`.
|
||||||
### `int 1`
|
### `int 1`
|
||||||
|
|
||||||
The interrupt 0 writes a string to standard output. `r0` contains the address of the string data.
|
The interrupt 0 writes a string to standard output. `r0` contains the address of the string data.
|
||||||
`r1` contains the length of the string. The string is encoded as `UTF-8`. After the interrupt completed,
|
`r1` contains the length of the string. The string is forwarded as raw bytes to the OS.
|
||||||
`r0` will contain a 0 if writing was successful, or a `1` if it failed.
|
After the interrupt completed, `r0` will contain a 0 if writing was successful, or a `1` if it failed.
|
||||||
|
|
@ -9,6 +9,8 @@
|
||||||
//! Decimal 1
|
//! Decimal 1
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
use logos::Span;
|
use logos::Span;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -33,8 +35,8 @@ struct InterpretCtx {
|
||||||
|
|
||||||
impl InterpretCtx {
|
impl InterpretCtx {
|
||||||
fn interpret(&mut self, stmts: Vec<Stmt>) -> Result<()> {
|
fn interpret(&mut self, stmts: Vec<Stmt>) -> Result<()> {
|
||||||
let stmt_i = self.ip;
|
while self.ip < stmts.len() {
|
||||||
while stmt_i < stmts.len() {
|
let stmt_i = self.ip;
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
self.interpret_stmt(stmt_i, &stmts)?
|
self.interpret_stmt(stmt_i, &stmts)?
|
||||||
}
|
}
|
||||||
|
|
@ -48,6 +50,10 @@ impl InterpretCtx {
|
||||||
let value = self.read_value(from);
|
let value = self.read_value(from);
|
||||||
self.write_place(to, value);
|
self.write_place(to, value);
|
||||||
}
|
}
|
||||||
|
Stmt::Movb { from, to } => {
|
||||||
|
let value = self.read_byte_value(from);
|
||||||
|
self.write_byte_place(to, value);
|
||||||
|
}
|
||||||
Stmt::Add { to, value } => {
|
Stmt::Add { to, value } => {
|
||||||
let old = self.read_place(to);
|
let old = self.read_place(to);
|
||||||
let value = self.read_value(value);
|
let value = self.read_value(value);
|
||||||
|
|
@ -96,8 +102,17 @@ impl InterpretCtx {
|
||||||
|
|
||||||
fn interrupt(&mut self, number: u64) {
|
fn interrupt(&mut self, number: u64) {
|
||||||
match number {
|
match number {
|
||||||
0 => todo!("exit"),
|
0 => {
|
||||||
1 => todo!("print"),
|
let code = self.reg(Register(0));
|
||||||
|
std::process::exit(code as i32);
|
||||||
|
}
|
||||||
|
1 => {
|
||||||
|
let str_addr = self.reg_addr(Register(0));
|
||||||
|
let str_len = self.reg_addr(Register(1));
|
||||||
|
let slice = &self.memory[str_addr..][..str_len];
|
||||||
|
let is_ok = std::io::stdout().lock().write_all(slice).is_ok();
|
||||||
|
*self.reg_mut(Register(0)) = if is_ok { 0 } else { 1 };
|
||||||
|
}
|
||||||
_ => panic!("invalid interrupt!"),
|
_ => panic!("invalid interrupt!"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -109,11 +124,18 @@ impl InterpretCtx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_byte_value(&self, value: &Value) -> u8 {
|
||||||
|
match value {
|
||||||
|
Value::Literal(n) => *n as u8,
|
||||||
|
Value::Place(place) => self.read_byte_place(place),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn read_place(&self, place: &Place) -> u64 {
|
fn read_place(&self, place: &Place) -> u64 {
|
||||||
match place {
|
match place {
|
||||||
Place::Register(reg) => self.registers[reg.as_index()],
|
Place::Register(reg) => self.reg(*reg),
|
||||||
Place::AddrRegister(reg) => {
|
Place::AddrRegister(reg) => {
|
||||||
let addr = self.registers[reg.as_index()] as usize;
|
let addr = self.reg_addr(*reg);
|
||||||
self.read_addr(addr)
|
self.read_addr(addr)
|
||||||
}
|
}
|
||||||
Place::AddrLiteral(addr) => {
|
Place::AddrLiteral(addr) => {
|
||||||
|
|
@ -123,14 +145,27 @@ impl InterpretCtx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_byte_place(&self, place: &Place) -> u8 {
|
||||||
|
match place {
|
||||||
|
Place::Register(reg) => self.reg(*reg) as u8,
|
||||||
|
Place::AddrRegister(reg) => {
|
||||||
|
let addr = self.reg_addr(*reg);
|
||||||
|
self.memory[addr]
|
||||||
|
}
|
||||||
|
Place::AddrLiteral(addr) => {
|
||||||
|
let addr = *addr as usize;
|
||||||
|
self.memory[addr]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn write_place(&mut self, place: &Place, value: u64) {
|
fn write_place(&mut self, place: &Place, value: u64) {
|
||||||
match place {
|
match place {
|
||||||
Place::Register(reg) => {
|
Place::Register(reg) => {
|
||||||
let r = &mut self.registers[reg.as_index()];
|
*self.reg_mut(*reg) = value;
|
||||||
*r = value;
|
|
||||||
}
|
}
|
||||||
Place::AddrRegister(reg) => {
|
Place::AddrRegister(reg) => {
|
||||||
let addr = self.registers[reg.as_index()] as usize;
|
let addr = self.reg_addr(*reg);
|
||||||
self.write_addr(addr, value);
|
self.write_addr(addr, value);
|
||||||
}
|
}
|
||||||
Place::AddrLiteral(addr) => {
|
Place::AddrLiteral(addr) => {
|
||||||
|
|
@ -140,6 +175,22 @@ impl InterpretCtx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_byte_place(&mut self, place: &Place, value: u8) {
|
||||||
|
match place {
|
||||||
|
Place::Register(reg) => {
|
||||||
|
*self.reg_mut(*reg) = value.into();
|
||||||
|
}
|
||||||
|
Place::AddrRegister(reg) => {
|
||||||
|
let addr = self.reg_addr(*reg);
|
||||||
|
self.memory[addr] = value;
|
||||||
|
}
|
||||||
|
Place::AddrLiteral(addr) => {
|
||||||
|
let addr = *addr as usize;
|
||||||
|
self.memory[addr] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn read_addr(&self, addr: usize) -> u64 {
|
fn read_addr(&self, addr: usize) -> u64 {
|
||||||
u64::from_le_bytes([
|
u64::from_le_bytes([
|
||||||
self.memory[addr],
|
self.memory[addr],
|
||||||
|
|
@ -160,6 +211,18 @@ impl InterpretCtx {
|
||||||
self.memory[addr + i] = bytes[i];
|
self.memory[addr + i] = bytes[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reg(&self, reg: Register) -> u64 {
|
||||||
|
self.registers[reg.as_index()]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reg_mut(&mut self, reg: Register) -> &mut u64 {
|
||||||
|
&mut self.registers[reg.as_index()]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reg_addr(&self, reg: Register) -> usize {
|
||||||
|
self.reg(reg) as usize
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interpret(stmts: Vec<Stmt>, _spans: Vec<Span>) -> Result<()> {
|
pub fn interpret(stmts: Vec<Stmt>, _spans: Vec<Span>) -> Result<()> {
|
||||||
|
|
|
||||||
13
src/ir.rs
13
src/ir.rs
|
|
@ -35,6 +35,7 @@ pub struct Location {
|
||||||
#[derive(Debug, Clone, Copy, DebugPls)]
|
#[derive(Debug, Clone, Copy, DebugPls)]
|
||||||
pub enum Stmt {
|
pub enum Stmt {
|
||||||
Mov { to: Place, from: Value },
|
Mov { to: Place, from: Value },
|
||||||
|
Movb { to: Place, from: Value },
|
||||||
Add { to: Place, value: Value },
|
Add { to: Place, value: Value },
|
||||||
Sub { to: Place, value: Value },
|
Sub { to: Place, value: Value },
|
||||||
Mul { to: Place, value: Value },
|
Mul { to: Place, value: Value },
|
||||||
|
|
@ -75,6 +76,11 @@ impl CompileCtx {
|
||||||
let to = self.compile_place(to)?;
|
let to = self.compile_place(to)?;
|
||||||
Stmt::Mov { from, to }
|
Stmt::Mov { from, to }
|
||||||
}
|
}
|
||||||
|
StmtKind::Movb { from, to } => {
|
||||||
|
let from = self.compile_value(from)?;
|
||||||
|
let to = self.compile_place(to)?;
|
||||||
|
Stmt::Movb { from, to }
|
||||||
|
}
|
||||||
StmtKind::Add { to, value } => {
|
StmtKind::Add { to, value } => {
|
||||||
let to = self.compile_place(to)?;
|
let to = self.compile_place(to)?;
|
||||||
let value = self.compile_value(value)?;
|
let value = self.compile_value(value)?;
|
||||||
|
|
@ -97,10 +103,13 @@ impl CompileCtx {
|
||||||
}
|
}
|
||||||
StmtKind::Int { number } => {
|
StmtKind::Int { number } => {
|
||||||
if number > 1 {
|
if number > 1 {
|
||||||
return Err(CompilerError::simple("invalid interrupt".to_string(), p_stmt.span));
|
return Err(CompilerError::simple(
|
||||||
|
"invalid interrupt".to_string(),
|
||||||
|
p_stmt.span,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Stmt::Int { number }
|
Stmt::Int { number }
|
||||||
},
|
}
|
||||||
StmtKind::Jmp { to } => {
|
StmtKind::Jmp { to } => {
|
||||||
let to = self.compile_location(to, self.stmts.len())?;
|
let to = self.compile_location(to, self.stmts.len())?;
|
||||||
Stmt::Jmp { to }
|
Stmt::Jmp { to }
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ use crate::error::{CompilerError, Result};
|
||||||
pub enum Token<'a> {
|
pub enum Token<'a> {
|
||||||
#[token("mov")]
|
#[token("mov")]
|
||||||
Mov,
|
Mov,
|
||||||
|
#[token("movb")]
|
||||||
|
Movb,
|
||||||
#[token("jmp")]
|
#[token("jmp")]
|
||||||
Jmp,
|
Jmp,
|
||||||
#[token("je")]
|
#[token("je")]
|
||||||
|
|
@ -63,6 +65,7 @@ impl DebugPls for Stmt {
|
||||||
#[derive(Debug, PartialEq, Eq, DebugPls)]
|
#[derive(Debug, PartialEq, Eq, DebugPls)]
|
||||||
pub enum StmtKind {
|
pub enum StmtKind {
|
||||||
Mov { to: Expr, from: Expr },
|
Mov { to: Expr, from: Expr },
|
||||||
|
Movb { to: Expr, from: Expr },
|
||||||
Add { to: Expr, value: Expr },
|
Add { to: Expr, value: Expr },
|
||||||
Sub { to: Expr, value: Expr },
|
Sub { to: Expr, value: Expr },
|
||||||
Mul { to: Expr, value: Expr },
|
Mul { to: Expr, value: Expr },
|
||||||
|
|
@ -160,6 +163,12 @@ where
|
||||||
let from = self.expr()?;
|
let from = self.expr()?;
|
||||||
stmt(span.start..from.span.end, StmtKind::Mov { to, from })
|
stmt(span.start..from.span.end, StmtKind::Mov { to, from })
|
||||||
}
|
}
|
||||||
|
Token::Movb => {
|
||||||
|
let to = self.expr()?;
|
||||||
|
expect!(self, Token::Comma);
|
||||||
|
let from = self.expr()?;
|
||||||
|
stmt(span.start..from.span.end, StmtKind::Movb { to, from })
|
||||||
|
}
|
||||||
Token::Jmp => {
|
Token::Jmp => {
|
||||||
let to = self.expr()?;
|
let to = self.expr()?;
|
||||||
stmt(span.start..to.span.end, StmtKind::Jmp { to })
|
stmt(span.start..to.span.end, StmtKind::Jmp { to })
|
||||||
|
|
@ -260,6 +269,7 @@ where
|
||||||
expr(ExprKind::Symbol(name.to_owned()), span)
|
expr(ExprKind::Symbol(name.to_owned()), span)
|
||||||
}
|
}
|
||||||
Token::Mov => return Err(CompilerError::not_allowed(span, "mov")),
|
Token::Mov => return Err(CompilerError::not_allowed(span, "mov")),
|
||||||
|
Token::Movb => return Err(CompilerError::not_allowed(span, "movb")),
|
||||||
Token::Jmp => return Err(CompilerError::not_allowed(span, "jmp")),
|
Token::Jmp => return Err(CompilerError::not_allowed(span, "jmp")),
|
||||||
Token::Je => return Err(CompilerError::not_allowed(span, "je")),
|
Token::Je => return Err(CompilerError::not_allowed(span, "je")),
|
||||||
Token::Cmp => return Err(CompilerError::not_allowed(span, "cmp")),
|
Token::Cmp => return Err(CompilerError::not_allowed(span, "cmp")),
|
||||||
|
|
|
||||||
21
test.at
21
test.at
|
|
@ -1,14 +1,7 @@
|
||||||
mov r0, 3
|
mov [0], 40
|
||||||
cmp r0, 8
|
mov [1], 41
|
||||||
je true
|
mov [2], 42
|
||||||
jmp false
|
mov [3], 43
|
||||||
true:
|
mov r0, 0
|
||||||
jmp exit
|
mov r1, 4
|
||||||
|
int 1
|
||||||
// loop
|
|
||||||
false:
|
|
||||||
mov r5, [8]
|
|
||||||
jmp false
|
|
||||||
|
|
||||||
|
|
||||||
exit:
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue