1use std::fmt;
2
3use byteorder::{LittleEndian, WriteBytesExt};
4use nom::types::CompleteStr;
5
6use assembler::comment_parsers::comment;
7use assembler::label_parsers::label_declaration;
8use assembler::opcode_parsers::*;
9use assembler::operand_parsers::operand;
10use assembler::{SymbolTable, Token};
11use instruction;
12
13const MAX_I16: i32 = 32768;
14const MIN_I16: i32 = -32768;
15
16#[derive(Debug, PartialEq)]
17pub struct AssemblerInstruction {
18 pub opcode: Option<Token>,
19 pub label: Option<Token>,
20 pub directive: Option<Token>,
21 pub operand1: Option<Token>,
22 pub operand2: Option<Token>,
23 pub operand3: Option<Token>,
24}
25
26impl AssemblerInstruction {
27 pub fn to_bytes(&self, symbols: &SymbolTable) -> Vec<u8> {
28 let mut results: Vec<u8> = vec![];
29 if let Some(ref token) = self.opcode {
30 match token {
31 Token::Op { code } => match code {
32 _ => {
33 let b: u8 = (*code).into();
34 results.push(b);
35 }
36 },
37 _ => {
38 println!("Non-opcode found in opcode field");
39 }
40 }
41 }
42 for operand in &[&self.operand1, &self.operand2, &self.operand3] {
43 if let Some(token) = operand {
44 AssemblerInstruction::extract_operand(token, &mut results, symbols);
45 }
46 }
47 while results.len() < 4 {
48 results.push(0);
49 }
50
51 results
52 }
53
54 pub fn is_label(&self) -> bool {
55 self.label.is_some()
56 }
57
58 pub fn is_opcode(&self) -> bool {
59 self.opcode.is_some()
60 }
61
62 pub fn is_integer_needs_splitting(&self) -> bool {
63 if let Some(ref op) = self.opcode {
64 match op {
65 Token::Op{ code } => {
66 match code {
67 instruction::Opcode::LOAD => {
68 if let Some(ref first_half) = self.operand2 {
69 match first_half {
70 Token::IntegerOperand{ ref value } => {
71 if *value > MAX_I16 || *value < MIN_I16 {
72 return true;
73 }
74 return false;
75 },
76 _ => {
77 return false;
78 }
79 }
80 }
81 return true;
82 },
83 _ => { return false; }
84 }
85 }
86 _ => { return false; }
87 }
88 }
89 false
90 }
91
92 pub fn is_directive(&self) -> bool {
93 self.directive.is_some()
94 }
95
96 pub fn get_integer_value(&self) -> Option<i16> {
97 if let Some(ref operand) = self.operand2 {
98 match operand {
99 Token::IntegerOperand{ ref value } => {
100 return Some(*value as i16)
101 },
102 _ => {
103 return None
104 }
105 }
106 }
107 None
108 }
109
110 pub fn get_register_number(&self) -> Option<u8> {
111 match self.operand1 {
112 Some(ref reg_token) => {
113 match reg_token {
114 Token::Register{ ref reg_num } => {
115 Some(reg_num.clone())
116 },
117 _ => { None }
118 }
119 },
120 None => { None }
121 }
122 }
123
124 pub fn set_opernand_two(&mut self, t: Token) {
125 self.operand2 = Some(t)
126 }
127
128 pub fn set_operand_three(&mut self, t: Token) {
129 self.operand3 = Some(t)
130 }
131
132 pub fn has_operands(&self) -> bool {
134 self.operand1.is_some() || self.operand2.is_some() || self.operand3.is_some()
135 }
136
137 pub fn get_directive_name(&self) -> Option<String> {
138 match &self.directive {
139 Some(d) => match d {
140 Token::Directive { name } => Some(name.to_string()),
141 _ => None,
142 },
143 None => None,
144 }
145 }
146
147 pub fn get_string_constant(&self) -> Option<String> {
148 match &self.operand1 {
149 Some(d) => match d {
150 Token::IrString { name } => Some(name.to_string()),
151 _ => None,
152 },
153 None => None,
154 }
155 }
156
157 pub fn get_i32_constant(&self) -> Option<i32> {
158 match &self.operand1 {
159 Some(d) => match d {
160 Token::IntegerOperand { value } => Some(*value),
161 _ => None,
162 },
163 None => None,
164 }
165 }
166
167 pub fn get_label_name(&self) -> Option<String> {
168 match &self.label {
169 Some(l) => match l {
170 Token::LabelDeclaration { name } => Some(name.clone()),
171 _ => None,
172 },
173 None => None,
174 }
175 }
176
177 fn extract_operand(t: &Token, results: &mut Vec<u8>, symbols: &SymbolTable) {
178 match t {
179 Token::Register { reg_num } => {
180 results.push(*reg_num);
181 },
182 Token::IntegerOperand { value } => {
183 let mut wtr = vec![];
184 wtr.write_i16::<LittleEndian>(*value as i16).unwrap();
185 results.push(wtr[1]);
186 results.push(wtr[0]);
187 },
188 Token::LabelUsage { name } => {
189 if let Some(value) = symbols.symbol_value(name) {
190 let mut wtr = vec![];
191 wtr.write_u32::<LittleEndian>(value).unwrap();
192 results.push(wtr[1]);
193 results.push(wtr[0]);
194 } else {
195 error!("No value found for {:?}", name);
196 }
197 }
198 _ => {
199 error!("Opcode found in operand field: {:#?}", t);
200 }
201 };
202 }
203}
204
205impl fmt::Display for AssemblerInstruction {
206 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
207 write!(f, "(Label: {:?} Opcode: {:?} Directive: {:?} Operand #1: {:?} Operand #2: {:?} Operand #3: {:?})", self.label, self.opcode, self.directive, self.operand1, self.operand2, self.operand3)
208 }
209}
210
211named!(instruction_combined<CompleteStr, AssemblerInstruction>,
212 do_parse!(
213 opt!(comment) >>
214 l: opt!(label_declaration) >>
215 o: opcode >>
216 o1: opt!(operand) >>
217 o2: opt!(operand) >>
218 o3: opt!(operand) >>
219 opt!(comment) >>
220 (
221 {
222 AssemblerInstruction{
223 opcode: Some(o),
224 label: l,
225 directive: None,
226 operand1: o1,
227 operand2: o2,
228 operand3: o3,
229 }
230 }
231 )
232 )
233);
234
235named!(pub instruction<CompleteStr, AssemblerInstruction>,
237 do_parse!(
238 ins: alt!(
239 instruction_combined
240 ) >>
241 (
242 ins
243 )
244 )
245);
246
247#[cfg(test)]
248mod tests {
249 use super::*;
250 use instruction::Opcode;
251
252 #[test]
253 fn test_parse_instruction_form_one() {
254 let result = instruction_combined(CompleteStr("load $0 #100\n"));
255 assert_eq!(
256 result,
257 Ok((
258 CompleteStr(""),
259 AssemblerInstruction {
260 opcode: Some(Token::Op { code: Opcode::LOAD }),
261 label: None,
262 directive: None,
263 operand1: Some(Token::Register { reg_num: 0 }),
264 operand2: Some(Token::IntegerOperand { value: 100 }),
265 operand3: None
266 }
267 ))
268 );
269 }
270
271 #[test]
272 fn test_parse_instruction_form_one_with_label() {
273 let result = instruction_combined(CompleteStr("load $0 @test1\n"));
274 assert_eq!(
275 result,
276 Ok((
277 CompleteStr(""),
278 AssemblerInstruction {
279 opcode: Some(Token::Op { code: Opcode::LOAD }),
280 label: None,
281 directive: None,
282 operand1: Some(Token::Register { reg_num: 0 }),
283 operand2: Some(Token::LabelUsage {
284 name: "test1".to_string()
285 }),
286 operand3: None
287 }
288 ))
289 );
290 }
291
292 #[test]
293 fn test_parse_instruction_form_two() {
294 let result = instruction_combined(CompleteStr("hlt"));
295 assert_eq!(
296 result,
297 Ok((
298 CompleteStr(""),
299 AssemblerInstruction {
300 opcode: Some(Token::Op { code: Opcode::HLT }),
301 label: None,
302 directive: None,
303 operand1: None,
304 operand2: None,
305 operand3: None
306 }
307 ))
308 );
309 }
310
311 #[test]
312 fn test_parse_instruction_form_three() {
313 let result = instruction_combined(CompleteStr("add $0 $1 $2\n"));
314 assert_eq!(
315 result,
316 Ok((
317 CompleteStr(""),
318 AssemblerInstruction {
319 opcode: Some(Token::Op { code: Opcode::ADD }),
320 label: None,
321 directive: None,
322 operand1: Some(Token::Register { reg_num: 0 }),
323 operand2: Some(Token::Register { reg_num: 1 }),
324 operand3: Some(Token::Register { reg_num: 2 }),
325 }
326 ))
327 );
328 }
329
330 #[test]
331 fn test_parse_instruction_with_comment_one() {
332 let result = instruction_combined(CompleteStr("; this is a test\nadd $0 $1 $2\n"));
333 assert_eq!(
334 result,
335 Ok((
336 CompleteStr(""),
337 AssemblerInstruction {
338 opcode: Some(Token::Op { code: Opcode::ADD }),
339 label: None,
340 directive: None,
341 operand1: Some(Token::Register { reg_num: 0 }),
342 operand2: Some(Token::Register { reg_num: 1 }),
343 operand3: Some(Token::Register { reg_num: 2 }),
344 }
345 ))
346 );
347 }
348
349 #[test]
350 fn test_parse_instruction_with_comment_two() {
351 let result = instruction_combined(CompleteStr("add $0 $1 $2 ; this is a test\n"));
352 assert_eq!(
353 result,
354 Ok((
355 CompleteStr(""),
356 AssemblerInstruction {
357 opcode: Some(Token::Op { code: Opcode::ADD }),
358 label: None,
359 directive: None,
360 operand1: Some(Token::Register { reg_num: 0 }),
361 operand2: Some(Token::Register { reg_num: 1 }),
362 operand3: Some(Token::Register { reg_num: 2 }),
363 }
364 ))
365 );
366 }
367
368 #[test]
369 fn test_parse_cloop() {
370 let result = instruction_combined(CompleteStr("cloop #10\n"));
371 assert_eq!(
372 result,
373 Ok((
374 CompleteStr(""),
375 AssemblerInstruction {
376 opcode: Some(Token::Op {
377 code: Opcode::CLOOP
378 }),
379 label: None,
380 directive: None,
381 operand1: Some(Token::IntegerOperand { value: 10 }),
382 operand2: None,
383 operand3: None
384 }
385 ))
386 );
387 }
388}