lmc_assembly/
lib.rs

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)))), // DAT can have an operand, but doesn't have to
41            _ => 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        // do instruction
214        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                // handle overflow to -999
229                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                // handle underflow to 999
241                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}