csx64 0.1.0

An Intel-style x64 assembler and executor.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
use std::collections::{HashMap, BTreeMap, BTreeSet};

use super::expr::*;
use super::{Size, AsmSegment};
use super::caseless::Caseless;

macro_rules! insert {
    ($m:ident : $key:expr => $val:expr) => {
        assert!($m.insert($key, $val).is_none())
    };
    ($s:ident : $val:expr) => {
        assert!($s.insert($val))
    }
}
macro_rules! alias {
    ($m:ident : $from:expr => $to:expr) => {{
        let v = *$m.get(&$to).unwrap();
        insert!($m: $from => v);
    }}
}

pub(super) const COMMENT_CHAR: char = ';';
pub(super) const LABEL_DEF_CHAR: char = ':';

pub(super) const MAX_ALIGN: u64 = 1024;

// these must be ordered in descending order of length to parse correctly (hence array)
pub(super) const BINARY_OP_STR: &'static[(&'static str, OP)] = &[
    ("<<", OP::SHL),
    (">>", OP::SHR),
    ("==", OP::Equ),
    ("!=", OP::Neq),
    ("<=", OP::LessE),
    (">=", OP::GreatE),

    ("*", OP::Mul),
    ("/", OP::Div),
    ("%", OP::Mod),
    ("+", OP::Add),
    ("-", OP::Sub),
    ("<", OP::Less),
    (">", OP::Great),
    ("&", OP::And),
    ("^", OP::Xor),
    ("|", OP::Or),
];

#[derive(Clone, Copy, PartialEq, Eq)]
pub(super) enum Associativity {
    Left, //Right, // currently everything we support is left associative, but maybe that'll change at some point
}

lazy_static! {
    pub(super) static ref PRECEDENCE: HashMap<OP, (i32, Associativity)> = {
        let mut m = HashMap::new();
        
        insert!(m: OP::Mul => (5, Associativity::Left));

        insert!(m: OP::Div => (5, Associativity::Left));
        insert!(m: OP::Mod => (5, Associativity::Left));

        insert!(m: OP::Add => (6, Associativity::Left));
        insert!(m: OP::Sub => (6, Associativity::Left));

        insert!(m: OP::SHL => (7, Associativity::Left));
        insert!(m: OP::SHR => (7, Associativity::Left));

        insert!(m: OP::Less => (9, Associativity::Left));
        insert!(m: OP::LessE => (9, Associativity::Left));
        insert!(m: OP::Great => (9, Associativity::Left));
        insert!(m: OP::GreatE => (9, Associativity::Left));

        insert!(m: OP::Equ => (10, Associativity::Left));
        insert!(m: OP::Neq => (10, Associativity::Left));

        insert!(m: OP::And => (11, Associativity::Left));
        insert!(m: OP::Xor => (12, Associativity::Left));
        insert!(m: OP::Or => (13, Associativity::Left));

        m
    };
}

lazy_static! {
    pub(super) static ref UNARY_FUNCTION_OPERATOR_TO_OP: BTreeMap<&'static str, OP> = {
        let mut m = BTreeMap::new();

        insert!(m: "$len" => OP::Length);
        
        m
    };
}

pub(super) fn get_seg_offset_str(seg: AsmSegment) -> &'static str {
    match seg {
        AsmSegment::Text => "#t",
        AsmSegment::Rodata => "#r",
        AsmSegment::Data => "#d",
        AsmSegment::Bss => "#b",
    }
}
pub(super) fn get_seg_origin_str(seg: AsmSegment) -> &'static str {
    match seg {
        AsmSegment::Text => "#T",
        AsmSegment::Rodata => "#R",
        AsmSegment::Data => "#D",
        AsmSegment::Bss => "#B",
    }
}

pub(super) const BINARY_LITERAL_SYMBOL_PREFIX: &'static str = "#L";

pub(super) const PTRDIFF_IDS: &[&'static str] = &["#t", "#r", "#d", "#b", "#T", "#R", "#D", "#B"];

lazy_static! {
    pub(super) static ref SIZE_KEYWORDS: BTreeMap<Caseless<'static>, Size> = {
        let mut m = BTreeMap::new();

        insert!(m: Caseless("BYTE") => Size::Byte);
        insert!(m: Caseless("WORD") => Size::Word);
        insert!(m: Caseless("DWORD") => Size::Dword);
        insert!(m: Caseless("QWORD") => Size::Qword);
        insert!(m: Caseless("XWORD") => Size::Xword);
        insert!(m: Caseless("YWORD") => Size::Yword);
        insert!(m: Caseless("ZWORD") => Size::Zword);
        insert!(m: Caseless("TWORD") => Size::Tword);

        m
    };
}

