diff --git a/README.md b/README.md index 95ff4f9..8d95b33 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ A virtual machine for controlling a wifi led strip. | load (rgp, rgd) | loads the value the pointer register points to into the data register | 0x04 | | clear \ | clears a register (sets it to 0x00) | 0x05 | | write (rgd, rgp) | writes the value in the data register to the address of the pointer register | 0x06 | -| label (rgl) | creates a label with rgd as the name | 0x07 | -| goto (rgl) | goes to the label with name rgd | 0x08 | +| label | creates a label at the current position. | 0x07 | +| goto (rgl) | goes to the label with name rgl | 0x08 | | debug (*) | prints out the state for debug information | 0x09 | | add (rgd, rgi, rgo) | adds the value of rgi to the value of rgd and writes the result into rgo | 0x10 | | sub (rgd, rgi, rgo) | substracts rgi from rgd and writes the result into rgo | 0x11 | @@ -52,4 +52,13 @@ A virtual machine for controlling a wifi led strip. - the rgi register stores the input for operations that require two input values - the rgo register stores the result of operations - the rgl register stores as label name that can be jumped to -- comments start with # \ No newline at end of file +- comments start with # + +## The Runtime + +The runtime works in three stages. + +1. Connect to the led strip +2. Parse the bytecode into a vector of tokens + - if the instruction creates a label, add the label to the map of labels +3. Execute the token vector \ No newline at end of file diff --git a/src/bin/lsambler.rs b/src/bin/lsambler.rs index 327e5ca..cfff0e0 100644 --- a/src/bin/lsambler.rs +++ b/src/bin/lsambler.rs @@ -68,7 +68,7 @@ fn get_token(line: &str) -> Option> { value: parse_value(instr_parts.next()?).expect(&format!( "Failed to parse the hex value into a u8: {}.", line - )), + )) as u8, register: get_register_code_by_name(instr_parts.next()?)?, }), "copy" => some_box!(CopyToken { @@ -80,7 +80,9 @@ fn get_token(line: &str) -> Option> { register: get_register_code_by_name(instr_parts.next()?)?, }), "write" => some_box!(WriteToken), - "label" => some_box!(LabelToken), + "label" => some_box!(LabelToken { + value: parse_value(instr_parts.next()?).expect("Failed to parse label name") + }), "goto" => some_box!(GotoToken), "debug" => some_box!(DebugToken), "add" => some_box!(AddToken), @@ -102,11 +104,11 @@ fn get_token(line: &str) -> Option> { /// Parses a value depending on if it starts with 0x (as a hex value) /// or just is a plain base-10 number -fn parse_value(value: &str) -> Result { +fn parse_value(value: &str) -> Result { if value.starts_with("0x") { let value = value.trim_start_matches("0x"); - Ok(i64::from_str_radix(value, 16)? as u8) + Ok(i64::from_str_radix(value, 16)? as u32) } else { - value.parse::() + value.parse::() } } diff --git a/src/runtime.rs b/src/runtime.rs index dfa60fc..f0612fc 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -27,7 +27,7 @@ pub struct Runtime { pub rgl: Rgl, pub memory: HashMap, text: Rc>>>, - labels: HashMap, + pub labels: HashMap, pub strip_controller: Rc>, exit: Option, current_index: usize, @@ -63,6 +63,7 @@ impl Runtime { pub fn parse_bytecode(&mut self, bytecode: Vec) { let mut code_iter = bytecode.iter(); let mut text = self.text.borrow_mut(); + let mut index = 0; while let Some(instruction) = code_iter.next() { match *instruction { @@ -86,7 +87,17 @@ impl Runtime { code_iter.next().unwrap(), ]))), T_WRITE => text.push(Box::new(WriteToken)), - T_LABEL => text.push(Box::new(LabelToken)), + T_LABEL => { + let token = LabelToken::from_bytecode(&[ + instruction, + code_iter.next().unwrap(), + code_iter.next().unwrap(), + code_iter.next().unwrap(), + code_iter.next().unwrap(), + ]); + self.labels.insert(token.value, index); + text.push(Box::new(token)); + } T_GOTO => text.push(Box::new(GotoToken)), T_DEBUG => text.push(Box::new(DebugToken)), T_ADD => text.push(Box::new(AddToken)), @@ -104,6 +115,7 @@ impl Runtime { T_SEND => text.push(Box::new(SendToken)), _ => panic!("unknown instruction {}", instruction), }; + index += 1; } } diff --git a/src/tokens.rs b/src/tokens.rs index 2652a40..3d6f633 100644 --- a/src/tokens.rs +++ b/src/tokens.rs @@ -1,6 +1,7 @@ use crate::registers::{Register, RCS}; use crate::runtime::Runtime; use std::io; +use std::mem; use std::thread::sleep; use std::time::Duration; @@ -242,23 +243,30 @@ impl FromBytecode for WriteToken { } #[derive(Debug, Clone)] -pub struct LabelToken; +pub struct LabelToken { + pub value: u32, +} impl Token for LabelToken { fn to_bytecode(&self) -> Vec { - vec![T_LABEL] + let mut bytecode = vec![T_LABEL]; + bytecode.append(&mut self.value.to_be_bytes().to_vec()); + + bytecode } fn invoke(&self, runtime: &mut Runtime) -> io::Result<()> { - runtime.create_label(runtime.rgl.get()); + runtime.create_label(self.value); Ok(()) } } impl FromBytecode for LabelToken { - fn from_bytecode(_: &[&u8]) -> Self { - Self + fn from_bytecode(code: &[&u8]) -> Self { + Self { + value: u32::from_be_bytes([*code[1], *code[2], *code[3], *code[4]]), + } } } @@ -295,6 +303,7 @@ impl Token for DebugToken { println!("rgo: {}", runtime.rgo.get()); println!("rgl: {}", runtime.rgl.get()); println!("\n--- Runtime ---"); + println!("Labels: {:?}", runtime.labels); println!("Memory: {:?}", runtime.memory); println!();