interrupts!

This commit is contained in:
nora 2022-06-20 15:18:26 +02:00
parent b56c293581
commit ce7deb7dc6
4 changed files with 64 additions and 17 deletions

View file

@ -88,6 +88,14 @@ The result is stored in the `place` `A`.
Div divides the `place` `A` by the `value` `B`. Div divides the `place` `A` by the `value` `B`.
The result is stored in the `place` `A`. 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
`cmp A, B` `cmp A, B`
@ -112,4 +120,16 @@ the next instruction executed will be the instruction located at `L`.
`<IDENT>:` `<IDENT>:`
A label is an identifier (regex: `[a-zA-Z]\w+`) followed by a colon (`:`). Jumps (like `jmp` or `je`) will be able 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. 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.

View file

@ -22,29 +22,27 @@ impl Register {
} }
} }
const MEMORY_SIZE = 1024 * 1024 * 1024; const MEMORY_SIZE: usize = 1024 * 1024 * 1024;
struct InterpretCtx { struct InterpretCtx {
memory: Vec<u8>, memory: Vec<u8>,
registers: [u64; 16], registers: [u64; 16],
flag: bool, flag: bool,
stmts: Vec<Stmt>,
spans: Vec<Span>,
ip: usize, ip: usize,
} }
impl InterpretCtx { impl InterpretCtx {
fn interpret(&mut self) -> Result<()> { fn interpret(&mut self, stmts: Vec<Stmt>) -> Result<()> {
let stmt_i = self.ip; let stmt_i = self.ip;
while stmt_i < self.stmts.len() { while stmt_i < stmts.len() {
self.ip += 1; self.ip += 1;
self.interpret_stmt(stmt_i)? self.interpret_stmt(stmt_i, &stmts)?
} }
Ok(()) Ok(())
} }
fn interpret_stmt(&mut self, stmt_i: usize) -> Result<()> { fn interpret_stmt(&mut self, stmt_i: usize, stmts: &[Stmt]) -> Result<()> {
let stmt = &self.stmts[stmt_i]; let stmt = &stmts[stmt_i];
match stmt { match stmt {
Stmt::Mov { from, to } => { Stmt::Mov { from, to } => {
let value = self.read_value(from); let value = self.read_value(from);
@ -74,6 +72,9 @@ impl InterpretCtx {
let new = old.wrapping_div(value); let new = old.wrapping_div(value);
self.write_place(to, new); self.write_place(to, new);
} }
Stmt::Int { number } => {
self.interrupt(*number);
}
Stmt::Jmp { to } => { Stmt::Jmp { to } => {
let index = to.index; let index = to.index;
self.ip = index; self.ip = index;
@ -93,6 +94,14 @@ impl InterpretCtx {
Ok(()) 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 { fn read_value(&self, value: &Value) -> u64 {
match value { match value {
Value::Literal(n) => *n, Value::Literal(n) => *n,
@ -153,16 +162,13 @@ impl InterpretCtx {
} }
} }
pub fn interpret(stmts: Vec<Stmt>, _spans: Vec<Span>) -> Result<()> {
pub fn interpret(stmts: Vec<Stmt>, spans: Vec<Span>) -> Result<()> {
let mut ctx = InterpretCtx { let mut ctx = InterpretCtx {
memory: vec![0; MEMORY_SIZE], memory: vec![0; MEMORY_SIZE],
registers: [0; 16], registers: [0; 16],
flag: false, flag: false,
stmts,
spans,
ip: 0, ip: 0,
}; };
ctx.interpret() ctx.interpret(stmts)
} }

View file

@ -1,5 +1,4 @@
use std::collections::HashMap; use std::{collections::HashMap, mem};
use std::mem;
use dbg_pls::DebugPls; use dbg_pls::DebugPls;
use logos::Span; use logos::Span;
@ -40,6 +39,7 @@ pub enum Stmt {
Sub { to: Place, value: Value }, Sub { to: Place, value: Value },
Mul { to: Place, value: Value }, Mul { to: Place, value: Value },
Div { to: Place, value: Value }, Div { to: Place, value: Value },
Int { number: u64 },
Jmp { to: Location }, Jmp { to: Location },
Je { to: Location }, Je { to: Location },
Cmp { lhs: Value, rhs: Value }, Cmp { lhs: Value, rhs: Value },
@ -95,6 +95,12 @@ impl CompileCtx {
let value = self.compile_value(value)?; let value = self.compile_value(value)?;
Stmt::Div { to, 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 } => { 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 }
@ -194,7 +200,7 @@ impl CompileCtx {
Ok(()) 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(|| { let (location, _) = self.labels.get(label).ok_or_else(|| {
CompilerError::simple( CompilerError::simple(
format!("label {label} not found"), format!("label {label} not found"),

View file

@ -23,6 +23,8 @@ pub enum Token<'a> {
Mul, Mul,
#[token("div")] #[token("div")]
Div, Div,
#[token("int")]
Int,
#[token("[")] #[token("[")]
BracketOpen, BracketOpen,
#[token("]")] #[token("]")]
@ -65,6 +67,7 @@ pub enum StmtKind {
Sub { to: Expr, value: Expr }, Sub { to: Expr, value: Expr },
Mul { to: Expr, value: Expr }, Mul { to: Expr, value: Expr },
Div { to: Expr, value: Expr }, Div { to: Expr, value: Expr },
Int { number: u64 },
Jmp { to: Expr }, Jmp { to: Expr },
Je { to: Expr }, Je { to: Expr },
Cmp { lhs: Expr, rhs: Expr }, Cmp { lhs: Expr, rhs: Expr },
@ -195,6 +198,17 @@ where
let value = self.expr()?; let value = self.expr()?;
stmt(span.start..value.span.end, StmtKind::Div { to, value }) 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) => { Token::Label(name) => {
let name = name let name = name
.strip_suffix(":") .strip_suffix(":")
@ -253,6 +267,7 @@ where
Token::Sub => return Err(CompilerError::not_allowed(span, "sub")), Token::Sub => return Err(CompilerError::not_allowed(span, "sub")),
Token::Mul => return Err(CompilerError::not_allowed(span, "mul")), Token::Mul => return Err(CompilerError::not_allowed(span, "mul")),
Token::Div => return Err(CompilerError::not_allowed(span, "div")), 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::BracketClose => return Err(CompilerError::not_allowed(span, "]")),
Token::Comma => return Err(CompilerError::not_allowed(span, ",")), Token::Comma => return Err(CompilerError::not_allowed(span, ",")),
Token::Label(_) => return Err(CompilerError::not_allowed(span, "{label}")), Token::Label(_) => return Err(CompilerError::not_allowed(span, "{label}")),