#[derive(Clone, Copy, Debug)]
pub(super) struct CPURegisterInfo {
    pub(super) id: u8,
    pub(super) size: Size,
    pub(super) high: bool,
}
lazy_static! {
    pub(super) static ref CPU_REGISTER_INFO: BTreeMap<Caseless<'static>, CPURegisterInfo> = {
        let mut m = BTreeMap::new();

        insert!(m: Caseless("RAX") => CPURegisterInfo { id: 0, size: Size::Qword, high: false });
        insert!(m: Caseless("RBX") => CPURegisterInfo { id: 1, size: Size::Qword, high: false });
        insert!(m: Caseless("RCX") => CPURegisterInfo { id: 2, size: Size::Qword, high: false });
        insert!(m: Caseless("RDX") => CPURegisterInfo { id: 3, size: Size::Qword, high: false });
        insert!(m: Caseless("RSI") => CPURegisterInfo { id: 4, size: Size::Qword, high: false });
        insert!(m: Caseless("RDI") => CPURegisterInfo { id: 5, size: Size::Qword, high: false });
        insert!(m: Caseless("RBP") => CPURegisterInfo { id: 6, size: Size::Qword, high: false });
        insert!(m: Caseless("RSP") => CPURegisterInfo { id: 7, size: Size::Qword, high: false });
        insert!(m: Caseless("R8") => CPURegisterInfo { id: 8, size: Size::Qword, high: false });
        insert!(m: Caseless("R9") => CPURegisterInfo { id: 9, size: Size::Qword, high: false });
        insert!(m: Caseless("R10") => CPURegisterInfo { id: 10, size: Size::Qword, high: false });
        insert!(m: Caseless("R11") => CPURegisterInfo { id: 11, size: Size::Qword, high: false });
        insert!(m: Caseless("R12") => CPURegisterInfo { id: 12, size: Size::Qword, high: false });
        insert!(m: Caseless("R13") => CPURegisterInfo { id: 13, size: Size::Qword, high: false });
        insert!(m: Caseless("R14") => CPURegisterInfo { id: 14, size: Size::Qword, high: false });
        insert!(m: Caseless("R15") => CPURegisterInfo { id: 15, size: Size::Qword, high: false });

        insert!(m: Caseless("EAX") => CPURegisterInfo { id: 0, size: Size::Dword, high: false });
        insert!(m: Caseless("EBX") => CPURegisterInfo { id: 1, size: Size::Dword, high: false });
        insert!(m: Caseless("ECX") => CPURegisterInfo { id: 2, size: Size::Dword, high: false });
        insert!(m: Caseless("EDX") => CPURegisterInfo { id: 3, size: Size::Dword, high: false });
        insert!(m: Caseless("ESI") => CPURegisterInfo { id: 4, size: Size::Dword, high: false });
        insert!(m: Caseless("EDI") => CPURegisterInfo { id: 5, size: Size::Dword, high: false });
        insert!(m: Caseless("EBP") => CPURegisterInfo { id: 6, size: Size::Dword, high: false });
        insert!(m: Caseless("ESP") => CPURegisterInfo { id: 7, size: Size::Dword, high: false });
        insert!(m: Caseless("R8D") => CPURegisterInfo { id: 8, size: Size::Dword, high: false });
        insert!(m: Caseless("R9D") => CPURegisterInfo { id: 9, size: Size::Dword, high: false });
        insert!(m: Caseless("R10D") => CPURegisterInfo { id: 10, size: Size::Dword, high: false });
        insert!(m: Caseless("R11D") => CPURegisterInfo { id: 11, size: Size::Dword, high: false });
        insert!(m: Caseless("R12D") => CPURegisterInfo { id: 12, size: Size::Dword, high: false });
        insert!(m: Caseless("R13D") => CPURegisterInfo { id: 13, size: Size::Dword, high: false });
        insert!(m: Caseless("R14D") => CPURegisterInfo { id: 14, size: Size::Dword, high: false });
        insert!(m: Caseless("R15D") => CPURegisterInfo { id: 15, size: Size::Dword, high: false });

        insert!(m: Caseless("AX") => CPURegisterInfo { id: 0, size: Size::Word, high: false });
        insert!(m: Caseless("BX") => CPURegisterInfo { id: 1, size: Size::Word, high: false });
        insert!(m: Caseless("CX") => CPURegisterInfo { id: 2, size: Size::Word, high: false });
        insert!(m: Caseless("DX") => CPURegisterInfo { id: 3, size: Size::Word, high: false });
        insert!(m: Caseless("SI") => CPURegisterInfo { id: 4, size: Size::Word, high: false });
        insert!(m: Caseless("DI") => CPURegisterInfo { id: 5, size: Size::Word, high: false });
        insert!(m: Caseless("BP") => CPURegisterInfo { id: 6, size: Size::Word, high: false });
        insert!(m: Caseless("SP") => CPURegisterInfo { id: 7, size: Size::Word, high: false });
        insert!(m: Caseless("R8W") => CPURegisterInfo { id: 8, size: Size::Word, high: false });
        insert!(m: Caseless("R9W") => CPURegisterInfo { id: 9, size: Size::Word, high: false });
        insert!(m: Caseless("R10W") => CPURegisterInfo { id: 10, size: Size::Word, high: false });
        insert!(m: Caseless("R11W") => CPURegisterInfo { id: 11, size: Size::Word, high: false });
        insert!(m: Caseless("R12W") => CPURegisterInfo { id: 12, size: Size::Word, high: false });
        insert!(m: Caseless("R13W") => CPURegisterInfo { id: 13, size: Size::Word, high: false });
        insert!(m: Caseless("R14W") => CPURegisterInfo { id: 14, size: Size::Word, high: false });
        insert!(m: Caseless("R15W") => CPURegisterInfo { id: 15, size: Size::Word, high: false });

        insert!(m: Caseless("AL") => CPURegisterInfo { id: 0, size: Size::Byte, high: false });
        insert!(m: Caseless("BL") => CPURegisterInfo { id: 1, size: Size::Byte, high: false });
        insert!(m: Caseless("CL") => CPURegisterInfo { id: 2, size: Size::Byte, high: false });
        insert!(m: Caseless("DL") => CPURegisterInfo { id: 3, size: Size::Byte, high: false });
        insert!(m: Caseless("SIL") => CPURegisterInfo { id: 4, size: Size::Byte, high: false });
        insert!(m: Caseless("DIL") => CPURegisterInfo { id: 5, size: Size::Byte, high: false });
        insert!(m: Caseless("BPL") => CPURegisterInfo { id: 6, size: Size::Byte, high: false });
        insert!(m: Caseless("SPL") => CPURegisterInfo { id: 7, size: Size::Byte, high: false });
        insert!(m: Caseless("R8B") => CPURegisterInfo { id: 8, size: Size::Byte, high: false });
        insert!(m: Caseless("R9B") => CPURegisterInfo { id: 9, size: Size::Byte, high: false });
        insert!(m: Caseless("R10B") => CPURegisterInfo { id: 10, size: Size::Byte, high: false });
        insert!(m: Caseless("R11B") => CPURegisterInfo { id: 11, size: Size::Byte, high: false });
        insert!(m: Caseless("R12B") => CPURegisterInfo { id: 12, size: Size::Byte, high: false });
        insert!(m: Caseless("R13B") => CPURegisterInfo { id: 13, size: Size::Byte, high: false });
        insert!(m: Caseless("R14B") => CPURegisterInfo { id: 14, size: Size::Byte, high: false });
        insert!(m: Caseless("R15B") => CPURegisterInfo { id: 15, size: Size::Byte, high: false });

        insert!(m: Caseless("AH") => CPURegisterInfo { id: 0, size: Size::Byte, high: true });
        insert!(m: Caseless("BH") => CPURegisterInfo { id: 1, size: Size::Byte, high: true });
        insert!(m: Caseless("CH") => CPURegisterInfo { id: 2, size: Size::Byte, high: true });
        insert!(m: Caseless("DH") => CPURegisterInfo { id: 3, size: Size::Byte, high: true });

        m
    };
}

