lc3_toolchain/ast/
raw_ast.rs

1use crate::ast::parse;
2use either::Either;
3use getset::Getters;
4use parse::Rule;
5use pest::iterators::Pair;
6
7#[derive(Debug)]
8pub struct Program {
9    items: Vec<ProgramItem>,
10}
11
12impl Program {
13    pub fn items(self) -> Vec<ProgramItem> {
14        self.items
15    }
16}
17
18#[derive(Debug, Clone, Getters)]
19pub struct Span {
20    #[get = "pub"]
21    start: usize,
22    #[get = "pub"]
23    end: usize,
24}
25
26#[derive(Debug)]
27pub enum ProgramItem {
28    Comment(Comment),
29    Label(Label),
30    Instruction(Instruction),
31    Directive(Directive),
32}
33
34#[derive(Debug, Clone, Getters)]
35pub struct Comment {
36    #[get = "pub"]
37    content: String,
38    #[get = "pub"]
39    span: Span,
40}
41
42#[derive(Debug, Clone, Getters)]
43pub struct Label {
44    #[get = "pub"]
45    content: String,
46    #[get = "pub"]
47    span: Span,
48}
49
50#[derive(Debug, Copy, Clone)]
51pub enum RegisterType {
52    R0,
53    R1,
54    R2,
55    R3,
56    R4,
57    R5,
58    R6,
59    R7,
60}
61
62#[derive(Debug, Clone, Getters)]
63pub struct Register {
64    #[get = "pub"]
65    content: String,
66    #[get = "pub"]
67    span: Span,
68    #[get = "pub"]
69    register_type: RegisterType,
70}
71
72#[derive(Debug, Clone, Getters)]
73pub struct LabelReference {
74    #[get = "pub"]
75    content: String,
76    #[get = "pub"]
77    span: Span,
78}
79
80#[derive(Debug, Copy, Clone)]
81pub enum BrType {
82    N,
83    Z,
84    P,
85    Nz,
86    Zp,
87    Np,
88    Nzp,
89    None,
90}
91
92#[derive(Debug, Clone)]
93pub enum InstructionType {
94    // arithmetic
95    Add(Register, Register, Either<Register, Immediate>),
96    And(Register, Register, Either<Register, Immediate>),
97    Not(Register, Register),
98    // load and store
99    Ld(Register, LabelReference),
100    Ldi(Register, LabelReference),
101    Ldr(Register, Register, Immediate),
102    Lea(Register, LabelReference),
103    St(Register, LabelReference),
104    Sti(Register, LabelReference),
105    Str(Register, Register, Immediate),
106    // branch
107    Br(BrType, LabelReference),
108    Jmp(Register),
109    Jsr(LabelReference),
110    Jsrr(Register),
111    // control
112    Nop,
113    Ret,
114    Halt,
115    // io
116    Puts,
117    Getc,
118    Out,
119    In,
120    // trap
121    Trap(HexAddress),
122}
123
124#[derive(Debug, Clone, Getters)]
125pub struct Instruction {
126    #[get = "pub"]
127    instruction_type: InstructionType,
128    #[get = "pub"]
129    content: String,
130    #[get = "pub"]
131    span: Span,
132}
133
134#[derive(Debug, Clone, Getters)]
135pub struct StringLiteral {
136    #[get = "pub"]
137    content: String,
138    #[get = "pub"]
139    span: Span,
140}
141
142#[derive(Debug, Clone, Getters)]
143pub struct Immediate {
144    #[get = "pub"]
145    content: String,
146    #[get = "pub"]
147    span: Span,
148}
149
150#[derive(Debug, Clone, Getters)]
151pub struct HexAddress {
152    #[get = "pub"]
153    content: String,
154    #[get = "pub"]
155    span: Span,
156}
157
158#[derive(Debug, Clone)]
159pub enum DirectiveType {
160    ORIG(HexAddress),
161    END,
162    BLKW(Immediate),
163    FILL(Immediate),
164    STRINGZ(StringLiteral),
165}
166
167#[derive(Debug, Clone, Getters)]
168pub struct Directive {
169    #[get = "pub"]
170    directive_type: DirectiveType,
171    #[get = "pub"]
172    content: String,
173    #[get = "pub"]
174    span: Span,
175}
176
177pub fn parse_ast(pair: Pair<Rule>) -> Program {
178    if pair.as_rule() != Rule::Program {
179        unreachable!();
180    }
181    Program {
182        items: pair
183            .into_inner()
184            .into_iter()
185            .map_while(|p| parse_program_item(p))
186            .collect(),
187    }
188}
189
190fn parse_program_item(pair: Pair<Rule>) -> Option<ProgramItem> {
191    match pair.as_rule() {
192        Rule::Comment => Some(ProgramItem::Comment(parse_comment(pair))),
193        Rule::Label => Some(ProgramItem::Label(parse_label(pair))),
194        Rule::Instruction => Some(ProgramItem::Instruction(parse_instruction(pair))),
195        Rule::Directive => Some(ProgramItem::Directive(parse_directive(pair))),
196        Rule::EOI => None,
197        _ => {
198            unreachable!();
199        }
200    }
201}
202
203fn parse_comment(pair: Pair<Rule>) -> Comment {
204    Comment {
205        content: pair.as_str().to_string(),
206        span: Span::from(pair.as_span()),
207    }
208}
209
210fn parse_label(pair: Pair<Rule>) -> Label {
211    Label {
212        content: pair.as_str().to_owned(),
213        span: Span::from(pair.as_span()),
214    }
215}
216
217fn parse_instruction(pair: Pair<Rule>) -> Instruction {
218    assert_eq!(pair.as_rule(), Rule::Instruction);
219    let mut inner = pair.into_inner().into_iter();
220    let instruction = inner.next();
221    assert!(instruction.is_some());
222    let instruction = instruction.unwrap();
223    let mut instruction_line = instruction.clone().into_inner().into_iter();
224    let true_instruction = instruction_line.next();
225    assert!(true_instruction.is_some());
226    let true_instruction = true_instruction.unwrap();
227    Instruction {
228        instruction_type: match true_instruction.as_rule() {
229            Rule::AddInstruction => {
230                let register1 = instruction_line.next();
231                let register2 = instruction_line.next();
232                let register_or_immediate = instruction_line.next();
233                assert!(
234                    register1.is_some() && register2.is_some() && register_or_immediate.is_some()
235                );
236                let register1 = register1.unwrap();
237                let register2 = register2.unwrap();
238                let register_or_immediate = register_or_immediate.unwrap();
239                InstructionType::Add(
240                    parse_register(register1),
241                    parse_register(register2),
242                    parse_register_immediate(register_or_immediate),
243                )
244            }
245            Rule::AndInstruction => {
246                let register1 = instruction_line.next();
247                let register2 = instruction_line.next();
248                let register_or_immediate = instruction_line.next();
249                assert!(
250                    register1.is_some() && register2.is_some() && register_or_immediate.is_some()
251                );
252                let register1 = register1.unwrap();
253                let register2 = register2.unwrap();
254                let register_or_immediate = register_or_immediate.unwrap();
255                InstructionType::And(
256                    parse_register(register1),
257                    parse_register(register2),
258                    parse_register_immediate(register_or_immediate),
259                )
260            }
261            Rule::NotInstruction => {
262                let register1 = instruction_line.next();
263                let register2 = instruction_line.next();
264                assert!(register1.is_some() && register2.is_some());
265                let register1 = register1.unwrap();
266                let register2 = register2.unwrap();
267                InstructionType::Not(parse_register(register1), parse_register(register2))
268            }
269            Rule::LdInstruction => {
270                let register = instruction_line.next();
271                let label_reference = instruction_line.next();
272                assert!(register.is_some() && label_reference.is_some());
273                let register = register.unwrap();
274                let label_reference = label_reference.unwrap();
275                InstructionType::Ld(
276                    parse_register(register),
277                    parse_label_reference(label_reference),
278                )
279            }
280            Rule::LdiInstruction => {
281                let register = instruction_line.next();
282                let label_reference = instruction_line.next();
283                assert!(register.is_some() && label_reference.is_some());
284                let register = register.unwrap();
285                let label_reference = label_reference.unwrap();
286                InstructionType::Ldi(
287                    parse_register(register),
288                    parse_label_reference(label_reference),
289                )
290            }
291            Rule::LdrInstruction => {
292                let register1 = instruction_line.next();
293                let register2 = instruction_line.next();
294                let immediate = instruction_line.next();
295                assert!(register1.is_some() && register2.is_some() && immediate.is_some());
296                let register1 = register1.unwrap();
297                let register2 = register2.unwrap();
298                let immediate = immediate.unwrap();
299                InstructionType::Ldr(
300                    parse_register(register1),
301                    parse_register(register2),
302                    parse_immediate(immediate),
303                )
304            }
305            Rule::LeaInstruction => {
306                let register = instruction_line.next();
307                let label_reference = instruction_line.next();
308                assert!(register.is_some() && label_reference.is_some());
309                let register = register.unwrap();
310                let label_reference = label_reference.unwrap();
311                InstructionType::Lea(
312                    parse_register(register),
313                    parse_label_reference(label_reference),
314                )
315            }
316            Rule::StInstruction => {
317                let register = instruction_line.next();
318                let label_reference = instruction_line.next();
319                assert!(register.is_some() && label_reference.is_some());
320                let register = register.unwrap();
321                let label_reference = label_reference.unwrap();
322                InstructionType::St(
323                    parse_register(register),
324                    parse_label_reference(label_reference),
325                )
326            }
327            Rule::StiInstruction => {
328                let register = instruction_line.next();
329                let label_reference = instruction_line.next();
330                assert!(register.is_some() && label_reference.is_some());
331                let register = register.unwrap();
332                let label_reference = label_reference.unwrap();
333                InstructionType::Sti(
334                    parse_register(register),
335                    parse_label_reference(label_reference),
336                )
337            }
338            Rule::StrInstruction => {
339                let register1 = instruction_line.next();
340                let register2 = instruction_line.next();
341                let immediate = instruction_line.next();
342                assert!(register1.is_some() && register2.is_some() && immediate.is_some());
343                let register1 = register1.unwrap();
344                let register2 = register2.unwrap();
345                let immediate = immediate.unwrap();
346                InstructionType::Str(
347                    parse_register(register1),
348                    parse_register(register2),
349                    parse_immediate(immediate),
350                )
351            }
352            Rule::BrInstruction => {
353                let instruction_type = instruction;
354                assert_eq!(instruction_type.as_rule(), Rule::Br);
355                let instruction = instruction_type.as_str().split_whitespace().next();
356                assert!(instruction.is_some());
357                let instruction = instruction.unwrap().to_uppercase();
358                let instruction_tp = instruction.strip_prefix("BR");
359                assert!(instruction_tp.is_some());
360                let instruction_tp = instruction_tp.unwrap();
361
362                let br_tp = if instruction_tp.contains('N')
363                    && instruction_tp.contains('Z')
364                    && instruction_tp.contains('P')
365                {
366                    BrType::Nzp
367                } else if instruction_tp.contains('N') && instruction_tp.contains('Z') {
368                    BrType::Nz
369                } else if instruction_tp.contains('N') && instruction_tp.contains('P') {
370                    BrType::Np
371                } else if instruction_tp.contains('Z') && instruction_tp.contains('P') {
372                    BrType::Zp
373                } else if instruction_tp.contains('N') {
374                    BrType::N
375                } else if instruction_tp.contains('P') {
376                    BrType::P
377                } else if instruction_tp.contains('Z') {
378                    BrType::Z
379                } else if instruction_tp.is_empty() {
380                    BrType::None
381                } else {
382                    unreachable!()
383                };
384
385                let label_reference = instruction_line.next();
386                assert!(label_reference.is_some());
387                let label_reference = label_reference.unwrap();
388
389                InstructionType::Br(br_tp, parse_label_reference(label_reference))
390            }
391            Rule::JmpInstruction => {
392                let register1 = instruction_line.next();
393                assert!(register1.is_some());
394                let register1 = register1.unwrap();
395                InstructionType::Jmp(parse_register(register1))
396            }
397            Rule::JsrInstruction => {
398                let label_ref = instruction_line.next();
399                assert!(label_ref.is_some());
400                let label_ref = label_ref.unwrap();
401                InstructionType::Jsr(parse_label_reference(label_ref))
402            }
403            Rule::JsrrInstruction => {
404                let register1 = instruction_line.next();
405                assert!(register1.is_some());
406                let register1 = register1.unwrap();
407                InstructionType::Jsrr(parse_register(register1))
408            }
409            Rule::NopInstruction => InstructionType::Nop,
410            Rule::RetInstruction => InstructionType::Ret,
411            Rule::HaltInstruction => InstructionType::Halt,
412            Rule::PutsInstruction => InstructionType::Puts,
413            Rule::GetcInstruction => InstructionType::Getc,
414            Rule::OutInstruction => InstructionType::Out,
415            Rule::InInstruction => InstructionType::In,
416            Rule::TrapInstruction => {
417                let hex_address = instruction_line.next();
418                assert!(hex_address.is_some());
419                let hex_address = hex_address.unwrap();
420                InstructionType::Trap(parse_hex_address(hex_address))
421            }
422            _ => {
423                unreachable!()
424            }
425        },
426        content: true_instruction.as_str().to_owned(),
427        span: Span::from(true_instruction.as_span()),
428    }
429}
430
431fn parse_directive(pair: Pair<Rule>) -> Directive {
432    assert_eq!(pair.as_rule(), Rule::Directive);
433    let mut inner = pair.into_inner().into_iter();
434    let directive_line = inner.next();
435    assert!(directive_line.is_some());
436    let mut directive_line = directive_line.unwrap().into_inner().into_iter();
437    let directive = directive_line.next();
438    assert!(directive.is_some());
439    let directive = directive.unwrap();
440    Directive {
441        directive_type: match directive.as_rule() {
442            Rule::StringzDirective => {
443                let string = directive_line.next();
444                assert!(string.is_some());
445                DirectiveType::STRINGZ(parse_string_literal(string.unwrap()))
446            }
447            Rule::FillDirective => {
448                let immediate = directive_line.next();
449                assert!(immediate.is_some());
450                DirectiveType::FILL(parse_immediate(immediate.unwrap()))
451            }
452            Rule::OrigDirective => {
453                let address = directive_line.next();
454                assert!(address.is_some());
455                DirectiveType::ORIG(parse_hex_address(address.unwrap()))
456            }
457            Rule::EndDirective => DirectiveType::END,
458            Rule::BlkwDirective => {
459                let immediate = directive_line.next();
460                assert!(immediate.is_some());
461                DirectiveType::BLKW(parse_immediate(immediate.unwrap()))
462            }
463            _ => {
464                unreachable!()
465            }
466        },
467        content: directive.as_span().as_str().to_owned(),
468        span: Span::from(directive.as_span()),
469    }
470}
471
472fn parse_string_literal(pair: Pair<Rule>) -> StringLiteral {
473    assert_eq!(pair.as_rule(), Rule::StringLiteral);
474    StringLiteral {
475        content: pair.as_str().to_owned(),
476        span: Span::from(pair.as_span()),
477    }
478}
479
480fn parse_immediate(pair: Pair<Rule>) -> Immediate {
481    assert_eq!(pair.as_rule(), Rule::Immediate);
482    Immediate {
483        content: pair.as_str().to_owned(),
484        span: Span::from(pair.as_span()),
485    }
486}
487
488fn parse_hex_address(pair: Pair<Rule>) -> HexAddress {
489    assert_eq!(pair.as_rule(), Rule::HexAddress);
490    HexAddress {
491        content: pair.as_str().to_owned(),
492        span: Span::from(pair.as_span()),
493    }
494}
495
496fn parse_register(pair: Pair<Rule>) -> Register {
497    assert_eq!(pair.as_rule(), Rule::Register);
498    Register {
499        content: pair.as_str().to_owned(),
500        span: Span::from(pair.as_span()),
501        register_type: match pair.as_str().to_uppercase().as_str() {
502            "R0" => RegisterType::R0,
503            "R1" => RegisterType::R1,
504            "R2" => RegisterType::R2,
505            "R3" => RegisterType::R3,
506            "R4" => RegisterType::R4,
507            "R5" => RegisterType::R5,
508            "R6" => RegisterType::R6,
509            "R7" => RegisterType::R7,
510            _ => {
511                unreachable!()
512            }
513        },
514    }
515}
516
517fn parse_register_immediate(pair: Pair<Rule>) -> Either<Register, Immediate> {
518    if pair.as_rule() == Rule::Register {
519        return Either::Left(parse_register(pair));
520    }
521    Either::Right(parse_immediate(pair))
522}
523
524fn parse_label_reference(pair: Pair<Rule>) -> LabelReference {
525    assert_eq!(pair.as_rule(), Rule::LabelReference);
526    LabelReference {
527        content: pair.as_str().to_owned(),
528        span: Span::from(pair.as_span()),
529    }
530}
531
532impl<'a> From<pest::Span<'a>> for Span {
533    fn from(value: pest::Span) -> Self {
534        Span {
535            start: value.start(),
536            end: value.end(),
537        }
538    }
539}