Website Summary Files Commits Branches @commit @diff @stats
path: root / assembler / src / parser / mod.rs
blob: 7061286b27975cdc477744fd5ce72ba520c74312 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use std::collections::HashMap;
use crate::{ Word, lexer::Token };

#[derive(Debug, Default)]
pub(crate) struct Instruction {
    name: String,
    args: Vec<Address>,
}

#[derive(Debug, Default, PartialEq, Eq, Clone)]
pub(crate) enum Address {
    Memory(usize),
    Constants(usize),
    Definitions(String),
    Instruction(usize),
    #[default]
    None,
}

impl Address {
    fn take(&mut self) -> Address {
        let val = self.clone();
        *self = Address::None;
        val
    }
}

#[derive(Debug, Default)]
pub(crate) struct Program {
    definitions: HashMap<String, Address>,
    constants: Vec<Word>,
    instructions: Vec<Instruction>,
}

impl Program {
    pub(crate) fn new(tokens: Vec<Token>) -> Program {
        let mut prog = Program {..Default::default() };

        let mut op_name = String::new();
        let mut op_args = Vec::new();
        let mut value = Address::None;
        let mut symbol_def = String::new();

        for token in tokens {
            match token {
                /* Names (lvalue) */
                Token::Operator(name) => {
                    if ! op_name.is_empty() {
                        prog.instructions.push(Instruction {
                            name: op_name,
                            args: op_args.clone(),
                        });
                    }
                    op_name = name;
                    op_args.clear();
                },
                Token::Label(name) => {
                    // Predicting the index
                    let index = prog.instructions.len() + !op_name.is_empty() as usize;
                    prog.definitions.insert(name, Address::Instruction(index));
                },
                Token::SymbolDef(name) => symbol_def = name,

                /* Values (rvalue) */
                Token::Address(num) => {
                    value = Address::Memory(num as usize);
                },
                Token::Number(num) => {
                    prog.constants.push(num);
                    value = Address::Constants(prog.constants.len() - 1);
                },
                Token::String(str) => {
                    let index = prog.constants.len();
                    for c in str.chars() {
                        prog.constants.push(c as Word);
                    }
                    value = Address::Constants(index);
                },
                Token::Symbol(name) => {
                    value = Address::Definitions(name);
                },
            }

            if value != Address::None {
                if ! symbol_def.is_empty() {
                    prog.definitions.insert(symbol_def.clone(), value.take());
                    symbol_def.clear();
                }
                else {
                    op_args.push(value.take());
                }
            }
        }

        if ! op_name.is_empty() {
            prog.instructions.push(Instruction {
                name: op_name,
                args: op_args.clone(),
            });
        }

        prog
    }
}