#[derive(Clone, Copy, Debug)]
pub(super) struct FPURegisterInfo {
    pub(super) id: u8,
}
lazy_static! {
    pub(super) static ref FPU_REGISTER_INFO: BTreeMap<Caseless<'static>, FPURegisterInfo> = {
        let mut m = BTreeMap::new();

        insert!(m: Caseless("ST") => FPURegisterInfo { id: 0 });

        insert!(m: Caseless("ST0") => FPURegisterInfo { id: 0 });
        insert!(m: Caseless("ST1") => FPURegisterInfo { id: 1 });
        insert!(m: Caseless("ST2") => FPURegisterInfo { id: 2 });
        insert!(m: Caseless("ST3") => FPURegisterInfo { id: 3 });
        insert!(m: Caseless("ST4") => FPURegisterInfo { id: 4 });
        insert!(m: Caseless("ST5") => FPURegisterInfo { id: 5 });
        insert!(m: Caseless("ST6") => FPURegisterInfo { id: 6 });
        insert!(m: Caseless("ST7") => FPURegisterInfo { id: 7 });

        m
    };
}

#[derive(Clone, Copy, Debug)]
pub(super) struct VPUMaskRegisterInfo {
    pub(super) id: u8,
}
lazy_static! {
    pub(super) static ref VPU_MASK_REGISTER_INFO: BTreeMap<Caseless<'static>, VPUMaskRegisterInfo> = {
        let mut m = BTreeMap::new();

        insert!(m: Caseless("K0") => VPUMaskRegisterInfo { id: 0 });
        insert!(m: Caseless("K1") => VPUMaskRegisterInfo { id: 1 });
        insert!(m: Caseless("K2") => VPUMaskRegisterInfo { id: 2 });
        insert!(m: Caseless("K3") => VPUMaskRegisterInfo { id: 3 });
        insert!(m: Caseless("K4") => VPUMaskRegisterInfo { id: 4 });
        insert!(m: Caseless("K5") => VPUMaskRegisterInfo { id: 5 });
        insert!(m: Caseless("K6") => VPUMaskRegisterInfo { id: 6 });
        insert!(m: Caseless("K7") => VPUMaskRegisterInfo { id: 7 });

        m
    };
}

#[derive(Clone, Copy, Debug)]
pub(super) struct VPURegisterInfo {
    pub(super) id: u8,
    pub(super) size: Size,
}
lazy_static! {
    pub(super) static ref VPU_REGISTER_INFO: BTreeMap<Caseless<'static>, VPURegisterInfo> = {
        let mut m = BTreeMap::new();

        insert!(m: Caseless("XMM0") => VPURegisterInfo { id: 0, size: Size::Xword });
        insert!(m: Caseless("XMM1") => VPURegisterInfo { id: 1, size: Size::Xword });
        insert!(m: Caseless("XMM2") => VPURegisterInfo { id: 2, size: Size::Xword });
        insert!(m: Caseless("XMM3") => VPURegisterInfo { id: 3, size: Size::Xword });
        insert!(m: Caseless("XMM4") => VPURegisterInfo { id: 4, size: Size::Xword });
        insert!(m: Caseless("XMM5") => VPURegisterInfo { id: 5, size: Size::Xword });
        insert!(m: Caseless("XMM6") => VPURegisterInfo { id: 6, size: Size::Xword });
        insert!(m: Caseless("XMM7") => VPURegisterInfo { id: 7, size: Size::Xword });
        insert!(m: Caseless("XMM8") => VPURegisterInfo { id: 8, size: Size::Xword });
        insert!(m: Caseless("XMM9") => VPURegisterInfo { id: 9, size: Size::Xword });
        insert!(m: Caseless("XMM10") => VPURegisterInfo { id: 10, size: Size::Xword });
        insert!(m: Caseless("XMM11") => VPURegisterInfo { id: 11, size: Size::Xword });
        insert!(m: Caseless("XMM12") => VPURegisterInfo { id: 12, size: Size::Xword });
        insert!(m: Caseless("XMM13") => VPURegisterInfo { id: 13, size: Size::Xword });
        insert!(m: Caseless("XMM14") => VPURegisterInfo { id: 14, size: Size::Xword });
        insert!(m: Caseless("XMM15") => VPURegisterInfo { id: 15, size: Size::Xword });

        insert!(m: Caseless("YMM0") => VPURegisterInfo { id: 0, size: Size::Yword });
        insert!(m: Caseless("YMM1") => VPURegisterInfo { id: 1, size: Size::Yword });
        insert!(m: Caseless("YMM2") => VPURegisterInfo { id: 2, size: Size::Yword });
        insert!(m: Caseless("YMM3") => VPURegisterInfo { id: 3, size: Size::Yword });
        insert!(m: Caseless("YMM4") => VPURegisterInfo { id: 4, size: Size::Yword });
        insert!(m: Caseless("YMM5") => VPURegisterInfo { id: 5, size: Size::Yword });
        insert!(m: Caseless("YMM6") => VPURegisterInfo { id: 6, size: Size::Yword });
        insert!(m: Caseless("YMM7") => VPURegisterInfo { id: 7, size: Size::Yword });
        insert!(m: Caseless("YMM8") => VPURegisterInfo { id: 8, size: Size::Yword });
        insert!(m: Caseless("YMM9") => VPURegisterInfo { id: 9, size: Size::Yword });
        insert!(m: Caseless("YMM10") => VPURegisterInfo { id: 10, size: Size::Yword });
        insert!(m: Caseless("YMM11") => VPURegisterInfo { id: 11, size: Size::Yword });
        insert!(m: Caseless("YMM12") => VPURegisterInfo { id: 12, size: Size::Yword });
        insert!(m: Caseless("YMM13") => VPURegisterInfo { id: 13, size: Size::Yword });
        insert!(m: Caseless("YMM14") => VPURegisterInfo { id: 14, size: Size::Yword });
        insert!(m: Caseless("YMM15") => VPURegisterInfo { id: 15, size: Size::Yword });

        insert!(m: Caseless("ZMM0") => VPURegisterInfo { id: 0, size: Size::Zword });
        insert!(m: Caseless("ZMM1") => VPURegisterInfo { id: 1, size: Size::Zword });
        insert!(m: Caseless("ZMM2") => VPURegisterInfo { id: 2, size: Size::Zword });
        insert!(m: Caseless("ZMM3") => VPURegisterInfo { id: 3, size: Size::Zword });
        insert!(m: Caseless("ZMM4") => VPURegisterInfo { id: 4, size: Size::Zword });
        insert!(m: Caseless("ZMM5") => VPURegisterInfo { id: 5, size: Size::Zword });
        insert!(m: Caseless("ZMM6") => VPURegisterInfo { id: 6, size: Size::Zword });
        insert!(m: Caseless("ZMM7") => VPURegisterInfo { id: 7, size: Size::Zword });
        insert!(m: Caseless("ZMM8") => VPURegisterInfo { id: 8, size: Size::Zword });
        insert!(m: Caseless("ZMM9") => VPURegisterInfo { id: 9, size: Size::Zword });
        insert!(m: Caseless("ZMM10") => VPURegisterInfo { id: 10, size: Size::Zword });
        insert!(m: Caseless("ZMM11") => VPURegisterInfo { id: 11, size: Size::Zword });
        insert!(m: Caseless("ZMM12") => VPURegisterInfo { id: 12, size: Size::Zword });
        insert!(m: Caseless("ZMM13") => VPURegisterInfo { id: 13, size: Size::Zword });
        insert!(m: Caseless("ZMM14") => VPURegisterInfo { id: 14, size: Size::Zword });
        insert!(m: Caseless("ZMM15") => VPURegisterInfo { id: 15, size: Size::Zword });
        insert!(m: Caseless("ZMM16") => VPURegisterInfo { id: 16, size: Size::Zword });
        insert!(m: Caseless("ZMM17") => VPURegisterInfo { id: 17, size: Size::Zword });
        insert!(m: Caseless("ZMM18") => VPURegisterInfo { id: 18, size: Size::Zword });
        insert!(m: Caseless("ZMM19") => VPURegisterInfo { id: 19, size: Size::Zword });
        insert!(m: Caseless("ZMM20") => VPURegisterInfo { id: 20, size: Size::Zword });
        insert!(m: Caseless("ZMM21") => VPURegisterInfo { id: 21, size: Size::Zword });
        insert!(m: Caseless("ZMM22") => VPURegisterInfo { id: 22, size: Size::Zword });
        insert!(m: Caseless("ZMM23") => VPURegisterInfo { id: 23, size: Size::Zword });
        insert!(m: Caseless("ZMM24") => VPURegisterInfo { id: 24, size: Size::Zword });
        insert!(m: Caseless("ZMM25") => VPURegisterInfo { id: 25, size: Size::Zword });
        insert!(m: Caseless("ZMM26") => VPURegisterInfo { id: 26, size: Size::Zword });
        insert!(m: Caseless("ZMM27") => VPURegisterInfo { id: 27, size: Size::Zword });
        insert!(m: Caseless("ZMM28") => VPURegisterInfo { id: 28, size: Size::Zword });
        insert!(m: Caseless("ZMM29") => VPURegisterInfo { id: 29, size: Size::Zword });
        insert!(m: Caseless("ZMM30") => VPURegisterInfo { id: 30, size: Size::Zword });
        insert!(m: Caseless("ZMM31") => VPURegisterInfo { id: 31, size: Size::Zword });

        m
    };
}

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub(super) enum Prefix {
    REP, REPZ, REPNZ,
    LOCK,
}

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub(super) enum Instruction {
    EQU,
    SEGMENT,
    GLOBAL, EXTERN,
    ALIGN,
    ASSERT,
    DECLARE(Size), RESERVE(Size),
    NOP, HLT, SYSCALL,
    LFENCE, SFENCE, MFENCE,
    MOV, CMOVcc(u8), SETcc(u8), LEA, XCHG,
    FLAGBIT(u8),
    ADD, SUB, CMP,
    AND, OR, XOR, TEST,
    SHIFT(u8), SHIFTX(u8), BTX(u8),
    MUL, IMUL, MULX, IMULX, DIV, IDIV,
    JMP, Jcc(u8), LOOPcc(u8), CALL, RET,
    PUSH, POP,
    INC, DEC, NEG, NOT,
    MOVS(Size), STOS(Size),
    FINIT,
    FLD(bool),
    FADD(bool, bool), FSUB(bool, bool), FSUBR(bool, bool),
    DEBUG(u8),
}

