Created
December 22, 2017 19:46
-
-
Save PurpleMyst/908f94abebabda64ead72711c9b6e3f5 to your computer and use it in GitHub Desktop.
An Assembunny interpreter. (AoC 2016 Day 12)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#[derive(Debug, Clone)] | |
enum Instruction { | |
Unary(String, String), | |
Binary(String, String, String) | |
} | |
#[derive(Debug)] | |
struct CPU { | |
a: isize, | |
b: isize, | |
c: isize, | |
d: isize, | |
pc: isize, | |
code: Vec<Instruction> | |
} | |
impl Instruction { | |
fn from_string(instruction: String) -> Self { | |
let mut instruction_ws = instruction.split_whitespace(); | |
macro_rules! next_argument { | |
() => { | |
instruction_ws.next().expect("Expected more arguments.").to_owned() | |
}; | |
} | |
macro_rules! instruction { | |
(unary, $mnemonic: ident) => { | |
Instruction::Unary($mnemonic.to_owned(), next_argument!()); | |
}; | |
(binary, $mnemonic: ident) => { | |
Instruction::Binary($mnemonic.to_owned(), next_argument!(), next_argument!()); | |
} | |
} | |
let mnemonic = instruction_ws.next().expect("No mnemonic found."); | |
match mnemonic { | |
"cpy" => instruction!(binary, mnemonic), | |
"inc" => instruction!(unary, mnemonic), | |
"dec" => instruction!(unary, mnemonic), | |
"jnz" => instruction!(binary, mnemonic), | |
"tgl" => instruction!(unary, mnemonic), | |
_ => panic!("Unknown instruction!") | |
} | |
} | |
} | |
impl CPU { | |
fn new<I: IntoIterator<Item = String>>(code: I) -> CPU { | |
CPU { | |
a: 0, | |
b: 0, | |
c: 0, | |
d: 0, | |
pc: 0, | |
code: code.into_iter().map(Instruction::from_string).collect() | |
} | |
} | |
fn get_value(&self, argument: &str) -> isize { | |
match argument { | |
"a" => self.a, | |
"b" => self.b, | |
"c" => self.c, | |
"d" => self.d, | |
_ => argument.parse().expect("Could not parse argument.") | |
} | |
} | |
fn set_value(&mut self, register: &str, value: isize) { | |
match register { | |
"a" => self.a = value, | |
"b" => self.b = value, | |
"c" => self.c = value, | |
"d" => self.d = value, | |
_ => panic!("Tried to set unknown register {:?}.", register) | |
} | |
} | |
fn execute_instruction(&mut self) -> bool { | |
if self.pc < 0 || self.pc >= (self.code.len() as isize) { | |
return false; | |
} | |
let instruction = &self.code[self.pc as usize].clone(); | |
match *instruction { | |
Instruction::Unary(ref mnemonic, ref x) => match mnemonic.as_ref() { | |
"inc" => { | |
let value = self.get_value(x); | |
self.set_value(x, value + 1); | |
}, | |
"dec" => { | |
let value = self.get_value(x); | |
self.set_value(x, value - 1); | |
} | |
_ => panic!("Unknown unary instruction!") | |
}, | |
Instruction::Binary(ref mnemonic, ref x, ref y) => match mnemonic.as_ref() { | |
"cpy" => { | |
let value = self.get_value(x); | |
self.set_value(y, value); | |
}, | |
"jnz" => { | |
let x_value = self.get_value(x); | |
let y_value = self.get_value(y); | |
if x_value != 0 { | |
// We offset y_value by one to account for the `self.pc += 1` later. | |
self.pc += y_value - 1; | |
} | |
}, | |
_ => panic!("Unknown binary instruction!") | |
} | |
} | |
self.pc += 1; | |
true | |
} | |
fn execute_all_instructions(&mut self) { | |
while self.execute_instruction() {} | |
} | |
} | |
fn main() { | |
let code = include_str!("assembunny_code.txt").split('\n') | |
.map(|s| s.to_owned()) | |
.filter(|s| s.len() > 0); | |
let mut cpu = CPU::new(code); | |
cpu.execute_all_instructions(); | |
println!("{}", cpu.a); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cpy 1 a | |
cpy 1 b | |
cpy 26 d | |
jnz c 2 | |
jnz 1 5 | |
cpy 7 c | |
inc d | |
dec c | |
jnz c -2 | |
cpy a c | |
inc a | |
dec b | |
jnz b -2 | |
cpy c b | |
dec d | |
jnz d -6 | |
cpy 13 c | |
cpy 14 d | |
inc a | |
dec d | |
jnz d -2 | |
dec c | |
jnz c -5 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The assembunny code you've extracted operates on four registers (a, b, c, and d) that start at 0 and can hold any integer. However, it seems to make use of only a few instructions: | |
cpy x y copies x (either an integer or the value of a register) into register y. | |
inc x increases the value of register x by one. | |
dec x decreases the value of register x by one. | |
jnz x y jumps to an instruction y away (positive means forward; negative means backward), but only if x is not zero. | |
The jnz instruction moves relative to itself: an offset of -1 would continue at the previous instruction, while an offset of 2 would skip over the next instruction. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment