1use crate::lexer::{Lexer, Token};
2use crate::opcodes::*;
3use crate::symbol_table::{SourceLine, SymbolTable};
4use crate::timex::{TIMEX_TABLE, TIMEX6_TABLE};
5use crate::utils::*;
6use std::cell::RefCell;
7use std::fs;
8use std::path::Path;
9use std::rc::Rc;
10use thiserror::Error;
11
12#[derive(Error, Debug)]
13pub enum AssemblerError {
14 #[error("Parse error at line {line}: {message}")]
15 ParseError { line: usize, message: String },
16 #[error("Symbol error: {message}")]
17 SymbolError { message: String },
18 #[error("Value out of range: {message}")]
19 RangeError { message: String },
20 #[error("IO error: {message}")]
21 IoError { message: String },
22}
23
24pub struct Assembler {
25 symbol_table: SymbolTable,
26 source_lines: Vec<Rc<RefCell<SourceLine>>>,
27 current_line: usize,
28 filename: String,
29 include_path: String,
30 errors: Vec<String>,
31 max_line: usize,
32}
33
34#[allow(unused_assignments)]
35impl Assembler {
36 pub fn new(filename: String) -> Self {
37 let base_dir = if let Some(dir) = Path::new(&filename).parent() {
39 dir.to_string_lossy().to_string()
40 } else {
41 ".".to_string()
42 };
43 let include_path = Path::new(&base_dir)
44 .join("include")
45 .to_string_lossy()
46 .to_string();
47
48 let mut assembler = Self {
49 symbol_table: SymbolTable::new(),
50 source_lines: Vec::new(),
51 current_line: 0,
52 filename,
53 include_path,
54 errors: Vec::new(),
55 max_line: 0,
56 };
57
58 for kw in KEYWORDS {
60 assembler
61 .symbol_table
62 .define_keyword(kw.name, kw.value as i32);
63 }
64
65 assembler
66 }
67
68 pub fn reset_errors(&mut self) {
69 self.errors.clear();
70 }
71
72 pub fn get_errors(&self) -> &[String] {
73 &self.errors
74 }
75
76 pub fn add_source_line(&mut self, line_num: usize) {
77 while self.source_lines.len() <= line_num {
78 self.source_lines
79 .push(Rc::new(RefCell::new(SourceLine::new())));
80 }
81
82 if line_num >= self.max_line {
83 self.max_line = line_num + 1;
84 }
85
86 let offset = if line_num == 0 {
87 0x0110
88 } else {
89 let prev_line = &self.source_lines[line_num - 1];
90 let prev_ref = prev_line.borrow();
91 prev_ref.get_offset() + prev_ref.get_byte_count() as i32
92 };
93
94 self.source_lines[line_num]
95 .borrow_mut()
96 .set_offset(offset, false);
97 }
98
99 pub fn parse_line(&mut self, line: &str, line_number: usize) -> Result<(), AssemblerError> {
100 let mut lexer = Lexer::new(expand_tabs(line, 8));
101 let mut data = Vec::new();
102 let mut opcode = 0u16;
103
104 self.current_line = line_number;
105
106 {
108 let source_line_rc = self.source_lines[line_number].clone();
109 let source_line_weak = Rc::downgrade(&source_line_rc);
110 let mut source_line = source_line_rc.borrow_mut();
111 source_line.reset_references(source_line_weak.clone());
112 source_line.set_definition(None, source_line_weak);
113 source_line.set_relative(-1);
114 }
115
116 let mut token = lexer.get_token();
117 let mut label = String::new();
118
119 if let Token::Symbol(name) = &token {
121 if self.symbol_table.lookup_keyword(name).is_none() {
122 label = name.clone();
123 token = lexer.get_token();
124 if token == Token::Colon {
126 token = lexer.get_token();
127 }
128 }
129 }
130
131 if let Token::Symbol(name) = &token {
133 if let Some(op_value) = self.symbol_table.lookup_keyword(name) {
134 opcode = op_value as u16;
135 token = lexer.get_token();
136 }
137 }
138
139 if (opcode >> 8) != (CAT_EQU >> 8) && !label.is_empty() {
141 let source_line_weak = Rc::downgrade(&self.source_lines[line_number]);
142 let offset = self.source_lines[line_number].borrow().get_offset();
143 let symbol = self
144 .symbol_table
145 .define_symbol(&label, source_line_weak, offset);
146 if symbol.borrow().get_definition_count() != 1 {
147 self.emit_error(&format!("Symbol {} defined on more than one line", label));
148 }
149 }
150
151 match opcode >> 8 {
153 cat if cat == (CAT_INH >> 8) => {
154 data.push((opcode & 0xff) as u8);
155 }
156 cat if cat == (CAT_REL >> 8) => {
157 let (new_token, value) = self.parse_level8(&mut lexer, token)?;
158 token = new_token;
159 data.push((opcode & 0xff) as u8);
160
161 self.source_lines[line_number]
162 .borrow_mut()
163 .set_relative(value);
164 let branch_distance =
165 value - self.source_lines[line_number].borrow().get_offset() - 2;
166
167 if branch_distance > 0x7f || branch_distance < -0x80 {
168 self.emit_error(&format!(
169 "Branch target out of range (Distance={})",
170 branch_distance
171 ));
172 }
173 data.push((branch_distance & 0xff) as u8);
174 }
175 cat if cat == (CAT_BSC >> 8) || cat == (CAT_BSCX >> 8) => {
176 if cat == (CAT_BSCX >> 8) {
177 let (new_token, bit_num) = self.parse_level8(&mut lexer, token)?;
178 token = new_token;
179 opcode += (bit_num * 2) as u16;
180 if token == Token::Comma {
181 token = lexer.get_token();
182 }
183 }
184
185 let (new_token, value) = self.parse_level8(&mut lexer, token)?;
186 token = new_token;
187 data.push((opcode & 0xff) as u8);
188
189 if value > 0xff || value < 0 {
190 self.emit_error(&format!(
191 "BSET/BCLR target ({:04x}) not in zero page",
192 value
193 ));
194 }
195 data.push((value & 0xff) as u8);
196 }
197 cat if cat == (CAT_BTB >> 8) || cat == (CAT_BTBX >> 8) => {
198 if cat == (CAT_BTBX >> 8) {
199 let (new_token, bit_num) = self.parse_level8(&mut lexer, token)?;
200 token = new_token;
201 opcode += (bit_num * 2) as u16;
202 if token == Token::Comma {
203 token = lexer.get_token();
204 }
205 }
206
207 data.push((opcode & 0xff) as u8);
208
209 let (new_token, value) = self.parse_level8(&mut lexer, token)?;
210 token = new_token;
211 if value > 0xff || value < 0 {
212 self.emit_error(&format!(
213 "BRSET/BRCLR target ({:04x}) not in zero page",
214 value
215 ));
216 }
217 data.push((value & 0xff) as u8);
218
219 if token == Token::Comma {
220 token = lexer.get_token();
221 }
222
223 let (new_token, branch_value) = self.parse_level8(&mut lexer, token)?;
224 token = new_token;
225 self.source_lines[line_number]
226 .borrow_mut()
227 .set_relative(branch_value);
228 let branch_distance =
229 branch_value - self.source_lines[line_number].borrow().get_offset() - 3;
230 data.push((branch_distance & 0xff) as u8);
231
232 if branch_distance > 0x7f || branch_distance < -0x80 {
233 self.emit_error(&format!(
234 "Branch target out of range (Distance={})",
235 branch_distance
236 ));
237 }
238 }
239 cat if cat == (CAT_IMM_DIR_EXT_IX1_IX1_IX >> 8) => {
240 if token == Token::Immed {
241 data.push((opcode & 0xff) as u8);
242 token = lexer.get_token();
243 let (new_token, value) = self.parse_level8(&mut lexer, token)?;
244 token = new_token;
245 if value > 0xff || value < 0 {
246 self.emit_error(&format!("Operand ({:04x}) out of range 00-FF", value));
247 }
248 data.push((value & 0xff) as u8);
249 } else {
250 self.process_addressing_mode(&mut lexer, &mut token, &mut data, opcode)?;
251 }
252 }
253 cat if cat == (CAT_DIR_EXT_IX1_IX1_IX >> 8) => {
254 self.process_addressing_mode(&mut lexer, &mut token, &mut data, opcode)?;
255 }
256 cat if cat == (CAT_DIR_IX1_IX >> 8) => {
257 self.process_dir_ix_addressing(&mut lexer, &mut token, &mut data, opcode)?;
258 }
259 cat if cat == (CAT_DB >> 8) => {
260 loop {
261 let (new_token, value) = self.parse_level8(&mut lexer, token)?;
262 token = new_token;
263 if value > 0xff || value < 0 {
264 self.emit_error(&format!("Operand ({:04x}) out of range $00-$FF", value));
265 }
266 data.push((value & 0xff) as u8);
267
268 if token != Token::Comma {
269 break;
270 }
271 token = lexer.get_token();
272 }
273 }
274 cat if cat == (CAT_DW >> 8) => {
275 loop {
276 let (new_token, value) = self.parse_level8(&mut lexer, token)?;
277 token = new_token;
278 data.push(((value >> 8) & 0xff) as u8);
279 data.push((value & 0xff) as u8);
280
281 if token != Token::Comma {
282 break;
283 }
284 token = lexer.get_token();
285 }
286 }
287 cat if cat == (CAT_EQU >> 8) => {
288 if label.is_empty() {
289 self.emit_error("No label for EQU statement");
290 } else {
291 let (new_token, value) = self.parse_level8(&mut lexer, token)?;
292 token = new_token;
293
294 let source_line_weak = Rc::downgrade(&self.source_lines[line_number]);
295 let symbol = self
296 .symbol_table
297 .define_symbol(&label, source_line_weak, value);
298
299 if symbol.borrow().get_definition_count() != 1 {
300 self.emit_error(&format!("Symbol {} defined on more than one line", label));
301 }
302 }
303 }
304 cat if cat == (CAT_ORIGIN >> 8) => {
305 let (new_token, value) = self.parse_level8(&mut lexer, token)?;
306 token = new_token;
307 self.source_lines[line_number]
308 .borrow_mut()
309 .set_offset(value, true);
310 }
311 cat if cat == (CAT_INCLUDE >> 8) => {
312 if let Token::String(filename) = token {
313 let symbol = self.symbol_table.lookup_symbol(&filename);
315 if symbol.borrow().get_value() == 0 {
316 match self.read_include_file(&filename) {
318 Ok(content) => {
319 let content_bytes = content.len();
320 let source_line_weak =
322 Rc::downgrade(&self.source_lines[line_number]);
323 symbol.borrow_mut().set_value(1);
324 symbol.borrow_mut().add_definition(source_line_weak);
325
326 self.source_lines[line_number]
328 .borrow_mut()
329 .set_include_bytes_read(content_bytes);
330
331 for line in content.lines() {
333 let mut include_lexer = Lexer::new(expand_tabs(line, 8));
334 let mut include_token = include_lexer.get_token();
335
336 if let Token::Symbol(symbol_name) = include_token {
337 include_token = include_lexer.get_token();
338 if let Token::Symbol(equ_name) = &include_token {
339 if equ_name.to_uppercase() == "EQU" {
340 include_token = include_lexer.get_token();
341 if let Ok((_, value)) =
342 self.parse_level8(&mut include_lexer, include_token)
343 {
344 self.symbol_table.define_symbol(
345 &symbol_name,
346 Rc::downgrade(
347 &self.source_lines[line_number],
348 ),
349 value,
350 );
351 }
352 }
353 }
354 }
355 }
356 }
357 Err(e) => {
358 self.emit_error(&format!("Unable to open '{}': {}", filename, e));
359 }
360 }
361 }
362 token = lexer.get_token();
363 } else {
364 self.emit_error("Include file must be enclosed in quotes");
365 }
366 }
367 cat if cat == (CAT_ASCII >> 8) => {
368 if let Token::String(s) = token {
369 for ch in s.chars() {
370 data.push((ch as u8) & 0x7f);
371 }
372 token = lexer.get_token();
373 }
374 }
375 cat if cat == (CAT_TIMEX >> 8) => {
376 if let Token::String(s) = token {
377 for ch in s.chars() {
378 let idx = (ch as u8 & 0x7f) as usize;
379 if idx < TIMEX_TABLE.len() {
380 data.push(TIMEX_TABLE[idx]);
381 }
382 }
383 token = lexer.get_token();
384 }
385 }
386 cat if cat == (CAT_TIMEX6 >> 8) => {
387 if let Token::String(s) = token {
388 let mut chars: Vec<char> = s.chars().collect();
390 chars.resize(6, ' '); for ch in chars.iter().take(6) {
393 let idx = (*ch as u8 & 0x7f) as usize;
394 if idx < TIMEX6_TABLE.len() {
395 data.push(TIMEX6_TABLE[idx]);
396 } else {
397 data.push(0x1d); }
399 }
400 token = lexer.get_token();
401 }
402 }
403 0 => {
404 }
406 _ => {
407 self.emit_error("Unrecognized opcode");
408 }
409 }
410
411 if token != Token::End {
412 self.emit_error("Junk past the end of the instruction");
413 }
414
415 let delta = self.source_lines[line_number]
417 .borrow_mut()
418 .set_data(&data);
419 self.source_lines[line_number]
420 .borrow_mut()
421 .mark_dirty(false);
422
423 if delta != 0 {
425 let current_offset = self.source_lines[line_number].borrow().get_offset();
426 for i in (line_number + 1)..self.max_line {
427 self.source_lines[i].borrow_mut().adjust_offset(delta);
428 let rel_offset = self.source_lines[i].borrow().get_relative_offset();
429 if rel_offset >= 0 && rel_offset < current_offset {
430 self.source_lines[i].borrow_mut().mark_dirty(true);
431 }
432 }
433 for i in (0..line_number).rev() {
434 if self.source_lines[i].borrow().get_offset() > current_offset {
435 self.source_lines[i].borrow_mut().mark_dirty(true);
436 }
437 }
438 }
439
440 Ok(())
441 }
442
443 fn process_addressing_mode(
444 &mut self,
445 lexer: &mut Lexer,
446 token: &mut Token,
447 data: &mut Vec<u8>,
448 opcode: u16,
449 ) -> Result<(), AssemblerError> {
450 let value = if *token == Token::Comma {
451 0
452 } else {
453 let (new_token, val) = self.parse_level8(lexer, token.clone())?;
454 *token = new_token;
455 val
456 };
457
458 if *token == Token::Comma {
459 *token = lexer.get_token();
461 if let Token::Symbol(name) = token {
462 if stricmp(name, "X") != 0 {
463 self.emit_error("Missing X after ,");
464 } else {
465 *token = lexer.get_token();
466 }
467 }
468
469 if value == 0 {
470 data.push(((opcode & 0xff) + 0x50) as u8);
472 } else if value >= -256 && value < 256 {
473 data.push(((opcode & 0xff) + 0x40) as u8);
475 data.push((value & 0xff) as u8);
476 } else {
477 data.push(((opcode & 0xff) + 0x30) as u8);
479 data.push(((value >> 8) & 0xff) as u8);
480 data.push((value & 0xff) as u8);
481 }
482 } else {
483 if value >= -256 && value < 256 {
485 data.push(((opcode & 0xff) + 0x10) as u8);
487 data.push((value & 0xff) as u8);
488 } else {
489 data.push(((opcode & 0xff) + 0x20) as u8);
491 data.push(((value >> 8) & 0xff) as u8);
492 data.push((value & 0xff) as u8);
493 }
494 }
495
496 Ok(())
497 }
498
499 fn process_dir_ix_addressing(
500 &mut self,
501 lexer: &mut Lexer,
502 token: &mut Token,
503 data: &mut Vec<u8>,
504 opcode: u16,
505 ) -> Result<(), AssemblerError> {
506 let value = if *token == Token::Comma {
507 0
508 } else {
509 let (new_token, val) = self.parse_level8(lexer, token.clone())?;
510 *token = new_token;
511 val
512 };
513
514 if *token == Token::Comma {
515 *token = lexer.get_token();
517 if let Token::Symbol(name) = token {
518 if stricmp(name, "X") != 0 {
519 self.emit_error("Missing X after ,");
520 } else {
521 *token = lexer.get_token();
522 }
523 }
524
525 if value == 0 {
526 data.push(((opcode & 0xff) + 0x40) as u8);
528 } else {
529 data.push(((opcode & 0xff) + 0x30) as u8);
531 if value > 0xff || value < 0 {
532 self.emit_error(&format!("Operand ({:04x}) out of range $00-$FF", value));
533 }
534 data.push((value & 0xff) as u8);
535 }
536 } else {
537 data.push((opcode & 0xff) as u8);
539 if value > 0xff || value < 0 {
540 self.emit_error(&format!("Operand ({:04x}) out of range $00-$FF", value));
541 }
542 data.push((value & 0xff) as u8);
543 }
544
545 Ok(())
546 }
547
548 fn parse_level1(
550 &mut self,
551 lexer: &mut Lexer,
552 token: Token,
553 ) -> Result<(Token, i32), AssemblerError> {
554 match token {
555 Token::LParen => {
556 let next_token = lexer.get_token();
557 let (token, value) = self.parse_level8(lexer, next_token)?;
558 if token == Token::RParen {
559 Ok((lexer.get_token(), value))
560 } else {
561 Ok((token, value))
562 }
563 }
564 Token::Const(val) => Ok((lexer.get_token(), val)),
565 Token::Symbol(name) => {
566 let source_line_weak = Rc::downgrade(&self.source_lines[self.current_line]);
567 let symbol = self
568 .symbol_table
569 .lookup_symbol_with_reference(&name, source_line_weak);
570 let value = symbol.borrow().get_value();
571 if symbol.borrow().get_definition_count() == 0 {
572 self.emit_error(&format!("Undefined symbol '{}' Value={}", name, value));
573 }
574 Ok((lexer.get_token(), value))
575 }
576 Token::Star => {
577 let value = self.source_lines[self.current_line].borrow().get_offset();
578 Ok((lexer.get_token(), value))
579 }
580 Token::String(_) | Token::Comma | Token::End => Ok((token, 0)),
581 _ => {
582 self.emit_error("Unable to parse this line");
583 Ok((token, 0))
584 }
585 }
586 }
587
588 fn parse_level2(
589 &mut self,
590 lexer: &mut Lexer,
591 token: Token,
592 ) -> Result<(Token, i32), AssemblerError> {
593 if token == Token::Not {
594 let next_token = lexer.get_token();
595 let (token, value) = self.parse_level1(lexer, next_token)?;
596 Ok((token, !value))
597 } else {
598 self.parse_level1(lexer, token)
599 }
600 }
601
602 fn parse_level3(
603 &mut self,
604 lexer: &mut Lexer,
605 token: Token,
606 ) -> Result<(Token, i32), AssemblerError> {
607 let (mut token, mut value) = self.parse_level2(lexer, token)?;
608 if matches!(token, Token::Star | Token::Divide) {
609 let op = token;
610 let next_token = lexer.get_token();
611 let (new_token, right_value) = self.parse_level3(lexer, next_token)?;
612 token = new_token;
613 if op == Token::Star {
614 value *= right_value;
615 } else {
616 if right_value == 0 {
617 self.emit_error("Division by zero");
618 value = 0;
619 } else {
620 value /= right_value;
621 }
622 }
623 }
624 Ok((token, value))
625 }
626
627 fn parse_level4(
628 &mut self,
629 lexer: &mut Lexer,
630 token: Token,
631 ) -> Result<(Token, i32), AssemblerError> {
632 let (mut token, mut value) = self.parse_level3(lexer, token)?;
633 if matches!(token, Token::Plus | Token::Minus) {
634 let op = token;
635 let next_token = lexer.get_token();
636 let (new_token, right_value) = self.parse_level4(lexer, next_token)?;
637 token = new_token;
638 if op == Token::Plus {
639 value += right_value;
640 } else {
641 value -= right_value;
642 }
643 }
644 Ok((token, value))
645 }
646
647 fn parse_level5(
648 &mut self,
649 lexer: &mut Lexer,
650 token: Token,
651 ) -> Result<(Token, i32), AssemblerError> {
652 let (mut token, mut value) = self.parse_level4(lexer, token)?;
653 if matches!(token, Token::LShift | Token::RShift) {
654 let op = token;
655 let next_token = lexer.get_token();
656 let (new_token, right_value) = self.parse_level5(lexer, next_token)?;
657 token = new_token;
658 if op == Token::LShift {
659 value <<= right_value;
660 } else {
661 value >>= right_value;
662 }
663 }
664 Ok((token, value))
665 }
666
667 fn parse_level6(
668 &mut self,
669 lexer: &mut Lexer,
670 token: Token,
671 ) -> Result<(Token, i32), AssemblerError> {
672 let (mut token, mut value) = self.parse_level5(lexer, token)?;
673 if token == Token::And {
674 let next_token = lexer.get_token();
675 let (new_token, right_value) = self.parse_level6(lexer, next_token)?;
676 token = new_token;
677 value &= right_value;
678 }
679 Ok((token, value))
680 }
681
682 fn parse_level7(
683 &mut self,
684 lexer: &mut Lexer,
685 token: Token,
686 ) -> Result<(Token, i32), AssemblerError> {
687 let (mut token, mut value) = self.parse_level6(lexer, token)?;
688 if token == Token::Xor {
689 let next_token = lexer.get_token();
690 let (new_token, right_value) = self.parse_level7(lexer, next_token)?;
691 token = new_token;
692 value ^= right_value;
693 }
694 Ok((token, value))
695 }
696
697 fn parse_level8(
698 &mut self,
699 lexer: &mut Lexer,
700 token: Token,
701 ) -> Result<(Token, i32), AssemblerError> {
702 let (mut token, mut value) = self.parse_level7(lexer, token)?;
703 if token == Token::Or {
704 let next_token = lexer.get_token();
705 let (new_token, right_value) = self.parse_level8(lexer, next_token)?;
706 token = new_token;
707 value |= right_value;
708 }
709 Ok((token, value))
710 }
711
712 fn read_include_file(&self, filename: &str) -> Result<String, std::io::Error> {
713 let include_file_path = Path::new(&self.include_path).join(filename);
714 fs::read_to_string(include_file_path)
715 }
716
717 fn emit_error(&mut self, message: &str) {
718 let error_msg = format!(
719 "{}({}): {}",
720 self.filename,
721 self.current_line + 1,
722 message
723 );
724 self.errors.push(error_msg);
725 }
726
727 pub fn get_hex(&self) -> String {
728 let mut result = String::new();
729 for line in &self.source_lines[..self.max_line] {
730 let line_ref = line.borrow();
731 let data = line_ref.get_data();
732 for byte in data {
733 result.push_str(&format!("{:02x}", byte));
734 }
735 }
736 result
737 }
738
739 pub fn generate_listing(&self, source_data: &[String]) -> Vec<String> {
740 let mut result = Vec::new();
741
742 for (line_num, line) in self.source_lines.iter().enumerate().take(self.max_line) {
743 let line_ref = line.borrow();
744 let offset = line_ref.get_offset();
745 let data = line_ref.get_data();
746 let source_line = source_data.get(line_num).map(|s| s.as_str()).unwrap_or("");
747
748 let listing_line = if data.is_empty() {
749 if let Some(bytes_read) = line_ref.include_bytes_read {
751 format!(
752 "{:4}| {} bytes read |{}",
753 line_num + 1,
754 bytes_read,
755 source_line
756 )
757 }
758 else if let Some(symbol_def) = &line_ref.definition {
760 if let Some(symbol) = symbol_def.upgrade() {
761 let value = symbol.borrow().get_value();
762 format!(
763 "{:4}| ={:04x} |{}",
764 line_num + 1,
765 value,
766 source_line
767 )
768 } else {
769 format!("{:4}| |{}", line_num + 1, source_line)
770 }
771 } else {
772 format!("{:4}| |{}", line_num + 1, source_line)
773 }
774 } else if data.len() == 1 {
775 format!(
776 "{:4}| {:04x}: {:02x} |{}",
777 line_num + 1,
778 offset,
779 data[0],
780 source_line
781 )
782 } else if data.len() == 2 {
783 format!(
784 "{:4}| {:04x}: {:02x} {:02x} |{}",
785 line_num + 1,
786 offset,
787 data[0],
788 data[1],
789 source_line
790 )
791 } else {
792 format!(
793 "{:4}| {:04x}: {:02x} {:02x} {:02x} |{}",
794 line_num + 1,
795 offset,
796 data[0],
797 data[1],
798 data[2],
799 source_line
800 )
801 };
802
803 result.push(listing_line);
804 }
805
806 result
807 }
808}
809
810pub fn assemble(
811 filename: String,
812 source_data: Vec<String>,
813) -> Result<(Vec<String>, String, Vec<String>), Vec<AssemblerError>> {
814 let mut assembler = Assembler::new(filename);
815 let mut errors = Vec::new();
816
817 assembler.reset_errors();
819 for (line_num, line) in source_data.iter().enumerate() {
820 assembler.add_source_line(line_num);
821 if let Err(e) = assembler.parse_line(&expand_tabs(line, 8), line_num) {
822 errors.push(e);
823 }
824 }
825
826 assembler.reset_errors();
828 for (line_num, line) in source_data.iter().enumerate() {
829 if let Err(e) = assembler.parse_line(&expand_tabs(line, 8), line_num) {
830 errors.push(e);
831 }
832 }
833 let mut dirty = true;
835 while dirty {
836 dirty = false;
837 assembler.reset_errors();
838 for line_num in 0..assembler.max_line {
839 if assembler.source_lines[line_num].borrow().is_dirty() {
840 dirty = true;
841 if let Err(e) =
842 assembler.parse_line(&expand_tabs(&source_data[line_num], 8), line_num)
843 {
844 errors.push(e);
845 }
846 }
847 }
848 }
849
850 assembler.reset_errors();
852 for line_num in 0..assembler.max_line {
853 if let Err(e) = assembler.parse_line(&expand_tabs(&source_data[line_num], 8), line_num) {
854 errors.push(e);
855 }
856 }
857
858 if !errors.is_empty() {
859 }
861
862 let error_strings: Vec<String> = assembler.get_errors().to_vec();
863 let hex_output = assembler.get_hex();
864 let listing = assembler.generate_listing(&source_data);
865
866 Ok((error_strings, hex_output, listing))
867}