lazy_static! {
    pub(super) static ref PREFIXES: BTreeMap<Caseless<'static>, Prefix> = {
        let mut m = BTreeMap::new();

        insert!(m: Caseless("REP") => Prefix::REP);
        insert!(m: Caseless("REPZ") => Prefix::REPZ);
        insert!(m: Caseless("REPNZ") => Prefix::REPNZ);

        alias!(m: Caseless("REPE") => Caseless("REPZ"));
        alias!(m: Caseless("REPNE") => Caseless("REPNZ"));

        insert!(m: Caseless("LOCK") => Prefix::LOCK);

        m
    };
    pub(super) static ref INSTRUCTIONS: BTreeMap<Caseless<'static>, Instruction> = {
        let mut m = BTreeMap::new();
        
        insert!(m: Caseless("EQU") => Instruction::EQU);
        insert!(m: Caseless("SEGMENT") => Instruction::SEGMENT);

        insert!(m: Caseless("GLOBAL") => Instruction::GLOBAL);
        insert!(m: Caseless("EXTERN") => Instruction::EXTERN);

        insert!(m: Caseless("ALIGN") => Instruction::ALIGN);

        insert!(m: Caseless("STATIC_ASSERT") => Instruction::ASSERT);
        
        insert!(m: Caseless("DB") => Instruction::DECLARE(Size::Byte));
        insert!(m: Caseless("DW") => Instruction::DECLARE(Size::Word));
        insert!(m: Caseless("DD") => Instruction::DECLARE(Size::Dword));
        insert!(m: Caseless("DQ") => Instruction::DECLARE(Size::Qword));
        insert!(m: Caseless("DX") => Instruction::DECLARE(Size::Xword));
        insert!(m: Caseless("DY") => Instruction::DECLARE(Size::Yword));
        insert!(m: Caseless("DZ") => Instruction::DECLARE(Size::Zword));
        insert!(m: Caseless("DT") => Instruction::DECLARE(Size::Tword));

        insert!(m: Caseless("RESB") => Instruction::RESERVE(Size::Byte));
        insert!(m: Caseless("RESW") => Instruction::RESERVE(Size::Word));
        insert!(m: Caseless("RESD") => Instruction::RESERVE(Size::Dword));
        insert!(m: Caseless("RESQ") => Instruction::RESERVE(Size::Qword));
        insert!(m: Caseless("RESX") => Instruction::RESERVE(Size::Xword));
        insert!(m: Caseless("RESY") => Instruction::RESERVE(Size::Yword));
        insert!(m: Caseless("RESZ") => Instruction::RESERVE(Size::Zword));
        insert!(m: Caseless("REST") => Instruction::RESERVE(Size::Tword));

        insert!(m: Caseless("NOP") => Instruction::NOP);
        insert!(m: Caseless("HLT") => Instruction::HLT);
        insert!(m: Caseless("SYSCALL") => Instruction::SYSCALL);

        alias!(m: Caseless("PAUSE") => Caseless("HLT"));

        insert!(m: Caseless("LFENCE") => Instruction::LFENCE);
        insert!(m: Caseless("SFENCE") => Instruction::SFENCE);
        insert!(m: Caseless("MFENCE") => Instruction::MFENCE);
        
        insert!(m: Caseless("MOV") => Instruction::MOV);
        
        insert!(m: Caseless("CMOVZ") => Instruction::CMOVcc(0));
        insert!(m: Caseless("CMOVNZ") => Instruction::CMOVcc(1));
        insert!(m: Caseless("CMOVS") => Instruction::CMOVcc(2));
        insert!(m: Caseless("CMOVNS") => Instruction::CMOVcc(3));
        insert!(m: Caseless("CMOVP") => Instruction::CMOVcc(4));
        insert!(m: Caseless("CMOVNP") => Instruction::CMOVcc(5));
        insert!(m: Caseless("CMOVO") => Instruction::CMOVcc(6));
        insert!(m: Caseless("CMOVNO") => Instruction::CMOVcc(7));
        insert!(m: Caseless("CMOVC") => Instruction::CMOVcc(8));
        insert!(m: Caseless("CMOVNC") => Instruction::CMOVcc(9));
        insert!(m: Caseless("CMOVB") => Instruction::CMOVcc(10));
        insert!(m: Caseless("CMOVBE") => Instruction::CMOVcc(11));
        insert!(m: Caseless("CMOVA") => Instruction::CMOVcc(12));
        insert!(m: Caseless("CMOVAE") => Instruction::CMOVcc(13));
        insert!(m: Caseless("CMOVL") => Instruction::CMOVcc(14));
        insert!(m: Caseless("CMOVLE") => Instruction::CMOVcc(15));
        insert!(m: Caseless("CMOVG") => Instruction::CMOVcc(16));
        insert!(m: Caseless("CMOVGE") => Instruction::CMOVcc(17));

        alias!(m: Caseless("CMOVE") => Caseless("CMOVZ"));
        alias!(m: Caseless("CMOVNE") => Caseless("CMOVNZ"));
        alias!(m: Caseless("CMOVPE") => Caseless("CMOVP"));
        alias!(m: Caseless("CMOVPO") => Caseless("CMOVNP"));
        alias!(m: Caseless("CMOVNAE") => Caseless("CMOVB"));
        alias!(m: Caseless("CMOVNA") => Caseless("CMOVBE"));
        alias!(m: Caseless("CMOVNBE") => Caseless("CMOVA"));
        alias!(m: Caseless("CMOVNB") => Caseless("CMOVAE"));
        alias!(m: Caseless("CMOVNGE") => Caseless("CMOVL"));
        alias!(m: Caseless("CMOVNG") => Caseless("CMOVLE"));
        alias!(m: Caseless("CMOVNLE") => Caseless("CMOVG"));
        alias!(m: Caseless("CMOVNL") => Caseless("CMOVGE"));
        
        insert!(m: Caseless("LEA") => Instruction::LEA);
        insert!(m: Caseless("XCHG") => Instruction::XCHG);

        insert!(m: Caseless("SETZ") => Instruction::SETcc(0));
        insert!(m: Caseless("SETNZ") => Instruction::SETcc(1));
        insert!(m: Caseless("SETS") => Instruction::SETcc(2));
        insert!(m: Caseless("SETNS") => Instruction::SETcc(3));
        insert!(m: Caseless("SETP") => Instruction::SETcc(4));
        insert!(m: Caseless("SETNP") => Instruction::SETcc(5));
        insert!(m: Caseless("SETO") => Instruction::SETcc(6));
        insert!(m: Caseless("SETNO") => Instruction::SETcc(7));
        insert!(m: Caseless("SETC") => Instruction::SETcc(8));
        insert!(m: Caseless("SETNC") => Instruction::SETcc(9));
        insert!(m: Caseless("SETB") => Instruction::SETcc(10));
        insert!(m: Caseless("SETBE") => Instruction::SETcc(11));
        insert!(m: Caseless("SETA") => Instruction::SETcc(12));
        insert!(m: Caseless("SETAE") => Instruction::SETcc(13));
        insert!(m: Caseless("SETL") => Instruction::SETcc(14));
        insert!(m: Caseless("SETLE") => Instruction::SETcc(15));
        insert!(m: Caseless("SETG") => Instruction::SETcc(16));
        insert!(m: Caseless("SETGE") => Instruction::SETcc(17));

        alias!(m: Caseless("SETE") => Caseless("SETZ"));
        alias!(m: Caseless("SETNE") => Caseless("SETNZ"));
        alias!(m: Caseless("SETPE") => Caseless("SETP"));
        alias!(m: Caseless("SETPO") => Caseless("SETNP"));
        alias!(m: Caseless("SETNAE") => Caseless("SETB"));
        alias!(m: Caseless("SETNA") => Caseless("SETBE"));
        alias!(m: Caseless("SETBNE") => Caseless("SETA"));
        alias!(m: Caseless("SETNB") => Caseless("SETAE"));
        alias!(m: Caseless("SETNGE") => Caseless("SETL"));
        alias!(m: Caseless("SETNG") => Caseless("SETLE"));
        alias!(m: Caseless("SETNLE") => Caseless("SETG"));
        alias!(m: Caseless("SETNL") => Caseless("SETGE"));

        insert!(m: Caseless("STAC") => Instruction::FLAGBIT(0));
        insert!(m: Caseless("CLAC") => Instruction::FLAGBIT(1));
        insert!(m: Caseless("CMAC") => Instruction::FLAGBIT(2));
        insert!(m: Caseless("STC") => Instruction::FLAGBIT(3));
        insert!(m: Caseless("CLC") => Instruction::FLAGBIT(4));
        insert!(m: Caseless("CMC") => Instruction::FLAGBIT(5));
        insert!(m: Caseless("STD") => Instruction::FLAGBIT(6));
        insert!(m: Caseless("CLD") => Instruction::FLAGBIT(7));
        insert!(m: Caseless("CMD") => Instruction::FLAGBIT(8));
        insert!(m: Caseless("STI") => Instruction::FLAGBIT(9));
        insert!(m: Caseless("CLI") => Instruction::FLAGBIT(10));
        insert!(m: Caseless("CMI") => Instruction::FLAGBIT(11));

        insert!(m: Caseless("ADD") => Instruction::ADD);
        insert!(m: Caseless("SUB") => Instruction::SUB);
        insert!(m: Caseless("CMP") => Instruction::CMP);

        insert!(m: Caseless("AND") => Instruction::AND);
        insert!(m: Caseless("OR") => Instruction::OR);
        insert!(m: Caseless("XOR") => Instruction::XOR);
        insert!(m: Caseless("TEST") => Instruction::TEST);

        insert!(m: Caseless("SHL") => Instruction::SHIFT(0));
        insert!(m: Caseless("SHR") => Instruction::SHIFT(1));
        insert!(m: Caseless("SAR") => Instruction::SHIFT(2));
        
        insert!(m: Caseless("ROL") => Instruction::SHIFT(3));
        insert!(m: Caseless("ROR") => Instruction::SHIFT(4));
        insert!(m: Caseless("RCL") => Instruction::SHIFT(5));
        insert!(m: Caseless("RCR") => Instruction::SHIFT(6));

        insert!(m: Caseless("SHLX") => Instruction::SHIFTX(7));
        insert!(m: Caseless("SHRX") => Instruction::SHIFTX(8));
        insert!(m: Caseless("SARX") => Instruction::SHIFTX(9));

        alias!(m: Caseless("SAL") => Caseless("SHL"));
        alias!(m: Caseless("SALX") => Caseless("SHLX"));

        insert!(m: Caseless("BT") => Instruction::BTX(10));
        insert!(m: Caseless("BTC") => Instruction::BTX(11));
        insert!(m: Caseless("BTR") => Instruction::BTX(12));
        insert!(m: Caseless("BTS") => Instruction::BTX(13));

        insert!(m: Caseless("MUL") => Instruction::MUL);
        insert!(m: Caseless("IMUL") => Instruction::IMUL);
        insert!(m: Caseless("MULX") => Instruction::MULX);
        insert!(m: Caseless("IMULX") => Instruction::IMULX);

        insert!(m: Caseless("DIV") => Instruction::DIV);
        insert!(m: Caseless("IDIV") => Instruction::IDIV);

        insert!(m: Caseless("JMP") => Instruction::JMP);

        insert!(m: Caseless("JZ") => Instruction::Jcc(0));
        insert!(m: Caseless("JNZ") => Instruction::Jcc(1));
        insert!(m: Caseless("JS") => Instruction::Jcc(2));
        insert!(m: Caseless("JNS") => Instruction::Jcc(3));
        insert!(m: Caseless("JP") => Instruction::Jcc(4));
        insert!(m: Caseless("JNP") => Instruction::Jcc(5));
        insert!(m: Caseless("JO") => Instruction::Jcc(6));
        insert!(m: Caseless("JNO") => Instruction::Jcc(7));
        insert!(m: Caseless("JC") => Instruction::Jcc(8));
        insert!(m: Caseless("JNC") => Instruction::Jcc(9));
        insert!(m: Caseless("JB") => Instruction::Jcc(10));
        insert!(m: Caseless("JBE") => Instruction::Jcc(11));
        insert!(m: Caseless("JA") => Instruction::Jcc(12));
        insert!(m: Caseless("JAE") => Instruction::Jcc(13));
        insert!(m: Caseless("JL") => Instruction::Jcc(14));
        insert!(m: Caseless("JLE") => Instruction::Jcc(15));
        insert!(m: Caseless("JG") => Instruction::Jcc(16));
        insert!(m: Caseless("JGE") => Instruction::Jcc(17));
        insert!(m: Caseless("JCXZ") => Instruction::Jcc(18));
        insert!(m: Caseless("JECXZ") => Instruction::Jcc(19));
        insert!(m: Caseless("JRCXZ") => Instruction::Jcc(20));

        alias!(m: Caseless("JE") => Caseless("JZ"));
        alias!(m: Caseless("JNE") => Caseless("JNZ"));
        alias!(m: Caseless("JPE") => Caseless("JP"));
        alias!(m: Caseless("JPO") => Caseless("JNP"));
        alias!(m: Caseless("JNAE") => Caseless("JB"));
        alias!(m: Caseless("JNA") => Caseless("JBE"));
        alias!(m: Caseless("JNBE") => Caseless("JA"));
        alias!(m: Caseless("JNB") => Caseless("JAE"));
        alias!(m: Caseless("JNGE") => Caseless("JL"));
        alias!(m: Caseless("JNG") => Caseless("JLE"));
        alias!(m: Caseless("JNLE") => Caseless("JG"));
        alias!(m: Caseless("JNL") => Caseless("JGE"));

        insert!(m: Caseless("LOOP") => Instruction::LOOPcc(0));
        insert!(m: Caseless("LOOPZ") => Instruction::LOOPcc(1));
        insert!(m: Caseless("LOOPNZ") => Instruction::LOOPcc(2));

        alias!(m: Caseless("LOOPE") => Caseless("LOOPZ"));
        alias!(m: Caseless("LOOPNE") => Caseless("LOOPNZ"));

        insert!(m: Caseless("CALL") => Instruction::CALL);
        insert!(m: Caseless("RET") => Instruction::RET);

        insert!(m: Caseless("PUSH") => Instruction::PUSH);
        insert!(m: Caseless("POP") => Instruction::POP);

        insert!(m: Caseless("INC") => Instruction::INC);
        insert!(m: Caseless("DEC") => Instruction::DEC);
        insert!(m: Caseless("NEG") => Instruction::NEG);
        insert!(m: Caseless("NOT") => Instruction::NOT);

        insert!(m: Caseless("MOVSB") => Instruction::MOVS(Size::Byte));
        insert!(m: Caseless("MOVSW") => Instruction::MOVS(Size::Word));
        insert!(m: Caseless("MOVSD") => Instruction::MOVS(Size::Dword));
        insert!(m: Caseless("MOVSQ") => Instruction::MOVS(Size::Qword));

        insert!(m: Caseless("STOSB") => Instruction::STOS(Size::Byte));
        insert!(m: Caseless("STOSW") => Instruction::STOS(Size::Word));
        insert!(m: Caseless("STOSD") => Instruction::STOS(Size::Dword));
        insert!(m: Caseless("STOSQ") => Instruction::STOS(Size::Qword));

        insert!(m: Caseless("FINIT") => Instruction::FINIT);

        insert!(m: Caseless("FLD") => Instruction::FLD(false));
        insert!(m: Caseless("FILD") => Instruction::FLD(true));

        insert!(m: Caseless("FADD") => Instruction::FADD(false, false));
        insert!(m: Caseless("FADDP") => Instruction::FADD(false, true));
        insert!(m: Caseless("FIADD") => Instruction::FADD(true, false));

        insert!(m: Caseless("FSUB") => Instruction::FSUB(false, false));
        insert!(m: Caseless("FSUBP") => Instruction::FSUB(false, true));
        insert!(m: Caseless("FISUB") => Instruction::FSUB(true, false));

        insert!(m: Caseless("FSUBR") => Instruction::FSUBR(false, false));
        insert!(m: Caseless("FSUBRP") => Instruction::FSUBR(false, true));
        insert!(m: Caseless("FISUBR") => Instruction::FSUBR(true, false));

        insert!(m: Caseless("DEBUG_CPU") => Instruction::DEBUG(0));

        m
    };
}

