This commit is contained in:
nora 2022-06-20 17:06:43 +02:00
parent ce7deb7dc6
commit f9a3d93558
5 changed files with 108 additions and 27 deletions

View file

@ -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.
`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.

View file

@ -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<Stmt>) -> 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<Stmt>, _spans: Vec<Span>) -> Result<()> {

View file

@ -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 }

View file

@ -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")),

21
test.at
View file

@ -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:
mov [0], 40
mov [1], 41
mov [2], 42
mov [3], 43
mov r0, 0
mov r1, 4
int 1