az65/z80/mod.rs
1use std::{
2 fmt::{self, Display, Formatter},
3 io::Read,
4};
5
6use crate::{
7 assembler::{ArchAssembler, Assembler, AssemblerError},
8 expr::ExprNode,
9 fileman::FileSystem,
10 lexer::{self, ArchTokens, SourceLoc, SymbolName, Token},
11 linker::Link,
12};
13
14#[cfg(test)]
15mod tests;
16
17macro_rules! asm_err {
18 ($loc:expr, $($arg:tt)*) => {
19 Err(($loc, AssemblerError(format!($($arg)*))))
20 };
21}
22
23#[derive(Debug, Copy, Clone, Eq, PartialEq)]
24pub enum OperationName {
25 Adc,
26 Add,
27 And,
28 Bit,
29 Call,
30 Ccf,
31 Cp,
32 Cpd,
33 Cpdr,
34 Cpi,
35 Cpir,
36 Cpl,
37 Daa,
38 Dec,
39 Di,
40 Djnz,
41 Ei,
42 Ex,
43 Exx,
44 Halt,
45 Im,
46 In,
47 Inc,
48 Ind,
49 Indr,
50 Ini,
51 Inir,
52 Jp,
53 Jr,
54 Ld,
55 Ldd,
56 Lddr,
57 Ldi,
58 Ldir,
59 Neg,
60 Nop,
61 Or,
62 Otdr,
63 Otir,
64 Out,
65 Outd,
66 Outi,
67 Pop,
68 Push,
69 Res,
70 Ret,
71 Reti,
72 Retn,
73 Rl,
74 Rla,
75 Rlc,
76 Rlca,
77 Rld,
78 Rr,
79 Rra,
80 Rrc,
81 Rrca,
82 Rrd,
83 Rst,
84 Sbc,
85 Scf,
86 Set,
87 Sla,
88 Sll,
89 Sra,
90 Srl,
91 Sub,
92 Xor,
93}
94
95impl lexer::OperationName for OperationName {
96 fn parse<S: AsRef<str>>(s: S) -> Option<Self> {
97 match s.as_ref() {
98 "adc" | "ADC" => Some(Self::Adc),
99 "add" | "ADD" => Some(Self::Add),
100 "and" | "AND" => Some(Self::And),
101 "bit" | "BIT" => Some(Self::Bit),
102 "call" | "CALL" => Some(Self::Call),
103 "ccf" | "CCF" => Some(Self::Ccf),
104 "cp" | "CP" => Some(Self::Cp),
105 "cpd" | "CPD" => Some(Self::Cpd),
106 "cpdr" | "CPDR" => Some(Self::Cpdr),
107 "cpi" | "CPI" => Some(Self::Cpi),
108 "cpir" | "CPIR" => Some(Self::Cpir),
109 "cpl" | "CPL" => Some(Self::Cpl),
110 "daa" | "DAA" => Some(Self::Daa),
111 "dec" | "DEC" => Some(Self::Dec),
112 "di" | "DI" => Some(Self::Di),
113 "djnz" | "DJNZ" => Some(Self::Djnz),
114 "ei" | "EI" => Some(Self::Ei),
115 "ex" | "EX" => Some(Self::Ex),
116 "exx" | "EXX" => Some(Self::Exx),
117 "halt" | "HALT" => Some(Self::Halt),
118 "im" | "IM" => Some(Self::Im),
119 "in" | "IN" => Some(Self::In),
120 "inc" | "INC" => Some(Self::Inc),
121 "ind" | "IND" => Some(Self::Ind),
122 "indr" | "INDR" => Some(Self::Indr),
123 "ini" | "INI" => Some(Self::Ini),
124 "inir" | "INIR" => Some(Self::Inir),
125 "jp" | "JP" => Some(Self::Jp),
126 "jr" | "JR" => Some(Self::Jr),
127 "ld" | "LD" => Some(Self::Ld),
128 "ldd" | "LDD" => Some(Self::Ldd),
129 "lddr" | "LDDR" => Some(Self::Lddr),
130 "ldi" | "LDI" => Some(Self::Ldi),
131 "ldir" | "LDIR" => Some(Self::Ldir),
132 "neg" | "NEG" => Some(Self::Neg),
133 "nop" | "NOP" => Some(Self::Nop),
134 "or" | "OR" => Some(Self::Or),
135 "otdr" | "OTDR" => Some(Self::Otdr),
136 "otir" | "OTIR" => Some(Self::Otir),
137 "out" | "OUT" => Some(Self::Out),
138 "outd" | "OUTD" => Some(Self::Outd),
139 "outi" | "OUTI" => Some(Self::Outi),
140 "pop" | "POP" => Some(Self::Pop),
141 "push" | "PUSH" => Some(Self::Push),
142 "res" | "RES" => Some(Self::Res),
143 "ret" | "RET" => Some(Self::Ret),
144 "reti" | "RETI" => Some(Self::Reti),
145 "retn" | "RETN" => Some(Self::Retn),
146 "rl" | "RL" => Some(Self::Rl),
147 "rla" | "RLA" => Some(Self::Rla),
148 "rlc" | "RLC" => Some(Self::Rlc),
149 "rlca" | "RLCA" => Some(Self::Rlca),
150 "rld" | "RLD" => Some(Self::Rld),
151 "rr" | "RR" => Some(Self::Rr),
152 "rra" | "RRA" => Some(Self::Rra),
153 "rrc" | "RRC" => Some(Self::Rrc),
154 "rrca" | "RRCA" => Some(Self::Rrca),
155 "rrd" | "RRD" => Some(Self::Rrd),
156 "rst" | "RST" => Some(Self::Rst),
157 "sbc" | "SBC" => Some(Self::Sbc),
158 "scf" | "SCF" => Some(Self::Scf),
159 "set" | "SET" => Some(Self::Set),
160 "sla" | "SLA" => Some(Self::Sla),
161 "sll" | "SLL" => Some(Self::Sll),
162 "sra" | "SRA" => Some(Self::Sra),
163 "srl" | "SRL" => Some(Self::Srl),
164 "sub" | "SUB" => Some(Self::Sub),
165 "xor" | "XOR" => Some(Self::Xor),
166 _ => None,
167 }
168 }
169}
170
171impl Display for OperationName {
172 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
173 write!(
174 f,
175 "{}",
176 match self {
177 Self::Adc => "adc",
178 Self::Add => "add",
179 Self::And => "and",
180 Self::Bit => "bit",
181 Self::Call => "call",
182 Self::Ccf => "ccf",
183 Self::Cp => "cp",
184 Self::Cpd => "cpd",
185 Self::Cpdr => "cpdr",
186 Self::Cpi => "cpi",
187 Self::Cpir => "cpir",
188 Self::Cpl => "cpl",
189 Self::Daa => "daa",
190 Self::Dec => "dec",
191 Self::Di => "di",
192 Self::Djnz => "djnz",
193 Self::Ei => "ei",
194 Self::Ex => "ex",
195 Self::Exx => "exx",
196 Self::Halt => "halt",
197 Self::Im => "im",
198 Self::In => "in",
199 Self::Inc => "inc",
200 Self::Ind => "ind",
201 Self::Indr => "indr",
202 Self::Ini => "ini",
203 Self::Inir => "inir",
204 Self::Jp => "jp",
205 Self::Jr => "jr",
206 Self::Ld => "ld",
207 Self::Ldd => "ldd",
208 Self::Lddr => "lddr",
209 Self::Ldi => "ldi",
210 Self::Ldir => "ldir",
211 Self::Neg => "neg",
212 Self::Nop => "nop",
213 Self::Or => "or",
214 Self::Otdr => "otdr",
215 Self::Otir => "otir",
216 Self::Out => "out",
217 Self::Outd => "outd",
218 Self::Outi => "outi",
219 Self::Pop => "pop",
220 Self::Push => "push",
221 Self::Res => "res",
222 Self::Ret => "ret",
223 Self::Reti => "reti",
224 Self::Retn => "retn",
225 Self::Rl => "rl",
226 Self::Rla => "rla",
227 Self::Rlc => "rlc",
228 Self::Rlca => "rlca",
229 Self::Rld => "rld",
230 Self::Rr => "rr",
231 Self::Rra => "rra",
232 Self::Rrc => "rrc",
233 Self::Rrca => "rrca",
234 Self::Rrd => "rrd",
235 Self::Rst => "rst",
236 Self::Sbc => "sbc",
237 Self::Scf => "scf",
238 Self::Set => "set",
239 Self::Sla => "sla",
240 Self::Sll => "sll",
241 Self::Sra => "sra",
242 Self::Srl => "srl",
243 Self::Sub => "sub",
244 Self::Xor => "xor",
245 }
246 )
247 }
248}
249
250#[derive(Debug, Copy, Clone, Eq, PartialEq)]
251pub enum RegisterName {
252 A,
253 B,
254 C,
255 D,
256 E,
257 H,
258 L,
259 AF,
260 BC,
261 DE,
262 HL,
263 IX,
264 IY,
265 IXL,
266 IXH,
267 IYL,
268 IYH,
269 PC,
270 SP,
271 AFPrime,
272 I,
273 R,
274}
275
276impl lexer::RegisterName for RegisterName {
277 fn parse<S: AsRef<str>>(s: S) -> Option<Self> {
278 match s.as_ref() {
279 "a" | "A" => Some(Self::A),
280 "b" | "B" => Some(Self::B),
281 "c" | "C" => Some(Self::C),
282 "d" | "D" => Some(Self::D),
283 "e" | "E" => Some(Self::E),
284 "h" | "H" => Some(Self::H),
285 "l" | "L" => Some(Self::L),
286 "af" | "AF" => Some(Self::AF),
287 "bc" | "BC" => Some(Self::BC),
288 "de" | "DE" => Some(Self::DE),
289 "hl" | "HL" => Some(Self::HL),
290 "ix" | "IX" => Some(Self::IX),
291 "iy" | "IY" => Some(Self::IY),
292 "ixl" | "IXL" => Some(Self::IXL),
293 "ixh" | "IXH" => Some(Self::IXH),
294 "iyl" | "IYL" => Some(Self::IYL),
295 "iyh" | "IYH" => Some(Self::IYH),
296 "pc" | "PC" => Some(Self::PC),
297 "sp" | "SP" => Some(Self::SP),
298 "af'" | "AF'" => Some(Self::AFPrime),
299 "i" | "I" => Some(Self::I),
300 "r" | "R" => Some(Self::R),
301 _ => None,
302 }
303 }
304}
305
306impl Display for RegisterName {
307 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
308 write!(
309 f,
310 "{}",
311 match self {
312 Self::A => "a",
313 Self::B => "b",
314 Self::C => "c",
315 Self::D => "d",
316 Self::E => "e",
317 Self::H => "h",
318 Self::L => "l",
319 Self::AF => "af",
320 Self::BC => "bc",
321 Self::DE => "de",
322 Self::HL => "hl",
323 Self::IX => "ix",
324 Self::IY => "iy",
325 Self::IXL => "ixl",
326 Self::IXH => "ixh",
327 Self::IYL => "iyl",
328 Self::IYH => "iyh",
329 Self::PC => "pc",
330 Self::SP => "sp",
331 Self::AFPrime => "af'",
332 Self::I => "i",
333 Self::R => "r",
334 }
335 )
336 }
337}
338
339#[derive(Debug, Copy, Clone, Eq, PartialEq)]
340pub enum FlagName {
341 Zero,
342 NotZero,
343 NotCarry,
344 ParityEven,
345 ParityOdd,
346 Positive,
347 Negative,
348}
349
350impl lexer::FlagName for FlagName {
351 fn parse<S: AsRef<str>>(s: S) -> Option<Self> {
352 match s.as_ref() {
353 "z" | "Z" => Some(Self::Zero),
354 "nz" | "NZ" => Some(Self::NotZero),
355 "nc" | "NC" => Some(Self::NotCarry),
356 "pe" | "PE" => Some(Self::ParityEven),
357 "po" | "PO" => Some(Self::ParityOdd),
358 "p" | "P" => Some(Self::Positive),
359 "m" | "M" => Some(Self::Negative),
360 _ => None,
361 }
362 }
363}
364
365impl Display for FlagName {
366 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
367 write!(
368 f,
369 "{}",
370 match self {
371 Self::Zero => "zero flag",
372 Self::NotZero => "not zero flag",
373 Self::NotCarry => "not carry flag",
374 Self::ParityEven => "parity even flag",
375 Self::ParityOdd => "parity odd flag",
376 Self::Positive => "positive flag",
377 Self::Negative => "negative/minus flag",
378 }
379 )
380 }
381}
382
383pub struct Z80;
384
385#[derive(Copy, Clone)]
386pub struct Z80Tokens;
387
388impl ArchTokens for Z80Tokens {
389 type RegisterName = RegisterName;
390 type FlagName = FlagName;
391 type OperationName = OperationName;
392}
393
394impl<S, R> ArchAssembler<S, R, Z80Tokens> for Z80
395where
396 S: FileSystem<Reader = R>,
397 R: Read,
398{
399 fn parse(
400 asm: &mut Assembler<S, R, Z80Tokens, Self>,
401 name: OperationName,
402 ) -> Result<(), (SourceLoc, AssemblerError)> {
403 match name {
404 OperationName::Adc => {
405 asm.next()?;
406 match asm.next()? {
407 None => return asm.end_of_input_err(),
408 Some(Token::Register {
409 name: RegisterName::A,
410 ..
411 }) => {
412 asm.expect_symbol(SymbolName::Comma)?;
413
414 match asm.peek()? {
415 None => return asm.end_of_input_err(),
416 Some(Token::Register {
417 name: RegisterName::A,
418 ..
419 }) => {
420 asm.next()?;
421 asm.data.push(0x8F);
422 }
423
424 Some(Token::Register {
425 name: RegisterName::B,
426 ..
427 }) => {
428 asm.next()?;
429 asm.data.push(0x88);
430 }
431
432 Some(Token::Register {
433 name: RegisterName::C,
434 ..
435 }) => {
436 asm.next()?;
437 asm.data.push(0x89);
438 }
439
440 Some(Token::Register {
441 name: RegisterName::D,
442 ..
443 }) => {
444 asm.next()?;
445 asm.data.push(0x8A);
446 }
447
448 Some(Token::Register {
449 name: RegisterName::E,
450 ..
451 }) => {
452 asm.next()?;
453 asm.data.push(0x8B);
454 }
455
456 Some(Token::Register {
457 name: RegisterName::H,
458 ..
459 }) => {
460 asm.next()?;
461 asm.data.push(0x8C);
462 }
463
464 Some(Token::Register {
465 name: RegisterName::L,
466 ..
467 }) => {
468 asm.next()?;
469 asm.data.push(0x8D);
470 }
471
472 Some(Token::Register {
473 name: RegisterName::IXH,
474 ..
475 }) => {
476 asm.next()?;
477 asm.data.push(0xDD);
478 asm.data.push(0x8C);
479 }
480
481 Some(Token::Register {
482 name: RegisterName::IXL,
483 ..
484 }) => {
485 asm.next()?;
486 asm.data.push(0xDD);
487 asm.data.push(0x8D);
488 }
489
490 Some(Token::Register {
491 name: RegisterName::IYH,
492 ..
493 }) => {
494 asm.next()?;
495 asm.data.push(0xFD);
496 asm.data.push(0x8C);
497 }
498
499 Some(Token::Register {
500 name: RegisterName::IYL,
501 ..
502 }) => {
503 asm.next()?;
504 asm.data.push(0xFD);
505 asm.data.push(0x8D);
506 }
507
508 Some(Token::Symbol {
509 name: SymbolName::ParenOpen,
510 ..
511 }) => {
512 asm.next()?;
513 match asm.next()? {
514 None => return asm.end_of_input_err(),
515
516 Some(Token::Register {
517 name: RegisterName::HL,
518 ..
519 }) => {
520 asm.expect_symbol(SymbolName::ParenClose)?;
521 asm.data.push(0x8E);
522 }
523
524 Some(Token::Register {
525 name: RegisterName::IX,
526 ..
527 }) => {
528 asm.expect_symbol(SymbolName::Plus)?;
529 asm.data.push(0xDD);
530 asm.data.push(0x8E);
531 let (loc, expr) = asm.expr()?;
532 if let Some(value) =
533 expr.evaluate(&asm.symtab, &asm.str_interner)
534 {
535 if (value as u32) > (u8::MAX as u32) {
536 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
537 }
538 asm.data.push(value as u8);
539 } else {
540 asm.links.push(Link::byte(loc, asm.data.len(), expr));
541 asm.data.push(0);
542 }
543 asm.expect_symbol(SymbolName::ParenClose)?;
544 }
545
546 Some(Token::Register {
547 name: RegisterName::IY,
548 ..
549 }) => {
550 asm.expect_symbol(SymbolName::Plus)?;
551 asm.data.push(0xFD);
552 asm.data.push(0x8E);
553 let (loc, expr) = asm.expr()?;
554 if let Some(value) =
555 expr.evaluate(&asm.symtab, &asm.str_interner)
556 {
557 if (value as u32) > (u8::MAX as u32) {
558 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
559 }
560 asm.data.push(value as u8);
561 } else {
562 asm.links.push(Link::byte(loc, asm.data.len(), expr));
563 asm.data.push(0);
564 }
565 asm.expect_symbol(SymbolName::ParenClose)?;
566 }
567
568 Some(_) => {
569 asm.data.push(0xCE);
570 let (loc, expr) = asm.expr()?;
571 if let Some(value) =
572 expr.evaluate(&asm.symtab, &asm.str_interner)
573 {
574 if (value as u32) > (u8::MAX as u32) {
575 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
576 }
577 asm.data.push(value as u8);
578 } else {
579 asm.links.push(Link::byte(loc, asm.data.len(), expr));
580 asm.data.push(0);
581 }
582 asm.expect_symbol(SymbolName::ParenClose)?;
583 }
584 }
585 }
586
587 Some(_) => {
588 asm.data.push(0xCE);
589 let (loc, expr) = asm.expr()?;
590 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
591 if (value as u32) > (u8::MAX as u32) {
592 return asm_err!(
593 loc,
594 "Expression result ({value}) will not fit in a byte"
595 );
596 }
597 asm.data.push(value as u8);
598 } else {
599 asm.links.push(Link::byte(loc, asm.data.len(), expr));
600 asm.data.push(0);
601 }
602 }
603 }
604 }
605
606 Some(Token::Register {
607 name: RegisterName::HL,
608 ..
609 }) => {
610 asm.expect_symbol(SymbolName::Comma)?;
611 match asm.next()? {
612 None => return asm.end_of_input_err(),
613 Some(Token::Register {
614 name: RegisterName::BC,
615 ..
616 }) => {
617 asm.data.push(0xED);
618 asm.data.push(0x4A);
619 }
620
621 Some(Token::Register {
622 name: RegisterName::DE,
623 ..
624 }) => {
625 asm.data.push(0xED);
626 asm.data.push(0x5A);
627 }
628
629 Some(Token::Register {
630 name: RegisterName::HL,
631 ..
632 }) => {
633 asm.data.push(0xED);
634 asm.data.push(0x6A);
635 }
636
637 Some(Token::Register {
638 name: RegisterName::SP,
639 ..
640 }) => {
641 asm.data.push(0xED);
642 asm.data.push(0x7A);
643 }
644
645 Some(tok) => {
646 return asm_err!(
647 tok.loc(),
648 "Unexpected {}, expected register \"bc\", \"de\", \"hl\" or \"sp\"",
649 tok.as_display(&asm.str_interner)
650 )
651 }
652 }
653 }
654
655 Some(tok) => {
656 return asm_err!(
657 tok.loc(),
658 "Unexpected {}, expected register \"a\" or \"hl\"",
659 tok.as_display(&asm.str_interner)
660 )
661 }
662 }
663 }
664
665 OperationName::Add => {
666 asm.next()?;
667 match asm.next()? {
668 None => return asm.end_of_input_err(),
669 Some(Token::Register {
670 name: RegisterName::A,
671 ..
672 }) => {
673 asm.expect_symbol(SymbolName::Comma)?;
674
675 match asm.peek()? {
676 None => return asm.end_of_input_err(),
677 Some(Token::Register {
678 name: RegisterName::A,
679 ..
680 }) => {
681 asm.next()?;
682 asm.data.push(0x87);
683 }
684
685 Some(Token::Register {
686 name: RegisterName::B,
687 ..
688 }) => {
689 asm.next()?;
690 asm.data.push(0x80);
691 }
692
693 Some(Token::Register {
694 name: RegisterName::C,
695 ..
696 }) => {
697 asm.next()?;
698 asm.data.push(0x81);
699 }
700
701 Some(Token::Register {
702 name: RegisterName::D,
703 ..
704 }) => {
705 asm.next()?;
706 asm.data.push(0x82);
707 }
708
709 Some(Token::Register {
710 name: RegisterName::E,
711 ..
712 }) => {
713 asm.next()?;
714 asm.data.push(0x83);
715 }
716
717 Some(Token::Register {
718 name: RegisterName::H,
719 ..
720 }) => {
721 asm.next()?;
722 asm.data.push(0x84);
723 }
724
725 Some(Token::Register {
726 name: RegisterName::L,
727 ..
728 }) => {
729 asm.next()?;
730 asm.data.push(0x85);
731 }
732
733 Some(Token::Register {
734 name: RegisterName::IXH,
735 ..
736 }) => {
737 asm.next()?;
738 asm.data.push(0xDD);
739 asm.data.push(0x84);
740 }
741
742 Some(Token::Register {
743 name: RegisterName::IXL,
744 ..
745 }) => {
746 asm.next()?;
747 asm.data.push(0xDD);
748 asm.data.push(0x85);
749 }
750
751 Some(Token::Register {
752 name: RegisterName::IYH,
753 ..
754 }) => {
755 asm.next()?;
756 asm.data.push(0xFD);
757 asm.data.push(0x84);
758 }
759
760 Some(Token::Register {
761 name: RegisterName::IYL,
762 ..
763 }) => {
764 asm.next()?;
765 asm.data.push(0xFD);
766 asm.data.push(0x85);
767 }
768
769 Some(Token::Symbol {
770 name: SymbolName::ParenOpen,
771 ..
772 }) => {
773 asm.next()?;
774 match asm.next()? {
775 None => return asm.end_of_input_err(),
776 Some(Token::Register {
777 name: RegisterName::HL,
778 ..
779 }) => {
780 asm.data.push(0x86);
781 asm.expect_symbol(SymbolName::ParenClose)?;
782 }
783
784 Some(Token::Register {
785 name: RegisterName::IX,
786 ..
787 }) => {
788 asm.expect_symbol(SymbolName::Plus)?;
789 asm.data.push(0xDD);
790 asm.data.push(0x86);
791 let (loc, expr) = asm.expr()?;
792 if let Some(value) =
793 expr.evaluate(&asm.symtab, &asm.str_interner)
794 {
795 if (value as u32) > (u8::MAX as u32) {
796 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
797 }
798 asm.data.push(value as u8);
799 } else {
800 asm.links.push(Link::byte(loc, asm.data.len(), expr));
801 asm.data.push(0);
802 }
803 asm.expect_symbol(SymbolName::ParenClose)?;
804 }
805
806 Some(Token::Register {
807 name: RegisterName::IY,
808 ..
809 }) => {
810 asm.expect_symbol(SymbolName::Plus)?;
811 asm.data.push(0xFD);
812 asm.data.push(0x86);
813 let (loc, expr) = asm.expr()?;
814 if let Some(value) =
815 expr.evaluate(&asm.symtab, &asm.str_interner)
816 {
817 if (value as u32) > (u8::MAX as u32) {
818 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
819 }
820 asm.data.push(value as u8);
821 } else {
822 asm.links.push(Link::byte(loc, asm.data.len(), expr));
823 asm.data.push(0);
824 }
825 asm.expect_symbol(SymbolName::ParenClose)?;
826 }
827
828 Some(_) => {
829 asm.data.push(0xC6);
830 let (loc, expr) = asm.expr()?;
831 if let Some(value) =
832 expr.evaluate(&asm.symtab, &asm.str_interner)
833 {
834 if (value as u32) > (u8::MAX as u32) {
835 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
836 }
837 asm.data.push(value as u8);
838 } else {
839 asm.links.push(Link::byte(loc, asm.data.len(), expr));
840 asm.data.push(0);
841 }
842 asm.expect_symbol(SymbolName::ParenClose)?;
843 }
844 }
845 }
846
847 Some(_) => {
848 asm.data.push(0xC6);
849 let (loc, expr) = asm.expr()?;
850 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
851 if (value as u32) > (u8::MAX as u32) {
852 return asm_err!(
853 loc,
854 "Expression result ({value}) will not fit in a byte"
855 );
856 }
857 asm.data.push(value as u8);
858 } else {
859 asm.links.push(Link::byte(loc, asm.data.len(), expr));
860 asm.data.push(0);
861 }
862 }
863 }
864 }
865
866 Some(Token::Register {
867 name: RegisterName::HL,
868 ..
869 }) => {
870 asm.expect_symbol(SymbolName::Comma)?;
871 match asm.next()? {
872 None => return asm.end_of_input_err(),
873 Some(Token::Register {
874 name: RegisterName::BC,
875 ..
876 }) => {
877 asm.data.push(0x09);
878 }
879
880 Some(Token::Register {
881 name: RegisterName::DE,
882 ..
883 }) => {
884 asm.data.push(0x19);
885 }
886
887 Some(Token::Register {
888 name: RegisterName::HL,
889 ..
890 }) => {
891 asm.data.push(0x29);
892 }
893
894 Some(Token::Register {
895 name: RegisterName::SP,
896 ..
897 }) => {
898 asm.data.push(0x39);
899 }
900
901 Some(tok) => {
902 return asm_err!(
903 tok.loc(),
904 "Unexpected {}, expected register \"bc\", \"de\", \"hl\" or \"sp\"",
905 tok.as_display(&asm.str_interner)
906 )
907 }
908 }
909 }
910
911 Some(Token::Register {
912 name: RegisterName::IX,
913 ..
914 }) => {
915 asm.expect_symbol(SymbolName::Comma)?;
916 match asm.next()? {
917 None => return asm.end_of_input_err(),
918 Some(Token::Register {
919 name: RegisterName::BC,
920 ..
921 }) => {
922 asm.data.push(0xDD);
923 asm.data.push(0x09);
924 }
925
926 Some(Token::Register {
927 name: RegisterName::DE,
928 ..
929 }) => {
930 asm.data.push(0xDD);
931 asm.data.push(0x19);
932 }
933
934 Some(Token::Register {
935 name: RegisterName::IX,
936 ..
937 }) => {
938 asm.data.push(0xDD);
939 asm.data.push(0x29);
940 }
941
942 Some(Token::Register {
943 name: RegisterName::SP,
944 ..
945 }) => {
946 asm.data.push(0xDD);
947 asm.data.push(0x39);
948 }
949
950 Some(tok) => {
951 return asm_err!(
952 tok.loc(),
953 "Unexpected {}, expected register \"bc\", \"de\", \"ix\" or \"sp\"",
954 tok.as_display(&asm.str_interner)
955 )
956 }
957 }
958 }
959
960 Some(Token::Register {
961 name: RegisterName::IY,
962 ..
963 }) => {
964 asm.expect_symbol(SymbolName::Comma)?;
965 match asm.next()? {
966 None => return asm.end_of_input_err(),
967 Some(Token::Register {
968 name: RegisterName::BC,
969 ..
970 }) => {
971 asm.data.push(0xFD);
972 asm.data.push(0x09);
973 }
974
975 Some(Token::Register {
976 name: RegisterName::DE,
977 ..
978 }) => {
979 asm.data.push(0xFD);
980 asm.data.push(0x19);
981 }
982
983 Some(Token::Register {
984 name: RegisterName::IY,
985 ..
986 }) => {
987 asm.data.push(0xFD);
988 asm.data.push(0x29);
989 }
990
991 Some(Token::Register {
992 name: RegisterName::SP,
993 ..
994 }) => {
995 asm.data.push(0xFD);
996 asm.data.push(0x39);
997 }
998
999 Some(tok) => {
1000 return asm_err!(
1001 tok.loc(),
1002 "Unexpected {}, expected register \"bc\", \"de\", \"iy\" or \"sp\"",
1003 tok.as_display(&asm.str_interner)
1004 )
1005 }
1006 }
1007 }
1008
1009 Some(tok) => {
1010 return asm_err!(
1011 tok.loc(),
1012 "Unexpected {}, expected register \"a\" or \"hl\"",
1013 tok.as_display(&asm.str_interner)
1014 )
1015 }
1016 }
1017 }
1018
1019 OperationName::And => {
1020 asm.next()?;
1021 match asm.peek()? {
1022 None => return asm.end_of_input_err(),
1023 Some(Token::Register {
1024 name: RegisterName::A,
1025 ..
1026 }) => {
1027 asm.next()?;
1028 asm.data.push(0xA7);
1029 }
1030
1031 Some(Token::Register {
1032 name: RegisterName::B,
1033 ..
1034 }) => {
1035 asm.next()?;
1036 asm.data.push(0xA0);
1037 }
1038
1039 Some(Token::Register {
1040 name: RegisterName::C,
1041 ..
1042 }) => {
1043 asm.next()?;
1044 asm.data.push(0xA1);
1045 }
1046
1047 Some(Token::Register {
1048 name: RegisterName::D,
1049 ..
1050 }) => {
1051 asm.next()?;
1052 asm.data.push(0xA2);
1053 }
1054
1055 Some(Token::Register {
1056 name: RegisterName::E,
1057 ..
1058 }) => {
1059 asm.next()?;
1060 asm.data.push(0xA3);
1061 }
1062
1063 Some(Token::Register {
1064 name: RegisterName::H,
1065 ..
1066 }) => {
1067 asm.next()?;
1068 asm.data.push(0xA4);
1069 }
1070
1071 Some(Token::Register {
1072 name: RegisterName::L,
1073 ..
1074 }) => {
1075 asm.next()?;
1076 asm.data.push(0xA5);
1077 }
1078
1079 Some(Token::Register {
1080 name: RegisterName::IXH,
1081 ..
1082 }) => {
1083 asm.next()?;
1084 asm.data.push(0xDD);
1085 asm.data.push(0xA4);
1086 }
1087
1088 Some(Token::Register {
1089 name: RegisterName::IXL,
1090 ..
1091 }) => {
1092 asm.next()?;
1093 asm.data.push(0xDD);
1094 asm.data.push(0xA5);
1095 }
1096
1097 Some(Token::Register {
1098 name: RegisterName::IYH,
1099 ..
1100 }) => {
1101 asm.next()?;
1102 asm.data.push(0xFD);
1103 asm.data.push(0xA4);
1104 }
1105
1106 Some(Token::Register {
1107 name: RegisterName::IYL,
1108 ..
1109 }) => {
1110 asm.next()?;
1111 asm.data.push(0xFD);
1112 asm.data.push(0xA5);
1113 }
1114
1115 Some(Token::Symbol {
1116 name: SymbolName::ParenOpen,
1117 ..
1118 }) => {
1119 asm.next()?;
1120 match asm.next()? {
1121 None => return asm.end_of_input_err(),
1122 Some(Token::Register {
1123 name: RegisterName::HL,
1124 ..
1125 }) => {
1126 asm.data.push(0xA6);
1127 asm.expect_symbol(SymbolName::ParenClose)?;
1128 }
1129
1130 Some(Token::Register {
1131 name: RegisterName::IX,
1132 ..
1133 }) => {
1134 asm.expect_symbol(SymbolName::Plus)?;
1135 asm.data.push(0xDD);
1136 asm.data.push(0xA6);
1137 let (loc, expr) = asm.expr()?;
1138 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
1139 if (value as u32) > (u8::MAX as u32) {
1140 return asm_err!(
1141 loc,
1142 "Expression result ({value}) will not fit in a byte"
1143 );
1144 }
1145 asm.data.push(value as u8);
1146 } else {
1147 asm.links.push(Link::byte(loc, asm.data.len(), expr));
1148 asm.data.push(0);
1149 }
1150 asm.expect_symbol(SymbolName::ParenClose)?;
1151 }
1152
1153 Some(Token::Register {
1154 name: RegisterName::IY,
1155 ..
1156 }) => {
1157 asm.expect_symbol(SymbolName::Plus)?;
1158 asm.data.push(0xFD);
1159 asm.data.push(0xA6);
1160 let (loc, expr) = asm.expr()?;
1161 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
1162 if (value as u32) > (u8::MAX as u32) {
1163 return asm_err!(
1164 loc,
1165 "Expression result ({value}) will not fit in a byte"
1166 );
1167 }
1168 asm.data.push(value as u8);
1169 } else {
1170 asm.links.push(Link::byte(loc, asm.data.len(), expr));
1171 asm.data.push(0);
1172 }
1173 asm.expect_symbol(SymbolName::ParenClose)?;
1174 }
1175
1176 Some(tok) => {
1177 return asm_err!(
1178 tok.loc(),
1179 "Unexpected {}, expected registers \"hl\", \"ix\", or \"iy\"",
1180 tok.as_display(&asm.str_interner)
1181 )
1182 }
1183 }
1184 }
1185
1186 Some(_) => {
1187 asm.data.push(0xE6);
1188 let (loc, expr) = asm.expr()?;
1189 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
1190 if (value as u32) > (u8::MAX as u32) {
1191 return asm_err!(
1192 loc,
1193 "Expression result ({value}) will not fit in a byte"
1194 );
1195 }
1196 asm.data.push(value as u8);
1197 } else {
1198 asm.links.push(Link::byte(loc, asm.data.len(), expr));
1199 asm.data.push(0);
1200 }
1201 }
1202 }
1203 }
1204
1205 OperationName::Bit => {
1206 asm.next()?;
1207 match asm.const_expr()? {
1208 (loc, None) => return asm_err!(loc, "Bit index must be immediately solvable"),
1209 (loc, Some(value)) => {
1210 if !(0..=7).contains(&value) {
1211 return asm_err!(loc, "Bit index ({value}) must be between 0 and 7");
1212 }
1213
1214 asm.expect_symbol(SymbolName::Comma)?;
1215
1216 match asm.next()? {
1217 Some(Token::Register {
1218 name: RegisterName::A,
1219 ..
1220 }) => {
1221 asm.data.push(0xCB);
1222 asm.data.push(match value {
1223 0 => 0x47,
1224 1 => 0x4F,
1225 2 => 0x57,
1226 3 => 0x5F,
1227 4 => 0x67,
1228 5 => 0x6F,
1229 6 => 0x77,
1230 7 => 0x7F,
1231 _ => unreachable!(),
1232 });
1233 }
1234
1235 Some(Token::Register {
1236 name: RegisterName::B,
1237 ..
1238 }) => {
1239 asm.data.push(0xCB);
1240 asm.data.push(match value {
1241 0 => 0x40,
1242 1 => 0x48,
1243 2 => 0x50,
1244 3 => 0x58,
1245 4 => 0x60,
1246 5 => 0x68,
1247 6 => 0x70,
1248 7 => 0x78,
1249 _ => unreachable!(),
1250 });
1251 }
1252
1253 Some(Token::Register {
1254 name: RegisterName::C,
1255 ..
1256 }) => {
1257 asm.data.push(0xCB);
1258 asm.data.push(match value {
1259 0 => 0x41,
1260 1 => 0x49,
1261 2 => 0x51,
1262 3 => 0x59,
1263 4 => 0x61,
1264 5 => 0x69,
1265 6 => 0x71,
1266 7 => 0x79,
1267 _ => unreachable!(),
1268 });
1269 }
1270
1271 Some(Token::Register {
1272 name: RegisterName::D,
1273 ..
1274 }) => {
1275 asm.data.push(0xCB);
1276 asm.data.push(match value {
1277 0 => 0x42,
1278 1 => 0x4A,
1279 2 => 0x52,
1280 3 => 0x5A,
1281 4 => 0x62,
1282 5 => 0x6A,
1283 6 => 0x72,
1284 7 => 0x7A,
1285 _ => unreachable!(),
1286 });
1287 }
1288
1289 Some(Token::Register {
1290 name: RegisterName::E,
1291 ..
1292 }) => {
1293 asm.data.push(0xCB);
1294 asm.data.push(match value {
1295 0 => 0x43,
1296 1 => 0x4B,
1297 2 => 0x53,
1298 3 => 0x5B,
1299 4 => 0x63,
1300 5 => 0x6B,
1301 6 => 0x73,
1302 7 => 0x7B,
1303 _ => unreachable!(),
1304 });
1305 }
1306
1307 Some(Token::Register {
1308 name: RegisterName::H,
1309 ..
1310 }) => {
1311 asm.data.push(0xCB);
1312 asm.data.push(match value {
1313 0 => 0x44,
1314 1 => 0x4C,
1315 2 => 0x54,
1316 3 => 0x5C,
1317 4 => 0x64,
1318 5 => 0x6C,
1319 6 => 0x74,
1320 7 => 0x7C,
1321 _ => unreachable!(),
1322 });
1323 }
1324
1325 Some(Token::Register {
1326 name: RegisterName::L,
1327 ..
1328 }) => {
1329 asm.data.push(0xCB);
1330 asm.data.push(match value {
1331 0 => 0x45,
1332 1 => 0x4D,
1333 2 => 0x55,
1334 3 => 0x5D,
1335 4 => 0x65,
1336 5 => 0x6D,
1337 6 => 0x75,
1338 7 => 0x7D,
1339 _ => unreachable!(),
1340 });
1341 }
1342
1343 Some(Token::Symbol {
1344 name: SymbolName::ParenOpen,
1345 ..
1346 }) => {
1347 match asm.next()? {
1348 Some(Token::Register { name: RegisterName::HL, .. }) => {
1349 asm.data.push(0xCB);
1350 asm.data.push(match value {
1351 0 => 0x46,
1352 1 => 0x4E,
1353 2 => 0x56,
1354 3 => 0x5E,
1355 4 => 0x66,
1356 5 => 0x6E,
1357 6 => 0x76,
1358 7 => 0x7E,
1359 _ => unreachable!(),
1360 });
1361 }
1362
1363 Some(Token::Register { name: RegisterName::IX, .. }) => {
1364 asm.expect_symbol(SymbolName::Plus)?;
1365 asm.data.push(0xDD);
1366 asm.data.push(0xCB);
1367 let (loc, expr) = asm.expr()?;
1368 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
1369 if (value as u32) > (u8::MAX as u32) {
1370 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
1371 }
1372 asm.data.push(value as u8);
1373 } else {
1374 asm.links.push(Link::byte(loc, asm.data.len(), expr));
1375 asm.data.push(0);
1376 }
1377 asm.data.push(match value {
1378 0 => 0x46,
1379 1 => 0x4E,
1380 2 => 0x56,
1381 3 => 0x5E,
1382 4 => 0x66,
1383 5 => 0x6E,
1384 6 => 0x76,
1385 7 => 0x7E,
1386 _ => unreachable!(),
1387 });
1388 }
1389
1390 Some(Token::Register { name: RegisterName::IY, .. }) => {
1391 asm.expect_symbol(SymbolName::Plus)?;
1392 asm.data.push(0xFD);
1393 asm.data.push(0xCB);
1394 let (loc, expr) = asm.expr()?;
1395 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
1396 if (value as u32) > (u8::MAX as u32) {
1397 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
1398 }
1399 asm.data.push(value as u8);
1400 } else {
1401 asm.links.push(Link::byte(loc, asm.data.len(), expr));
1402 asm.data.push(0);
1403 }
1404 asm.data.push(match value {
1405 0 => 0x46,
1406 1 => 0x4E,
1407 2 => 0x56,
1408 3 => 0x5E,
1409 4 => 0x66,
1410 5 => 0x6E,
1411 6 => 0x76,
1412 7 => 0x7E,
1413 _ => unreachable!(),
1414 });
1415 }
1416
1417 Some(tok) => return asm_err!(tok.loc(),"Unexpected {}, expected register \"hl\", \"ix\", or \"iy\"",tok.as_display(&asm.str_interner)),
1418 None => return asm.end_of_input_err(),
1419 }
1420 asm.expect_symbol(SymbolName::ParenClose)?;
1421 }
1422
1423 Some(tok) => {
1424 return asm_err!(
1425 tok.loc(),
1426 "Unexpected {}, expected a register",
1427 tok.as_display(&asm.str_interner)
1428 )
1429 }
1430 None => return asm.end_of_input_err(),
1431 }
1432 }
1433 }
1434 }
1435
1436 OperationName::Call => {
1437 asm.next()?;
1438 match asm.peek()? {
1439 Some(Token::Flag {
1440 name: FlagName::Zero,
1441 ..
1442 }) => {
1443 asm.next()?;
1444 asm.data.push(0xCC);
1445 asm.expect_symbol(SymbolName::Comma)?;
1446 }
1447 Some(Token::Flag {
1448 name: FlagName::NotZero,
1449 ..
1450 }) => {
1451 asm.next()?;
1452 asm.data.push(0xC4);
1453 asm.expect_symbol(SymbolName::Comma)?;
1454 }
1455 Some(Token::Register {
1456 name: RegisterName::C,
1457 ..
1458 }) => {
1459 asm.next()?;
1460 asm.data.push(0xDC);
1461 asm.expect_symbol(SymbolName::Comma)?;
1462 }
1463 Some(Token::Flag {
1464 name: FlagName::NotCarry,
1465 ..
1466 }) => {
1467 asm.next()?;
1468 asm.data.push(0xD4);
1469 asm.expect_symbol(SymbolName::Comma)?;
1470 }
1471 Some(Token::Flag {
1472 name: FlagName::ParityEven,
1473 ..
1474 }) => {
1475 asm.next()?;
1476 asm.data.push(0xEC);
1477 asm.expect_symbol(SymbolName::Comma)?;
1478 }
1479 Some(Token::Flag {
1480 name: FlagName::ParityOdd,
1481 ..
1482 }) => {
1483 asm.next()?;
1484 asm.data.push(0xE4);
1485 asm.expect_symbol(SymbolName::Comma)?;
1486 }
1487 Some(Token::Flag {
1488 name: FlagName::Positive,
1489 ..
1490 }) => {
1491 asm.next()?;
1492 asm.data.push(0xF4);
1493 asm.expect_symbol(SymbolName::Comma)?;
1494 }
1495 Some(Token::Flag {
1496 name: FlagName::Negative,
1497 ..
1498 }) => {
1499 asm.next()?;
1500 asm.data.push(0xFC);
1501 asm.expect_symbol(SymbolName::Comma)?;
1502 }
1503 Some(_) => {
1504 asm.data.push(0xCD);
1505 }
1506 None => return asm.end_of_input_err(),
1507 }
1508 let (loc, expr) = asm.expr()?;
1509 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
1510 if (value as u32) > (u16::MAX as u32) {
1511 return asm_err!(loc, "Expression result ({value}) will not fit in a word");
1512 }
1513 asm.data.extend_from_slice(&(value as u16).to_le_bytes());
1514 } else {
1515 asm.links.push(Link::word(loc, asm.data.len(), expr));
1516 asm.data.push(0);
1517 asm.data.push(0);
1518 }
1519 }
1520
1521 OperationName::Ccf => {
1522 asm.next()?;
1523 asm.data.push(0x3F);
1524 }
1525
1526 OperationName::Cp => {
1527 asm.next()?;
1528 match asm.peek()? {
1529 None => return asm.end_of_input_err(),
1530 Some(Token::Register {
1531 name: RegisterName::A,
1532 ..
1533 }) => {
1534 asm.next()?;
1535 asm.data.push(0xBF);
1536 }
1537
1538 Some(Token::Register {
1539 name: RegisterName::B,
1540 ..
1541 }) => {
1542 asm.next()?;
1543 asm.data.push(0xB8);
1544 }
1545
1546 Some(Token::Register {
1547 name: RegisterName::C,
1548 ..
1549 }) => {
1550 asm.next()?;
1551 asm.data.push(0xB9);
1552 }
1553
1554 Some(Token::Register {
1555 name: RegisterName::D,
1556 ..
1557 }) => {
1558 asm.next()?;
1559 asm.data.push(0xBA);
1560 }
1561
1562 Some(Token::Register {
1563 name: RegisterName::E,
1564 ..
1565 }) => {
1566 asm.next()?;
1567 asm.data.push(0xBB);
1568 }
1569
1570 Some(Token::Register {
1571 name: RegisterName::H,
1572 ..
1573 }) => {
1574 asm.next()?;
1575 asm.data.push(0xBC);
1576 }
1577
1578 Some(Token::Register {
1579 name: RegisterName::L,
1580 ..
1581 }) => {
1582 asm.next()?;
1583 asm.data.push(0xBD);
1584 }
1585
1586 Some(Token::Register {
1587 name: RegisterName::IXH,
1588 ..
1589 }) => {
1590 asm.next()?;
1591 asm.data.push(0xDD);
1592 asm.data.push(0xBC);
1593 }
1594
1595 Some(Token::Register {
1596 name: RegisterName::IXL,
1597 ..
1598 }) => {
1599 asm.next()?;
1600 asm.data.push(0xDD);
1601 asm.data.push(0xBD);
1602 }
1603
1604 Some(Token::Register {
1605 name: RegisterName::IYH,
1606 ..
1607 }) => {
1608 asm.next()?;
1609 asm.data.push(0xFD);
1610 asm.data.push(0xBC);
1611 }
1612
1613 Some(Token::Register {
1614 name: RegisterName::IYL,
1615 ..
1616 }) => {
1617 asm.next()?;
1618 asm.data.push(0xFD);
1619 asm.data.push(0xBD);
1620 }
1621
1622 Some(Token::Symbol {
1623 name: SymbolName::ParenOpen,
1624 ..
1625 }) => {
1626 asm.next()?;
1627 match asm.next()? {
1628 None => return asm.end_of_input_err(),
1629 Some(Token::Register {
1630 name: RegisterName::HL,
1631 ..
1632 }) => {
1633 asm.data.push(0xBE);
1634 asm.expect_symbol(SymbolName::ParenClose)?;
1635 }
1636
1637 Some(Token::Register {
1638 name: RegisterName::IX,
1639 ..
1640 }) => {
1641 asm.expect_symbol(SymbolName::Plus)?;
1642 asm.data.push(0xDD);
1643 asm.data.push(0xBE);
1644 let (loc, expr) = asm.expr()?;
1645 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
1646 if (value as u32) > (u8::MAX as u32) {
1647 return asm_err!(
1648 loc,
1649 "Expression result ({value}) will not fit in a byte"
1650 );
1651 }
1652 asm.data.push(value as u8);
1653 } else {
1654 asm.links.push(Link::byte(loc, asm.data.len(), expr));
1655 asm.data.push(0);
1656 }
1657 asm.expect_symbol(SymbolName::ParenClose)?;
1658 }
1659
1660 Some(Token::Register {
1661 name: RegisterName::IY,
1662 ..
1663 }) => {
1664 asm.expect_symbol(SymbolName::Plus)?;
1665 asm.data.push(0xFD);
1666 asm.data.push(0xBE);
1667 let (loc, expr) = asm.expr()?;
1668 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
1669 if (value as u32) > (u8::MAX as u32) {
1670 return asm_err!(
1671 loc,
1672 "Expression result ({value}) will not fit in a byte"
1673 );
1674 }
1675 asm.data.push(value as u8);
1676 } else {
1677 asm.links.push(Link::byte(loc, asm.data.len(), expr));
1678 asm.data.push(0);
1679 }
1680 asm.expect_symbol(SymbolName::ParenClose)?;
1681 }
1682
1683 Some(_) => {
1684 asm.data.push(0xFE);
1685 let (loc, expr) = asm.expr()?;
1686 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
1687 if (value as u32) > (u8::MAX as u32) {
1688 return asm_err!(
1689 loc,
1690 "Expression result ({value}) will not fit in a byte"
1691 );
1692 }
1693 asm.data.push(value as u8);
1694 } else {
1695 asm.links.push(Link::byte(loc, asm.data.len(), expr));
1696 asm.data.push(0);
1697 }
1698 asm.expect_symbol(SymbolName::ParenClose)?;
1699 }
1700 }
1701 }
1702
1703 Some(_) => {
1704 asm.data.push(0xFE);
1705 let (loc, expr) = asm.expr()?;
1706 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
1707 if (value as u32) > (u8::MAX as u32) {
1708 return asm_err!(
1709 loc,
1710 "Expression result ({value}) will not fit in a byte"
1711 );
1712 }
1713 asm.data.push(value as u8);
1714 } else {
1715 asm.links.push(Link::byte(loc, asm.data.len(), expr));
1716 asm.data.push(0);
1717 }
1718 }
1719 }
1720 }
1721
1722 OperationName::Cpd => {
1723 asm.next()?;
1724 asm.data.push(0xED);
1725 asm.data.push(0xA9);
1726 }
1727
1728 OperationName::Cpdr => {
1729 asm.next()?;
1730 asm.data.push(0xED);
1731 asm.data.push(0xB9);
1732 }
1733
1734 OperationName::Cpi => {
1735 asm.next()?;
1736 asm.data.push(0xED);
1737 asm.data.push(0xA1);
1738 }
1739
1740 OperationName::Cpir => {
1741 asm.next()?;
1742 asm.data.push(0xED);
1743 asm.data.push(0xB1);
1744 }
1745
1746 OperationName::Cpl => {
1747 asm.next()?;
1748 asm.data.push(0x2F);
1749 }
1750
1751 OperationName::Daa => {
1752 asm.next()?;
1753 asm.data.push(0x27);
1754 }
1755
1756 OperationName::Dec => {
1757 asm.next()?;
1758 match asm.next()? {
1759 Some(Token::Register {
1760 name: RegisterName::A,
1761 ..
1762 }) => {
1763 asm.data.push(0x3D);
1764 }
1765
1766 Some(Token::Register {
1767 name: RegisterName::B,
1768 ..
1769 }) => {
1770 asm.data.push(0x05);
1771 }
1772
1773 Some(Token::Register {
1774 name: RegisterName::C,
1775 ..
1776 }) => {
1777 asm.data.push(0x0D);
1778 }
1779
1780 Some(Token::Register {
1781 name: RegisterName::D,
1782 ..
1783 }) => {
1784 asm.data.push(0x15);
1785 }
1786
1787 Some(Token::Register {
1788 name: RegisterName::E,
1789 ..
1790 }) => {
1791 asm.data.push(0x1D);
1792 }
1793
1794 Some(Token::Register {
1795 name: RegisterName::H,
1796 ..
1797 }) => {
1798 asm.data.push(0x25);
1799 }
1800
1801 Some(Token::Register {
1802 name: RegisterName::L,
1803 ..
1804 }) => {
1805 asm.data.push(0x2D);
1806 }
1807
1808 Some(Token::Register {
1809 name: RegisterName::IXH,
1810 ..
1811 }) => {
1812 asm.data.push(0xDD);
1813 asm.data.push(0x25);
1814 }
1815
1816 Some(Token::Register {
1817 name: RegisterName::IXL,
1818 ..
1819 }) => {
1820 asm.data.push(0xDD);
1821 asm.data.push(0x2D);
1822 }
1823
1824 Some(Token::Register {
1825 name: RegisterName::IYH,
1826 ..
1827 }) => {
1828 asm.data.push(0xFD);
1829 asm.data.push(0x25);
1830 }
1831
1832 Some(Token::Register {
1833 name: RegisterName::IYL,
1834 ..
1835 }) => {
1836 asm.data.push(0xFD);
1837 asm.data.push(0x2D);
1838 }
1839
1840 Some(Token::Register {
1841 name: RegisterName::BC,
1842 ..
1843 }) => {
1844 asm.data.push(0x0B);
1845 }
1846
1847 Some(Token::Register {
1848 name: RegisterName::DE,
1849 ..
1850 }) => {
1851 asm.data.push(0x1B);
1852 }
1853
1854 Some(Token::Register {
1855 name: RegisterName::HL,
1856 ..
1857 }) => {
1858 asm.data.push(0x2B);
1859 }
1860
1861 Some(Token::Register {
1862 name: RegisterName::SP,
1863 ..
1864 }) => {
1865 asm.data.push(0x3B);
1866 }
1867
1868 Some(Token::Register {
1869 name: RegisterName::IX,
1870 ..
1871 }) => {
1872 asm.data.push(0xDD);
1873 asm.data.push(0x2B);
1874 }
1875
1876 Some(Token::Register {
1877 name: RegisterName::IY,
1878 ..
1879 }) => {
1880 asm.data.push(0xFD);
1881 asm.data.push(0x2B);
1882 }
1883
1884 Some(Token::Symbol {
1885 name: SymbolName::ParenOpen,
1886 ..
1887 }) => match asm.next()? {
1888 None => return asm.end_of_input_err(),
1889
1890 Some(Token::Register {
1891 name: RegisterName::HL,
1892 ..
1893 }) => {
1894 asm.data.push(0x35);
1895 asm.expect_symbol(SymbolName::ParenClose)?;
1896 }
1897
1898 Some(Token::Register {
1899 name: RegisterName::IX,
1900 ..
1901 }) => {
1902 asm.expect_symbol(SymbolName::Plus)?;
1903 asm.data.push(0xDD);
1904 asm.data.push(0x35);
1905 let (loc, expr) = asm.expr()?;
1906 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
1907 if (value as u32) > (u8::MAX as u32) {
1908 return asm_err!(
1909 loc,
1910 "Expression result ({value}) will not fit in a byte"
1911 );
1912 }
1913 asm.data.push(value as u8);
1914 } else {
1915 asm.links.push(Link::byte(loc, asm.data.len(), expr));
1916 asm.data.push(0);
1917 }
1918 asm.expect_symbol(SymbolName::ParenClose)?;
1919 }
1920
1921 Some(Token::Register {
1922 name: RegisterName::IY,
1923 ..
1924 }) => {
1925 asm.expect_symbol(SymbolName::Plus)?;
1926 asm.data.push(0xFD);
1927 asm.data.push(0x35);
1928 let (loc, expr) = asm.expr()?;
1929 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
1930 if (value as u32) > (u8::MAX as u32) {
1931 return asm_err!(
1932 loc,
1933 "Expression result ({value}) will not fit in a byte"
1934 );
1935 }
1936 asm.data.push(value as u8);
1937 } else {
1938 asm.links.push(Link::byte(loc, asm.data.len(), expr));
1939 asm.data.push(0);
1940 }
1941 asm.expect_symbol(SymbolName::ParenClose)?;
1942 }
1943
1944 Some(tok) => {
1945 return asm_err!(
1946 tok.loc(),
1947 "Unexpected {}, expected registers \"hl\", \"ix\", or \"iy\"",
1948 tok.as_display(&asm.str_interner)
1949 )
1950 }
1951 },
1952
1953 Some(tok) => {
1954 return asm_err!(
1955 tok.loc(),
1956 "Unexpected {}, expected a register",
1957 tok.as_display(&asm.str_interner)
1958 )
1959 }
1960 None => return asm.end_of_input_err(),
1961 }
1962 }
1963
1964 OperationName::Di => {
1965 asm.next()?;
1966 asm.data.push(0xF3);
1967 }
1968
1969 OperationName::Djnz => {
1970 asm.next()?;
1971 asm.data.push(0x10);
1972 let (loc, mut expr) = asm.expr()?;
1973 // Make the expression relative to @here
1974 expr.push(ExprNode::Value(asm.here.wrapping_add(2) as i32));
1975 expr.push(ExprNode::Sub);
1976 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
1977 if (value < (i8::MIN as i32)) || (value > (i8::MAX as i32)) {
1978 return asm_err!(loc, "Jump distance ({value}) will not fit in a byte");
1979 }
1980 asm.data.push(value as u8);
1981 } else {
1982 asm.links.push(Link::signed_byte(loc, asm.data.len(), expr));
1983 asm.data.push(0);
1984 }
1985 }
1986
1987 OperationName::Ei => {
1988 asm.next()?;
1989 asm.data.push(0xFB);
1990 }
1991
1992 OperationName::Ex => {
1993 asm.next()?;
1994 match asm.next()? {
1995 None => return asm.end_of_input_err(),
1996
1997 Some(Token::Register {
1998 name: RegisterName::AF,
1999 ..
2000 }) => {
2001 asm.expect_symbol(SymbolName::Comma)?;
2002 asm.expect_register(RegisterName::AFPrime)?;
2003 asm.data.push(0x08);
2004 }
2005
2006 Some(Token::Register {
2007 name: RegisterName::DE,
2008 ..
2009 }) => {
2010 asm.expect_symbol(SymbolName::Comma)?;
2011 asm.expect_register(RegisterName::HL)?;
2012 asm.data.push(0xEB);
2013 }
2014
2015 Some(Token::Symbol {
2016 name: SymbolName::ParenOpen,
2017 ..
2018 }) => {
2019 asm.expect_register(RegisterName::SP)?;
2020 asm.expect_symbol(SymbolName::ParenClose)?;
2021 asm.expect_symbol(SymbolName::Comma)?;
2022
2023 match asm.next()? {
2024 None => return asm.end_of_input_err(),
2025
2026 Some(Token::Register {
2027 name: RegisterName::HL,
2028 ..
2029 }) => {
2030 asm.data.push(0xE3);
2031 }
2032
2033 Some(Token::Register {
2034 name: RegisterName::IX,
2035 ..
2036 }) => {
2037 asm.data.push(0xDD);
2038 asm.data.push(0xE3);
2039 }
2040
2041 Some(Token::Register {
2042 name: RegisterName::IY,
2043 ..
2044 }) => {
2045 asm.data.push(0xFD);
2046 asm.data.push(0xE3);
2047 }
2048
2049 Some(tok) => {
2050 return asm_err!(
2051 tok.loc(),
2052 "Unexpected {}, expected the registers \"hl\", \"ix\", or \"iy\"",
2053 tok.as_display(&asm.str_interner)
2054 )
2055 }
2056 }
2057 }
2058
2059 Some(tok) => {
2060 return asm_err!(
2061 tok.loc(),
2062 "Unexpected {}, expected the registers \"af\", \"de\", or \"(sp)\"",
2063 tok.as_display(&asm.str_interner)
2064 )
2065 }
2066 }
2067 }
2068
2069 OperationName::Exx => {
2070 asm.next()?;
2071 asm.data.push(0xD9);
2072 }
2073
2074 OperationName::Halt => {
2075 asm.next()?;
2076 asm.data.push(0x76);
2077 }
2078
2079 OperationName::Im => {
2080 asm.next()?;
2081 asm.data.push(0xED);
2082 match asm.next()? {
2083 None => return asm.end_of_input_err(),
2084
2085 Some(Token::Number { value: 0, .. }) => {
2086 asm.data.push(0x46);
2087 }
2088
2089 Some(Token::Number { value: 1, .. }) => {
2090 asm.data.push(0x56);
2091 }
2092
2093 Some(Token::Number { value: 2, .. }) => {
2094 asm.data.push(0x5E);
2095 }
2096
2097 Some(tok) => {
2098 return asm_err!(
2099 tok.loc(),
2100 "Unexpected {}, expected the numbers 0, 1, or 2",
2101 tok.as_display(&asm.str_interner)
2102 )
2103 }
2104 }
2105 }
2106
2107 OperationName::In => {
2108 asm.next()?;
2109 match asm.next()? {
2110 None => return asm.end_of_input_err(),
2111
2112 Some(Token::Register {
2113 name: RegisterName::A,
2114 ..
2115 }) => {
2116 asm.expect_symbol(SymbolName::Comma)?;
2117 asm.expect_symbol(SymbolName::ParenOpen)?;
2118 match asm.peek()? {
2119 None => return asm.end_of_input_err(),
2120
2121 Some(Token::Register {
2122 name: RegisterName::C,
2123 ..
2124 }) => {
2125 asm.next()?;
2126 asm.expect_symbol(SymbolName::ParenClose)?;
2127 asm.data.push(0xED);
2128 asm.data.push(0x78);
2129 }
2130
2131 Some(_) => {
2132 asm.data.push(0xDB);
2133 let (loc, expr) = asm.expr()?;
2134 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
2135 if (value as u32) > (u8::MAX as u32) {
2136 return asm_err!(
2137 loc,
2138 "Expression result ({value}) will not fit in a byte"
2139 );
2140 }
2141 asm.data.push(value as u8);
2142 } else {
2143 asm.links.push(Link::byte(loc, asm.data.len(), expr));
2144 asm.data.push(0);
2145 }
2146 asm.expect_symbol(SymbolName::ParenClose)?;
2147 }
2148 }
2149 }
2150
2151 Some(Token::Register {
2152 name: RegisterName::B,
2153 ..
2154 }) => {
2155 asm.data.push(0xED);
2156 asm.data.push(0x40);
2157 asm.expect_symbol(SymbolName::Comma)?;
2158 asm.expect_symbol(SymbolName::ParenOpen)?;
2159 asm.expect_register(RegisterName::C)?;
2160 asm.expect_symbol(SymbolName::ParenClose)?;
2161 }
2162
2163 Some(Token::Register {
2164 name: RegisterName::C,
2165 ..
2166 }) => {
2167 asm.data.push(0xED);
2168 asm.data.push(0x48);
2169 asm.expect_symbol(SymbolName::Comma)?;
2170 asm.expect_symbol(SymbolName::ParenOpen)?;
2171 asm.expect_register(RegisterName::C)?;
2172 asm.expect_symbol(SymbolName::ParenClose)?;
2173 }
2174
2175 Some(Token::Register {
2176 name: RegisterName::D,
2177 ..
2178 }) => {
2179 asm.data.push(0xED);
2180 asm.data.push(0x50);
2181 asm.expect_symbol(SymbolName::Comma)?;
2182 asm.expect_symbol(SymbolName::ParenOpen)?;
2183 asm.expect_register(RegisterName::C)?;
2184 asm.expect_symbol(SymbolName::ParenClose)?;
2185 }
2186
2187 Some(Token::Register {
2188 name: RegisterName::E,
2189 ..
2190 }) => {
2191 asm.data.push(0xED);
2192 asm.data.push(0x58);
2193 asm.expect_symbol(SymbolName::Comma)?;
2194 asm.expect_symbol(SymbolName::ParenOpen)?;
2195 asm.expect_register(RegisterName::C)?;
2196 asm.expect_symbol(SymbolName::ParenClose)?;
2197 }
2198
2199 Some(Token::Register {
2200 name: RegisterName::H,
2201 ..
2202 }) => {
2203 asm.data.push(0xED);
2204 asm.data.push(0x60);
2205 asm.expect_symbol(SymbolName::Comma)?;
2206 asm.expect_symbol(SymbolName::ParenOpen)?;
2207 asm.expect_register(RegisterName::C)?;
2208 asm.expect_symbol(SymbolName::ParenClose)?;
2209 }
2210
2211 Some(Token::Register {
2212 name: RegisterName::L,
2213 ..
2214 }) => {
2215 asm.data.push(0xED);
2216 asm.data.push(0x68);
2217 asm.expect_symbol(SymbolName::Comma)?;
2218 asm.expect_symbol(SymbolName::ParenOpen)?;
2219 asm.expect_register(RegisterName::C)?;
2220 asm.expect_symbol(SymbolName::ParenClose)?;
2221 }
2222
2223 Some(tok) => {
2224 return asm_err!(
2225 tok.loc(),
2226 "Unexpected {}, expected a register",
2227 tok.as_display(&asm.str_interner)
2228 )
2229 }
2230 }
2231 }
2232
2233 OperationName::Inc => {
2234 asm.next()?;
2235 match asm.next()? {
2236 Some(Token::Register {
2237 name: RegisterName::A,
2238 ..
2239 }) => {
2240 asm.data.push(0x3C);
2241 }
2242
2243 Some(Token::Register {
2244 name: RegisterName::B,
2245 ..
2246 }) => {
2247 asm.data.push(0x04);
2248 }
2249
2250 Some(Token::Register {
2251 name: RegisterName::C,
2252 ..
2253 }) => {
2254 asm.data.push(0x0C);
2255 }
2256
2257 Some(Token::Register {
2258 name: RegisterName::D,
2259 ..
2260 }) => {
2261 asm.data.push(0x14);
2262 }
2263
2264 Some(Token::Register {
2265 name: RegisterName::E,
2266 ..
2267 }) => {
2268 asm.data.push(0x1C);
2269 }
2270
2271 Some(Token::Register {
2272 name: RegisterName::H,
2273 ..
2274 }) => {
2275 asm.data.push(0x24);
2276 }
2277
2278 Some(Token::Register {
2279 name: RegisterName::L,
2280 ..
2281 }) => {
2282 asm.data.push(0x2C);
2283 }
2284
2285 Some(Token::Register {
2286 name: RegisterName::IXH,
2287 ..
2288 }) => {
2289 asm.data.push(0xDD);
2290 asm.data.push(0x24);
2291 }
2292
2293 Some(Token::Register {
2294 name: RegisterName::IXL,
2295 ..
2296 }) => {
2297 asm.data.push(0xDD);
2298 asm.data.push(0x2C);
2299 }
2300
2301 Some(Token::Register {
2302 name: RegisterName::IYH,
2303 ..
2304 }) => {
2305 asm.data.push(0xFD);
2306 asm.data.push(0x24);
2307 }
2308
2309 Some(Token::Register {
2310 name: RegisterName::IYL,
2311 ..
2312 }) => {
2313 asm.data.push(0xFD);
2314 asm.data.push(0x2C);
2315 }
2316
2317 Some(Token::Register {
2318 name: RegisterName::BC,
2319 ..
2320 }) => {
2321 asm.data.push(0x03);
2322 }
2323
2324 Some(Token::Register {
2325 name: RegisterName::DE,
2326 ..
2327 }) => {
2328 asm.data.push(0x13);
2329 }
2330
2331 Some(Token::Register {
2332 name: RegisterName::HL,
2333 ..
2334 }) => {
2335 asm.data.push(0x23);
2336 }
2337
2338 Some(Token::Register {
2339 name: RegisterName::SP,
2340 ..
2341 }) => {
2342 asm.data.push(0x33);
2343 }
2344
2345 Some(Token::Register {
2346 name: RegisterName::IX,
2347 ..
2348 }) => {
2349 asm.data.push(0xDD);
2350 asm.data.push(0x23);
2351 }
2352
2353 Some(Token::Register {
2354 name: RegisterName::IY,
2355 ..
2356 }) => {
2357 asm.data.push(0xFD);
2358 asm.data.push(0x23);
2359 }
2360
2361 Some(Token::Symbol {
2362 name: SymbolName::ParenOpen,
2363 ..
2364 }) => match asm.next()? {
2365 None => return asm.end_of_input_err(),
2366
2367 Some(Token::Register {
2368 name: RegisterName::HL,
2369 ..
2370 }) => {
2371 asm.data.push(0x34);
2372 asm.expect_symbol(SymbolName::ParenClose)?;
2373 }
2374
2375 Some(Token::Register {
2376 name: RegisterName::IX,
2377 ..
2378 }) => {
2379 asm.expect_symbol(SymbolName::Plus)?;
2380 asm.data.push(0xDD);
2381 asm.data.push(0x34);
2382 let (loc, expr) = asm.expr()?;
2383 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
2384 if (value as u32) > (u8::MAX as u32) {
2385 return asm_err!(
2386 loc,
2387 "Expression result ({value}) will not fit in a byte"
2388 );
2389 }
2390 asm.data.push(value as u8);
2391 } else {
2392 asm.links.push(Link::byte(loc, asm.data.len(), expr));
2393 asm.data.push(0);
2394 }
2395 asm.expect_symbol(SymbolName::ParenClose)?;
2396 }
2397
2398 Some(Token::Register {
2399 name: RegisterName::IY,
2400 ..
2401 }) => {
2402 asm.expect_symbol(SymbolName::Plus)?;
2403 asm.data.push(0xFD);
2404 asm.data.push(0x34);
2405 let (loc, expr) = asm.expr()?;
2406 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
2407 if (value as u32) > (u8::MAX as u32) {
2408 return asm_err!(
2409 loc,
2410 "Expression result ({value}) will not fit in a byte"
2411 );
2412 }
2413 asm.data.push(value as u8);
2414 } else {
2415 asm.links.push(Link::byte(loc, asm.data.len(), expr));
2416 asm.data.push(0);
2417 }
2418 asm.expect_symbol(SymbolName::ParenClose)?;
2419 }
2420
2421 Some(tok) => {
2422 return asm_err!(
2423 tok.loc(),
2424 "Unexpected {}, expected registers \"hl\", \"ix\", or \"iy\"",
2425 tok.as_display(&asm.str_interner)
2426 )
2427 }
2428 },
2429
2430 Some(tok) => {
2431 return asm_err!(
2432 tok.loc(),
2433 "Unexpected {}, expected a register",
2434 tok.as_display(&asm.str_interner)
2435 )
2436 }
2437 None => return asm.end_of_input_err(),
2438 }
2439 }
2440
2441 OperationName::Ind => {
2442 asm.next()?;
2443 asm.data.push(0xED);
2444 asm.data.push(0xAA);
2445 }
2446
2447 OperationName::Indr => {
2448 asm.next()?;
2449 asm.data.push(0xED);
2450 asm.data.push(0xBA);
2451 }
2452
2453 OperationName::Ini => {
2454 asm.next()?;
2455 asm.data.push(0xED);
2456 asm.data.push(0xA2);
2457 }
2458
2459 OperationName::Inir => {
2460 asm.next()?;
2461 asm.data.push(0xED);
2462 asm.data.push(0xB2);
2463 }
2464
2465 OperationName::Jp => {
2466 asm.next()?;
2467 match asm.peek()? {
2468 None => return asm.end_of_input_err(),
2469
2470 Some(Token::Symbol {
2471 name: SymbolName::ParenOpen,
2472 ..
2473 }) => {
2474 asm.next()?;
2475 match asm.next()? {
2476 None => return asm.end_of_input_err(),
2477
2478 Some(Token::Register {
2479 name: RegisterName::HL,
2480 ..
2481 }) => {
2482 asm.data.push(0xE9);
2483 }
2484
2485 Some(Token::Register {
2486 name: RegisterName::IX,
2487 ..
2488 }) => {
2489 asm.data.push(0xDD);
2490 asm.data.push(0xE9);
2491 }
2492
2493 Some(Token::Register {
2494 name: RegisterName::IY,
2495 ..
2496 }) => {
2497 asm.data.push(0xFD);
2498 asm.data.push(0xE9);
2499 }
2500
2501 Some(tok) => {
2502 return asm_err!(
2503 tok.loc(),
2504 "Unexpected {}, expected register \"hl\", \"ix\", or \"iy\"",
2505 tok.as_display(&asm.str_interner)
2506 )
2507 }
2508 }
2509 asm.expect_symbol(SymbolName::ParenClose)?;
2510 }
2511
2512 Some(_) => {
2513 match asm.peek()? {
2514 None => return asm.end_of_input_err(),
2515 Some(Token::Flag {
2516 name: FlagName::Zero,
2517 ..
2518 }) => {
2519 asm.next()?;
2520 asm.data.push(0xCA);
2521 asm.expect_symbol(SymbolName::Comma)?;
2522 }
2523 Some(Token::Flag {
2524 name: FlagName::NotZero,
2525 ..
2526 }) => {
2527 asm.next()?;
2528 asm.data.push(0xC2);
2529 asm.expect_symbol(SymbolName::Comma)?;
2530 }
2531 Some(Token::Register {
2532 name: RegisterName::C,
2533 ..
2534 }) => {
2535 asm.next()?;
2536 asm.data.push(0xDA);
2537 asm.expect_symbol(SymbolName::Comma)?;
2538 }
2539 Some(Token::Flag {
2540 name: FlagName::NotCarry,
2541 ..
2542 }) => {
2543 asm.next()?;
2544 asm.data.push(0xD2);
2545 asm.expect_symbol(SymbolName::Comma)?;
2546 }
2547 Some(Token::Flag {
2548 name: FlagName::ParityEven,
2549 ..
2550 }) => {
2551 asm.next()?;
2552 asm.data.push(0xEA);
2553 asm.expect_symbol(SymbolName::Comma)?;
2554 }
2555 Some(Token::Flag {
2556 name: FlagName::ParityOdd,
2557 ..
2558 }) => {
2559 asm.next()?;
2560 asm.data.push(0xE2);
2561 asm.expect_symbol(SymbolName::Comma)?;
2562 }
2563 Some(Token::Flag {
2564 name: FlagName::Positive,
2565 ..
2566 }) => {
2567 asm.next()?;
2568 asm.data.push(0xF2);
2569 asm.expect_symbol(SymbolName::Comma)?;
2570 }
2571 Some(Token::Flag {
2572 name: FlagName::Negative,
2573 ..
2574 }) => {
2575 asm.next()?;
2576 asm.data.push(0xFA);
2577 asm.expect_symbol(SymbolName::Comma)?;
2578 }
2579 Some(_) => {
2580 asm.data.push(0xC3);
2581 }
2582 }
2583 let (loc, expr) = asm.expr()?;
2584 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
2585 if (value as u32) > (u16::MAX as u32) {
2586 return asm_err!(
2587 loc,
2588 "Expression result ({value}) will not fit in a word"
2589 );
2590 }
2591 asm.data.extend_from_slice(&(value as u16).to_le_bytes());
2592 } else {
2593 asm.links.push(Link::word(loc, asm.data.len(), expr));
2594 asm.data.push(0);
2595 asm.data.push(0);
2596 }
2597 }
2598 }
2599 }
2600
2601 OperationName::Jr => {
2602 asm.next()?;
2603 match asm.peek()? {
2604 None => return asm.end_of_input_err(),
2605
2606 Some(Token::Flag {
2607 name: FlagName::NotZero,
2608 ..
2609 }) => {
2610 asm.next()?;
2611 asm.data.push(0x20);
2612 asm.expect_symbol(SymbolName::Comma)?;
2613 }
2614
2615 Some(Token::Flag {
2616 name: FlagName::Zero,
2617 ..
2618 }) => {
2619 asm.next()?;
2620 asm.data.push(0x28);
2621 asm.expect_symbol(SymbolName::Comma)?;
2622 }
2623
2624 Some(Token::Flag {
2625 name: FlagName::NotCarry,
2626 ..
2627 }) => {
2628 asm.next()?;
2629 asm.data.push(0x30);
2630 asm.expect_symbol(SymbolName::Comma)?;
2631 }
2632
2633 Some(Token::Register {
2634 name: RegisterName::C,
2635 ..
2636 }) => {
2637 asm.next()?;
2638 asm.data.push(0x38);
2639 asm.expect_symbol(SymbolName::Comma)?;
2640 }
2641
2642 Some(_) => {
2643 asm.data.push(0x18);
2644 }
2645 }
2646 let (loc, mut expr) = asm.expr()?;
2647 // Make the expression relative to @here
2648 expr.push(ExprNode::Value(asm.here.wrapping_add(2) as i32));
2649 expr.push(ExprNode::Sub);
2650 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
2651 if (value < (i8::MIN as i32)) || (value > (i8::MAX as i32)) {
2652 return asm_err!(loc, "Jump distance ({value}) will not fit in a byte");
2653 }
2654 asm.data.push(value as u8);
2655 } else {
2656 asm.links.push(Link::signed_byte(loc, asm.data.len(), expr));
2657 asm.data.push(0);
2658 }
2659 }
2660
2661 OperationName::Ld => {
2662 asm.next()?;
2663 match asm.next()? {
2664 None => return asm.end_of_input_err(),
2665 Some(Token::Register {
2666 name: RegisterName::A,
2667 ..
2668 }) => {
2669 asm.expect_symbol(SymbolName::Comma)?;
2670 match asm.peek()? {
2671 None => return asm.end_of_input_err(),
2672 Some(Token::Register {
2673 name: RegisterName::A,
2674 ..
2675 }) => {
2676 asm.next()?;
2677 asm.data.push(0x7F);
2678 }
2679 Some(Token::Register {
2680 name: RegisterName::B,
2681 ..
2682 }) => {
2683 asm.next()?;
2684 asm.data.push(0x78);
2685 }
2686 Some(Token::Register {
2687 name: RegisterName::C,
2688 ..
2689 }) => {
2690 asm.next()?;
2691 asm.data.push(0x79);
2692 }
2693 Some(Token::Register {
2694 name: RegisterName::D,
2695 ..
2696 }) => {
2697 asm.next()?;
2698 asm.data.push(0x7A);
2699 }
2700 Some(Token::Register {
2701 name: RegisterName::E,
2702 ..
2703 }) => {
2704 asm.next()?;
2705 asm.data.push(0x7B);
2706 }
2707 Some(Token::Register {
2708 name: RegisterName::H,
2709 ..
2710 }) => {
2711 asm.next()?;
2712 asm.data.push(0x7C);
2713 }
2714 Some(Token::Register {
2715 name: RegisterName::L,
2716 ..
2717 }) => {
2718 asm.next()?;
2719 asm.data.push(0x7D);
2720 }
2721 Some(Token::Register {
2722 name: RegisterName::IXH,
2723 ..
2724 }) => {
2725 asm.next()?;
2726 asm.data.push(0xDD);
2727 asm.data.push(0x7C);
2728 }
2729 Some(Token::Register {
2730 name: RegisterName::IXL,
2731 ..
2732 }) => {
2733 asm.next()?;
2734 asm.data.push(0xDD);
2735 asm.data.push(0x7D);
2736 }
2737 Some(Token::Register {
2738 name: RegisterName::IYH,
2739 ..
2740 }) => {
2741 asm.next()?;
2742 asm.data.push(0xFD);
2743 asm.data.push(0x7C);
2744 }
2745 Some(Token::Register {
2746 name: RegisterName::IYL,
2747 ..
2748 }) => {
2749 asm.next()?;
2750 asm.data.push(0xFD);
2751 asm.data.push(0x7D);
2752 }
2753 Some(Token::Register {
2754 name: RegisterName::I,
2755 ..
2756 }) => {
2757 asm.next()?;
2758 asm.data.push(0xED);
2759 asm.data.push(0x57);
2760 }
2761 Some(Token::Register {
2762 name: RegisterName::R,
2763 ..
2764 }) => {
2765 asm.next()?;
2766 asm.data.push(0xED);
2767 asm.data.push(0x5F);
2768 }
2769 Some(Token::Symbol {
2770 name: SymbolName::ParenOpen,
2771 ..
2772 }) => {
2773 asm.next()?;
2774 match asm.peek()? {
2775 None => return asm.end_of_input_err(),
2776
2777 Some(Token::Register {
2778 name: RegisterName::BC,
2779 ..
2780 }) => {
2781 asm.next()?;
2782 asm.data.push(0x0A);
2783 }
2784
2785 Some(Token::Register {
2786 name: RegisterName::DE,
2787 ..
2788 }) => {
2789 asm.next()?;
2790 asm.data.push(0x1A);
2791 }
2792
2793 Some(Token::Register {
2794 name: RegisterName::HL,
2795 ..
2796 }) => {
2797 asm.next()?;
2798 asm.data.push(0x7E);
2799 }
2800
2801 Some(Token::Register { loc, name }) => {
2802 asm.next()?;
2803 match name {
2804 RegisterName::IX => {
2805 asm.data.push(0xDD);
2806 asm.data.push(0x7E);
2807 }
2808 RegisterName::IY => {
2809 asm.data.push(0xFD);
2810 asm.data.push(0x7E);
2811 }
2812 _ => return asm_err!(loc,"Unexpected register \"{name}\", expected register \"ix\" or \"iy\""),
2813 }
2814 asm.expect_symbol(SymbolName::Plus)?;
2815 let (loc, expr) = asm.expr()?;
2816 if let Some(value) =
2817 expr.evaluate(&asm.symtab, &asm.str_interner)
2818 {
2819 if (value as u32) > (u8::MAX as u32) {
2820 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
2821 }
2822 asm.data.push(value as u8);
2823 } else {
2824 asm.links.push(Link::byte(loc, asm.data.len(), expr));
2825 asm.data.push(0);
2826 }
2827 }
2828
2829 Some(_) => {
2830 asm.data.push(0x3A);
2831 let (loc, expr) = asm.expr()?;
2832 if let Some(value) =
2833 expr.evaluate(&asm.symtab, &asm.str_interner)
2834 {
2835 if (value as u32) > (u16::MAX as u32) {
2836 return asm_err!(loc,"Expression result ({value}) will not fit in a word");
2837 }
2838 asm.data
2839 .extend_from_slice(&(value as u16).to_le_bytes());
2840 } else {
2841 asm.links.push(Link::word(loc, asm.data.len(), expr));
2842 asm.data.push(0);
2843 asm.data.push(0);
2844 }
2845 }
2846 }
2847 asm.expect_symbol(SymbolName::ParenClose)?;
2848 }
2849 Some(_) => {
2850 asm.data.push(0x3E);
2851 let (loc, expr) = asm.expr()?;
2852 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
2853 if (value as u32) > (u8::MAX as u32) {
2854 return asm_err!(
2855 loc,
2856 "Expression result ({value}) will not fit in a byte"
2857 );
2858 }
2859 asm.data.push(value as u8);
2860 } else {
2861 asm.links.push(Link::byte(loc, asm.data.len(), expr));
2862 asm.data.push(0);
2863 }
2864 }
2865 }
2866 }
2867
2868 Some(Token::Register {
2869 name: RegisterName::B,
2870 ..
2871 }) => {
2872 asm.expect_symbol(SymbolName::Comma)?;
2873 match asm.peek()? {
2874 None => return asm.end_of_input_err(),
2875 Some(Token::Register {
2876 name: RegisterName::A,
2877 ..
2878 }) => {
2879 asm.next()?;
2880 asm.data.push(0x47);
2881 }
2882 Some(Token::Register {
2883 name: RegisterName::B,
2884 ..
2885 }) => {
2886 asm.next()?;
2887 asm.data.push(0x40);
2888 }
2889 Some(Token::Register {
2890 name: RegisterName::C,
2891 ..
2892 }) => {
2893 asm.next()?;
2894 asm.data.push(0x41);
2895 }
2896 Some(Token::Register {
2897 name: RegisterName::D,
2898 ..
2899 }) => {
2900 asm.next()?;
2901 asm.data.push(0x42);
2902 }
2903 Some(Token::Register {
2904 name: RegisterName::E,
2905 ..
2906 }) => {
2907 asm.next()?;
2908 asm.data.push(0x43);
2909 }
2910 Some(Token::Register {
2911 name: RegisterName::H,
2912 ..
2913 }) => {
2914 asm.next()?;
2915 asm.data.push(0x44);
2916 }
2917 Some(Token::Register {
2918 name: RegisterName::L,
2919 ..
2920 }) => {
2921 asm.next()?;
2922 asm.data.push(0x45);
2923 }
2924 Some(Token::Register {
2925 name: RegisterName::IXH,
2926 ..
2927 }) => {
2928 asm.next()?;
2929 asm.data.push(0xDD);
2930 asm.data.push(0x44);
2931 }
2932 Some(Token::Register {
2933 name: RegisterName::IXL,
2934 ..
2935 }) => {
2936 asm.next()?;
2937 asm.data.push(0xDD);
2938 asm.data.push(0x45);
2939 }
2940 Some(Token::Register {
2941 name: RegisterName::IYH,
2942 ..
2943 }) => {
2944 asm.next()?;
2945 asm.data.push(0xFD);
2946 asm.data.push(0x44);
2947 }
2948 Some(Token::Register {
2949 name: RegisterName::IYL,
2950 ..
2951 }) => {
2952 asm.next()?;
2953 asm.data.push(0xFD);
2954 asm.data.push(0x45);
2955 }
2956 Some(Token::Symbol {
2957 name: SymbolName::ParenOpen,
2958 ..
2959 }) => {
2960 asm.next()?;
2961 match asm.peek()? {
2962 None => return asm.end_of_input_err(),
2963 Some(Token::Register { name: RegisterName::HL, .. }) => {
2964 asm.next()?;
2965 asm.data.push(0x46);
2966 }
2967 Some(Token::Register { loc, name }) => {
2968 asm.next()?;
2969 match name {
2970 RegisterName::IX => {
2971 asm.data.push(0xDD);
2972 asm.data.push(0x46);
2973 }
2974 RegisterName::IY => {
2975 asm.data.push(0xFD);
2976 asm.data.push(0x46);
2977 }
2978 _ => return asm_err!(loc,"Unexpected register \"{name}\", expected register \"ix\" or \"iy\""),
2979 }
2980 asm.expect_symbol(SymbolName::Plus)?;
2981 let (loc, expr) = asm.expr()?;
2982 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
2983 if (value as u32) > (u8::MAX as u32) {
2984 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
2985 }
2986 asm.data.push(value as u8);
2987 } else {
2988 asm.links.push(Link::byte(loc, asm.data.len(), expr));
2989 asm.data.push(0);
2990 }
2991 }
2992 Some(tok) => return asm_err!(tok.loc() ,"Unexpected {}, expected registers \"hl\", \"ix\", or \"iy\"",tok.as_display(&asm.str_interner)),
2993 }
2994 asm.expect_symbol(SymbolName::ParenClose)?;
2995 }
2996 Some(_) => {
2997 asm.data.push(0x06);
2998 let (loc, expr) = asm.expr()?;
2999 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
3000 if (value as u32) > (u8::MAX as u32) {
3001 return asm_err!(
3002 loc,
3003 "Expression result ({value}) will not fit in a byte"
3004 );
3005 }
3006 asm.data.push(value as u8);
3007 } else {
3008 asm.links.push(Link::byte(loc, asm.data.len(), expr));
3009 asm.data.push(0);
3010 }
3011 }
3012 }
3013 }
3014
3015 Some(Token::Register {
3016 name: RegisterName::C,
3017 ..
3018 }) => {
3019 asm.expect_symbol(SymbolName::Comma)?;
3020 match asm.peek()? {
3021 None => return asm.end_of_input_err(),
3022 Some(Token::Register {
3023 name: RegisterName::A,
3024 ..
3025 }) => {
3026 asm.next()?;
3027 asm.data.push(0x4F);
3028 }
3029 Some(Token::Register {
3030 name: RegisterName::B,
3031 ..
3032 }) => {
3033 asm.next()?;
3034 asm.data.push(0x48);
3035 }
3036 Some(Token::Register {
3037 name: RegisterName::C,
3038 ..
3039 }) => {
3040 asm.next()?;
3041 asm.data.push(0x49);
3042 }
3043 Some(Token::Register {
3044 name: RegisterName::D,
3045 ..
3046 }) => {
3047 asm.next()?;
3048 asm.data.push(0x4A);
3049 }
3050 Some(Token::Register {
3051 name: RegisterName::E,
3052 ..
3053 }) => {
3054 asm.next()?;
3055 asm.data.push(0x4B);
3056 }
3057 Some(Token::Register {
3058 name: RegisterName::H,
3059 ..
3060 }) => {
3061 asm.next()?;
3062 asm.data.push(0x4C);
3063 }
3064 Some(Token::Register {
3065 name: RegisterName::L,
3066 ..
3067 }) => {
3068 asm.next()?;
3069 asm.data.push(0x4D);
3070 }
3071 Some(Token::Register {
3072 name: RegisterName::IXH,
3073 ..
3074 }) => {
3075 asm.next()?;
3076 asm.data.push(0xDD);
3077 asm.data.push(0x4C);
3078 }
3079 Some(Token::Register {
3080 name: RegisterName::IXL,
3081 ..
3082 }) => {
3083 asm.next()?;
3084 asm.data.push(0xDD);
3085 asm.data.push(0x4D);
3086 }
3087 Some(Token::Register {
3088 name: RegisterName::IYH,
3089 ..
3090 }) => {
3091 asm.next()?;
3092 asm.data.push(0xFD);
3093 asm.data.push(0x4C);
3094 }
3095 Some(Token::Register {
3096 name: RegisterName::IYL,
3097 ..
3098 }) => {
3099 asm.next()?;
3100 asm.data.push(0xFD);
3101 asm.data.push(0x4D);
3102 }
3103 Some(Token::Symbol {
3104 name: SymbolName::ParenOpen,
3105 ..
3106 }) => {
3107 asm.next()?;
3108 match asm.peek()? {
3109 None => return asm.end_of_input_err(),
3110 Some(Token::Register { name: RegisterName::HL, .. }) => {
3111 asm.next()?;
3112 asm.data.push(0x4E);
3113 }
3114 Some(Token::Register { loc, name }) => {
3115 asm.next()?;
3116 match name {
3117 RegisterName::IX => {
3118 asm.data.push(0xDD);
3119 asm.data.push(0x4E);
3120 }
3121 RegisterName::IY => {
3122 asm.data.push(0xFD);
3123 asm.data.push(0x4E);
3124 }
3125 _ => return asm_err!(loc,"Unexpected register \"{name}\", expected register \"ix\" or \"iy\""),
3126 }
3127 asm.expect_symbol(SymbolName::Plus)?;
3128 let (loc, expr) = asm.expr()?;
3129 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
3130 if (value as u32) > (u8::MAX as u32) {
3131 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
3132 }
3133 asm.data.push(value as u8);
3134 } else {
3135 asm.links.push(Link::byte(loc, asm.data.len(), expr));
3136 asm.data.push(0);
3137 }
3138 }
3139 Some(tok) => return asm_err!(tok.loc(),"Unexpected {}, expected registers \"hl\", \"ix\", or \"iy\"",tok.as_display(&asm.str_interner)),
3140 }
3141 asm.expect_symbol(SymbolName::ParenClose)?;
3142 }
3143 Some(_) => {
3144 asm.data.push(0x0E);
3145 let (loc, expr) = asm.expr()?;
3146 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
3147 if (value as u32) > (u8::MAX as u32) {
3148 return asm_err!(
3149 loc,
3150 "Expression result ({value}) will not fit in a byte"
3151 );
3152 }
3153 asm.data.push(value as u8);
3154 } else {
3155 asm.links.push(Link::byte(loc, asm.data.len(), expr));
3156 asm.data.push(0);
3157 }
3158 }
3159 }
3160 }
3161
3162 Some(Token::Register {
3163 name: RegisterName::D,
3164 ..
3165 }) => {
3166 asm.expect_symbol(SymbolName::Comma)?;
3167 match asm.peek()? {
3168 None => return asm.end_of_input_err(),
3169 Some(Token::Register {
3170 name: RegisterName::A,
3171 ..
3172 }) => {
3173 asm.next()?;
3174 asm.data.push(0x57);
3175 }
3176 Some(Token::Register {
3177 name: RegisterName::B,
3178 ..
3179 }) => {
3180 asm.next()?;
3181 asm.data.push(0x50);
3182 }
3183 Some(Token::Register {
3184 name: RegisterName::C,
3185 ..
3186 }) => {
3187 asm.next()?;
3188 asm.data.push(0x51);
3189 }
3190 Some(Token::Register {
3191 name: RegisterName::D,
3192 ..
3193 }) => {
3194 asm.next()?;
3195 asm.data.push(0x52);
3196 }
3197 Some(Token::Register {
3198 name: RegisterName::E,
3199 ..
3200 }) => {
3201 asm.next()?;
3202 asm.data.push(0x53);
3203 }
3204 Some(Token::Register {
3205 name: RegisterName::H,
3206 ..
3207 }) => {
3208 asm.next()?;
3209 asm.data.push(0x54);
3210 }
3211 Some(Token::Register {
3212 name: RegisterName::L,
3213 ..
3214 }) => {
3215 asm.next()?;
3216 asm.data.push(0x55);
3217 }
3218 Some(Token::Register {
3219 name: RegisterName::IXH,
3220 ..
3221 }) => {
3222 asm.next()?;
3223 asm.data.push(0xDD);
3224 asm.data.push(0x54);
3225 }
3226 Some(Token::Register {
3227 name: RegisterName::IXL,
3228 ..
3229 }) => {
3230 asm.next()?;
3231 asm.data.push(0xDD);
3232 asm.data.push(0x55);
3233 }
3234 Some(Token::Register {
3235 name: RegisterName::IYH,
3236 ..
3237 }) => {
3238 asm.next()?;
3239 asm.data.push(0xFD);
3240 asm.data.push(0x54);
3241 }
3242 Some(Token::Register {
3243 name: RegisterName::IYL,
3244 ..
3245 }) => {
3246 asm.next()?;
3247 asm.data.push(0xFD);
3248 asm.data.push(0x55);
3249 }
3250 Some(Token::Symbol {
3251 name: SymbolName::ParenOpen,
3252 ..
3253 }) => {
3254 asm.next()?;
3255 match asm.peek()? {
3256 None => return asm.end_of_input_err(),
3257 Some(Token::Register { name: RegisterName::HL, .. }) => {
3258 asm.next()?;
3259 asm.data.push(0x56);
3260 }
3261 Some(Token::Register { loc, name }) => {
3262 asm.next()?;
3263 match name {
3264 RegisterName::IX => {
3265 asm.data.push(0xDD);
3266 asm.data.push(0x56);
3267 }
3268 RegisterName::IY => {
3269 asm.data.push(0xFD);
3270 asm.data.push(0x56);
3271 }
3272 _ => return asm_err!(loc,"Unexpected register \"{name}\", expected register \"ix\" or \"iy\""),
3273 }
3274 asm.expect_symbol(SymbolName::Plus)?;
3275 let (loc, expr) = asm.expr()?;
3276 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
3277 if (value as u32) > (u8::MAX as u32) {
3278 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
3279 }
3280 asm.data.push(value as u8);
3281 } else {
3282 asm.links.push(Link::byte(loc, asm.data.len(), expr));
3283 asm.data.push(0);
3284 }
3285 }
3286 Some(tok) => return asm_err!(tok.loc(),"Unexpected {}, expected registers \"hl\", \"ix\", or \"iy\"",tok.as_display(&asm.str_interner)),
3287 }
3288 asm.expect_symbol(SymbolName::ParenClose)?;
3289 }
3290 Some(_) => {
3291 asm.data.push(0x16);
3292 let (loc, expr) = asm.expr()?;
3293 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
3294 if (value as u32) > (u8::MAX as u32) {
3295 return asm_err!(
3296 loc,
3297 "Expression result ({value}) will not fit in a byte"
3298 );
3299 }
3300 asm.data.push(value as u8);
3301 } else {
3302 asm.links.push(Link::byte(loc, asm.data.len(), expr));
3303 asm.data.push(0);
3304 }
3305 }
3306 }
3307 }
3308
3309 Some(Token::Register {
3310 name: RegisterName::E,
3311 ..
3312 }) => {
3313 asm.expect_symbol(SymbolName::Comma)?;
3314 match asm.peek()? {
3315 None => return asm.end_of_input_err(),
3316 Some(Token::Register {
3317 name: RegisterName::A,
3318 ..
3319 }) => {
3320 asm.next()?;
3321 asm.data.push(0x5F);
3322 }
3323 Some(Token::Register {
3324 name: RegisterName::B,
3325 ..
3326 }) => {
3327 asm.next()?;
3328 asm.data.push(0x58);
3329 }
3330 Some(Token::Register {
3331 name: RegisterName::C,
3332 ..
3333 }) => {
3334 asm.next()?;
3335 asm.data.push(0x59);
3336 }
3337 Some(Token::Register {
3338 name: RegisterName::D,
3339 ..
3340 }) => {
3341 asm.next()?;
3342 asm.data.push(0x5A);
3343 }
3344 Some(Token::Register {
3345 name: RegisterName::E,
3346 ..
3347 }) => {
3348 asm.next()?;
3349 asm.data.push(0x5B);
3350 }
3351 Some(Token::Register {
3352 name: RegisterName::H,
3353 ..
3354 }) => {
3355 asm.next()?;
3356 asm.data.push(0x5C);
3357 }
3358 Some(Token::Register {
3359 name: RegisterName::L,
3360 ..
3361 }) => {
3362 asm.next()?;
3363 asm.data.push(0x5D);
3364 }
3365 Some(Token::Register {
3366 name: RegisterName::IXH,
3367 ..
3368 }) => {
3369 asm.next()?;
3370 asm.data.push(0xDD);
3371 asm.data.push(0x5C);
3372 }
3373 Some(Token::Register {
3374 name: RegisterName::IXL,
3375 ..
3376 }) => {
3377 asm.next()?;
3378 asm.data.push(0xDD);
3379 asm.data.push(0x5D);
3380 }
3381 Some(Token::Register {
3382 name: RegisterName::IYH,
3383 ..
3384 }) => {
3385 asm.next()?;
3386 asm.data.push(0xFD);
3387 asm.data.push(0x5C);
3388 }
3389 Some(Token::Register {
3390 name: RegisterName::IYL,
3391 ..
3392 }) => {
3393 asm.next()?;
3394 asm.data.push(0xFD);
3395 asm.data.push(0x5D);
3396 }
3397 Some(Token::Symbol {
3398 name: SymbolName::ParenOpen,
3399 ..
3400 }) => {
3401 asm.next()?;
3402 match asm.peek()? {
3403 None => return asm.end_of_input_err(),
3404 Some(Token::Register { name: RegisterName::HL, .. }) => {
3405 asm.next()?;
3406 asm.data.push(0x5E);
3407 }
3408 Some(Token::Register { loc, name }) => {
3409 asm.next()?;
3410 match name {
3411 RegisterName::IX => {
3412 asm.data.push(0xDD);
3413 asm.data.push(0x5E);
3414 }
3415 RegisterName::IY => {
3416 asm.data.push(0xFD);
3417 asm.data.push(0x5E);
3418 }
3419 _ => return asm_err!(loc,"Unexpected register \"{name}\", expected register \"ix\" or \"iy\""),
3420 }
3421 asm.expect_symbol(SymbolName::Plus)?;
3422 let (loc, expr) = asm.expr()?;
3423 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
3424 if (value as u32) > (u8::MAX as u32) {
3425 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
3426 }
3427 asm.data.push(value as u8);
3428 } else {
3429 asm.links.push(Link::byte(loc, asm.data.len(), expr));
3430 asm.data.push(0);
3431 }
3432 }
3433 Some(tok) => return asm_err!(tok.loc(),"Unexpected {}, expected registers \"hl\", \"ix\", or \"iy\"",tok.as_display(&asm.str_interner)),
3434 }
3435 asm.expect_symbol(SymbolName::ParenClose)?;
3436 }
3437 Some(_) => {
3438 asm.data.push(0x1E);
3439 let (loc, expr) = asm.expr()?;
3440 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
3441 if (value as u32) > (u8::MAX as u32) {
3442 return asm_err!(
3443 loc,
3444 "Expression result ({value}) will not fit in a byte"
3445 );
3446 }
3447 asm.data.push(value as u8);
3448 } else {
3449 asm.links.push(Link::byte(loc, asm.data.len(), expr));
3450 asm.data.push(0);
3451 }
3452 }
3453 }
3454 }
3455
3456 Some(Token::Register {
3457 name: RegisterName::H,
3458 ..
3459 }) => {
3460 asm.expect_symbol(SymbolName::Comma)?;
3461 match asm.peek()? {
3462 None => return asm.end_of_input_err(),
3463 Some(Token::Register {
3464 name: RegisterName::A,
3465 ..
3466 }) => {
3467 asm.next()?;
3468 asm.data.push(0x67);
3469 }
3470 Some(Token::Register {
3471 name: RegisterName::B,
3472 ..
3473 }) => {
3474 asm.next()?;
3475 asm.data.push(0x60);
3476 }
3477 Some(Token::Register {
3478 name: RegisterName::C,
3479 ..
3480 }) => {
3481 asm.next()?;
3482 asm.data.push(0x61);
3483 }
3484 Some(Token::Register {
3485 name: RegisterName::D,
3486 ..
3487 }) => {
3488 asm.next()?;
3489 asm.data.push(0x62);
3490 }
3491 Some(Token::Register {
3492 name: RegisterName::E,
3493 ..
3494 }) => {
3495 asm.next()?;
3496 asm.data.push(0x63);
3497 }
3498 Some(Token::Register {
3499 name: RegisterName::H,
3500 ..
3501 }) => {
3502 asm.next()?;
3503 asm.data.push(0x64);
3504 }
3505 Some(Token::Register {
3506 name: RegisterName::L,
3507 ..
3508 }) => {
3509 asm.next()?;
3510 asm.data.push(0x65);
3511 }
3512 Some(Token::Symbol {
3513 name: SymbolName::ParenOpen,
3514 ..
3515 }) => {
3516 asm.next()?;
3517 match asm.peek()? {
3518 None => return asm.end_of_input_err(),
3519 Some(Token::Register { name: RegisterName::HL, .. }) => {
3520 asm.next()?;
3521 asm.data.push(0x66);
3522 }
3523 Some(Token::Register { loc, name }) => {
3524 asm.next()?;
3525 match name {
3526 RegisterName::IX => {
3527 asm.data.push(0xDD);
3528 asm.data.push(0x66);
3529 }
3530 RegisterName::IY => {
3531 asm.data.push(0xFD);
3532 asm.data.push(0x66);
3533 }
3534 _ => return asm_err!(loc,"Unexpected register \"{name}\", expected register \"ix\" or \"iy\""),
3535 }
3536 asm.expect_symbol(SymbolName::Plus)?;
3537 let (loc, expr) = asm.expr()?;
3538 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
3539 if (value as u32) > (u8::MAX as u32) {
3540 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
3541 }
3542 asm.data.push(value as u8);
3543 } else {
3544 asm.links.push(Link::byte(loc, asm.data.len(), expr));
3545 asm.data.push(0);
3546 }
3547 }
3548 Some(tok) => return asm_err!(tok.loc(),"Unexpected {}, expected registers \"hl\", \"ix\", or \"iy\"",tok.as_display(&asm.str_interner)),
3549 }
3550 asm.expect_symbol(SymbolName::ParenClose)?;
3551 }
3552 Some(_) => {
3553 asm.data.push(0x26);
3554 let (loc, expr) = asm.expr()?;
3555 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
3556 if (value as u32) > (u8::MAX as u32) {
3557 return asm_err!(
3558 loc,
3559 "Expression result ({value}) will not fit in a byte"
3560 );
3561 }
3562 asm.data.push(value as u8);
3563 } else {
3564 asm.links.push(Link::byte(loc, asm.data.len(), expr));
3565 asm.data.push(0);
3566 }
3567 }
3568 }
3569 }
3570
3571 Some(Token::Register {
3572 name: RegisterName::L,
3573 ..
3574 }) => {
3575 asm.expect_symbol(SymbolName::Comma)?;
3576 match asm.peek()? {
3577 None => return asm.end_of_input_err(),
3578 Some(Token::Register {
3579 name: RegisterName::A,
3580 ..
3581 }) => {
3582 asm.next()?;
3583 asm.data.push(0x6F);
3584 }
3585 Some(Token::Register {
3586 name: RegisterName::B,
3587 ..
3588 }) => {
3589 asm.next()?;
3590 asm.data.push(0x68);
3591 }
3592 Some(Token::Register {
3593 name: RegisterName::C,
3594 ..
3595 }) => {
3596 asm.next()?;
3597 asm.data.push(0x69);
3598 }
3599 Some(Token::Register {
3600 name: RegisterName::D,
3601 ..
3602 }) => {
3603 asm.next()?;
3604 asm.data.push(0x6A);
3605 }
3606 Some(Token::Register {
3607 name: RegisterName::E,
3608 ..
3609 }) => {
3610 asm.next()?;
3611 asm.data.push(0x6B);
3612 }
3613 Some(Token::Register {
3614 name: RegisterName::H,
3615 ..
3616 }) => {
3617 asm.next()?;
3618 asm.data.push(0x6C);
3619 }
3620 Some(Token::Register {
3621 name: RegisterName::L,
3622 ..
3623 }) => {
3624 asm.next()?;
3625 asm.data.push(0x6D);
3626 }
3627 Some(Token::Symbol {
3628 name: SymbolName::ParenOpen,
3629 ..
3630 }) => {
3631 asm.next()?;
3632 match asm.peek()? {
3633 None => return asm.end_of_input_err(),
3634 Some(Token::Register { name: RegisterName::HL, .. }) => {
3635 asm.next()?;
3636 asm.data.push(0x6E);
3637 }
3638 Some(Token::Register { loc, name }) => {
3639 asm.next()?;
3640 match name {
3641 RegisterName::IX => {
3642 asm.data.push(0xDD);
3643 asm.data.push(0x6E);
3644 }
3645 RegisterName::IY => {
3646 asm.data.push(0xFD);
3647 asm.data.push(0x6E);
3648 }
3649 _ => return asm_err!(loc,"Unexpected register \"{name}\", expected register \"ix\" or \"iy\""),
3650 }
3651 asm.expect_symbol(SymbolName::Plus)?;
3652 let (loc, expr) = asm.expr()?;
3653 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
3654 if (value as u32) > (u8::MAX as u32) {
3655 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
3656 }
3657 asm.data.push(value as u8);
3658 } else {
3659 asm.links.push(Link::byte(loc, asm.data.len(), expr));
3660 asm.data.push(0);
3661 }
3662 }
3663 Some(tok) => return asm_err!(tok.loc(),"Unexpected {}, expected registers \"hl\", \"ix\", or \"iy\"",tok.as_display(&asm.str_interner)),
3664 }
3665 asm.expect_symbol(SymbolName::ParenClose)?;
3666 }
3667 Some(_) => {
3668 asm.data.push(0x2E);
3669 let (loc, expr) = asm.expr()?;
3670 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
3671 if (value as u32) > (u8::MAX as u32) {
3672 return asm_err!(
3673 loc,
3674 "Expression result ({value}) will not fit in a byte"
3675 );
3676 }
3677 asm.data.push(value as u8);
3678 } else {
3679 asm.links.push(Link::byte(loc, asm.data.len(), expr));
3680 asm.data.push(0);
3681 }
3682 }
3683 }
3684 }
3685
3686 Some(Token::Register {
3687 name: RegisterName::IXH,
3688 ..
3689 }) => {
3690 asm.expect_symbol(SymbolName::Comma)?;
3691 match asm.peek()? {
3692 None => return asm.end_of_input_err(),
3693 Some(Token::Register {
3694 name: RegisterName::A,
3695 ..
3696 }) => {
3697 asm.next()?;
3698 asm.data.push(0xDD);
3699 asm.data.push(0x67);
3700 }
3701 Some(Token::Register {
3702 name: RegisterName::B,
3703 ..
3704 }) => {
3705 asm.next()?;
3706 asm.data.push(0xDD);
3707 asm.data.push(0x60);
3708 }
3709 Some(Token::Register {
3710 name: RegisterName::C,
3711 ..
3712 }) => {
3713 asm.next()?;
3714 asm.data.push(0xDD);
3715 asm.data.push(0x61);
3716 }
3717 Some(Token::Register {
3718 name: RegisterName::D,
3719 ..
3720 }) => {
3721 asm.next()?;
3722 asm.data.push(0xDD);
3723 asm.data.push(0x62);
3724 }
3725 Some(Token::Register {
3726 name: RegisterName::E,
3727 ..
3728 }) => {
3729 asm.next()?;
3730 asm.data.push(0xDD);
3731 asm.data.push(0x63);
3732 }
3733 Some(Token::Register {
3734 name: RegisterName::IXH,
3735 ..
3736 }) => {
3737 asm.next()?;
3738 asm.data.push(0xDD);
3739 asm.data.push(0x64);
3740 }
3741 Some(Token::Register {
3742 name: RegisterName::IXL,
3743 ..
3744 }) => {
3745 asm.next()?;
3746 asm.data.push(0xDD);
3747 asm.data.push(0x65);
3748 }
3749 Some(_) => {
3750 asm.data.push(0xDD);
3751 asm.data.push(0x26);
3752 let (loc, expr) = asm.expr()?;
3753 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
3754 if (value as u32) > (u8::MAX as u32) {
3755 return asm_err!(
3756 loc,
3757 "Expression result ({value}) will not fit in a byte"
3758 );
3759 }
3760 asm.data.push(value as u8);
3761 } else {
3762 asm.links.push(Link::byte(loc, asm.data.len(), expr));
3763 asm.data.push(0);
3764 }
3765 }
3766 }
3767 }
3768
3769 Some(Token::Register {
3770 name: RegisterName::IXL,
3771 ..
3772 }) => {
3773 asm.expect_symbol(SymbolName::Comma)?;
3774 match asm.peek()? {
3775 None => return asm.end_of_input_err(),
3776 Some(Token::Register {
3777 name: RegisterName::A,
3778 ..
3779 }) => {
3780 asm.next()?;
3781 asm.data.push(0xDD);
3782 asm.data.push(0x6F);
3783 }
3784 Some(Token::Register {
3785 name: RegisterName::B,
3786 ..
3787 }) => {
3788 asm.next()?;
3789 asm.data.push(0xDD);
3790 asm.data.push(0x68);
3791 }
3792 Some(Token::Register {
3793 name: RegisterName::C,
3794 ..
3795 }) => {
3796 asm.next()?;
3797 asm.data.push(0xDD);
3798 asm.data.push(0x69);
3799 }
3800 Some(Token::Register {
3801 name: RegisterName::D,
3802 ..
3803 }) => {
3804 asm.next()?;
3805 asm.data.push(0xDD);
3806 asm.data.push(0x6A);
3807 }
3808 Some(Token::Register {
3809 name: RegisterName::E,
3810 ..
3811 }) => {
3812 asm.next()?;
3813 asm.data.push(0xDD);
3814 asm.data.push(0x6B);
3815 }
3816 Some(Token::Register {
3817 name: RegisterName::IXH,
3818 ..
3819 }) => {
3820 asm.next()?;
3821 asm.data.push(0xDD);
3822 asm.data.push(0x6C);
3823 }
3824 Some(Token::Register {
3825 name: RegisterName::IXL,
3826 ..
3827 }) => {
3828 asm.next()?;
3829 asm.data.push(0xDD);
3830 asm.data.push(0x6D);
3831 }
3832 Some(_) => {
3833 asm.data.push(0xDD);
3834 asm.data.push(0x2E);
3835 let (loc, expr) = asm.expr()?;
3836 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
3837 if (value as u32) > (u8::MAX as u32) {
3838 return asm_err!(
3839 loc,
3840 "Expression result ({value}) will not fit in a byte"
3841 );
3842 }
3843 asm.data.push(value as u8);
3844 } else {
3845 asm.links.push(Link::byte(loc, asm.data.len(), expr));
3846 asm.data.push(0);
3847 }
3848 }
3849 }
3850 }
3851
3852 Some(Token::Register {
3853 name: RegisterName::IYH,
3854 ..
3855 }) => {
3856 asm.expect_symbol(SymbolName::Comma)?;
3857 match asm.peek()? {
3858 None => return asm.end_of_input_err(),
3859 Some(Token::Register {
3860 name: RegisterName::A,
3861 ..
3862 }) => {
3863 asm.next()?;
3864 asm.data.push(0xFD);
3865 asm.data.push(0x67);
3866 }
3867 Some(Token::Register {
3868 name: RegisterName::B,
3869 ..
3870 }) => {
3871 asm.next()?;
3872 asm.data.push(0xFD);
3873 asm.data.push(0x60);
3874 }
3875 Some(Token::Register {
3876 name: RegisterName::C,
3877 ..
3878 }) => {
3879 asm.next()?;
3880 asm.data.push(0xFD);
3881 asm.data.push(0x61);
3882 }
3883 Some(Token::Register {
3884 name: RegisterName::D,
3885 ..
3886 }) => {
3887 asm.next()?;
3888 asm.data.push(0xFD);
3889 asm.data.push(0x62);
3890 }
3891 Some(Token::Register {
3892 name: RegisterName::E,
3893 ..
3894 }) => {
3895 asm.next()?;
3896 asm.data.push(0xFD);
3897 asm.data.push(0x63);
3898 }
3899 Some(Token::Register {
3900 name: RegisterName::IYH,
3901 ..
3902 }) => {
3903 asm.next()?;
3904 asm.data.push(0xFD);
3905 asm.data.push(0x64);
3906 }
3907 Some(Token::Register {
3908 name: RegisterName::IYL,
3909 ..
3910 }) => {
3911 asm.next()?;
3912 asm.data.push(0xFD);
3913 asm.data.push(0x65);
3914 }
3915 Some(_) => {
3916 asm.data.push(0xFD);
3917 asm.data.push(0x26);
3918 let (loc, expr) = asm.expr()?;
3919 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
3920 if (value as u32) > (u8::MAX as u32) {
3921 return asm_err!(
3922 loc,
3923 "Expression result ({value}) will not fit in a byte"
3924 );
3925 }
3926 asm.data.push(value as u8);
3927 } else {
3928 asm.links.push(Link::byte(loc, asm.data.len(), expr));
3929 asm.data.push(0);
3930 }
3931 }
3932 }
3933 }
3934
3935 Some(Token::Register {
3936 name: RegisterName::IYL,
3937 ..
3938 }) => {
3939 asm.expect_symbol(SymbolName::Comma)?;
3940 match asm.peek()? {
3941 None => return asm.end_of_input_err(),
3942 Some(Token::Register {
3943 name: RegisterName::A,
3944 ..
3945 }) => {
3946 asm.next()?;
3947 asm.data.push(0xFD);
3948 asm.data.push(0x6F);
3949 }
3950 Some(Token::Register {
3951 name: RegisterName::B,
3952 ..
3953 }) => {
3954 asm.next()?;
3955 asm.data.push(0xFD);
3956 asm.data.push(0x68);
3957 }
3958 Some(Token::Register {
3959 name: RegisterName::C,
3960 ..
3961 }) => {
3962 asm.next()?;
3963 asm.data.push(0xFD);
3964 asm.data.push(0x69);
3965 }
3966 Some(Token::Register {
3967 name: RegisterName::D,
3968 ..
3969 }) => {
3970 asm.next()?;
3971 asm.data.push(0xFD);
3972 asm.data.push(0x6A);
3973 }
3974 Some(Token::Register {
3975 name: RegisterName::E,
3976 ..
3977 }) => {
3978 asm.next()?;
3979 asm.data.push(0xFD);
3980 asm.data.push(0x6B);
3981 }
3982 Some(Token::Register {
3983 name: RegisterName::IYH,
3984 ..
3985 }) => {
3986 asm.next()?;
3987 asm.data.push(0xFD);
3988 asm.data.push(0x6C);
3989 }
3990 Some(Token::Register {
3991 name: RegisterName::IYL,
3992 ..
3993 }) => {
3994 asm.next()?;
3995 asm.data.push(0xFD);
3996 asm.data.push(0x6D);
3997 }
3998 Some(_) => {
3999 asm.data.push(0xFD);
4000 asm.data.push(0x2E);
4001 let (loc, expr) = asm.expr()?;
4002 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
4003 if (value as u32) > (u8::MAX as u32) {
4004 return asm_err!(
4005 loc,
4006 "Expression result ({value}) will not fit in a byte"
4007 );
4008 }
4009 asm.data.push(value as u8);
4010 } else {
4011 asm.links.push(Link::byte(loc, asm.data.len(), expr));
4012 asm.data.push(0);
4013 }
4014 }
4015 }
4016 }
4017
4018 Some(Token::Register {
4019 name: RegisterName::R,
4020 ..
4021 }) => {
4022 asm.data.push(0xED);
4023 asm.data.push(0x4F);
4024 asm.expect_symbol(SymbolName::Comma)?;
4025 asm.expect_register(RegisterName::A)?;
4026 }
4027
4028 Some(Token::Register {
4029 name: RegisterName::I,
4030 ..
4031 }) => {
4032 asm.data.push(0xED);
4033 asm.data.push(0x47);
4034 asm.expect_symbol(SymbolName::Comma)?;
4035 asm.expect_register(RegisterName::A)?;
4036 }
4037
4038 Some(Token::Register {
4039 name: RegisterName::SP,
4040 ..
4041 }) => {
4042 asm.expect_symbol(SymbolName::Comma)?;
4043 match asm.peek()? {
4044 None => return asm.end_of_input_err(),
4045 Some(Token::Register {
4046 name: RegisterName::HL,
4047 ..
4048 }) => {
4049 asm.next()?;
4050 asm.data.push(0xF9);
4051 }
4052 Some(Token::Register {
4053 name: RegisterName::IX,
4054 ..
4055 }) => {
4056 asm.next()?;
4057 asm.data.push(0xDD);
4058 asm.data.push(0xF9);
4059 }
4060 Some(Token::Register {
4061 name: RegisterName::IY,
4062 ..
4063 }) => {
4064 asm.next()?;
4065 asm.data.push(0xFD);
4066 asm.data.push(0xF9);
4067 }
4068 Some(_) => {
4069 let indirect = matches!(
4070 asm.peek()?,
4071 Some(Token::Symbol {
4072 name: SymbolName::ParenOpen,
4073 ..
4074 })
4075 );
4076 if indirect {
4077 asm.next()?;
4078 asm.data.push(0xED);
4079 asm.data.push(0x7B);
4080 } else {
4081 asm.data.push(0x31);
4082 }
4083 let (loc, expr) = asm.expr()?;
4084 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
4085 if (value as u32) > (u16::MAX as u32) {
4086 return asm_err!(
4087 loc,
4088 "Expression result ({value}) will not fit in a word"
4089 );
4090 }
4091 asm.data.extend_from_slice(&(value as u16).to_le_bytes());
4092 } else {
4093 asm.links.push(Link::word(loc, asm.data.len(), expr));
4094 asm.data.push(0);
4095 asm.data.push(0);
4096 }
4097 if indirect {
4098 asm.expect_symbol(SymbolName::ParenClose)?;
4099 }
4100 }
4101 }
4102 }
4103
4104 Some(Token::Register {
4105 name: RegisterName::BC,
4106 ..
4107 }) => {
4108 asm.expect_symbol(SymbolName::Comma)?;
4109 let indirect = matches!(
4110 asm.peek()?,
4111 Some(Token::Symbol {
4112 name: SymbolName::ParenOpen,
4113 ..
4114 })
4115 );
4116 if indirect {
4117 asm.next()?;
4118 asm.data.push(0xED);
4119 asm.data.push(0x4B);
4120 } else {
4121 asm.data.push(0x01);
4122 }
4123 let (loc, expr) = asm.expr()?;
4124 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
4125 if (value as u32) > (u16::MAX as u32) {
4126 return asm_err!(
4127 loc,
4128 "Expression result ({value}) will not fit in a word"
4129 );
4130 }
4131 asm.data.extend_from_slice(&(value as u16).to_le_bytes());
4132 } else {
4133 asm.links.push(Link::word(loc, asm.data.len(), expr));
4134 asm.data.push(0);
4135 asm.data.push(0);
4136 }
4137 if indirect {
4138 asm.expect_symbol(SymbolName::ParenClose)?;
4139 }
4140 }
4141
4142 Some(Token::Register {
4143 name: RegisterName::DE,
4144 ..
4145 }) => {
4146 asm.expect_symbol(SymbolName::Comma)?;
4147 let indirect = matches!(
4148 asm.peek()?,
4149 Some(Token::Symbol {
4150 name: SymbolName::ParenOpen,
4151 ..
4152 })
4153 );
4154 if indirect {
4155 asm.next()?;
4156 asm.data.push(0xED);
4157 asm.data.push(0x5B);
4158 } else {
4159 asm.data.push(0x11);
4160 }
4161 let (loc, expr) = asm.expr()?;
4162 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
4163 if (value as u32) > (u16::MAX as u32) {
4164 return asm_err!(
4165 loc,
4166 "Expression result ({value}) will not fit in a word"
4167 );
4168 }
4169 asm.data.extend_from_slice(&(value as u16).to_le_bytes());
4170 } else {
4171 asm.links.push(Link::word(loc, asm.data.len(), expr));
4172 asm.data.push(0);
4173 asm.data.push(0);
4174 }
4175 if indirect {
4176 asm.expect_symbol(SymbolName::ParenClose)?;
4177 }
4178 }
4179
4180 Some(Token::Register {
4181 name: RegisterName::HL,
4182 ..
4183 }) => {
4184 asm.expect_symbol(SymbolName::Comma)?;
4185 let indirect = matches!(
4186 asm.peek()?,
4187 Some(Token::Symbol {
4188 name: SymbolName::ParenOpen,
4189 ..
4190 })
4191 );
4192 if indirect {
4193 asm.next()?;
4194 asm.data.push(0x2A);
4195 } else {
4196 asm.data.push(0x21);
4197 }
4198 let (loc, expr) = asm.expr()?;
4199 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
4200 if (value as u32) > (u16::MAX as u32) {
4201 return asm_err!(
4202 loc,
4203 "Expression result ({value}) will not fit in a word"
4204 );
4205 }
4206 asm.data.extend_from_slice(&(value as u16).to_le_bytes());
4207 } else {
4208 asm.links.push(Link::word(loc, asm.data.len(), expr));
4209 asm.data.push(0);
4210 asm.data.push(0);
4211 }
4212 if indirect {
4213 asm.expect_symbol(SymbolName::ParenClose)?;
4214 }
4215 }
4216
4217 Some(Token::Register {
4218 name: RegisterName::IX,
4219 ..
4220 }) => {
4221 asm.expect_symbol(SymbolName::Comma)?;
4222 asm.data.push(0xDD);
4223 let indirect = matches!(
4224 asm.peek()?,
4225 Some(Token::Symbol {
4226 name: SymbolName::ParenOpen,
4227 ..
4228 })
4229 );
4230 if indirect {
4231 asm.next()?;
4232 asm.data.push(0x2A);
4233 } else {
4234 asm.data.push(0x21);
4235 }
4236 let (loc, expr) = asm.expr()?;
4237 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
4238 if (value as u32) > (u16::MAX as u32) {
4239 return asm_err!(
4240 loc,
4241 "Expression result ({value}) will not fit in a word"
4242 );
4243 }
4244 asm.data.extend_from_slice(&(value as u16).to_le_bytes());
4245 } else {
4246 asm.links.push(Link::word(loc, asm.data.len(), expr));
4247 asm.data.push(0);
4248 asm.data.push(0);
4249 }
4250 if indirect {
4251 asm.expect_symbol(SymbolName::ParenClose)?;
4252 }
4253 }
4254
4255 Some(Token::Register {
4256 name: RegisterName::IY,
4257 ..
4258 }) => {
4259 asm.expect_symbol(SymbolName::Comma)?;
4260 asm.data.push(0xFD);
4261 let indirect = matches!(
4262 asm.peek()?,
4263 Some(Token::Symbol {
4264 name: SymbolName::ParenOpen,
4265 ..
4266 })
4267 );
4268 if indirect {
4269 asm.next()?;
4270 asm.data.push(0x2A);
4271 } else {
4272 asm.data.push(0x21);
4273 }
4274 let (loc, expr) = asm.expr()?;
4275 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
4276 if (value as u32) > (u16::MAX as u32) {
4277 return asm_err!(
4278 loc,
4279 "Expression result ({value}) will not fit in a word"
4280 );
4281 }
4282 asm.data.extend_from_slice(&(value as u16).to_le_bytes());
4283 } else {
4284 asm.links.push(Link::word(loc, asm.data.len(), expr));
4285 asm.data.push(0);
4286 asm.data.push(0);
4287 }
4288 if indirect {
4289 asm.expect_symbol(SymbolName::ParenClose)?;
4290 }
4291 }
4292
4293 Some(Token::Symbol {
4294 name: SymbolName::ParenOpen,
4295 ..
4296 }) => match asm.peek()? {
4297 None => return asm.end_of_input_err(),
4298 Some(Token::Register {
4299 name: RegisterName::BC,
4300 ..
4301 }) => {
4302 asm.next()?;
4303 asm.expect_symbol(SymbolName::ParenClose)?;
4304 asm.expect_symbol(SymbolName::Comma)?;
4305 asm.expect_register(RegisterName::A)?;
4306 asm.data.push(0x02);
4307 }
4308 Some(Token::Register {
4309 name: RegisterName::DE,
4310 ..
4311 }) => {
4312 asm.next()?;
4313 asm.expect_symbol(SymbolName::ParenClose)?;
4314 asm.expect_symbol(SymbolName::Comma)?;
4315 asm.expect_register(RegisterName::A)?;
4316 asm.data.push(0x12);
4317 }
4318 Some(Token::Register {
4319 name: RegisterName::HL,
4320 ..
4321 }) => {
4322 asm.next()?;
4323 asm.expect_symbol(SymbolName::ParenClose)?;
4324 asm.expect_symbol(SymbolName::Comma)?;
4325 match asm.peek()? {
4326 None => return asm.end_of_input_err(),
4327 Some(Token::Register {
4328 name: RegisterName::A,
4329 ..
4330 }) => {
4331 asm.next()?;
4332 asm.data.push(0x77);
4333 }
4334 Some(Token::Register {
4335 name: RegisterName::B,
4336 ..
4337 }) => {
4338 asm.next()?;
4339 asm.data.push(0x70);
4340 }
4341 Some(Token::Register {
4342 name: RegisterName::C,
4343 ..
4344 }) => {
4345 asm.next()?;
4346 asm.data.push(0x71);
4347 }
4348 Some(Token::Register {
4349 name: RegisterName::D,
4350 ..
4351 }) => {
4352 asm.next()?;
4353 asm.data.push(0x72);
4354 }
4355 Some(Token::Register {
4356 name: RegisterName::E,
4357 ..
4358 }) => {
4359 asm.next()?;
4360 asm.data.push(0x73);
4361 }
4362 Some(Token::Register {
4363 name: RegisterName::H,
4364 ..
4365 }) => {
4366 asm.next()?;
4367 asm.data.push(0x74);
4368 }
4369 Some(Token::Register {
4370 name: RegisterName::L,
4371 ..
4372 }) => {
4373 asm.next()?;
4374 asm.data.push(0x75);
4375 }
4376 Some(_) => {
4377 asm.data.push(0x36);
4378 let (loc, expr) = asm.expr()?;
4379 if let Some(value) =
4380 expr.evaluate(&asm.symtab, &asm.str_interner)
4381 {
4382 if (value as u32) > (u8::MAX as u32) {
4383 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
4384 }
4385 asm.data.push(value as u8);
4386 } else {
4387 asm.links.push(Link::byte(loc, asm.data.len(), expr));
4388 asm.data.push(0);
4389 }
4390 }
4391 }
4392 }
4393 Some(Token::Register {
4394 name: RegisterName::IX,
4395 ..
4396 }) => {
4397 asm.next()?;
4398 asm.expect_symbol(SymbolName::Plus)?;
4399 asm.data.push(0xDD);
4400 let (loc, expr) = asm.expr()?;
4401 let offset = if let Some(value) =
4402 expr.evaluate(&asm.symtab, &asm.str_interner)
4403 {
4404 if (value as u32) > (u8::MAX as u32) {
4405 return asm_err!(
4406 loc,
4407 "Expression result ({value}) will not fit in a byte"
4408 );
4409 }
4410 value as u8
4411 } else {
4412 asm.links.push(Link::byte(loc, asm.data.len() + 1, expr));
4413 0
4414 };
4415 asm.expect_symbol(SymbolName::ParenClose)?;
4416 asm.expect_symbol(SymbolName::Comma)?;
4417 match asm.peek()? {
4418 None => return asm.end_of_input_err(),
4419 Some(Token::Register {
4420 name: RegisterName::A,
4421 ..
4422 }) => {
4423 asm.next()?;
4424 asm.data.push(0x77);
4425 asm.data.push(offset);
4426 }
4427 Some(Token::Register {
4428 name: RegisterName::B,
4429 ..
4430 }) => {
4431 asm.next()?;
4432 asm.data.push(0x70);
4433 asm.data.push(offset);
4434 }
4435 Some(Token::Register {
4436 name: RegisterName::C,
4437 ..
4438 }) => {
4439 asm.next()?;
4440 asm.data.push(0x71);
4441 asm.data.push(offset);
4442 }
4443 Some(Token::Register {
4444 name: RegisterName::D,
4445 ..
4446 }) => {
4447 asm.next()?;
4448 asm.data.push(0x72);
4449 asm.data.push(offset);
4450 }
4451 Some(Token::Register {
4452 name: RegisterName::E,
4453 ..
4454 }) => {
4455 asm.next()?;
4456 asm.data.push(0x73);
4457 asm.data.push(offset);
4458 }
4459 Some(Token::Register {
4460 name: RegisterName::H,
4461 ..
4462 }) => {
4463 asm.next()?;
4464 asm.data.push(0x74);
4465 asm.data.push(offset);
4466 }
4467 Some(Token::Register {
4468 name: RegisterName::L,
4469 ..
4470 }) => {
4471 asm.next()?;
4472 asm.data.push(0x75);
4473 asm.data.push(offset);
4474 }
4475 Some(_) => {
4476 asm.data.push(0x36);
4477 asm.data.push(offset);
4478 let (loc, expr) = asm.expr()?;
4479 if let Some(value) =
4480 expr.evaluate(&asm.symtab, &asm.str_interner)
4481 {
4482 if (value as u32) > (u8::MAX as u32) {
4483 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
4484 }
4485 asm.data.push(value as u8);
4486 } else {
4487 asm.links.push(Link::byte(loc, asm.data.len(), expr));
4488 asm.data.push(0);
4489 }
4490 }
4491 }
4492 }
4493 Some(Token::Register {
4494 name: RegisterName::IY,
4495 ..
4496 }) => {
4497 asm.next()?;
4498 asm.expect_symbol(SymbolName::Plus)?;
4499 asm.data.push(0xFD);
4500 let (loc, expr) = asm.expr()?;
4501 let offset = if let Some(value) =
4502 expr.evaluate(&asm.symtab, &asm.str_interner)
4503 {
4504 if (value as u32) > (u8::MAX as u32) {
4505 return asm_err!(
4506 loc,
4507 "Expression result ({value}) will not fit in a byte"
4508 );
4509 }
4510 value as u8
4511 } else {
4512 asm.links.push(Link::byte(loc, asm.data.len() + 1, expr));
4513 0
4514 };
4515 asm.expect_symbol(SymbolName::ParenClose)?;
4516 asm.expect_symbol(SymbolName::Comma)?;
4517 match asm.peek()? {
4518 None => return asm.end_of_input_err(),
4519 Some(Token::Register {
4520 name: RegisterName::A,
4521 ..
4522 }) => {
4523 asm.next()?;
4524 asm.data.push(0x77);
4525 asm.data.push(offset);
4526 }
4527 Some(Token::Register {
4528 name: RegisterName::B,
4529 ..
4530 }) => {
4531 asm.next()?;
4532 asm.data.push(0x70);
4533 asm.data.push(offset);
4534 }
4535 Some(Token::Register {
4536 name: RegisterName::C,
4537 ..
4538 }) => {
4539 asm.next()?;
4540 asm.data.push(0x71);
4541 asm.data.push(offset);
4542 }
4543 Some(Token::Register {
4544 name: RegisterName::D,
4545 ..
4546 }) => {
4547 asm.next()?;
4548 asm.data.push(0x72);
4549 asm.data.push(offset);
4550 }
4551 Some(Token::Register {
4552 name: RegisterName::E,
4553 ..
4554 }) => {
4555 asm.next()?;
4556 asm.data.push(0x73);
4557 asm.data.push(offset);
4558 }
4559 Some(Token::Register {
4560 name: RegisterName::H,
4561 ..
4562 }) => {
4563 asm.next()?;
4564 asm.data.push(0x74);
4565 asm.data.push(offset);
4566 }
4567 Some(Token::Register {
4568 name: RegisterName::L,
4569 ..
4570 }) => {
4571 asm.next()?;
4572 asm.data.push(0x75);
4573 asm.data.push(offset);
4574 }
4575 Some(_) => {
4576 asm.data.push(0x36);
4577 asm.data.push(offset);
4578 let (loc, expr) = asm.expr()?;
4579 if let Some(value) =
4580 expr.evaluate(&asm.symtab, &asm.str_interner)
4581 {
4582 if (value as u32) > (u8::MAX as u32) {
4583 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
4584 }
4585 asm.data.push(value as u8);
4586 } else {
4587 asm.links.push(Link::byte(loc, asm.data.len(), expr));
4588 asm.data.push(0);
4589 }
4590 }
4591 }
4592 }
4593 Some(_) => {
4594 let (loc, expr) = asm.expr()?;
4595 asm.expect_symbol(SymbolName::ParenClose)?;
4596 asm.expect_symbol(SymbolName::Comma)?;
4597 match asm.next()? {
4598 None => return asm.end_of_input_err(),
4599 Some(Token::Register { name: RegisterName::A, .. }) => {
4600 asm.data.push(0x32);
4601 }
4602 Some(Token::Register { name: RegisterName::BC, .. }) => {
4603 asm.data.push(0xED);
4604 asm.data.push(0x43);
4605 }
4606 Some(Token::Register { name: RegisterName::DE, .. }) => {
4607 asm.data.push(0xED);
4608 asm.data.push(0x53);
4609 }
4610 Some(Token::Register { name: RegisterName::HL, .. }) => {
4611 asm.data.push(0x22);
4612 }
4613 Some(Token::Register { name: RegisterName::SP, .. }) => {
4614 asm.data.push(0xED);
4615 asm.data.push(0x73);
4616 }
4617 Some(Token::Register { name: RegisterName::IX, .. }) => {
4618 asm.data.push(0xDD);
4619 asm.data.push(0x22);
4620 }
4621 Some(Token::Register { name: RegisterName::IY, .. }) => {
4622 asm.data.push(0xFD);
4623 asm.data.push(0x22);
4624 }
4625 Some(tok) => return asm_err!(tok.loc(),"Unexpected {}, expected registers \"a\", \"bc\", \"de\", \"hl\", \"sp\", \"ix\", or \"iy\"",tok.as_display(&asm.str_interner)),
4626 }
4627 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
4628 if (value as u32) > (u16::MAX as u32) {
4629 return asm_err!(
4630 loc,
4631 "Expression result ({value}) will not fit in a word"
4632 );
4633 }
4634 asm.data.extend_from_slice(&(value as u16).to_le_bytes());
4635 } else {
4636 asm.links.push(Link::word(loc, asm.data.len(), expr));
4637 asm.data.push(0);
4638 asm.data.push(0);
4639 }
4640 }
4641 },
4642
4643 Some(tok) => {
4644 return asm_err!(
4645 tok.loc(),
4646 "Unexpected {}, expected a valid \"ld\" destination",
4647 tok.as_display(&asm.str_interner)
4648 )
4649 }
4650 }
4651 }
4652
4653 OperationName::Ldd => {
4654 asm.next()?;
4655 asm.data.push(0xED);
4656 asm.data.push(0xA8);
4657 }
4658
4659 OperationName::Lddr => {
4660 asm.next()?;
4661 asm.data.push(0xED);
4662 asm.data.push(0xB8);
4663 }
4664
4665 OperationName::Ldi => {
4666 asm.next()?;
4667 asm.data.push(0xED);
4668 asm.data.push(0xA0);
4669 }
4670
4671 OperationName::Ldir => {
4672 asm.next()?;
4673 asm.data.push(0xED);
4674 asm.data.push(0xB0);
4675 }
4676
4677 OperationName::Neg => {
4678 asm.next()?;
4679 asm.data.push(0xED);
4680 asm.data.push(0x44);
4681 }
4682
4683 OperationName::Nop => {
4684 asm.next()?;
4685 asm.data.push(0x00);
4686 }
4687
4688 OperationName::Or => {
4689 asm.next()?;
4690 match asm.peek()? {
4691 None => return asm.end_of_input_err(),
4692 Some(Token::Register {
4693 name: RegisterName::A,
4694 ..
4695 }) => {
4696 asm.next()?;
4697 asm.data.push(0xB7);
4698 }
4699
4700 Some(Token::Register {
4701 name: RegisterName::B,
4702 ..
4703 }) => {
4704 asm.next()?;
4705 asm.data.push(0xB0);
4706 }
4707
4708 Some(Token::Register {
4709 name: RegisterName::C,
4710 ..
4711 }) => {
4712 asm.next()?;
4713 asm.data.push(0xB1);
4714 }
4715
4716 Some(Token::Register {
4717 name: RegisterName::D,
4718 ..
4719 }) => {
4720 asm.next()?;
4721 asm.data.push(0xB2);
4722 }
4723
4724 Some(Token::Register {
4725 name: RegisterName::E,
4726 ..
4727 }) => {
4728 asm.next()?;
4729 asm.data.push(0xB3);
4730 }
4731
4732 Some(Token::Register {
4733 name: RegisterName::H,
4734 ..
4735 }) => {
4736 asm.next()?;
4737 asm.data.push(0xB4);
4738 }
4739
4740 Some(Token::Register {
4741 name: RegisterName::L,
4742 ..
4743 }) => {
4744 asm.next()?;
4745 asm.data.push(0xB5);
4746 }
4747
4748 Some(Token::Register {
4749 name: RegisterName::IXH,
4750 ..
4751 }) => {
4752 asm.next()?;
4753 asm.data.push(0xDD);
4754 asm.data.push(0xB4);
4755 }
4756
4757 Some(Token::Register {
4758 name: RegisterName::IXL,
4759 ..
4760 }) => {
4761 asm.next()?;
4762 asm.data.push(0xDD);
4763 asm.data.push(0xB5);
4764 }
4765
4766 Some(Token::Register {
4767 name: RegisterName::IYH,
4768 ..
4769 }) => {
4770 asm.next()?;
4771 asm.data.push(0xFD);
4772 asm.data.push(0xB4);
4773 }
4774
4775 Some(Token::Register {
4776 name: RegisterName::IYL,
4777 ..
4778 }) => {
4779 asm.next()?;
4780 asm.data.push(0xFD);
4781 asm.data.push(0xB5);
4782 }
4783
4784 Some(Token::Symbol {
4785 name: SymbolName::ParenOpen,
4786 ..
4787 }) => {
4788 asm.next()?;
4789 match asm.next()? {
4790 None => return asm.end_of_input_err(),
4791 Some(Token::Register {
4792 name: RegisterName::HL,
4793 ..
4794 }) => {
4795 asm.data.push(0xB6);
4796 asm.expect_symbol(SymbolName::ParenClose)?;
4797 }
4798
4799 Some(Token::Register {
4800 name: RegisterName::IX,
4801 ..
4802 }) => {
4803 asm.expect_symbol(SymbolName::Plus)?;
4804 asm.data.push(0xDD);
4805 asm.data.push(0xB6);
4806 let (loc, expr) = asm.expr()?;
4807 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
4808 if (value as u32) > (u8::MAX as u32) {
4809 return asm_err!(
4810 loc,
4811 "Expression result ({value}) will not fit in a byte"
4812 );
4813 }
4814 asm.data.push(value as u8);
4815 } else {
4816 asm.links.push(Link::byte(loc, asm.data.len(), expr));
4817 asm.data.push(0);
4818 }
4819 asm.expect_symbol(SymbolName::ParenClose)?;
4820 }
4821
4822 Some(Token::Register {
4823 name: RegisterName::IY,
4824 ..
4825 }) => {
4826 asm.expect_symbol(SymbolName::Plus)?;
4827 asm.data.push(0xFD);
4828 asm.data.push(0xB6);
4829 let (loc, expr) = asm.expr()?;
4830 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
4831 if (value as u32) > (u8::MAX as u32) {
4832 return asm_err!(
4833 loc,
4834 "Expression result ({value}) will not fit in a byte"
4835 );
4836 }
4837 asm.data.push(value as u8);
4838 } else {
4839 asm.links.push(Link::byte(loc, asm.data.len(), expr));
4840 asm.data.push(0);
4841 }
4842 asm.expect_symbol(SymbolName::ParenClose)?;
4843 }
4844 Some(tok) => {
4845 return asm_err!(
4846 tok.loc(),
4847 "Unexpected {}, expected registers \"hl\", \"ix\", or \"iy\"",
4848 tok.as_display(&asm.str_interner)
4849 )
4850 }
4851 }
4852 }
4853
4854 Some(_) => {
4855 asm.data.push(0xF6);
4856 let (loc, expr) = asm.expr()?;
4857 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
4858 if (value as u32) > (u8::MAX as u32) {
4859 return asm_err!(
4860 loc,
4861 "Expression result ({value}) will not fit in a byte"
4862 );
4863 }
4864 asm.data.push(value as u8);
4865 } else {
4866 asm.links.push(Link::byte(loc, asm.data.len(), expr));
4867 asm.data.push(0);
4868 }
4869 }
4870 }
4871 }
4872
4873 OperationName::Otdr => {
4874 asm.next()?;
4875 asm.data.push(0xED);
4876 asm.data.push(0xBB);
4877 }
4878
4879 OperationName::Otir => {
4880 asm.next()?;
4881 asm.data.push(0xED);
4882 asm.data.push(0xB3);
4883 }
4884
4885 OperationName::Out => {
4886 asm.next()?;
4887 asm.expect_symbol(SymbolName::ParenOpen)?;
4888 match asm.peek()? {
4889 None => return asm.end_of_input_err(),
4890
4891 Some(Token::Register {
4892 name: RegisterName::C,
4893 ..
4894 }) => {
4895 asm.next()?;
4896 asm.expect_symbol(SymbolName::ParenClose)?;
4897 asm.expect_symbol(SymbolName::Comma)?;
4898 asm.data.push(0xED);
4899 match asm.next()? {
4900 None => return asm.end_of_input_err(),
4901 Some(Token::Register {
4902 name: RegisterName::A,
4903 ..
4904 }) => {
4905 asm.data.push(0x79);
4906 }
4907 Some(Token::Register {
4908 name: RegisterName::B,
4909 ..
4910 }) => {
4911 asm.data.push(0x41);
4912 }
4913 Some(Token::Register {
4914 name: RegisterName::C,
4915 ..
4916 }) => {
4917 asm.data.push(0x49);
4918 }
4919 Some(Token::Register {
4920 name: RegisterName::D,
4921 ..
4922 }) => {
4923 asm.data.push(0x51);
4924 }
4925 Some(Token::Register {
4926 name: RegisterName::E,
4927 ..
4928 }) => {
4929 asm.data.push(0x59);
4930 }
4931 Some(Token::Register {
4932 name: RegisterName::H,
4933 ..
4934 }) => {
4935 asm.data.push(0x61);
4936 }
4937 Some(Token::Register {
4938 name: RegisterName::L,
4939 ..
4940 }) => {
4941 asm.data.push(0x69);
4942 }
4943 Some(tok) => {
4944 return asm_err!(
4945 tok.loc(),
4946 "Unexpected {}, expected a register",
4947 tok.as_display(&asm.str_interner)
4948 )
4949 }
4950 }
4951 }
4952
4953 Some(_) => {
4954 asm.data.push(0xD3);
4955 let (loc, expr) = asm.expr()?;
4956 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
4957 if (value as u32) > (u8::MAX as u32) {
4958 return asm_err!(
4959 loc,
4960 "Expression result ({value}) will not fit in a byte"
4961 );
4962 }
4963 asm.data.push(value as u8);
4964 } else {
4965 asm.links.push(Link::byte(loc, asm.data.len(), expr));
4966 asm.data.push(0);
4967 }
4968 asm.expect_symbol(SymbolName::ParenClose)?;
4969 asm.expect_symbol(SymbolName::Comma)?;
4970 asm.expect_register(RegisterName::A)?;
4971 }
4972 }
4973 }
4974
4975 OperationName::Outd => {
4976 asm.next()?;
4977 asm.data.push(0xED);
4978 asm.data.push(0xAB);
4979 }
4980
4981 OperationName::Outi => {
4982 asm.next()?;
4983 asm.data.push(0xED);
4984 asm.data.push(0xA3);
4985 }
4986
4987 OperationName::Pop => {
4988 asm.next()?;
4989 match asm.next()? {
4990 None => return asm.end_of_input_err(),
4991 Some(Token::Register { name: RegisterName::BC, .. }) => {
4992 asm.data.push(0xC1);
4993 }
4994 Some(Token::Register { name: RegisterName::DE, .. }) => {
4995 asm.data.push(0xD1);
4996 }
4997 Some(Token::Register { name: RegisterName::HL, .. }) => {
4998 asm.data.push(0xE1);
4999 }
5000 Some(Token::Register { name: RegisterName::AF, .. }) => {
5001 asm.data.push(0xF1);
5002 }
5003 Some(Token::Register { name: RegisterName::IX, .. }) => {
5004 asm.data.push(0xDD);
5005 asm.data.push(0xE1);
5006 }
5007 Some(Token::Register { name: RegisterName::IY, .. }) => {
5008 asm.data.push(0xFD);
5009 asm.data.push(0xE1);
5010 }
5011 Some(tok) => return asm_err!(tok.loc(),"Unexpected {}, expected register \"bc\", \"de\", \"hl\", \"af\", \"ix\", or \"iy\"",tok.as_display(&asm.str_interner)),
5012 }
5013 }
5014
5015 OperationName::Push => {
5016 asm.next()?;
5017 match asm.next()? {
5018 None => return asm.end_of_input_err(),
5019 Some(Token::Register { name: RegisterName::BC, .. }) => {
5020 asm.data.push(0xC5);
5021 }
5022 Some(Token::Register { name: RegisterName::DE, .. }) => {
5023 asm.data.push(0xD5);
5024 }
5025 Some(Token::Register { name: RegisterName::HL, .. }) => {
5026 asm.data.push(0xE5);
5027 }
5028 Some(Token::Register { name: RegisterName::AF, .. }) => {
5029 asm.data.push(0xF5);
5030 }
5031 Some(Token::Register { name: RegisterName::IX, .. }) => {
5032 asm.data.push(0xDD);
5033 asm.data.push(0xE5);
5034 }
5035 Some(Token::Register { name: RegisterName::IY, .. }) => {
5036 asm.data.push(0xFD);
5037 asm.data.push(0xE5);
5038 }
5039 Some(tok) => return asm_err!(tok.loc(),"Unexpected {}, expected register \"bc\", \"de\", \"hl\", \"af\", \"ix\", or \"iy\"",tok.as_display(&asm.str_interner)),
5040 }
5041 }
5042
5043 OperationName::Res => {
5044 asm.next()?;
5045 match asm.const_expr()? {
5046 (loc, None) => return asm_err!(loc, "Bit index must be immediately solvable"),
5047 (loc, Some(value)) => {
5048 if !(0..=7).contains(&value) {
5049 return asm_err!(loc, "Bit index ({value}) must be between 0 and 7");
5050 }
5051
5052 asm.expect_symbol(SymbolName::Comma)?;
5053
5054 match asm.next()? {
5055 None => return asm.end_of_input_err(),
5056 Some(Token::Register {
5057 name: RegisterName::A,
5058 ..
5059 }) => {
5060 asm.data.push(0xCB);
5061 asm.data.push(match value {
5062 0 => 0x87,
5063 1 => 0x8F,
5064 2 => 0x97,
5065 3 => 0x9F,
5066 4 => 0xA7,
5067 5 => 0xAF,
5068 6 => 0xB7,
5069 7 => 0xBF,
5070 _ => unreachable!(),
5071 });
5072 }
5073
5074 Some(Token::Register {
5075 name: RegisterName::B,
5076 ..
5077 }) => {
5078 asm.data.push(0xCB);
5079 asm.data.push(match value {
5080 0 => 0x80,
5081 1 => 0x88,
5082 2 => 0x90,
5083 3 => 0x98,
5084 4 => 0xA0,
5085 5 => 0xA8,
5086 6 => 0xB0,
5087 7 => 0xB8,
5088 _ => unreachable!(),
5089 });
5090 }
5091
5092 Some(Token::Register {
5093 name: RegisterName::C,
5094 ..
5095 }) => {
5096 asm.data.push(0xCB);
5097 asm.data.push(match value {
5098 0 => 0x81,
5099 1 => 0x89,
5100 2 => 0x91,
5101 3 => 0x99,
5102 4 => 0xA1,
5103 5 => 0xA9,
5104 6 => 0xB1,
5105 7 => 0xB9,
5106 _ => unreachable!(),
5107 });
5108 }
5109
5110 Some(Token::Register {
5111 name: RegisterName::D,
5112 ..
5113 }) => {
5114 asm.data.push(0xCB);
5115 asm.data.push(match value {
5116 0 => 0x82,
5117 1 => 0x8A,
5118 2 => 0x92,
5119 3 => 0x9A,
5120 4 => 0xA2,
5121 5 => 0xAA,
5122 6 => 0xB2,
5123 7 => 0xBA,
5124 _ => unreachable!(),
5125 });
5126 }
5127
5128 Some(Token::Register {
5129 name: RegisterName::E,
5130 ..
5131 }) => {
5132 asm.data.push(0xCB);
5133 asm.data.push(match value {
5134 0 => 0x83,
5135 1 => 0x8B,
5136 2 => 0x93,
5137 3 => 0x9B,
5138 4 => 0xA3,
5139 5 => 0xAB,
5140 6 => 0xB3,
5141 7 => 0xBB,
5142 _ => unreachable!(),
5143 });
5144 }
5145
5146 Some(Token::Register {
5147 name: RegisterName::H,
5148 ..
5149 }) => {
5150 asm.data.push(0xCB);
5151 asm.data.push(match value {
5152 0 => 0x84,
5153 1 => 0x8C,
5154 2 => 0x94,
5155 3 => 0x9C,
5156 4 => 0xA4,
5157 5 => 0xAC,
5158 6 => 0xB4,
5159 7 => 0xBC,
5160 _ => unreachable!(),
5161 });
5162 }
5163
5164 Some(Token::Register {
5165 name: RegisterName::L,
5166 ..
5167 }) => {
5168 asm.data.push(0xCB);
5169 asm.data.push(match value {
5170 0 => 0x85,
5171 1 => 0x8D,
5172 2 => 0x95,
5173 3 => 0x9D,
5174 4 => 0xA5,
5175 5 => 0xAD,
5176 6 => 0xB5,
5177 7 => 0xBD,
5178 _ => unreachable!(),
5179 });
5180 }
5181
5182 Some(Token::Symbol {
5183 name: SymbolName::ParenOpen,
5184 ..
5185 }) => {
5186 match asm.next()? {
5187 None => return asm.end_of_input_err(),
5188 Some(Token::Register { name: RegisterName::HL, .. }) => {
5189 asm.data.push(0xCB);
5190 asm.data.push(match value {
5191 0 => 0x86,
5192 1 => 0x8E,
5193 2 => 0x96,
5194 3 => 0x9E,
5195 4 => 0xA6,
5196 5 => 0xAE,
5197 6 => 0xB6,
5198 7 => 0xBE,
5199 _ => unreachable!(),
5200 });
5201 }
5202
5203 Some(Token::Register { name: RegisterName::IX, .. }) => {
5204 asm.expect_symbol(SymbolName::Plus)?;
5205 asm.data.push(0xDD);
5206 asm.data.push(0xCB);
5207 let (loc, expr) = asm.expr()?;
5208 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
5209 if (value as u32) > (u8::MAX as u32) {
5210 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
5211 }
5212 asm.data.push(value as u8);
5213 } else {
5214 asm.links.push(Link::byte(loc, asm.data.len(), expr));
5215 asm.data.push(0);
5216 }
5217 asm.data.push(match value {
5218 0 => 0x86,
5219 1 => 0x8E,
5220 2 => 0x96,
5221 3 => 0x9E,
5222 4 => 0xA6,
5223 5 => 0xAE,
5224 6 => 0xB6,
5225 7 => 0xBE,
5226 _ => unreachable!(),
5227 });
5228 }
5229
5230 Some(Token::Register { name: RegisterName::IY, .. }) => {
5231 asm.expect_symbol(SymbolName::Plus)?;
5232 asm.data.push(0xFD);
5233 asm.data.push(0xCB);
5234 let (loc, expr) = asm.expr()?;
5235 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
5236 if (value as u32) > (u8::MAX as u32) {
5237 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
5238 }
5239 asm.data.push(value as u8);
5240 } else {
5241 asm.links.push(Link::byte(loc, asm.data.len(), expr));
5242 asm.data.push(0);
5243 }
5244 asm.data.push(match value {
5245 0 => 0x86,
5246 1 => 0x8E,
5247 2 => 0x96,
5248 3 => 0x9E,
5249 4 => 0xA6,
5250 5 => 0xAE,
5251 6 => 0xB6,
5252 7 => 0xBE,
5253 _ => unreachable!(),
5254 });
5255 }
5256
5257 Some(tok) => return asm_err!(tok.loc(),"Unexpected {}, expected register \"hl\", \"ix\", or \"iy\"",tok.as_display(&asm.str_interner)),
5258 }
5259 asm.expect_symbol(SymbolName::ParenClose)?;
5260 }
5261
5262 Some(tok) => {
5263 return asm_err!(
5264 tok.loc(),
5265 "Unexpected {}, expected a register",
5266 tok.as_display(&asm.str_interner)
5267 )
5268 }
5269 }
5270 }
5271 }
5272 }
5273
5274 OperationName::Ret => {
5275 asm.next()?;
5276 match asm.peek()? {
5277 None => return asm.end_of_input_err()?,
5278 Some(Token::Flag {
5279 name: FlagName::NotZero,
5280 ..
5281 }) => {
5282 asm.next()?;
5283 asm.data.push(0xC0);
5284 }
5285 Some(Token::Flag {
5286 name: FlagName::Zero,
5287 ..
5288 }) => {
5289 asm.next()?;
5290 asm.data.push(0xC8);
5291 }
5292 Some(Token::Flag {
5293 name: FlagName::NotCarry,
5294 ..
5295 }) => {
5296 asm.next()?;
5297 asm.data.push(0xD0);
5298 }
5299 Some(Token::Register {
5300 name: RegisterName::C,
5301 ..
5302 }) => {
5303 asm.next()?;
5304 asm.data.push(0xD8);
5305 }
5306 Some(Token::Flag {
5307 name: FlagName::ParityOdd,
5308 ..
5309 }) => {
5310 asm.next()?;
5311 asm.data.push(0xE0);
5312 }
5313 Some(Token::Flag {
5314 name: FlagName::ParityEven,
5315 ..
5316 }) => {
5317 asm.next()?;
5318 asm.data.push(0xE8);
5319 }
5320 Some(Token::Flag {
5321 name: FlagName::Positive,
5322 ..
5323 }) => {
5324 asm.next()?;
5325 asm.data.push(0xF0);
5326 }
5327 Some(Token::Flag {
5328 name: FlagName::Negative,
5329 ..
5330 }) => {
5331 asm.next()?;
5332 asm.data.push(0xF8);
5333 }
5334 Some(_) => {
5335 asm.data.push(0xC9);
5336 }
5337 }
5338 }
5339
5340 OperationName::Reti => {
5341 asm.next()?;
5342 asm.data.push(0xED);
5343 asm.data.push(0x4D);
5344 }
5345
5346 OperationName::Retn => {
5347 asm.next()?;
5348 asm.data.push(0xED);
5349 asm.data.push(0x45);
5350 }
5351
5352 OperationName::Rl => {
5353 asm.next()?;
5354 match asm.next()? {
5355 None => return asm.end_of_input_err(),
5356 Some(Token::Register {
5357 name: RegisterName::A,
5358 ..
5359 }) => {
5360 asm.data.push(0xCB);
5361 asm.data.push(0x17);
5362 }
5363 Some(Token::Register {
5364 name: RegisterName::B,
5365 ..
5366 }) => {
5367 asm.data.push(0xCB);
5368 asm.data.push(0x10);
5369 }
5370 Some(Token::Register {
5371 name: RegisterName::C,
5372 ..
5373 }) => {
5374 asm.data.push(0xCB);
5375 asm.data.push(0x11);
5376 }
5377 Some(Token::Register {
5378 name: RegisterName::D,
5379 ..
5380 }) => {
5381 asm.data.push(0xCB);
5382 asm.data.push(0x12);
5383 }
5384 Some(Token::Register {
5385 name: RegisterName::E,
5386 ..
5387 }) => {
5388 asm.data.push(0xCB);
5389 asm.data.push(0x13);
5390 }
5391 Some(Token::Register {
5392 name: RegisterName::H,
5393 ..
5394 }) => {
5395 asm.data.push(0xCB);
5396 asm.data.push(0x14);
5397 }
5398 Some(Token::Register {
5399 name: RegisterName::L,
5400 ..
5401 }) => {
5402 asm.data.push(0xCB);
5403 asm.data.push(0x15);
5404 }
5405 Some(Token::Symbol {
5406 name: SymbolName::ParenOpen,
5407 ..
5408 }) => {
5409 match asm.next()? {
5410 None => return asm.end_of_input_err(),
5411 Some(Token::Register {
5412 name: RegisterName::HL,
5413 ..
5414 }) => {
5415 asm.data.push(0xCB);
5416 asm.data.push(0x16);
5417 }
5418 Some(Token::Register {
5419 name: RegisterName::IX,
5420 ..
5421 }) => {
5422 asm.expect_symbol(SymbolName::Plus)?;
5423 asm.data.push(0xDD);
5424 asm.data.push(0xCB);
5425 let (loc, expr) = asm.expr()?;
5426 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
5427 if (value as u32) > (u8::MAX as u32) {
5428 return asm_err!(
5429 loc,
5430 "Expression result ({value}) will not fit in a byte"
5431 );
5432 }
5433 asm.data.push(value as u8);
5434 } else {
5435 asm.links.push(Link::byte(loc, asm.data.len(), expr));
5436 asm.data.push(0);
5437 }
5438 asm.data.push(0x16);
5439 }
5440 Some(Token::Register {
5441 name: RegisterName::IY,
5442 ..
5443 }) => {
5444 asm.expect_symbol(SymbolName::Plus)?;
5445 asm.data.push(0xFD);
5446 asm.data.push(0xCB);
5447 let (loc, expr) = asm.expr()?;
5448 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
5449 if (value as u32) > (u8::MAX as u32) {
5450 return asm_err!(
5451 loc,
5452 "Expression result ({value}) will not fit in a byte"
5453 );
5454 }
5455 asm.data.push(value as u8);
5456 } else {
5457 asm.links.push(Link::byte(loc, asm.data.len(), expr));
5458 asm.data.push(0);
5459 }
5460 asm.data.push(0x16);
5461 }
5462 Some(tok) => {
5463 return asm_err!(
5464 tok.loc(),
5465 "Unexpected {}, expected register \"hl\", \"ix\", or \"iy\"",
5466 tok.as_display(&asm.str_interner)
5467 )
5468 }
5469 }
5470 asm.expect_symbol(SymbolName::ParenClose)?;
5471 }
5472 Some(tok) => {
5473 return asm_err!(
5474 tok.loc(),
5475 "Unexpected {}, expected register",
5476 tok.as_display(&asm.str_interner)
5477 )
5478 }
5479 }
5480 }
5481
5482 OperationName::Rla => {
5483 asm.next()?;
5484 asm.data.push(0x17);
5485 }
5486
5487 OperationName::Rlc => {
5488 asm.next()?;
5489 match asm.next()? {
5490 None => return asm.end_of_input_err(),
5491 Some(Token::Register {
5492 name: RegisterName::A,
5493 ..
5494 }) => {
5495 asm.data.push(0xCB);
5496 asm.data.push(0x07);
5497 }
5498 Some(Token::Register {
5499 name: RegisterName::B,
5500 ..
5501 }) => {
5502 asm.data.push(0xCB);
5503 asm.data.push(0x00);
5504 }
5505 Some(Token::Register {
5506 name: RegisterName::C,
5507 ..
5508 }) => {
5509 asm.data.push(0xCB);
5510 asm.data.push(0x01);
5511 }
5512 Some(Token::Register {
5513 name: RegisterName::D,
5514 ..
5515 }) => {
5516 asm.data.push(0xCB);
5517 asm.data.push(0x02);
5518 }
5519 Some(Token::Register {
5520 name: RegisterName::E,
5521 ..
5522 }) => {
5523 asm.data.push(0xCB);
5524 asm.data.push(0x03);
5525 }
5526 Some(Token::Register {
5527 name: RegisterName::H,
5528 ..
5529 }) => {
5530 asm.data.push(0xCB);
5531 asm.data.push(0x04);
5532 }
5533 Some(Token::Register {
5534 name: RegisterName::L,
5535 ..
5536 }) => {
5537 asm.data.push(0xCB);
5538 asm.data.push(0x05);
5539 }
5540 Some(Token::Symbol {
5541 name: SymbolName::ParenOpen,
5542 ..
5543 }) => {
5544 match asm.next()? {
5545 None => return asm.end_of_input_err(),
5546 Some(Token::Register {
5547 name: RegisterName::HL,
5548 ..
5549 }) => {
5550 asm.data.push(0xCB);
5551 asm.data.push(0x06);
5552 }
5553 Some(Token::Register {
5554 name: RegisterName::IX,
5555 ..
5556 }) => {
5557 asm.expect_symbol(SymbolName::Plus)?;
5558 asm.data.push(0xDD);
5559 asm.data.push(0xCB);
5560 let (loc, expr) = asm.expr()?;
5561 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
5562 if (value as u32) > (u8::MAX as u32) {
5563 return asm_err!(
5564 loc,
5565 "Expression result ({value}) will not fit in a byte"
5566 );
5567 }
5568 asm.data.push(value as u8);
5569 } else {
5570 asm.links.push(Link::byte(loc, asm.data.len(), expr));
5571 asm.data.push(0);
5572 }
5573 asm.data.push(0x06);
5574 }
5575 Some(Token::Register {
5576 name: RegisterName::IY,
5577 ..
5578 }) => {
5579 asm.expect_symbol(SymbolName::Plus)?;
5580 asm.data.push(0xFD);
5581 asm.data.push(0xCB);
5582 let (loc, expr) = asm.expr()?;
5583 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
5584 if (value as u32) > (u8::MAX as u32) {
5585 return asm_err!(
5586 loc,
5587 "Expression result ({value}) will not fit in a byte"
5588 );
5589 }
5590 asm.data.push(value as u8);
5591 } else {
5592 asm.links.push(Link::byte(loc, asm.data.len(), expr));
5593 asm.data.push(0);
5594 }
5595 asm.data.push(0x06);
5596 }
5597 Some(tok) => {
5598 return asm_err!(
5599 tok.loc(),
5600 "Unexpected {}, expected register \"hl\", \"ix\", or \"iy\"",
5601 tok.as_display(&asm.str_interner)
5602 )
5603 }
5604 }
5605 asm.expect_symbol(SymbolName::ParenClose)?;
5606 }
5607 Some(tok) => {
5608 return asm_err!(
5609 tok.loc(),
5610 "Unexpected {}, expected register",
5611 tok.as_display(&asm.str_interner)
5612 )
5613 }
5614 }
5615 }
5616
5617 OperationName::Rlca => {
5618 asm.next()?;
5619 asm.data.push(0x07);
5620 }
5621
5622 OperationName::Rld => {
5623 asm.next()?;
5624 asm.data.push(0xED);
5625 asm.data.push(0x6F);
5626 }
5627
5628 OperationName::Rr => {
5629 asm.next()?;
5630 match asm.next()? {
5631 None => return asm.end_of_input_err(),
5632 Some(Token::Register {
5633 name: RegisterName::A,
5634 ..
5635 }) => {
5636 asm.data.push(0xCB);
5637 asm.data.push(0x1F);
5638 }
5639 Some(Token::Register {
5640 name: RegisterName::B,
5641 ..
5642 }) => {
5643 asm.data.push(0xCB);
5644 asm.data.push(0x18);
5645 }
5646 Some(Token::Register {
5647 name: RegisterName::C,
5648 ..
5649 }) => {
5650 asm.data.push(0xCB);
5651 asm.data.push(0x19);
5652 }
5653 Some(Token::Register {
5654 name: RegisterName::D,
5655 ..
5656 }) => {
5657 asm.data.push(0xCB);
5658 asm.data.push(0x1A);
5659 }
5660 Some(Token::Register {
5661 name: RegisterName::E,
5662 ..
5663 }) => {
5664 asm.data.push(0xCB);
5665 asm.data.push(0x1B);
5666 }
5667 Some(Token::Register {
5668 name: RegisterName::H,
5669 ..
5670 }) => {
5671 asm.data.push(0xCB);
5672 asm.data.push(0x1C);
5673 }
5674 Some(Token::Register {
5675 name: RegisterName::L,
5676 ..
5677 }) => {
5678 asm.data.push(0xCB);
5679 asm.data.push(0x1D);
5680 }
5681 Some(Token::Symbol {
5682 name: SymbolName::ParenOpen,
5683 ..
5684 }) => {
5685 match asm.next()? {
5686 None => return asm.end_of_input_err(),
5687 Some(Token::Register {
5688 name: RegisterName::HL,
5689 ..
5690 }) => {
5691 asm.data.push(0xCB);
5692 asm.data.push(0x1E);
5693 }
5694 Some(Token::Register {
5695 name: RegisterName::IX,
5696 ..
5697 }) => {
5698 asm.expect_symbol(SymbolName::Plus)?;
5699 asm.data.push(0xDD);
5700 asm.data.push(0xCB);
5701 let (loc, expr) = asm.expr()?;
5702 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
5703 if (value as u32) > (u8::MAX as u32) {
5704 return asm_err!(
5705 loc,
5706 "Expression result ({value}) will not fit in a byte"
5707 );
5708 }
5709 asm.data.push(value as u8);
5710 } else {
5711 asm.links.push(Link::byte(loc, asm.data.len(), expr));
5712 asm.data.push(0);
5713 }
5714 asm.data.push(0x1E);
5715 }
5716 Some(Token::Register {
5717 name: RegisterName::IY,
5718 ..
5719 }) => {
5720 asm.expect_symbol(SymbolName::Plus)?;
5721 asm.data.push(0xFD);
5722 asm.data.push(0xCB);
5723 let (loc, expr) = asm.expr()?;
5724 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
5725 if (value as u32) > (u8::MAX as u32) {
5726 return asm_err!(
5727 loc,
5728 "Expression result ({value}) will not fit in a byte"
5729 );
5730 }
5731 asm.data.push(value as u8);
5732 } else {
5733 asm.links.push(Link::byte(loc, asm.data.len(), expr));
5734 asm.data.push(0);
5735 }
5736 asm.data.push(0x1E);
5737 }
5738 Some(tok) => {
5739 return asm_err!(
5740 tok.loc(),
5741 "Unexpected {}, expected register \"hl\", \"ix\", or \"iy\"",
5742 tok.as_display(&asm.str_interner)
5743 )
5744 }
5745 }
5746 asm.expect_symbol(SymbolName::ParenClose)?;
5747 }
5748 Some(tok) => {
5749 return asm_err!(
5750 tok.loc(),
5751 "Unexpected {}, expected register",
5752 tok.as_display(&asm.str_interner)
5753 )
5754 }
5755 }
5756 }
5757
5758 OperationName::Rra => {
5759 asm.next()?;
5760 asm.data.push(0x1F);
5761 }
5762
5763 OperationName::Rrc => {
5764 asm.next()?;
5765 match asm.next()? {
5766 None => return asm.end_of_input_err(),
5767 Some(Token::Register {
5768 name: RegisterName::A,
5769 ..
5770 }) => {
5771 asm.data.push(0xCB);
5772 asm.data.push(0x0F);
5773 }
5774 Some(Token::Register {
5775 name: RegisterName::B,
5776 ..
5777 }) => {
5778 asm.data.push(0xCB);
5779 asm.data.push(0x08);
5780 }
5781 Some(Token::Register {
5782 name: RegisterName::C,
5783 ..
5784 }) => {
5785 asm.data.push(0xCB);
5786 asm.data.push(0x09);
5787 }
5788 Some(Token::Register {
5789 name: RegisterName::D,
5790 ..
5791 }) => {
5792 asm.data.push(0xCB);
5793 asm.data.push(0x0A);
5794 }
5795 Some(Token::Register {
5796 name: RegisterName::E,
5797 ..
5798 }) => {
5799 asm.data.push(0xCB);
5800 asm.data.push(0x0B);
5801 }
5802 Some(Token::Register {
5803 name: RegisterName::H,
5804 ..
5805 }) => {
5806 asm.data.push(0xCB);
5807 asm.data.push(0x0C);
5808 }
5809 Some(Token::Register {
5810 name: RegisterName::L,
5811 ..
5812 }) => {
5813 asm.data.push(0xCB);
5814 asm.data.push(0x0D);
5815 }
5816 Some(Token::Symbol {
5817 name: SymbolName::ParenOpen,
5818 ..
5819 }) => {
5820 match asm.next()? {
5821 None => return asm.end_of_input_err(),
5822 Some(Token::Register {
5823 name: RegisterName::HL,
5824 ..
5825 }) => {
5826 asm.data.push(0xCB);
5827 asm.data.push(0x0E);
5828 }
5829 Some(Token::Register {
5830 name: RegisterName::IX,
5831 ..
5832 }) => {
5833 asm.expect_symbol(SymbolName::Plus)?;
5834 asm.data.push(0xDD);
5835 asm.data.push(0xCB);
5836 let (loc, expr) = asm.expr()?;
5837 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
5838 if (value as u32) > (u8::MAX as u32) {
5839 return asm_err!(
5840 loc,
5841 "Expression result ({value}) will not fit in a byte"
5842 );
5843 }
5844 asm.data.push(value as u8);
5845 } else {
5846 asm.links.push(Link::byte(loc, asm.data.len(), expr));
5847 asm.data.push(0);
5848 }
5849 asm.data.push(0x0E);
5850 }
5851 Some(Token::Register {
5852 name: RegisterName::IY,
5853 ..
5854 }) => {
5855 asm.expect_symbol(SymbolName::Plus)?;
5856 asm.data.push(0xFD);
5857 asm.data.push(0xCB);
5858 let (loc, expr) = asm.expr()?;
5859 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
5860 if (value as u32) > (u8::MAX as u32) {
5861 return asm_err!(
5862 loc,
5863 "Expression result ({value}) will not fit in a byte"
5864 );
5865 }
5866 asm.data.push(value as u8);
5867 } else {
5868 asm.links.push(Link::byte(loc, asm.data.len(), expr));
5869 asm.data.push(0);
5870 }
5871 asm.data.push(0x0E);
5872 }
5873 Some(tok) => {
5874 return asm_err!(
5875 tok.loc(),
5876 "Unexpected {}, expected register \"hl\", \"ix\", or \"iy\"",
5877 tok.as_display(&asm.str_interner)
5878 )
5879 }
5880 }
5881 asm.expect_symbol(SymbolName::ParenClose)?;
5882 }
5883 Some(tok) => {
5884 return asm_err!(
5885 tok.loc(),
5886 "Unexpected {}, expected register",
5887 tok.as_display(&asm.str_interner)
5888 )
5889 }
5890 }
5891 }
5892
5893 OperationName::Rrca => {
5894 asm.next()?;
5895 asm.data.push(0x0F);
5896 }
5897
5898 OperationName::Rrd => {
5899 asm.next()?;
5900 asm.data.push(0xED);
5901 asm.data.push(0x67);
5902 }
5903
5904 OperationName::Rst => {
5905 asm.next()?;
5906 match asm.const_expr()? {
5907 (loc, None) => return asm_err!(loc,"The expression following an \"rst\" instruction must be immediately solvable"),
5908 (loc, Some(value)) => {
5909 let byte = match value {
5910 0x00 => 0xC7,
5911 0x08 => 0xCF,
5912 0x10 => 0xD7,
5913 0x18 => 0xDF,
5914 0x20 => 0xE7,
5915 0x28 => 0xEF,
5916 0x30 => 0xF7,
5917 0x38 => 0xFF,
5918 _ => return asm_err!(loc,"The \"rst\" value ({value}) is not valid"),
5919 };
5920 asm.data.push(byte);
5921 }
5922 }
5923 }
5924
5925 OperationName::Sbc => {
5926 asm.next()?;
5927 match asm.next()? {
5928 None => return asm.end_of_input_err(),
5929 Some(Token::Register {
5930 name: RegisterName::A,
5931 ..
5932 }) => {
5933 asm.expect_symbol(SymbolName::Comma)?;
5934
5935 match asm.peek()? {
5936 None => return asm.end_of_input_err(),
5937 Some(Token::Register {
5938 name: RegisterName::A,
5939 ..
5940 }) => {
5941 asm.next()?;
5942 asm.data.push(0x9F);
5943 }
5944
5945 Some(Token::Register {
5946 name: RegisterName::B,
5947 ..
5948 }) => {
5949 asm.next()?;
5950 asm.data.push(0x98);
5951 }
5952
5953 Some(Token::Register {
5954 name: RegisterName::C,
5955 ..
5956 }) => {
5957 asm.next()?;
5958 asm.data.push(0x99);
5959 }
5960
5961 Some(Token::Register {
5962 name: RegisterName::D,
5963 ..
5964 }) => {
5965 asm.next()?;
5966 asm.data.push(0x9A);
5967 }
5968
5969 Some(Token::Register {
5970 name: RegisterName::E,
5971 ..
5972 }) => {
5973 asm.next()?;
5974 asm.data.push(0x9B);
5975 }
5976
5977 Some(Token::Register {
5978 name: RegisterName::H,
5979 ..
5980 }) => {
5981 asm.next()?;
5982 asm.data.push(0x9C);
5983 }
5984
5985 Some(Token::Register {
5986 name: RegisterName::L,
5987 ..
5988 }) => {
5989 asm.next()?;
5990 asm.data.push(0x9D);
5991 }
5992
5993 Some(Token::Register {
5994 name: RegisterName::IXH,
5995 ..
5996 }) => {
5997 asm.next()?;
5998 asm.data.push(0xDD);
5999 asm.data.push(0x9C);
6000 }
6001
6002 Some(Token::Register {
6003 name: RegisterName::IXL,
6004 ..
6005 }) => {
6006 asm.next()?;
6007 asm.data.push(0xDD);
6008 asm.data.push(0x9D);
6009 }
6010
6011 Some(Token::Register {
6012 name: RegisterName::IYH,
6013 ..
6014 }) => {
6015 asm.next()?;
6016 asm.data.push(0xFD);
6017 asm.data.push(0x9C);
6018 }
6019
6020 Some(Token::Register {
6021 name: RegisterName::IYL,
6022 ..
6023 }) => {
6024 asm.next()?;
6025 asm.data.push(0xFD);
6026 asm.data.push(0x9D);
6027 }
6028
6029 Some(Token::Symbol {
6030 name: SymbolName::ParenOpen,
6031 ..
6032 }) => {
6033 asm.next()?;
6034 match asm.next()? {
6035 None => return asm.end_of_input_err(),
6036 Some(Token::Register {
6037 name: RegisterName::HL,
6038 ..
6039 }) => {
6040 asm.data.push(0x9E);
6041 asm.expect_symbol(SymbolName::ParenClose)?;
6042 }
6043
6044 Some(Token::Register {
6045 name: RegisterName::IX,
6046 ..
6047 }) => {
6048 asm.expect_symbol(SymbolName::Plus)?;
6049 asm.data.push(0xDD);
6050 asm.data.push(0x9E);
6051 let (loc, expr) = asm.expr()?;
6052 if let Some(value) =
6053 expr.evaluate(&asm.symtab, &asm.str_interner)
6054 {
6055 if (value as u32) > (u8::MAX as u32) {
6056 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
6057 }
6058 asm.data.push(value as u8);
6059 } else {
6060 asm.links.push(Link::byte(loc, asm.data.len(), expr));
6061 asm.data.push(0);
6062 }
6063 asm.expect_symbol(SymbolName::ParenClose)?;
6064 }
6065
6066 Some(Token::Register {
6067 name: RegisterName::IY,
6068 ..
6069 }) => {
6070 asm.expect_symbol(SymbolName::Plus)?;
6071 asm.data.push(0xFD);
6072 asm.data.push(0x9E);
6073 let (loc, expr) = asm.expr()?;
6074 if let Some(value) =
6075 expr.evaluate(&asm.symtab, &asm.str_interner)
6076 {
6077 if (value as u32) > (u8::MAX as u32) {
6078 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
6079 }
6080 asm.data.push(value as u8);
6081 } else {
6082 asm.links.push(Link::byte(loc, asm.data.len(), expr));
6083 asm.data.push(0);
6084 }
6085 asm.expect_symbol(SymbolName::ParenClose)?;
6086 }
6087
6088 Some(_) => {
6089 asm.data.push(0x9E);
6090 let (loc, expr) = asm.expr()?;
6091 if let Some(value) =
6092 expr.evaluate(&asm.symtab, &asm.str_interner)
6093 {
6094 if (value as u32) > (u8::MAX as u32) {
6095 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
6096 }
6097 asm.data.push(value as u8);
6098 } else {
6099 asm.links.push(Link::byte(loc, asm.data.len(), expr));
6100 asm.data.push(0);
6101 }
6102 asm.expect_symbol(SymbolName::ParenClose)?;
6103 }
6104 }
6105 }
6106
6107 Some(_) => {
6108 asm.data.push(0xDE);
6109 let (loc, expr) = asm.expr()?;
6110 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
6111 if (value as u32) > (u8::MAX as u32) {
6112 return asm_err!(
6113 loc,
6114 "Expression result ({value}) will not fit in a byte"
6115 );
6116 }
6117 asm.data.push(value as u8);
6118 } else {
6119 asm.links.push(Link::byte(loc, asm.data.len(), expr));
6120 asm.data.push(0);
6121 }
6122 }
6123 }
6124 }
6125
6126 Some(Token::Register {
6127 name: RegisterName::HL,
6128 ..
6129 }) => {
6130 asm.expect_symbol(SymbolName::Comma)?;
6131 match asm.next()? {
6132 None => return asm.end_of_input_err(),
6133 Some(Token::Register {
6134 name: RegisterName::BC,
6135 ..
6136 }) => {
6137 asm.data.push(0xED);
6138 asm.data.push(0x42);
6139 }
6140
6141 Some(Token::Register {
6142 name: RegisterName::DE,
6143 ..
6144 }) => {
6145 asm.data.push(0xED);
6146 asm.data.push(0x52);
6147 }
6148
6149 Some(Token::Register {
6150 name: RegisterName::HL,
6151 ..
6152 }) => {
6153 asm.data.push(0xED);
6154 asm.data.push(0x62);
6155 }
6156
6157 Some(Token::Register {
6158 name: RegisterName::SP,
6159 ..
6160 }) => {
6161 asm.data.push(0xED);
6162 asm.data.push(0x72);
6163 }
6164
6165 Some(tok) => {
6166 return asm_err!(
6167 tok.loc(),
6168 "Unexpected {}, expected register \"bc\", \"de\", \"hl\" or \"sp\"",
6169 tok.as_display(&asm.str_interner)
6170 )
6171 }
6172 }
6173 }
6174
6175 Some(tok) => {
6176 return asm_err!(
6177 tok.loc(),
6178 "Unexpected {}, expected register \"a\" or \"hl\"",
6179 tok.as_display(&asm.str_interner)
6180 )
6181 }
6182 }
6183 }
6184
6185 OperationName::Scf => {
6186 asm.next()?;
6187 asm.data.push(0x37);
6188 }
6189
6190 OperationName::Set => {
6191 asm.next()?;
6192 match asm.const_expr()? {
6193 (loc, None) => return asm_err!(loc, "Bit index must be immediately solvable"),
6194 (loc, Some(value)) => {
6195 if !(0..=7).contains(&value) {
6196 return asm_err!(loc, "Bit index ({value}) must be between 0 and 7");
6197 }
6198
6199 asm.expect_symbol(SymbolName::Comma)?;
6200
6201 match asm.next()? {
6202 None => return asm.end_of_input_err(),
6203 Some(Token::Register {
6204 name: RegisterName::A,
6205 ..
6206 }) => {
6207 asm.data.push(0xCB);
6208 asm.data.push(match value {
6209 0 => 0xC7,
6210 1 => 0xCF,
6211 2 => 0xD7,
6212 3 => 0xDF,
6213 4 => 0xE7,
6214 5 => 0xEF,
6215 6 => 0xF7,
6216 7 => 0xFF,
6217 _ => unreachable!(),
6218 });
6219 }
6220
6221 Some(Token::Register {
6222 name: RegisterName::B,
6223 ..
6224 }) => {
6225 asm.data.push(0xCB);
6226 asm.data.push(match value {
6227 0 => 0xC0,
6228 1 => 0xC8,
6229 2 => 0xD0,
6230 3 => 0xD8,
6231 4 => 0xE0,
6232 5 => 0xE8,
6233 6 => 0xF0,
6234 7 => 0xF8,
6235 _ => unreachable!(),
6236 });
6237 }
6238
6239 Some(Token::Register {
6240 name: RegisterName::C,
6241 ..
6242 }) => {
6243 asm.data.push(0xCB);
6244 asm.data.push(match value {
6245 0 => 0xC1,
6246 1 => 0xC9,
6247 2 => 0xD1,
6248 3 => 0xD9,
6249 4 => 0xE1,
6250 5 => 0xE9,
6251 6 => 0xF1,
6252 7 => 0xF9,
6253 _ => unreachable!(),
6254 });
6255 }
6256
6257 Some(Token::Register {
6258 name: RegisterName::D,
6259 ..
6260 }) => {
6261 asm.data.push(0xCB);
6262 asm.data.push(match value {
6263 0 => 0xC2,
6264 1 => 0xCA,
6265 2 => 0xD2,
6266 3 => 0xDA,
6267 4 => 0xE2,
6268 5 => 0xEA,
6269 6 => 0xF2,
6270 7 => 0xFA,
6271 _ => unreachable!(),
6272 });
6273 }
6274
6275 Some(Token::Register {
6276 name: RegisterName::E,
6277 ..
6278 }) => {
6279 asm.data.push(0xCB);
6280 asm.data.push(match value {
6281 0 => 0xC3,
6282 1 => 0xCB,
6283 2 => 0xD3,
6284 3 => 0xDB,
6285 4 => 0xE3,
6286 5 => 0xEB,
6287 6 => 0xF3,
6288 7 => 0xFB,
6289 _ => unreachable!(),
6290 });
6291 }
6292
6293 Some(Token::Register {
6294 name: RegisterName::H,
6295 ..
6296 }) => {
6297 asm.data.push(0xCB);
6298 asm.data.push(match value {
6299 0 => 0xC4,
6300 1 => 0xCC,
6301 2 => 0xD4,
6302 3 => 0xDC,
6303 4 => 0xE4,
6304 5 => 0xEC,
6305 6 => 0xF4,
6306 7 => 0xFC,
6307 _ => unreachable!(),
6308 });
6309 }
6310
6311 Some(Token::Register {
6312 name: RegisterName::L,
6313 ..
6314 }) => {
6315 asm.data.push(0xCB);
6316 asm.data.push(match value {
6317 0 => 0xC5,
6318 1 => 0xCD,
6319 2 => 0xD5,
6320 3 => 0xDD,
6321 4 => 0xE5,
6322 5 => 0xED,
6323 6 => 0xF5,
6324 7 => 0xFD,
6325 _ => unreachable!(),
6326 });
6327 }
6328
6329 Some(Token::Symbol {
6330 name: SymbolName::ParenOpen,
6331 ..
6332 }) => {
6333 match asm.next()? {
6334 None => return asm.end_of_input_err(),
6335 Some(Token::Register { name: RegisterName::HL, .. }) => {
6336 asm.data.push(0xCB);
6337 asm.data.push(match value {
6338 0 => 0xC6,
6339 1 => 0xCE,
6340 2 => 0xD6,
6341 3 => 0xDE,
6342 4 => 0xE6,
6343 5 => 0xEE,
6344 6 => 0xF6,
6345 7 => 0xFE,
6346 _ => unreachable!(),
6347 });
6348 }
6349
6350 Some(Token::Register { name: RegisterName::IX, .. }) => {
6351 asm.expect_symbol(SymbolName::Plus)?;
6352 asm.data.push(0xDD);
6353 asm.data.push(0xCB);
6354 let (loc, expr) = asm.expr()?;
6355 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
6356 if (value as u32) > (u8::MAX as u32) {
6357 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
6358 }
6359 asm.data.push(value as u8);
6360 } else {
6361 asm.links.push(Link::byte(loc, asm.data.len(), expr));
6362 asm.data.push(0);
6363 }
6364 asm.data.push(match value {
6365 0 => 0xC6,
6366 1 => 0xCE,
6367 2 => 0xD6,
6368 3 => 0xDE,
6369 4 => 0xE6,
6370 5 => 0xEE,
6371 6 => 0xF6,
6372 7 => 0xFE,
6373 _ => unreachable!(),
6374 });
6375 }
6376
6377 Some(Token::Register { name: RegisterName::IY, .. }) => {
6378 asm.expect_symbol(SymbolName::Plus)?;
6379 asm.data.push(0xFD);
6380 asm.data.push(0xCB);
6381 let (loc, expr) = asm.expr()?;
6382 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
6383 if (value as u32) > (u8::MAX as u32) {
6384 return asm_err!(loc,"Expression result ({value}) will not fit in a byte");
6385 }
6386 asm.data.push(value as u8);
6387 } else {
6388 asm.links.push(Link::byte(loc, asm.data.len(), expr));
6389 asm.data.push(0);
6390 }
6391 asm.data.push(match value {
6392 0 => 0xC6,
6393 1 => 0xCE,
6394 2 => 0xD6,
6395 3 => 0xDE,
6396 4 => 0xE6,
6397 5 => 0xEE,
6398 6 => 0xF6,
6399 7 => 0xFE,
6400 _ => unreachable!(),
6401 });
6402 }
6403
6404 Some(tok) => return asm_err!(tok.loc(),"Unexpected {}, expected register \"hl\", \"ix\", or \"iy\"",tok.as_display(&asm.str_interner)),
6405 }
6406 asm.expect_symbol(SymbolName::ParenClose)?;
6407 }
6408
6409 Some(tok) => {
6410 return asm_err!(
6411 tok.loc(),
6412 "Unexpected {}, expected a register",
6413 tok.as_display(&asm.str_interner)
6414 )
6415 }
6416 }
6417 }
6418 }
6419 }
6420
6421 OperationName::Sla => {
6422 asm.next()?;
6423 match asm.next()? {
6424 None => return asm.end_of_input_err(),
6425 Some(Token::Register {
6426 name: RegisterName::A,
6427 ..
6428 }) => {
6429 asm.data.push(0xCB);
6430 asm.data.push(0x27);
6431 }
6432 Some(Token::Register {
6433 name: RegisterName::B,
6434 ..
6435 }) => {
6436 asm.data.push(0xCB);
6437 asm.data.push(0x20);
6438 }
6439 Some(Token::Register {
6440 name: RegisterName::C,
6441 ..
6442 }) => {
6443 asm.data.push(0xCB);
6444 asm.data.push(0x21);
6445 }
6446 Some(Token::Register {
6447 name: RegisterName::D,
6448 ..
6449 }) => {
6450 asm.data.push(0xCB);
6451 asm.data.push(0x22);
6452 }
6453 Some(Token::Register {
6454 name: RegisterName::E,
6455 ..
6456 }) => {
6457 asm.data.push(0xCB);
6458 asm.data.push(0x23);
6459 }
6460 Some(Token::Register {
6461 name: RegisterName::H,
6462 ..
6463 }) => {
6464 asm.data.push(0xCB);
6465 asm.data.push(0x24);
6466 }
6467 Some(Token::Register {
6468 name: RegisterName::L,
6469 ..
6470 }) => {
6471 asm.data.push(0xCB);
6472 asm.data.push(0x25);
6473 }
6474 Some(Token::Symbol {
6475 name: SymbolName::ParenOpen,
6476 ..
6477 }) => {
6478 match asm.next()? {
6479 None => return asm.end_of_input_err(),
6480 Some(Token::Register {
6481 name: RegisterName::HL,
6482 ..
6483 }) => {
6484 asm.data.push(0xCB);
6485 asm.data.push(0x26);
6486 }
6487 Some(Token::Register {
6488 name: RegisterName::IX,
6489 ..
6490 }) => {
6491 asm.expect_symbol(SymbolName::Plus)?;
6492 asm.data.push(0xDD);
6493 asm.data.push(0xCB);
6494 let (loc, expr) = asm.expr()?;
6495 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
6496 if (value as u32) > (u8::MAX as u32) {
6497 return asm_err!(
6498 loc,
6499 "Expression result ({value}) will not fit in a byte"
6500 );
6501 }
6502 asm.data.push(value as u8);
6503 } else {
6504 asm.links.push(Link::byte(loc, asm.data.len(), expr));
6505 asm.data.push(0);
6506 }
6507 asm.data.push(0x26);
6508 }
6509 Some(Token::Register {
6510 name: RegisterName::IY,
6511 ..
6512 }) => {
6513 asm.expect_symbol(SymbolName::Plus)?;
6514 asm.data.push(0xFD);
6515 asm.data.push(0xCB);
6516 let (loc, expr) = asm.expr()?;
6517 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
6518 if (value as u32) > (u8::MAX as u32) {
6519 return asm_err!(
6520 loc,
6521 "Expression result ({value}) will not fit in a byte"
6522 );
6523 }
6524 asm.data.push(value as u8);
6525 } else {
6526 asm.links.push(Link::byte(loc, asm.data.len(), expr));
6527 asm.data.push(0);
6528 }
6529 asm.data.push(0x26);
6530 }
6531 Some(tok) => {
6532 return asm_err!(
6533 tok.loc(),
6534 "Unexpected {}, expected register \"hl\", \"ix\", or \"iy\"",
6535 tok.as_display(&asm.str_interner)
6536 )
6537 }
6538 }
6539 asm.expect_symbol(SymbolName::ParenClose)?;
6540 }
6541 Some(tok) => {
6542 return asm_err!(
6543 tok.loc(),
6544 "Unexpected {}, expected register",
6545 tok.as_display(&asm.str_interner)
6546 )
6547 }
6548 }
6549 }
6550
6551 OperationName::Sll => {
6552 asm.next()?;
6553 match asm.next()? {
6554 None => return asm.end_of_input_err(),
6555 Some(Token::Register {
6556 name: RegisterName::A,
6557 ..
6558 }) => {
6559 asm.data.push(0xCB);
6560 asm.data.push(0x37);
6561 }
6562 Some(Token::Register {
6563 name: RegisterName::B,
6564 ..
6565 }) => {
6566 asm.data.push(0xCB);
6567 asm.data.push(0x30);
6568 }
6569 Some(Token::Register {
6570 name: RegisterName::C,
6571 ..
6572 }) => {
6573 asm.data.push(0xCB);
6574 asm.data.push(0x31);
6575 }
6576 Some(Token::Register {
6577 name: RegisterName::D,
6578 ..
6579 }) => {
6580 asm.data.push(0xCB);
6581 asm.data.push(0x32);
6582 }
6583 Some(Token::Register {
6584 name: RegisterName::E,
6585 ..
6586 }) => {
6587 asm.data.push(0xCB);
6588 asm.data.push(0x33);
6589 }
6590 Some(Token::Register {
6591 name: RegisterName::H,
6592 ..
6593 }) => {
6594 asm.data.push(0xCB);
6595 asm.data.push(0x34);
6596 }
6597 Some(Token::Register {
6598 name: RegisterName::L,
6599 ..
6600 }) => {
6601 asm.data.push(0xCB);
6602 asm.data.push(0x35);
6603 }
6604 Some(Token::Symbol {
6605 name: SymbolName::ParenOpen,
6606 ..
6607 }) => {
6608 match asm.next()? {
6609 None => return asm.end_of_input_err(),
6610 Some(Token::Register {
6611 name: RegisterName::HL,
6612 ..
6613 }) => {
6614 asm.data.push(0xCB);
6615 asm.data.push(0x36);
6616 }
6617 Some(Token::Register {
6618 name: RegisterName::IX,
6619 ..
6620 }) => {
6621 asm.expect_symbol(SymbolName::Plus)?;
6622 asm.data.push(0xDD);
6623 asm.data.push(0xCB);
6624 let (loc, expr) = asm.expr()?;
6625 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
6626 if (value as u32) > (u8::MAX as u32) {
6627 return asm_err!(
6628 loc,
6629 "Expression result ({value}) will not fit in a byte"
6630 );
6631 }
6632 asm.data.push(value as u8);
6633 } else {
6634 asm.links.push(Link::byte(loc, asm.data.len(), expr));
6635 asm.data.push(0);
6636 }
6637 asm.data.push(0x36);
6638 }
6639 Some(Token::Register {
6640 name: RegisterName::IY,
6641 ..
6642 }) => {
6643 asm.expect_symbol(SymbolName::Plus)?;
6644 asm.data.push(0xFD);
6645 asm.data.push(0xCB);
6646 let (loc, expr) = asm.expr()?;
6647 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
6648 if (value as u32) > (u8::MAX as u32) {
6649 return asm_err!(
6650 loc,
6651 "Expression result ({value}) will not fit in a byte"
6652 );
6653 }
6654 asm.data.push(value as u8);
6655 } else {
6656 asm.links.push(Link::byte(loc, asm.data.len(), expr));
6657 asm.data.push(0);
6658 }
6659 asm.data.push(0x36);
6660 }
6661 Some(tok) => {
6662 return asm_err!(
6663 tok.loc(),
6664 "Unexpected {}, expected register \"hl\", \"ix\", or \"iy\"",
6665 tok.as_display(&asm.str_interner)
6666 )
6667 }
6668 }
6669 asm.expect_symbol(SymbolName::ParenClose)?;
6670 }
6671 Some(tok) => {
6672 return asm_err!(
6673 tok.loc(),
6674 "Unexpected {}, expected register",
6675 tok.as_display(&asm.str_interner)
6676 )
6677 }
6678 }
6679 }
6680
6681 OperationName::Sra => {
6682 asm.next()?;
6683 match asm.next()? {
6684 None => return asm.end_of_input_err(),
6685 Some(Token::Register {
6686 name: RegisterName::A,
6687 ..
6688 }) => {
6689 asm.data.push(0xCB);
6690 asm.data.push(0x2F);
6691 }
6692 Some(Token::Register {
6693 name: RegisterName::B,
6694 ..
6695 }) => {
6696 asm.data.push(0xCB);
6697 asm.data.push(0x28);
6698 }
6699 Some(Token::Register {
6700 name: RegisterName::C,
6701 ..
6702 }) => {
6703 asm.data.push(0xCB);
6704 asm.data.push(0x29);
6705 }
6706 Some(Token::Register {
6707 name: RegisterName::D,
6708 ..
6709 }) => {
6710 asm.data.push(0xCB);
6711 asm.data.push(0x2A);
6712 }
6713 Some(Token::Register {
6714 name: RegisterName::E,
6715 ..
6716 }) => {
6717 asm.data.push(0xCB);
6718 asm.data.push(0x2B);
6719 }
6720 Some(Token::Register {
6721 name: RegisterName::H,
6722 ..
6723 }) => {
6724 asm.data.push(0xCB);
6725 asm.data.push(0x2C);
6726 }
6727 Some(Token::Register {
6728 name: RegisterName::L,
6729 ..
6730 }) => {
6731 asm.data.push(0xCB);
6732 asm.data.push(0x2D);
6733 }
6734 Some(Token::Symbol {
6735 name: SymbolName::ParenOpen,
6736 ..
6737 }) => {
6738 match asm.next()? {
6739 None => return asm.end_of_input_err(),
6740 Some(Token::Register {
6741 name: RegisterName::HL,
6742 ..
6743 }) => {
6744 asm.data.push(0xCB);
6745 asm.data.push(0x2E);
6746 }
6747 Some(Token::Register {
6748 name: RegisterName::IX,
6749 ..
6750 }) => {
6751 asm.expect_symbol(SymbolName::Plus)?;
6752 asm.data.push(0xDD);
6753 asm.data.push(0xCB);
6754 let (loc, expr) = asm.expr()?;
6755 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
6756 if (value as u32) > (u8::MAX as u32) {
6757 return asm_err!(
6758 loc,
6759 "Expression result ({value}) will not fit in a byte"
6760 );
6761 }
6762 asm.data.push(value as u8);
6763 } else {
6764 asm.links.push(Link::byte(loc, asm.data.len(), expr));
6765 asm.data.push(0);
6766 }
6767 asm.data.push(0x2E);
6768 }
6769 Some(Token::Register {
6770 name: RegisterName::IY,
6771 ..
6772 }) => {
6773 asm.expect_symbol(SymbolName::Plus)?;
6774 asm.data.push(0xFD);
6775 asm.data.push(0xCB);
6776 let (loc, expr) = asm.expr()?;
6777 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
6778 if (value as u32) > (u8::MAX as u32) {
6779 return asm_err!(
6780 loc,
6781 "Expression result ({value}) will not fit in a byte"
6782 );
6783 }
6784 asm.data.push(value as u8);
6785 } else {
6786 asm.links.push(Link::byte(loc, asm.data.len(), expr));
6787 asm.data.push(0);
6788 }
6789 asm.data.push(0x2E);
6790 }
6791 Some(tok) => {
6792 return asm_err!(
6793 tok.loc(),
6794 "Unexpected {}, expected register \"hl\", \"ix\", or \"iy\"",
6795 tok.as_display(&asm.str_interner)
6796 )
6797 }
6798 }
6799 asm.expect_symbol(SymbolName::ParenClose)?;
6800 }
6801 Some(tok) => {
6802 return asm_err!(
6803 tok.loc(),
6804 "Unexpected {}, expected register",
6805 tok.as_display(&asm.str_interner)
6806 )
6807 }
6808 }
6809 }
6810
6811 OperationName::Srl => {
6812 asm.next()?;
6813 match asm.next()? {
6814 None => return asm.end_of_input_err(),
6815 Some(Token::Register {
6816 name: RegisterName::A,
6817 ..
6818 }) => {
6819 asm.data.push(0xCB);
6820 asm.data.push(0x3F);
6821 }
6822 Some(Token::Register {
6823 name: RegisterName::B,
6824 ..
6825 }) => {
6826 asm.data.push(0xCB);
6827 asm.data.push(0x38);
6828 }
6829 Some(Token::Register {
6830 name: RegisterName::C,
6831 ..
6832 }) => {
6833 asm.data.push(0xCB);
6834 asm.data.push(0x39);
6835 }
6836 Some(Token::Register {
6837 name: RegisterName::D,
6838 ..
6839 }) => {
6840 asm.data.push(0xCB);
6841 asm.data.push(0x3A);
6842 }
6843 Some(Token::Register {
6844 name: RegisterName::E,
6845 ..
6846 }) => {
6847 asm.data.push(0xCB);
6848 asm.data.push(0x3B);
6849 }
6850 Some(Token::Register {
6851 name: RegisterName::H,
6852 ..
6853 }) => {
6854 asm.data.push(0xCB);
6855 asm.data.push(0x3C);
6856 }
6857 Some(Token::Register {
6858 name: RegisterName::L,
6859 ..
6860 }) => {
6861 asm.data.push(0xCB);
6862 asm.data.push(0x3D);
6863 }
6864 Some(Token::Symbol {
6865 name: SymbolName::ParenOpen,
6866 ..
6867 }) => {
6868 match asm.next()? {
6869 None => return asm.end_of_input_err(),
6870 Some(Token::Register {
6871 name: RegisterName::HL,
6872 ..
6873 }) => {
6874 asm.data.push(0xCB);
6875 asm.data.push(0x3E);
6876 }
6877 Some(Token::Register {
6878 name: RegisterName::IX,
6879 ..
6880 }) => {
6881 asm.expect_symbol(SymbolName::Plus)?;
6882 asm.data.push(0xDD);
6883 asm.data.push(0xCB);
6884 let (loc, expr) = asm.expr()?;
6885 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
6886 if (value as u32) > (u8::MAX as u32) {
6887 return asm_err!(
6888 loc,
6889 "Expression result ({value}) will not fit in a byte"
6890 );
6891 }
6892 asm.data.push(value as u8);
6893 } else {
6894 asm.links.push(Link::byte(loc, asm.data.len(), expr));
6895 asm.data.push(0);
6896 }
6897 asm.data.push(0x3E);
6898 }
6899 Some(Token::Register {
6900 name: RegisterName::IY,
6901 ..
6902 }) => {
6903 asm.expect_symbol(SymbolName::Plus)?;
6904 asm.data.push(0xFD);
6905 asm.data.push(0xCB);
6906 let (loc, expr) = asm.expr()?;
6907 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
6908 if (value as u32) > (u8::MAX as u32) {
6909 return asm_err!(
6910 loc,
6911 "Expression result ({value}) will not fit in a byte"
6912 );
6913 }
6914 asm.data.push(value as u8);
6915 } else {
6916 asm.links.push(Link::byte(loc, asm.data.len(), expr));
6917 asm.data.push(0);
6918 }
6919 asm.data.push(0x3E);
6920 }
6921 Some(tok) => {
6922 return asm_err!(
6923 tok.loc(),
6924 "Unexpected {}, expected register \"hl\", \"ix\", or \"iy\"",
6925 tok.as_display(&asm.str_interner)
6926 )
6927 }
6928 }
6929 asm.expect_symbol(SymbolName::ParenClose)?;
6930 }
6931 Some(tok) => {
6932 return asm_err!(
6933 tok.loc(),
6934 "Unexpected {}, expected register",
6935 tok.as_display(&asm.str_interner)
6936 )
6937 }
6938 }
6939 }
6940
6941 OperationName::Sub => {
6942 asm.next()?;
6943 match asm.peek()? {
6944 None => return asm.end_of_input_err(),
6945 Some(Token::Register {
6946 name: RegisterName::A,
6947 ..
6948 }) => {
6949 asm.next()?;
6950 asm.data.push(0x97);
6951 }
6952
6953 Some(Token::Register {
6954 name: RegisterName::B,
6955 ..
6956 }) => {
6957 asm.next()?;
6958 asm.data.push(0x90);
6959 }
6960
6961 Some(Token::Register {
6962 name: RegisterName::C,
6963 ..
6964 }) => {
6965 asm.next()?;
6966 asm.data.push(0x91);
6967 }
6968
6969 Some(Token::Register {
6970 name: RegisterName::D,
6971 ..
6972 }) => {
6973 asm.next()?;
6974 asm.data.push(0x92);
6975 }
6976
6977 Some(Token::Register {
6978 name: RegisterName::E,
6979 ..
6980 }) => {
6981 asm.next()?;
6982 asm.data.push(0x93);
6983 }
6984
6985 Some(Token::Register {
6986 name: RegisterName::H,
6987 ..
6988 }) => {
6989 asm.next()?;
6990 asm.data.push(0x94);
6991 }
6992
6993 Some(Token::Register {
6994 name: RegisterName::L,
6995 ..
6996 }) => {
6997 asm.next()?;
6998 asm.data.push(0x95);
6999 }
7000
7001 Some(Token::Register {
7002 name: RegisterName::IXH,
7003 ..
7004 }) => {
7005 asm.next()?;
7006 asm.data.push(0xDD);
7007 asm.data.push(0x94);
7008 }
7009
7010 Some(Token::Register {
7011 name: RegisterName::IXL,
7012 ..
7013 }) => {
7014 asm.next()?;
7015 asm.data.push(0xDD);
7016 asm.data.push(0x95);
7017 }
7018
7019 Some(Token::Register {
7020 name: RegisterName::IYH,
7021 ..
7022 }) => {
7023 asm.next()?;
7024 asm.data.push(0xFD);
7025 asm.data.push(0x94);
7026 }
7027
7028 Some(Token::Register {
7029 name: RegisterName::IYL,
7030 ..
7031 }) => {
7032 asm.next()?;
7033 asm.data.push(0xFD);
7034 asm.data.push(0x95);
7035 }
7036
7037 Some(Token::Symbol {
7038 name: SymbolName::ParenOpen,
7039 ..
7040 }) => {
7041 asm.next()?;
7042 match asm.next()? {
7043 None => return asm.end_of_input_err(),
7044 Some(Token::Register {
7045 name: RegisterName::HL,
7046 ..
7047 }) => {
7048 asm.data.push(0x96);
7049 asm.expect_symbol(SymbolName::ParenClose)?;
7050 }
7051
7052 Some(Token::Register {
7053 name: RegisterName::IX,
7054 ..
7055 }) => {
7056 asm.expect_symbol(SymbolName::Plus)?;
7057 asm.data.push(0xDD);
7058 asm.data.push(0x96);
7059 let (loc, expr) = asm.expr()?;
7060 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
7061 if (value as u32) > (u8::MAX as u32) {
7062 return asm_err!(
7063 loc,
7064 "Expression result ({value}) will not fit in a byte"
7065 );
7066 }
7067 asm.data.push(value as u8);
7068 } else {
7069 asm.links.push(Link::byte(loc, asm.data.len(), expr));
7070 asm.data.push(0);
7071 }
7072 asm.expect_symbol(SymbolName::ParenClose)?;
7073 }
7074
7075 Some(Token::Register {
7076 name: RegisterName::IY,
7077 ..
7078 }) => {
7079 asm.expect_symbol(SymbolName::Plus)?;
7080 asm.data.push(0xFD);
7081 asm.data.push(0x96);
7082 let (loc, expr) = asm.expr()?;
7083 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
7084 if (value as u32) > (u8::MAX as u32) {
7085 return asm_err!(
7086 loc,
7087 "Expression result ({value}) will not fit in a byte"
7088 );
7089 }
7090 asm.data.push(value as u8);
7091 } else {
7092 asm.links.push(Link::byte(loc, asm.data.len(), expr));
7093 asm.data.push(0);
7094 }
7095 asm.expect_symbol(SymbolName::ParenClose)?;
7096 }
7097 Some(tok) => {
7098 return asm_err!(
7099 tok.loc(),
7100 "Unexpected {}, expected register \"hl\", \"ix\", or \"iy\"",
7101 tok.as_display(&asm.str_interner)
7102 )
7103 }
7104 }
7105 }
7106 Some(_) => {
7107 asm.data.push(0xD6);
7108 let (loc, expr) = asm.expr()?;
7109 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
7110 if (value as u32) > (u8::MAX as u32) {
7111 return asm_err!(
7112 loc,
7113 "Expression result ({value}) will not fit in a byte"
7114 );
7115 }
7116 asm.data.push(value as u8);
7117 } else {
7118 asm.links.push(Link::byte(loc, asm.data.len(), expr));
7119 asm.data.push(0);
7120 }
7121 }
7122 }
7123 }
7124
7125 OperationName::Xor => {
7126 asm.next()?;
7127 match asm.peek()? {
7128 None => return asm.end_of_input_err(),
7129 Some(Token::Register {
7130 name: RegisterName::A,
7131 ..
7132 }) => {
7133 asm.next()?;
7134 asm.data.push(0xAF);
7135 }
7136
7137 Some(Token::Register {
7138 name: RegisterName::B,
7139 ..
7140 }) => {
7141 asm.next()?;
7142 asm.data.push(0xA8);
7143 }
7144
7145 Some(Token::Register {
7146 name: RegisterName::C,
7147 ..
7148 }) => {
7149 asm.next()?;
7150 asm.data.push(0xA9);
7151 }
7152
7153 Some(Token::Register {
7154 name: RegisterName::D,
7155 ..
7156 }) => {
7157 asm.next()?;
7158 asm.data.push(0xAA);
7159 }
7160
7161 Some(Token::Register {
7162 name: RegisterName::E,
7163 ..
7164 }) => {
7165 asm.next()?;
7166 asm.data.push(0xAB);
7167 }
7168
7169 Some(Token::Register {
7170 name: RegisterName::H,
7171 ..
7172 }) => {
7173 asm.next()?;
7174 asm.data.push(0xAC);
7175 }
7176
7177 Some(Token::Register {
7178 name: RegisterName::L,
7179 ..
7180 }) => {
7181 asm.next()?;
7182 asm.data.push(0xAD);
7183 }
7184
7185 Some(Token::Register {
7186 name: RegisterName::IXH,
7187 ..
7188 }) => {
7189 asm.next()?;
7190 asm.data.push(0xDD);
7191 asm.data.push(0xAC);
7192 }
7193
7194 Some(Token::Register {
7195 name: RegisterName::IXL,
7196 ..
7197 }) => {
7198 asm.next()?;
7199 asm.data.push(0xDD);
7200 asm.data.push(0xAD);
7201 }
7202
7203 Some(Token::Register {
7204 name: RegisterName::IYH,
7205 ..
7206 }) => {
7207 asm.next()?;
7208 asm.data.push(0xFD);
7209 asm.data.push(0xAC);
7210 }
7211
7212 Some(Token::Register {
7213 name: RegisterName::IYL,
7214 ..
7215 }) => {
7216 asm.next()?;
7217 asm.data.push(0xFD);
7218 asm.data.push(0xAD);
7219 }
7220
7221 Some(Token::Symbol {
7222 name: SymbolName::ParenOpen,
7223 ..
7224 }) => {
7225 asm.next()?;
7226 match asm.next()? {
7227 None => return asm.end_of_input_err(),
7228 Some(Token::Register {
7229 name: RegisterName::HL,
7230 ..
7231 }) => {
7232 asm.data.push(0xAE);
7233 asm.expect_symbol(SymbolName::ParenClose)?;
7234 }
7235
7236 Some(Token::Register {
7237 name: RegisterName::IX,
7238 ..
7239 }) => {
7240 asm.expect_symbol(SymbolName::Plus)?;
7241 asm.data.push(0xDD);
7242 asm.data.push(0xAE);
7243 let (loc, expr) = asm.expr()?;
7244 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
7245 if (value as u32) > (u8::MAX as u32) {
7246 return asm_err!(
7247 loc,
7248 "Expression result ({value}) will not fit in a byte"
7249 );
7250 }
7251 asm.data.push(value as u8);
7252 } else {
7253 asm.links.push(Link::byte(loc, asm.data.len(), expr));
7254 asm.data.push(0);
7255 }
7256 asm.expect_symbol(SymbolName::ParenClose)?;
7257 }
7258
7259 Some(Token::Register {
7260 name: RegisterName::IY,
7261 ..
7262 }) => {
7263 asm.expect_symbol(SymbolName::Plus)?;
7264 asm.data.push(0xFD);
7265 asm.data.push(0xAE);
7266 let (loc, expr) = asm.expr()?;
7267 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
7268 if (value as u32) > (u8::MAX as u32) {
7269 return asm_err!(
7270 loc,
7271 "Expression result ({value}) will not fit in a byte"
7272 );
7273 }
7274 asm.data.push(value as u8);
7275 } else {
7276 asm.links.push(Link::byte(loc, asm.data.len(), expr));
7277 asm.data.push(0);
7278 }
7279 asm.expect_symbol(SymbolName::ParenClose)?;
7280 }
7281 Some(tok) => {
7282 return asm_err!(
7283 tok.loc(),
7284 "Unexpected {}, expected registers \"hl\", \"ix\", or \"iy\"",
7285 tok.as_display(&asm.str_interner)
7286 )
7287 }
7288 }
7289 }
7290
7291 Some(_) => {
7292 asm.data.push(0xEE);
7293 let (loc, expr) = asm.expr()?;
7294 if let Some(value) = expr.evaluate(&asm.symtab, &asm.str_interner) {
7295 if (value as u32) > (u8::MAX as u32) {
7296 return asm_err!(
7297 loc,
7298 "Expression result ({value}) will not fit in a byte"
7299 );
7300 }
7301 asm.data.push(value as u8);
7302 } else {
7303 asm.links.push(Link::byte(loc, asm.data.len(), expr));
7304 asm.data.push(0);
7305 }
7306 }
7307 }
7308 }
7309 }
7310 Ok(())
7311 }
7312}