From ce7deb7dc60acac0fadaf109873b708a867db268 Mon Sep 17 00:00:00 2001 From: nils <48135649+Nilstrieb@users.noreply.github.com> Date: Mon, 20 Jun 2022 15:18:26 +0200 Subject: [PATCH] interrupts! --- README.md | 22 +++++++++++++++++++++- src/interpret.rs | 32 +++++++++++++++++++------------- src/ir.rs | 12 +++++++++--- src/parser.rs | 15 +++++++++++++++ 4 files changed, 64 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 9aba163..fd49939 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,14 @@ The result is stored in the `place` `A`. Div divides the `place` `A` by the `value` `B`. The result is stored in the `place` `A`. +### Int + +`int N` + +Int performs the interrupt with the number `N`. `N` must be a number literal. + +For a list of interrupts, see the list below. + ### Cmp `cmp A, B` @@ -112,4 +120,16 @@ the next instruction executed will be the instruction located at `L`. `:` A label is an identifier (regex: `[a-zA-Z]\w+`) followed by a colon (`:`). Jumps (like `jmp` or `je`) will be able -to jump to this label. A label is applied to the *next* instruction in the code. \ No newline at end of file +to jump to this label. A label is applied to the *next* instruction in the code. + +## Interrupts + +### `int 0` + +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 diff --git a/src/interpret.rs b/src/interpret.rs index c90bd45..7e32f2e 100644 --- a/src/interpret.rs +++ b/src/interpret.rs @@ -22,29 +22,27 @@ impl Register { } } -const MEMORY_SIZE = 1024 * 1024 * 1024; +const MEMORY_SIZE: usize = 1024 * 1024 * 1024; struct InterpretCtx { memory: Vec, registers: [u64; 16], flag: bool, - stmts: Vec, - spans: Vec, ip: usize, } impl InterpretCtx { - fn interpret(&mut self) -> Result<()> { + fn interpret(&mut self, stmts: Vec) -> Result<()> { let stmt_i = self.ip; - while stmt_i < self.stmts.len() { + while stmt_i < stmts.len() { self.ip += 1; - self.interpret_stmt(stmt_i)? + self.interpret_stmt(stmt_i, &stmts)? } Ok(()) } - fn interpret_stmt(&mut self, stmt_i: usize) -> Result<()> { - let stmt = &self.stmts[stmt_i]; + fn interpret_stmt(&mut self, stmt_i: usize, stmts: &[Stmt]) -> Result<()> { + let stmt = &stmts[stmt_i]; match stmt { Stmt::Mov { from, to } => { let value = self.read_value(from); @@ -74,6 +72,9 @@ impl InterpretCtx { let new = old.wrapping_div(value); self.write_place(to, new); } + Stmt::Int { number } => { + self.interrupt(*number); + } Stmt::Jmp { to } => { let index = to.index; self.ip = index; @@ -93,6 +94,14 @@ impl InterpretCtx { Ok(()) } + fn interrupt(&mut self, number: u64) { + match number { + 0 => todo!("exit"), + 1 => todo!("print"), + _ => panic!("invalid interrupt!"), + } + } + fn read_value(&self, value: &Value) -> u64 { match value { Value::Literal(n) => *n, @@ -153,16 +162,13 @@ impl InterpretCtx { } } - -pub fn interpret(stmts: Vec, spans: Vec) -> Result<()> { +pub fn interpret(stmts: Vec, _spans: Vec) -> Result<()> { let mut ctx = InterpretCtx { memory: vec![0; MEMORY_SIZE], registers: [0; 16], flag: false, - stmts, - spans, ip: 0, }; - ctx.interpret() + ctx.interpret(stmts) } diff --git a/src/ir.rs b/src/ir.rs index e053d70..685f371 100644 --- a/src/ir.rs +++ b/src/ir.rs @@ -1,5 +1,4 @@ -use std::collections::HashMap; -use std::mem; +use std::{collections::HashMap, mem}; use dbg_pls::DebugPls; use logos::Span; @@ -40,6 +39,7 @@ pub enum Stmt { Sub { to: Place, value: Value }, Mul { to: Place, value: Value }, Div { to: Place, value: Value }, + Int { number: u64 }, Jmp { to: Location }, Je { to: Location }, Cmp { lhs: Value, rhs: Value }, @@ -95,6 +95,12 @@ impl CompileCtx { let value = self.compile_value(value)?; Stmt::Div { to, value } } + StmtKind::Int { number } => { + if number > 1 { + 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 } @@ -194,7 +200,7 @@ impl CompileCtx { Ok(()) } - fn resolve_location(&mut self, index: usize, label: &str) -> Result<()>{ + fn resolve_location(&mut self, index: usize, label: &str) -> Result<()> { let (location, _) = self.labels.get(label).ok_or_else(|| { CompilerError::simple( format!("label {label} not found"), diff --git a/src/parser.rs b/src/parser.rs index 42dc1d1..9eda353 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -23,6 +23,8 @@ pub enum Token<'a> { Mul, #[token("div")] Div, + #[token("int")] + Int, #[token("[")] BracketOpen, #[token("]")] @@ -65,6 +67,7 @@ pub enum StmtKind { Sub { to: Expr, value: Expr }, Mul { to: Expr, value: Expr }, Div { to: Expr, value: Expr }, + Int { number: u64 }, Jmp { to: Expr }, Je { to: Expr }, Cmp { lhs: Expr, rhs: Expr }, @@ -195,6 +198,17 @@ where let value = self.expr()?; stmt(span.start..value.span.end, StmtKind::Div { to, value }) } + Token::Int => { + let (next, next_span) = self.next()?; + if let Token::Number(number) = next { + stmt(span.start..next_span.end, StmtKind::Int { number }) + } else { + return Err(CompilerError::simple( + format!("Expected number, found {:?}", next,), + next_span, + )); + } + } Token::Label(name) => { let name = name .strip_suffix(":") @@ -253,6 +267,7 @@ where Token::Sub => return Err(CompilerError::not_allowed(span, "sub")), Token::Mul => return Err(CompilerError::not_allowed(span, "mul")), Token::Div => return Err(CompilerError::not_allowed(span, "div")), + Token::Int => return Err(CompilerError::not_allowed(span, "int")), Token::BracketClose => return Err(CompilerError::not_allowed(span, "]")), Token::Comma => return Err(CompilerError::not_allowed(span, ",")), Token::Label(_) => return Err(CompilerError::not_allowed(span, "{label}")),