nand7400/assembler/
mod.rs

1pub mod config;
2pub mod errors;
3pub mod parser;
4pub mod position;
5
6mod tests;
7
8use std::collections::HashMap;
9
10use crate::assembler::config::OpcodeArg;
11
12use self::parser::{
13    ast::{Argument, ArgumentKind, Ast, InstructionKind, Keyword, Label},
14    Parser,
15};
16use config::AssemblerConfig;
17use errors::AssemblerError;
18use num_traits::{FromPrimitive, Num, ToBytes, ToPrimitive};
19
20/// The main assember structure to be used.
21pub struct Assembler {
22    /// The configuration for the assembler.
23    config: AssemblerConfig,
24}
25
26/// Public API for the assembler.
27impl Assembler {
28    /// Create a new assembler with the given configuration.
29    pub fn new(config: AssemblerConfig) -> Self {
30        Self { config }
31    }
32
33    /// Replaces the configuration of the assembler with the given one.
34    pub fn set_config(&mut self, config: AssemblerConfig) {
35        self.config = config;
36    }
37
38    /// Assembles the given assembly code into binary.
39    pub fn assemble(&mut self, source: &str) -> Result<Vec<u8>, AssemblerError> {
40        Ok(self.assemble_with_ast(source)?.0)
41    }
42
43    /// Assembles the given assembly code into binary and associated AST.
44    pub fn assemble_with_ast(&mut self, source: &str) -> Result<(Vec<u8>, Ast), AssemblerError> {
45        let ast = Parser::new(source)?.parse()?; // Parse the source into an AST.
46        let mut next_mem_location = 0; // The next memory location to write to.
47        let mut binary = vec![]; // The binary to write to.
48
49        for instruction in &ast.instructions {
50            match &instruction.kind {
51                // Skip labels, as they;ve already been loaded into the symbol table.
52                InstructionKind::Label(_) => continue,
53
54                // Execute the keywords as they come in.
55                InstructionKind::Keyword { keyword, arguments } => match keyword {
56                    // Set the memory location to the 1st argument.
57                    Keyword::Org => {
58                        // Make sure there's only 1 argument.
59                        if arguments.len() != 1 {
60                            return Err(AssemblerError::WrongNumArgs {
61                                mnemonic: keyword.to_string(),
62                                expected: 1,
63                                given: arguments.len() as u16,
64                                mnemonic_span: instruction.token_span,
65                                args_span: arguments
66                                    .iter()
67                                    .map(|arg| arg.span)
68                                    .fold(instruction.token_span, |acc, span| acc.join(&span)),
69                            });
70                        }
71
72                        let arg = &arguments[0]; // This is safe because we already checked the length.
73
74                        // Now adjust the memory location based on the argument.
75                        next_mem_location = decode_arg_u16(&ast.symbols, arg)? as usize;
76                    }
77
78                    // Set the next byte(s) to the arguments.
79                    Keyword::Byte => {
80                        let mut bytes = vec![];
81
82                        for arg in arguments {
83                            bytes.extend(decode_arg_bytes(&ast.symbols, arg)?);
84                        }
85
86                        for (i, byte) in bytes.iter().enumerate() {
87                            binary.insert(next_mem_location + i, *byte);
88                        }
89
90                        next_mem_location += bytes.len();
91                    }
92                },
93
94                InstructionKind::Opcode {
95                    mnemonic,
96                    arguments,
97                } => {
98                    // Get the opcode from the configuration.
99                    let opcode = self.config.get_opcode(mnemonic).ok_or_else(|| {
100                        AssemblerError::OpcodeDNE {
101                            mnemonic: mnemonic.clone(),
102                            span: instruction.token_span,
103                        }
104                    })?;
105
106                    // Make sure the number of arguments is correct.
107                    if opcode.args.len() != instruction.args_len_bytes() {
108                        return Err(AssemblerError::WrongNumArgs {
109                            mnemonic: mnemonic.clone(),
110                            expected: opcode.args.len() as u16,
111                            given: arguments.len() as u16,
112                            mnemonic_span: instruction.token_span,
113                            args_span: arguments
114                                .iter()
115                                .map(|arg| arg.span)
116                                .fold(instruction.token_span, |acc, span| acc.join(&span)),
117                        });
118                    }
119
120                    // Now decode the arguments into bytes.
121                    let mut bytes = vec![opcode.binary];
122
123                    for (arg, arg_type) in arguments.iter().zip(opcode.args.iter()) {
124                        let given_arg_type = OpcodeArg::from(arg);
125
126                        // Check the argument type against the opcode.
127                        if given_arg_type != *arg_type {
128                            return Err(AssemblerError::WrongArgType {
129                                mnemonic: mnemonic.clone(),
130                                expected: *arg_type,
131                                given: given_arg_type,
132                                mnemonic_span: instruction.token_span,
133                                arg_span: arg.span,
134                            });
135                        }
136
137                        // Now decode the argument into bytes.
138                        bytes.extend(decode_arg_bytes(&ast.symbols, arg)?);
139                    }
140
141                    // Now insert the bytes into the binary.
142                    for (i, byte) in bytes.iter().enumerate() {
143                        binary.insert(next_mem_location + i, *byte);
144                    }
145
146                    // Adjust the memory location.
147                    next_mem_location += bytes.len();
148                }
149            }
150
151            // Adjust the binary buffer if the next location is out-of-range.
152            if next_mem_location > binary.len() {
153                binary.resize(next_mem_location, 0);
154            }
155        }
156
157        Ok((binary, ast))
158    }
159}
160
161/// Decodes an argument into a series of bytes. Numbers and labels are converted to little endian. However, if the trailing
162/// byte(s) is/are 0, then they are cut. This does not happen to labels, and only happens to numbers.
163pub fn decode_arg_bytes<T>(
164    symbol_table: &HashMap<Label, u16>,
165    arg: &Argument<T>,
166) -> Result<Vec<u8>, AssemblerError>
167where
168    T: Num + ToBytes + ToPrimitive + Clone,
169{
170    match &arg.kind {
171        ArgumentKind::ImmediateNumber(num) | ArgumentKind::IndirectNumber(num) => {
172            let mut bytes = num.to_le_bytes().as_ref().to_vec();
173
174            // Remove trailing 0s, except for the last one.
175            while bytes.last() == Some(&0) && bytes.len() > 1 {
176                bytes.pop();
177            }
178
179            Ok(bytes)
180        }
181
182        ArgumentKind::Label(label) => Ok(symbol_table
183            .get(label)
184            .ok_or_else(|| AssemblerError::LabelDNE {
185                mnemonic: label.clone(),
186                span: arg.span,
187            })?
188            .to_le_bytes()
189            .to_vec()),
190    }
191}
192
193/// Decodes an argument into a `u16` type.
194pub fn decode_arg_u16<T>(
195    symbol_table: &HashMap<Label, u16>,
196    arg: &Argument<T>,
197) -> Result<u16, AssemblerError>
198where
199    T: Num + ToBytes + ToPrimitive + Clone + FromPrimitive,
200{
201    match &arg.kind {
202        ArgumentKind::ImmediateNumber(num) | ArgumentKind::IndirectNumber(num) => {
203            Ok(num.to_u16().expect("Need to catch this error!"))
204        }
205
206        ArgumentKind::Label(label) => {
207            Ok(*symbol_table
208                .get(label)
209                .ok_or_else(|| AssemblerError::LabelDNE {
210                    mnemonic: label.clone(),
211                    span: arg.span,
212                })?)
213        }
214    }
215}