From f9a3d93558a7c6d82d672fa8e66daecde4c2a1ce Mon Sep 17 00:00:00 2001 From: nils <48135649+Nilstrieb@users.noreply.github.com> Date: Mon, 20 Jun 2022 17:06:43 +0200 Subject: [PATCH] mob --- README.md | 10 ++++-- src/interpret.rs | 81 ++++++++++++++++++++++++++++++++++++++++++------ src/ir.rs | 13 ++++++-- src/parser.rs | 10 ++++++ test.at | 21 +++++-------- 5 files changed, 108 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index fd49939..8af4a09 100644 --- a/README.md +++ b/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`. +### Movb + +`movb A, B` + +Mov moves the `value` `B` to the `place` `A`. Only a single byte is written. + ### Add `add A, B` @@ -131,5 +137,5 @@ The interrupt 0 exits the program. The exit code is passed in `r0`. ### `int 1` 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, -`r0` will contain a 0 if writing was successful, or a `1` if it failed. \ No newline at end of file +`r1` contains the length of the string. The string is forwarded as raw bytes to the OS. +After the interrupt completed, `r0` will contain a 0 if writing was successful, or a `1` if it failed. \ No newline at end of file diff --git a/src/interpret.rs b/src/interpret.rs index 7e32f2e..bc3874f 100644 --- a/src/interpret.rs +++ b/src/interpret.rs @@ -9,6 +9,8 @@ //! Decimal 1 //! ``` +use std::io::Write; + use logos::Span; use crate::{ @@ -33,8 +35,8 @@ struct InterpretCtx { impl InterpretCtx { fn interpret(&mut self, stmts: Vec) -> Result<()> { - let stmt_i = self.ip; - while stmt_i < stmts.len() { + while self.ip < stmts.len() { + let stmt_i = self.ip; self.ip += 1; self.interpret_stmt(stmt_i, &stmts)? } @@ -48,6 +50,10 @@ impl InterpretCtx { let value = self.read_value(from); 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 } => { let old = self.read_place(to); let value = self.read_value(value); @@ -96,8 +102,17 @@ impl InterpretCtx { fn interrupt(&mut self, number: u64) { match number { - 0 => todo!("exit"), - 1 => todo!("print"), + 0 => { + 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!"), } } @@ -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 { match place { - Place::Register(reg) => self.registers[reg.as_index()], + Place::Register(reg) => self.reg(*reg), Place::AddrRegister(reg) => { - let addr = self.registers[reg.as_index()] as usize; + let addr = self.reg_addr(*reg); self.read_addr(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) { match place { Place::Register(reg) => { - let r = &mut self.registers[reg.as_index()]; - *r = value; + *self.reg_mut(*reg) = value; } Place::AddrRegister(reg) => { - let addr = self.registers[reg.as_index()] as usize; + let addr = self.reg_addr(*reg); self.write_addr(addr, value); } 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 { u64::from_le_bytes([ self.memory[addr], @@ -160,6 +211,18 @@ impl InterpretCtx { 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, _spans: Vec) -> Result<()> { diff --git a/src/ir.rs b/src/ir.rs index 685f371..412635c 100644 --- a/src/ir.rs +++ b/src/ir.rs @@ -35,6 +35,7 @@ pub struct Location { #[derive(Debug, Clone, Copy, DebugPls)] pub enum Stmt { Mov { to: Place, from: Value }, + Movb { to: Place, from: Value }, Add { to: Place, value: Value }, Sub { to: Place, value: Value }, Mul { to: Place, value: Value }, @@ -75,6 +76,11 @@ impl CompileCtx { let to = self.compile_place(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 } => { let to = self.compile_place(to)?; let value = self.compile_value(value)?; @@ -97,10 +103,13 @@ impl CompileCtx { } StmtKind::Int { number } => { 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 } - }, + } StmtKind::Jmp { to } => { let to = self.compile_location(to, self.stmts.len())?; Stmt::Jmp { to } diff --git a/src/parser.rs b/src/parser.rs index 9eda353..46fd076 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -9,6 +9,8 @@ use crate::error::{CompilerError, Result}; pub enum Token<'a> { #[token("mov")] Mov, + #[token("movb")] + Movb, #[token("jmp")] Jmp, #[token("je")] @@ -63,6 +65,7 @@ impl DebugPls for Stmt { #[derive(Debug, PartialEq, Eq, DebugPls)] pub enum StmtKind { Mov { to: Expr, from: Expr }, + Movb { to: Expr, from: Expr }, Add { to: Expr, value: Expr }, Sub { to: Expr, value: Expr }, Mul { to: Expr, value: Expr }, @@ -160,6 +163,12 @@ where let from = self.expr()?; 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 => { let to = self.expr()?; stmt(span.start..to.span.end, StmtKind::Jmp { to }) @@ -260,6 +269,7 @@ where expr(ExprKind::Symbol(name.to_owned()), span) } 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::Je => return Err(CompilerError::not_allowed(span, "je")), Token::Cmp => return Err(CompilerError::not_allowed(span, "cmp")), diff --git a/test.at b/test.at index d9116a9..656a983 100644 --- a/test.at +++ b/test.at @@ -1,14 +1,7 @@ -mov r0, 3 -cmp r0, 8 -je true -jmp false -true: -jmp exit - -// loop -false: -mov r5, [8] -jmp false - - -exit: \ No newline at end of file +mov [0], 40 +mov [1], 41 +mov [2], 42 +mov [3], 43 +mov r0, 0 +mov r1, 4 +int 1 \ No newline at end of file