lazy_static! {
    pub(super) static ref SEGMENTS: BTreeMap<Caseless<'static>, AsmSegment> = {
        let mut m = BTreeMap::new();

        insert!(m: Caseless("TEXT") => AsmSegment::Text);
        insert!(m: Caseless("RODATA") => AsmSegment::Rodata);
        insert!(m: Caseless("DATA") => AsmSegment::Data);
        insert!(m: Caseless("BSS") => AsmSegment::Bss);

        m
    };
}

lazy_static! {
    pub(super) static ref RESERVED_SYMBOLS: BTreeSet<Caseless<'static>> = {
        let mut s = BTreeSet::new();

        insert!(s: Caseless("IF"));
        insert!(s: Caseless("TIMES"));

        insert!(s: Caseless("TRUE"));
        insert!(s: Caseless("FALSE"));
        insert!(s: Caseless("NULL"));

        insert!(s: Caseless("PTR"));

        s.extend(SIZE_KEYWORDS.keys().copied());
        s.extend(CPU_REGISTER_INFO.keys().copied());
        s.extend(FPU_REGISTER_INFO.keys().copied());
        s.extend(VPU_REGISTER_INFO.keys().copied());
        s.extend(SEGMENTS.keys().copied());
        s.extend(PREFIXES.keys().copied());
        s.extend(INSTRUCTIONS.keys().copied());

        s
    };
}