1use std::{
2 io::{self, Write},
3 str::FromStr,
4};
5
6#[cfg(feature = "serde")]
7use serde_derive::{Deserialize, Serialize};
8
9#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
10#[derive(Debug)]
11pub enum Instruction {
12 LDA(Operand),
13 STA(Operand),
14 ADD(Operand),
15 SUB(Operand),
16 INP,
17 OUT,
18 OTC,
19 HLT,
20 BRZ(Operand),
21 BRP(Operand),
22 BRA(Operand),
23 DAT(Operand),
24}
25
26impl Instruction {
27 pub fn from_string(opcode: &str, operand: Option<Operand>) -> Option<Self> {
28 match opcode.to_uppercase().as_str() {
29 "LDA" => Some(Instruction::LDA(operand.expect("LDA requires an operand"))),
30 "STA" => Some(Instruction::STA(operand.expect("STA requires an operand"))),
31 "ADD" => Some(Instruction::ADD(operand.expect("ADD requires an operand"))),
32 "SUB" => Some(Instruction::SUB(operand.expect("SUB requires an operand"))),
33 "INP" => Some(Instruction::INP),
34 "OUT" => Some(Instruction::OUT),
35 "OTC" => Some(Instruction::OTC),
36 "HLT" => Some(Instruction::HLT),
37 "BRZ" => Some(Instruction::BRZ(operand.expect("BRZ requires an operand"))),
38 "BRP" => Some(Instruction::BRP(operand.expect("BRP requires an operand"))),
39 "BRA" => Some(Instruction::BRA(operand.expect("BRA requires an operand"))),
40 "DAT" => Some(Instruction::DAT(operand.unwrap_or(Operand::Value(0)))), _ => None,
42 }
43 }
44 fn get_base(&self) -> i16 {
45 match self {
46 Self::LDA(_) => 500,
47 Self::STA(_) => 300,
48 Self::ADD(_) => 100,
49 Self::SUB(_) => 200,
50 Self::INP => 901,
51 Self::OUT => 902,
52 Self::OTC => 922,
53 Self::HLT => 0,
54 Self::BRZ(_) => 700,
55 Self::BRP(_) => 800,
56 Self::BRA(_) => 600,
57 Self::DAT(_) => 0,
58 }
59 }
60}
61
62#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
63#[derive(Debug)]
64pub enum Operand {
65 Value(i16),
66 Label(String),
67}
68
69impl FromStr for Operand {
70 type Err = String;
71
72 fn from_str(s: &str) -> Result<Self, Self::Err> {
73 match s.parse::<i16>() {
74 Ok(val) => Ok(Operand::Value(val)),
75 Err(_) => Ok(Operand::Label(s.to_string())),
76 }
77 }
78}
79
80impl Operand {
81 fn get_value(&self, program: &Program) -> Result<i16, String> {
82 match self {
83 Operand::Value(val) => Ok(*val),
84 Operand::Label(lbl) => {
85 for (pos, (label, _)) in program.iter().enumerate() {
86 if label == &Label::LBL(lbl.to_string()) {
87 return Ok(pos as i16);
88 }
89 }
90 Err(format!("Invalid label... {}", lbl))
91 }
92 }
93 }
94}
95
96#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
97#[derive(Debug)]
98pub enum Label {
99 LBL(String),
100 None,
101}
102
103impl PartialEq for Label {
104 fn eq(&self, other: &Self) -> bool {
105 match (self, other) {
106 (Label::LBL(a), Label::LBL(b)) => a == b,
107 (Label::None, Label::None) => true,
108 _ => false,
109 }
110 }
111}
112
113pub type Program = Vec<(Label, Instruction)>;
114
115pub fn parse(code: &str, debug_mode: bool) -> Result<Program, String> {
116 if debug_mode {
117 println!("Parsing code...");
118 }
119
120 let mut program: Program = vec![];
121
122 for line in code.lines() {
123 let tokens: Vec<&str> = line.split_whitespace().collect();
124
125 if debug_mode {
126 println!("{:?}", tokens);
127 }
128
129 if !tokens.is_empty() && tokens[0].starts_with("//") {
130 continue;
131 }
132
133 match tokens.len() {
134 0 => continue,
135 1 => {
136 let instruction = Instruction::from_string(tokens[0], None)
137 .ok_or_else(|| format!("Invalid opcode... {}", tokens[0]))?;
138
139 program.push((Label::None, instruction));
140 }
141 2 => {
142 let operand = tokens[1].parse::<Operand>()?;
143
144 match Instruction::from_string(tokens[0], Some(operand)) {
145 Some(val) => program.push((Label::None, val)),
146 None => {
147 let instruction = Instruction::from_string(tokens[1], None)
148 .ok_or_else(|| format!("Invalid opcode... {}", tokens[1]))?;
149
150 program.push((Label::LBL(tokens[0].to_string()), instruction));
151 }
152 }
153 }
154 3 => {
155 let operand = tokens[2].parse::<Operand>()?;
156
157 let instruction = Instruction::from_string(tokens[1], Some(operand))
158 .ok_or_else(|| format!("Invalid opcode... {}", tokens[1]))?;
159
160 program.push((Label::LBL(tokens[0].to_string()), instruction));
161 }
162 _ => return Err(format!("Error while reading line: {}", line)),
163 }
164 }
165
166 if debug_mode {
167 println!();
168 }
169
170 Ok(program)
171}
172
173pub fn assemble(program: Program) -> Result<[i16; 100], String> {
174 let mut ram = [0; 100];
175
176 for (i, (_, instruction)) in program.iter().enumerate() {
177 ram[i] = match instruction {
178 Instruction::BRZ(operand) | Instruction::BRP(operand) | Instruction::BRA(operand) => {
179 instruction.get_base() + operand.get_value(&program)?
180 }
181 Instruction::DAT(operand) => operand.get_value(&program)?,
182 Instruction::LDA(operand)
183 | Instruction::STA(operand)
184 | Instruction::ADD(operand)
185 | Instruction::SUB(operand) => instruction.get_base() + operand.get_value(&program)?,
186 Instruction::INP | Instruction::OUT | Instruction::OTC | Instruction::HLT => {
187 instruction.get_base()
188 }
189 }
190 }
191
192 Ok(ram)
193}
194
195#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
196#[derive(Debug)]
197pub struct ExecutionState {
198 pub pc: i16,
199 pub cir: i16,
200 pub mar: i16,
201 pub mdr: i16,
202 pub acc: i16,
203 #[cfg_attr(feature = "serde", serde(with = "serde_arrays"))]
204 pub ram: [i16; 100],
205}
206
207impl ExecutionState {
208 pub fn step<T: LMCIO>(&mut self, io_handler: &mut T) -> Result<(), String> {
209 self.mar = self.pc;
210 self.pc += 1;
211 self.mdr = self.ram[self.mar as usize];
212 self.cir = self.mdr;
213 match self.cir {
215 0 => self.pc = -1,
216 901 => {
217 let res = io_handler.get_input();
218 if !(-999..=999).contains(&res) {
219 return Err("Number out of range".to_string());
220 }
221 self.acc = res;
222 }
223 902 => io_handler.print_output(Output::Int(self.acc)),
224 922 => io_handler.print_output(Output::Char(self.acc as u8 as char)),
225 100..=199 => {
226 self.mar = self.cir - 100;
227 self.acc += self.ram[self.mar as usize];
228 if self.acc > 999 {
230 let diff = self.acc - 999;
231 self.acc = -999 + diff - 1;
232 } else if self.acc < -999 {
233 let diff = -999 - self.acc;
234 self.acc = 999 - diff + 1;
235 }
236 }
237 200..=299 => {
238 self.mar = self.cir - 200;
239 self.acc -= self.ram[self.mar as usize];
240 if self.acc < -999 {
242 let diff = -999 - self.acc;
243 self.acc = 999 - diff + 1;
244 } else if self.acc > 999 {
245 let diff = self.acc - 999;
246 self.acc = -999 + diff - 1;
247 }
248 }
249 300..=399 => {
250 self.mar = self.cir - 300;
251 self.ram[self.mar as usize] = self.acc;
252 }
253 500..=599 => {
254 self.mar = self.cir - 500;
255 self.acc = self.ram[self.mar as usize];
256 }
257 600..=699 => {
258 self.mar = self.cir - 600;
259 self.pc = self.mar;
260 }
261 700..=799 => {
262 self.mar = self.cir - 700;
263 if self.acc == 0 {
264 self.pc = self.mar;
265 }
266 }
267 800..=899 => {
268 self.mar = self.cir - 800;
269 if self.acc >= 0 {
270 self.pc = self.mar;
271 }
272 }
273 _ => return Err(format!("Invalid instruction: {}", self.cir)),
274 };
275
276 Ok(())
277 }
278}
279
280#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
281#[derive(Debug, PartialEq)]
282pub enum Output {
283 Char(char),
284 Int(i16),
285}
286
287pub trait LMCIO {
288 fn get_input(&mut self) -> i16;
289 fn print_output(&mut self, val: Output);
290}
291
292pub struct DefaultIO;
293
294impl LMCIO for DefaultIO {
295 fn get_input(&mut self) -> i16 {
296 print!("> ");
297 io::stdout().flush().unwrap();
298 let mut input = String::new();
299 io::stdin()
300 .read_line(&mut input)
301 .expect("Failed to read line");
302
303 input.trim().parse::<i16>().unwrap()
304 }
305
306 fn print_output(&mut self, val: Output) {
307 match val {
308 Output::Char(c) => print!("{}", c),
309 Output::Int(i) => println!("{}", i),
310 }
311 }
312}
313
314pub fn run<T: LMCIO>(
315 program: [i16; 100],
316 io_handler: &mut T,
317 debug_mode: bool,
318) -> Result<(), String> {
319 let mut state = ExecutionState {
320 pc: 0,
321 cir: 0,
322 mar: 0,
323 mdr: 0,
324 acc: 0,
325 ram: program,
326 };
327
328 loop {
329 state.step(io_handler)?;
330
331 if state.pc == -1 {
332 break;
333 }
334
335 if debug_mode {
336 println!("PC: {}", state.pc);
337 println!("CIR: {}", state.cir);
338 println!("MAR: {}", state.mar);
339 println!("MDR: {}", state.mdr);
340 println!("ACC: {}", state.acc);
341 println!("RAM: {:?}", state.ram);
342 println!();
343 }
344
345 if state.pc > 99 {
346 break;
347 }
348 }
349
350 Ok(())
351}