|
@@ -0,0 +1,76 @@
|
|
|
|
+use std::collections::BTreeMap;
|
|
|
|
+use super::ir;
|
|
|
|
+
|
|
|
|
+pub fn parse(code: &str) -> Result<Vec<ir::Instruction>, &str> {
|
|
|
|
+ let mut ptr: i64 = 0;
|
|
|
|
+ let mut add_map: BTreeMap<i64, i64> = BTreeMap::new();
|
|
|
|
+ let mut instruction_stack: Vec<Vec<ir::Instruction>> = Vec::new();
|
|
|
|
+ let mut instructions: Vec<ir::Instruction> = Vec::new();
|
|
|
|
+
|
|
|
|
+ let implement = |add_map: &mut BTreeMap<i64, i64>, instructions: &mut Vec<ir::Instruction>, ptr: &mut i64| {
|
|
|
|
+ for (&offset, &value) in add_map.iter() {
|
|
|
|
+ instructions.push(ir::Instruction::Add{ value, offset });
|
|
|
|
+ }
|
|
|
|
+ add_map.clear();
|
|
|
|
+ if *ptr != 0 {
|
|
|
|
+ instructions.push(ir::Instruction::MovePtr(*ptr));
|
|
|
|
+ *ptr = 0;
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ for c in code.chars() {
|
|
|
|
+ match c {
|
|
|
|
+ '+' => {
|
|
|
|
+ match add_map.get_mut(&ptr) {
|
|
|
|
+ Some(entry) => { *entry = entry.wrapping_add(1); },
|
|
|
|
+ None => { add_map.insert(ptr, 1); }
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ '-' => {
|
|
|
|
+ match add_map.get_mut(&ptr) {
|
|
|
|
+ Some(entry) => { *entry = entry.wrapping_sub(1); },
|
|
|
|
+ None => { add_map.insert(ptr, -1); }
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ '>' => { ptr += 1; },
|
|
|
|
+ '<' => { ptr -= 1; },
|
|
|
|
+ '.' => {
|
|
|
|
+ implement(&mut add_map, &mut instructions, &mut ptr);
|
|
|
|
+ instructions.push(ir::Instruction::Write(ptr));
|
|
|
|
+ },
|
|
|
|
+ ',' => {
|
|
|
|
+ implement(&mut add_map, &mut instructions, &mut ptr);
|
|
|
|
+ instructions.push(ir::Instruction::Read(ptr));
|
|
|
|
+ },
|
|
|
|
+ '[' => {
|
|
|
|
+ implement(&mut add_map, &mut instructions, &mut ptr);
|
|
|
|
+ instruction_stack.push(instructions);
|
|
|
|
+ instructions = Vec::new();
|
|
|
|
+ },
|
|
|
|
+ ']' => {
|
|
|
|
+ implement(&mut add_map, &mut instructions, &mut ptr);
|
|
|
|
+ let top = instruction_stack.pop();
|
|
|
|
+ if let Some(mut inst) = top {
|
|
|
|
+ inst.push(ir::Instruction::Loop(instructions));
|
|
|
|
+ instructions = inst;
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ // error, too many ']'
|
|
|
|
+ return Err("found ']' without matching '['");
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ _ => {}
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if instruction_stack.len() > 0 {
|
|
|
|
+ return Err("found '[' without matching ']'");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Ok(instructions)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|