Subversion Repositories Kolibri OS

Rev

Rev 8966 | Rev 8973 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
8834 Boppan 1
import re
8825 Boppan 2
import os
8837 Boppan 3
import argparse
8957 Boppan 4
import sys
8825 Boppan 5
 
8957 Boppan 6
""" TODO:
8963 Boppan 7
    - Optimize name and var_type checking
8
    - Translate dict in AsmReaderReadingComments into just a set of fields
9
    - Remove get_comment method from AsmReaderReadingComments
8966 Boppan 10
    - Check if we should return handled_files from handle_file
8957 Boppan 11
"""
12
 
8834 Boppan 13
# Parameters
8837 Boppan 14
# Path to doxygen folder to make doxygen files in: -o 
8834 Boppan 15
doxygen_src_path = 'docs/doxygen'
8837 Boppan 16
# Remove generated doxygen files: --clean
17
clean_generated_stuff = False
18
# Dump all defined symbols: --dump
8834 Boppan 19
dump_symbols = False
8837 Boppan 20
# Print symbol stats: --stats
8834 Boppan 21
print_stats = False
8855 Boppan 22
# Do not write warnings file: --nowarn
23
enable_warnings = True
8825 Boppan 24
 
8837 Boppan 25
# Constants
26
link_root = "http://websvn.kolibrios.org/filedetails.php?repname=Kolibri+OS&path=/kernel/trunk"
27
 
8957 Boppan 28
# fasm keywords
29
keywords = [
30
	# Generic keywords
31
	"align",
32
	"equ",
33
	"org",
34
	"while",
35
	"load",
36
	"store",
37
	"times",
38
	"repeat",
39
	"virtual",
40
	"display",
41
	"err",
42
	"assert",
43
	"if",
44
	# Instructions
45
	"aaa",
46
	"aad",
47
	"aam",
48
	"aas",
49
	"adc",
50
	"adcx",
51
	"add",
52
	"addpd",
53
	"addps",
54
	"addsd",
55
	"addss",
56
	"addsubpd",
57
	"addsubps",
58
	"adox",
59
	"aesdec",
60
	"aesdeclast",
61
	"aesenc",
62
	"aesenclast",
63
	"aesimc",
64
	"aeskeygenassist",
65
	"and",
66
	"andn",
67
	"andnpd",
68
	"andnps",
69
	"andpd",
70
	"andps",
71
	"arpl",
72
	"bextr",
73
	"blendpd",
74
	"blendps",
75
	"blendvpd",
76
	"blendvps",
77
	"blsi",
78
	"blsmsk",
79
	"blsr",
80
	"bndcl",
81
	"bndcn",
82
	"bndcu",
83
	"bndldx",
84
	"bndmk",
85
	"bndmov",
86
	"bndstx",
87
	"bound",
88
	"bsf",
89
	"bsr",
90
	"bswap",
91
	"bt",
92
	"btc",
93
	"btr",
94
	"bts",
95
	"bzhi",
96
	"call",
97
	"cbw",
98
	"cdq",
99
	"cdqe",
100
	"clac",
101
	"clc",
102
	"cld",
103
	"cldemote",
104
	"clflush",
105
	"clflushopt",
106
	"cli",
107
	"clts",
108
	"clwb",
109
	"cmc",
110
	"cmova",
111
	"cmovae",
112
	"cmovb",
113
	"cmovbe",
114
	"cmovc",
115
	"cmove",
116
	"cmovg",
117
	"cmovge",
118
	"cmovl",
119
	"cmovle",
120
	"cmovna",
121
	"cmovnae",
122
	"cmovnb",
123
	"cmovnbe",
124
	"cmovnc",
125
	"cmovne",
126
	"cmovng",
127
	"cmovnge",
128
	"cmovnl",
129
	"cmovnle",
130
	"cmovno",
131
	"cmovnp",
132
	"cmovns",
133
	"cmovnz",
134
	"cmovo",
135
	"cmovp",
136
	"cmovpe",
137
	"cmovpo",
138
	"cmovs",
139
	"cmovz",
140
	"cmp",
141
	"cmppd",
142
	"cmpps",
143
	"cmps",
144
	"cmpsb",
145
	"cmpsd",
146
	"cmpsd",
147
	"cmpsq",
148
	"cmpss",
149
	"cmpsw",
150
	"cmpxchg",
151
	"cmpxchg16b",
152
	"cmpxchg8b",
153
	"comisd",
154
	"comiss",
155
	"cpuid",
156
	"cqo",
157
	"crc32",
158
	"cvtdq2pd",
159
	"cvtdq2ps",
160
	"cvtpd2dq",
161
	"cvtpd2pi",
162
	"cvtpd2ps",
163
	"cvtpi2pd",
164
	"cvtpi2ps",
165
	"cvtps2dq",
166
	"cvtps2pd",
167
	"cvtps2pi",
168
	"cvtsd2si",
169
	"cvtsd2ss",
170
	"cvtsi2sd",
171
	"cvtsi2ss",
172
	"cvtss2sd",
173
	"cvtss2si",
174
	"cvttpd2dq",
175
	"cvttpd2pi",
176
	"cvttps2dq",
177
	"cvttps2pi",
178
	"cvttsd2si",
179
	"cvttss2si",
180
	"cwd",
181
	"cwde",
182
	"daa",
183
	"das",
184
	"dec",
185
	"div",
186
	"divpd",
187
	"divps",
188
	"divsd",
189
	"divss",
190
	"dppd",
191
	"dpps",
192
	"emms",
193
	"enter",
194
	"extractps",
195
	"f2xm1",
196
	"fabs",
197
	"fadd",
198
	"faddp",
199
	"fbld",
200
	"fbstp",
201
	"fchs",
202
	"fclex",
203
	"fcmova",
204
	"fcmovae",
205
	"fcmovb",
206
	"fcmovbe",
207
	"fcmovc",
208
	"fcmove",
209
	"fcmovg",
210
	"fcmovge",
211
	"fcmovl",
212
	"fcmovle",
213
	"fcmovna",
214
	"fcmovnae",
215
	"fcmovnb",
216
	"fcmovnbe",
217
	"fcmovnc",
218
	"fcmovne",
219
	"fcmovng",
220
	"fcmovnge",
221
	"fcmovnl",
222
	"fcmovnle",
223
	"fcmovno",
224
	"fcmovnp",
225
	"fcmovns",
226
	"fcmovnz",
227
	"fcmovo",
228
	"fcmovp",
229
	"fcmovpe",
230
	"fcmovpo",
231
	"fcmovs",
232
	"fcmovz",
233
	"fcom",
234
	"fcomi",
235
	"fcomip",
236
	"fcomp",
237
	"fcompp",
238
	"fcos",
239
	"fdecstp",
240
	"fdiv",
241
	"fdivp",
242
	"fdivr",
243
	"fdivrp",
244
	"ffree",
245
	"fiadd",
246
	"ficom",
247
	"ficomp",
248
	"fidiv",
249
	"fidivr",
250
	"fild",
251
	"fimul",
252
	"fincstp",
253
	"finit",
254
	"fist",
255
	"fistp",
256
	"fisttp",
257
	"fisub",
258
	"fisubr",
259
	"fld",
260
	"fld1",
261
	"fldcw",
262
	"fldenv",
263
	"fldl2e",
264
	"fldl2t",
265
	"fldlg2",
266
	"fldln2",
267
	"fldpi",
268
	"fldz",
269
	"fmul",
270
	"fmulp",
271
	"fnclex",
272
	"fninit",
273
	"fnop",
274
	"fnsave",
275
	"fnstcw",
276
	"fnstenv",
277
	"fnstsw",
278
	"fpatan",
279
	"fprem",
280
	"fprem1",
281
	"fptan",
282
	"frndint",
283
	"frstor",
284
	"fsave",
285
	"fscale",
286
	"fsin",
287
	"fsincos",
288
	"fsqrt",
289
	"fst",
290
	"fstcw",
291
	"fstenv",
292
	"fstp",
293
	"fstsw",
294
	"fsub",
295
	"fsubp",
296
	"fsubr",
297
	"fsubrp",
298
	"ftst",
299
	"fucom",
300
	"fucomi",
301
	"fucomip",
302
	"fucomp",
303
	"fucompp",
304
	"fwait",
305
	"fxam",
306
	"fxch",
307
	"fxrstor",
308
	"fxsave",
309
	"fxtract",
310
	"fyl2x",
311
	"fyl2xp1",
312
	"gf2p8affineinvqb",
313
	"gf2p8affineqb",
314
	"gf2p8mulb",
315
	"haddpd",
316
	"haddps",
317
	"hlt",
318
	"hsubpd",
319
	"hsubps",
320
	"idiv",
321
	"imul",
322
	"in",
323
	"inc",
324
	"ins",
325
	"insb",
326
	"insd",
327
	"insertps",
328
	"insw",
329
	"int",
330
	"int1",
331
	"int3",
332
	"into",
333
	"invd",
334
	"invlpg",
335
	"invpcid",
336
	"iret",
337
	"iretd",
338
	"jmp",
339
	"ja",
340
	"jae",
341
	"jb",
342
	"jbe",
343
	"jc",
344
	"jcxz",
345
	"jecxz",
346
	"je",
347
	"jg",
348
	"jge",
349
	"jl",
350
	"jle",
351
	"jna",
352
	"jnae",
353
	"jnb",
354
	"jnbe",
355
	"jnc",
356
	"jne",
357
	"jng",
358
	"jnge",
359
	"jnl",
360
	"jnle",
361
	"jno",
362
	"jnp",
363
	"jns",
364
	"jnz",
365
	"jo",
366
	"jp",
367
	"jpe",
368
	"jpo",
369
	"js",
370
	"jz",
371
	"kaddb",
372
	"kaddd",
373
	"kaddq",
374
	"kaddw",
375
	"kandb",
376
	"kandd",
377
	"kandnb",
378
	"kandnd",
379
	"kandnq",
380
	"kandnw",
381
	"kandq",
382
	"kandw",
383
	"kmovb",
384
	"kmovd",
385
	"kmovq",
386
	"kmovw",
387
	"knotb",
388
	"knotd",
389
	"knotq",
390
	"knotw",
391
	"korb",
392
	"kord",
393
	"korq",
394
	"kortestb",
395
	"kortestd",
396
	"kortestq",
397
	"kortestw",
398
	"korw",
399
	"kshiftlb",
400
	"kshiftld",
401
	"kshiftlq",
402
	"kshiftlw",
403
	"kshiftrb",
404
	"kshiftrd",
405
	"kshiftrq",
406
	"kshiftrw",
407
	"ktestb",
408
	"ktestd",
409
	"ktestq",
410
	"ktestw",
411
	"kunpckbw",
412
	"kunpckdq",
413
	"kunpckwd",
414
	"kxnorb",
415
	"kxnord",
416
	"kxnorq",
417
	"kxnorw",
418
	"kxorb",
419
	"kxord",
420
	"kxorq",
421
	"kxorw",
422
	"lahf",
423
	"lar",
424
	"lddqu",
425
	"ldmxcsr",
426
	"lds",
427
	"lea",
428
	"leave",
429
	"les",
430
	"lfence",
431
	"lfs",
432
	"lgdt",
433
	"lgs",
434
	"lidt",
435
	"lldt",
436
	"lmsw",
437
	"lock",
438
	"lods",
439
	"lodsb",
440
	"lodsd",
441
	"lodsq",
442
	"lodsw",
443
	"loop",
444
	"loopa",
445
	"loopae",
446
	"loopb",
447
	"loopbe",
448
	"loopc",
449
	"loope",
450
	"loopg",
451
	"loopge",
452
	"loopl",
453
	"loople",
454
	"loopna",
455
	"loopnae",
456
	"loopnb",
457
	"loopnbe",
458
	"loopnc",
459
	"loopne",
460
	"loopng",
461
	"loopnge",
462
	"loopnl",
463
	"loopnle",
464
	"loopno",
465
	"loopnp",
466
	"loopns",
467
	"loopnz",
468
	"loopo",
469
	"loopp",
470
	"looppe",
471
	"looppo",
472
	"loops",
473
	"loopz",
474
	"lsl",
475
	"lss",
476
	"ltr",
477
	"lzcnt",
478
	"maskmovdqu",
479
	"maskmovq",
480
	"maxpd",
481
	"maxps",
482
	"maxsd",
483
	"maxss",
484
	"mfence",
485
	"minpd",
486
	"minps",
487
	"minsd",
488
	"minss",
489
	"monitor",
490
	"mov",
491
	"movapd",
492
	"movaps",
493
	"movbe",
494
	"movd",
495
	"movddup",
496
	"movdir64b",
497
	"movdiri",
498
	"movdq2q",
499
	"movdqa",
500
	"movdqu",
501
	"movhlps",
502
	"movhpd",
503
	"movhps",
504
	"movlhps",
505
	"movlpd",
506
	"movlps",
507
	"movmskpd",
508
	"movmskps",
509
	"movntdq",
510
	"movntdqa",
511
	"movnti",
512
	"movntpd",
513
	"movntps",
514
	"movntq",
515
	"movq",
516
	"movq",
517
	"movq2dq",
518
	"movs",
519
	"movsb",
520
	"movsd",
521
	"movsd",
522
	"movshdup",
523
	"movsldup",
524
	"movsq",
525
	"movss",
526
	"movsw",
527
	"movsx",
528
	"movsxd",
529
	"movupd",
530
	"movups",
531
	"movzx",
532
	"mpsadbw",
533
	"mul",
534
	"mulpd",
535
	"mulps",
536
	"mulsd",
537
	"mulss",
538
	"mulx",
539
	"mwait",
540
	"neg",
541
	"nop",
542
	"not",
543
	"or",
544
	"orpd",
545
	"orps",
546
	"out",
547
	"outs",
548
	"outsb",
549
	"outsd",
550
	"outsw",
551
	"pabsb",
552
	"pabsd",
553
	"pabsq",
554
	"pabsw",
555
	"packssdw",
556
	"packsswb",
557
	"packusdw",
558
	"packuswb",
559
	"paddb",
560
	"paddd",
561
	"paddq",
562
	"paddsb",
563
	"paddsw",
564
	"paddusb",
565
	"paddusw",
566
	"paddw",
567
	"palignr",
568
	"pand",
569
	"pandn",
570
	"pause",
571
	"pavgb",
572
	"pavgw",
573
	"pblendvb",
574
	"pblendw",
575
	"pclmulqdq",
576
	"pcmpeqb",
577
	"pcmpeqd",
578
	"pcmpeqq",
579
	"pcmpeqw",
580
	"pcmpestri",
581
	"pcmpestrm",
582
	"pcmpgtb",
583
	"pcmpgtd",
584
	"pcmpgtq",
585
	"pcmpgtw",
586
	"pcmpistri",
587
	"pcmpistrm",
588
	"pdep",
589
	"pext",
590
	"pextrb",
591
	"pextrd",
592
	"pextrq",
593
	"pextrw",
594
	"phaddd",
595
	"phaddsw",
596
	"phaddw",
597
	"phminposuw",
598
	"phsubd",
599
	"phsubsw",
600
	"phsubw",
601
	"pinsrb",
602
	"pinsrd",
603
	"pinsrq",
604
	"pinsrw",
605
	"pmaddubsw",
606
	"pmaddwd",
607
	"pmaxsb",
608
	"pmaxsd",
609
	"pmaxsq",
610
	"pmaxsw",
611
	"pmaxub",
612
	"pmaxud",
613
	"pmaxuq",
614
	"pmaxuw",
615
	"pminsb",
616
	"pminsd",
617
	"pminsq",
618
	"pminsw",
619
	"pminub",
620
	"pminud",
621
	"pminuq",
622
	"pminuw",
623
	"pmovmskb",
624
	"pmovsx",
625
	"pmovzx",
626
	"pmuldq",
627
	"pmulhrsw",
628
	"pmulhuw",
629
	"pmulhw",
630
	"pmulld",
631
	"pmullq",
632
	"pmullw",
633
	"pmuludq",
634
	"pop",
635
	"popa",
636
	"popad",
637
	"popcnt",
638
	"popf",
639
	"popfd",
640
	"popfq",
641
	"por",
642
	"prefetchw",
643
	"prefetchh",
644
	"psadbw",
645
	"pshufb",
646
	"pshufd",
647
	"pshufhw",
648
	"pshuflw",
649
	"pshufw",
650
	"psignb",
651
	"psignd",
652
	"psignw",
653
	"pslld",
654
	"pslldq",
655
	"psllq",
656
	"psllw",
657
	"psrad",
658
	"psraq",
659
	"psraw",
660
	"psrld",
661
	"psrldq",
662
	"psrlq",
663
	"psrlw",
664
	"psubb",
665
	"psubd",
666
	"psubq",
667
	"psubsb",
668
	"psubsw",
669
	"psubusb",
670
	"psubusw",
671
	"psubw",
672
	"ptest",
673
	"ptwrite",
674
	"punpckhbw",
675
	"punpckhdq",
676
	"punpckhqdq",
677
	"punpckhwd",
678
	"punpcklbw",
679
	"punpckldq",
680
	"punpcklqdq",
681
	"punpcklwd",
682
	"push",
683
	"pushw",
684
	"pushd",
685
	"pusha",
686
	"pushad",
687
	"pushf",
688
	"pushfd",
689
	"pushfq",
690
	"pxor",
691
	"rcl",
692
	"rcpps",
693
	"rcpss",
694
	"rcr",
695
	"rdfsbase",
696
	"rdgsbase",
697
	"rdmsr",
698
	"rdpid",
699
	"rdpkru",
700
	"rdpmc",
701
	"rdrand",
702
	"rdseed",
703
	"rdtsc",
704
	"rdtscp",
705
	"rep",
706
	"repe",
707
	"repne",
708
	"repnz",
709
	"repz",
710
	"ret",
711
	"rol",
712
	"ror",
713
	"rorx",
714
	"roundpd",
715
	"roundps",
716
	"roundsd",
717
	"roundss",
718
	"rsm",
719
	"rsqrtps",
720
	"rsqrtss",
721
	"sahf",
722
	"sal",
723
	"sar",
724
	"sarx",
725
	"sbb",
726
	"scas",
727
	"scasb",
728
	"scasd",
729
	"scasw",
730
	"seta",
731
	"setae",
732
	"setb",
733
	"setbe",
734
	"setc",
735
	"sete",
736
	"setg",
737
	"setge",
738
	"setl",
739
	"setle",
740
	"setna",
741
	"setnae",
742
	"setnb",
743
	"setnbe",
744
	"setnc",
745
	"setne",
746
	"setng",
747
	"setnge",
748
	"setnl",
749
	"setnle",
750
	"setno",
751
	"setnp",
752
	"setns",
753
	"setnz",
754
	"seto",
755
	"setp",
756
	"setpe",
757
	"setpo",
758
	"sets",
759
	"setz",
760
	"sfence",
761
	"sgdt",
762
	"sha1msg1",
763
	"sha1msg2",
764
	"sha1nexte",
765
	"sha1rnds4",
766
	"sha256msg1",
767
	"sha256msg2",
768
	"sha256rnds2",
769
	"shl",
770
	"shld",
771
	"shlx",
772
	"shr",
773
	"shrd",
774
	"shrx",
775
	"shufpd",
776
	"shufps",
777
	"sidt",
778
	"sldt",
779
	"smsw",
780
	"sqrtpd",
781
	"sqrtps",
782
	"sqrtsd",
783
	"sqrtss",
784
	"stac",
785
	"stc",
786
	"std",
787
	"sti",
788
	"stmxcsr",
789
	"stos",
790
	"stosb",
791
	"stosd",
792
	"stosq",
793
	"stosw",
794
	"str",
795
	"sub",
796
	"subpd",
797
	"subps",
798
	"subsd",
799
	"subss",
800
	"swapgs",
801
	"syscall",
802
	"sysenter",
803
	"sysexit",
804
	"sysret",
805
	"test",
806
	"tpause",
807
	"tzcnt",
808
	"ucomisd",
809
	"ucomiss",
810
	"ud",
811
	"umonitor",
812
	"umwait",
813
	"unpckhpd",
814
	"unpckhps",
815
	"unpcklpd",
816
	"unpcklps",
817
	"valignd",
818
	"valignq",
819
	"vblendmpd",
820
	"vblendmps",
821
	"vbroadcast",
822
	"vcompresspd",
823
	"vcompressps",
824
	"vcvtpd2qq",
825
	"vcvtpd2udq",
826
	"vcvtpd2uqq",
827
	"vcvtph2ps",
828
	"vcvtps2ph",
829
	"vcvtps2qq",
830
	"vcvtps2udq",
831
	"vcvtps2uqq",
832
	"vcvtqq2pd",
833
	"vcvtqq2ps",
834
	"vcvtsd2usi",
835
	"vcvtss2usi",
836
	"vcvttpd2qq",
837
	"vcvttpd2udq",
838
	"vcvttpd2uqq",
839
	"vcvttps2qq",
840
	"vcvttps2udq",
841
	"vcvttps2uqq",
842
	"vcvttsd2usi",
843
	"vcvttss2usi",
844
	"vcvtudq2pd",
845
	"vcvtudq2ps",
846
	"vcvtuqq2pd",
847
	"vcvtuqq2ps",
848
	"vcvtusi2sd",
849
	"vcvtusi2ss",
850
	"vdbpsadbw",
851
	"verr",
852
	"verw",
853
	"vexpandpd",
854
	"vexpandps",
855
	"vextractf128",
856
	"vextractf32x4",
857
	"vextractf32x8",
858
	"vextractf64x2",
859
	"vextractf64x4",
860
	"vextracti128",
861
	"vextracti32x4",
862
	"vextracti32x8",
863
	"vextracti64x2",
864
	"vextracti64x4",
865
	"vfixupimmpd",
866
	"vfixupimmps",
867
	"vfixupimmsd",
868
	"vfixupimmss",
869
	"vfmadd132pd",
870
	"vfmadd132ps",
871
	"vfmadd132sd",
872
	"vfmadd132ss",
873
	"vfmadd213pd",
874
	"vfmadd213ps",
875
	"vfmadd213sd",
876
	"vfmadd213ss",
877
	"vfmadd231pd",
878
	"vfmadd231ps",
879
	"vfmadd231sd",
880
	"vfmadd231ss",
881
	"vfmaddsub132pd",
882
	"vfmaddsub132ps",
883
	"vfmaddsub213pd",
884
	"vfmaddsub213ps",
885
	"vfmaddsub231pd",
886
	"vfmaddsub231ps",
887
	"vfmsub132pd",
888
	"vfmsub132ps",
889
	"vfmsub132sd",
890
	"vfmsub132ss",
891
	"vfmsub213pd",
892
	"vfmsub213ps",
893
	"vfmsub213sd",
894
	"vfmsub213ss",
895
	"vfmsub231pd",
896
	"vfmsub231ps",
897
	"vfmsub231sd",
898
	"vfmsub231ss",
899
	"vfmsubadd132pd",
900
	"vfmsubadd132ps",
901
	"vfmsubadd213pd",
902
	"vfmsubadd213ps",
903
	"vfmsubadd231pd",
904
	"vfmsubadd231ps",
905
	"vfnmadd132pd",
906
	"vfnmadd132ps",
907
	"vfnmadd132sd",
908
	"vfnmadd132ss",
909
	"vfnmadd213pd",
910
	"vfnmadd213ps",
911
	"vfnmadd213sd",
912
	"vfnmadd213ss",
913
	"vfnmadd231pd",
914
	"vfnmadd231ps",
915
	"vfnmadd231sd",
916
	"vfnmadd231ss",
917
	"vfnmsub132pd",
918
	"vfnmsub132ps",
919
	"vfnmsub132sd",
920
	"vfnmsub132ss",
921
	"vfnmsub213pd",
922
	"vfnmsub213ps",
923
	"vfnmsub213sd",
924
	"vfnmsub213ss",
925
	"vfnmsub231pd",
926
	"vfnmsub231ps",
927
	"vfnmsub231sd",
928
	"vfnmsub231ss",
929
	"vfpclasspd",
930
	"vfpclassps",
931
	"vfpclasssd",
932
	"vfpclassss",
933
	"vgatherdpd",
934
	"vgatherdpd",
935
	"vgatherdps",
936
	"vgatherdps",
937
	"vgatherqpd",
938
	"vgatherqpd",
939
	"vgatherqps",
940
	"vgatherqps",
941
	"vgetexppd",
942
	"vgetexpps",
943
	"vgetexpsd",
944
	"vgetexpss",
945
	"vgetmantpd",
946
	"vgetmantps",
947
	"vgetmantsd",
948
	"vgetmantss",
949
	"vinsertf128",
950
	"vinsertf32x4",
951
	"vinsertf32x8",
952
	"vinsertf64x2",
953
	"vinsertf64x4",
954
	"vinserti128",
955
	"vinserti32x4",
956
	"vinserti32x8",
957
	"vinserti64x2",
958
	"vinserti64x4",
959
	"vmaskmov",
960
	"vmovdqa32",
961
	"vmovdqa64",
962
	"vmovdqu16",
963
	"vmovdqu32",
964
	"vmovdqu64",
965
	"vmovdqu8",
966
	"vpblendd",
967
	"vpblendmb",
968
	"vpblendmd",
969
	"vpblendmq",
970
	"vpblendmw",
971
	"vpbroadcast",
972
	"vpbroadcastb",
973
	"vpbroadcastd",
974
	"vpbroadcastm",
975
	"vpbroadcastq",
976
	"vpbroadcastw",
977
	"vpcmpb",
978
	"vpcmpd",
979
	"vpcmpq",
980
	"vpcmpub",
981
	"vpcmpud",
982
	"vpcmpuq",
983
	"vpcmpuw",
984
	"vpcmpw",
985
	"vpcompressd",
986
	"vpcompressq",
987
	"vpconflictd",
988
	"vpconflictq",
989
	"vperm2f128",
990
	"vperm2i128",
991
	"vpermb",
992
	"vpermd",
993
	"vpermi2b",
994
	"vpermi2d",
995
	"vpermi2pd",
996
	"vpermi2ps",
997
	"vpermi2q",
998
	"vpermi2w",
999
	"vpermilpd",
1000
	"vpermilps",
1001
	"vpermpd",
1002
	"vpermps",
1003
	"vpermq",
1004
	"vpermt2b",
1005
	"vpermt2d",
1006
	"vpermt2pd",
1007
	"vpermt2ps",
1008
	"vpermt2q",
1009
	"vpermt2w",
1010
	"vpermw",
1011
	"vpexpandd",
1012
	"vpexpandq",
1013
	"vpgatherdd",
1014
	"vpgatherdd",
1015
	"vpgatherdq",
1016
	"vpgatherdq",
1017
	"vpgatherqd",
1018
	"vpgatherqd",
1019
	"vpgatherqq",
1020
	"vpgatherqq",
1021
	"vplzcntd",
1022
	"vplzcntq",
1023
	"vpmadd52huq",
1024
	"vpmadd52luq",
1025
	"vpmaskmov",
1026
	"vpmovb2m",
1027
	"vpmovd2m",
1028
	"vpmovdb",
1029
	"vpmovdw",
1030
	"vpmovm2b",
1031
	"vpmovm2d",
1032
	"vpmovm2q",
1033
	"vpmovm2w",
1034
	"vpmovq2m",
1035
	"vpmovqb",
1036
	"vpmovqd",
1037
	"vpmovqw",
1038
	"vpmovsdb",
1039
	"vpmovsdw",
1040
	"vpmovsqb",
1041
	"vpmovsqd",
1042
	"vpmovsqw",
1043
	"vpmovswb",
1044
	"vpmovusdb",
1045
	"vpmovusdw",
1046
	"vpmovusqb",
1047
	"vpmovusqd",
1048
	"vpmovusqw",
1049
	"vpmovuswb",
1050
	"vpmovw2m",
1051
	"vpmovwb",
1052
	"vpmultishiftqb",
1053
	"vprold",
1054
	"vprolq",
1055
	"vprolvd",
1056
	"vprolvq",
1057
	"vprord",
1058
	"vprorq",
1059
	"vprorvd",
1060
	"vprorvq",
1061
	"vpscatterdd",
1062
	"vpscatterdq",
1063
	"vpscatterqd",
1064
	"vpscatterqq",
1065
	"vpsllvd",
1066
	"vpsllvq",
1067
	"vpsllvw",
1068
	"vpsravd",
1069
	"vpsravq",
1070
	"vpsravw",
1071
	"vpsrlvd",
1072
	"vpsrlvq",
1073
	"vpsrlvw",
1074
	"vpternlogd",
1075
	"vpternlogq",
1076
	"vptestmb",
1077
	"vptestmd",
1078
	"vptestmq",
1079
	"vptestmw",
1080
	"vptestnmb",
1081
	"vptestnmd",
1082
	"vptestnmq",
1083
	"vptestnmw",
1084
	"vrangepd",
1085
	"vrangeps",
1086
	"vrangesd",
1087
	"vrangess",
1088
	"vrcp14pd",
1089
	"vrcp14ps",
1090
	"vrcp14sd",
1091
	"vrcp14ss",
1092
	"vreducepd",
1093
	"vreduceps",
1094
	"vreducesd",
1095
	"vreducess",
1096
	"vrndscalepd",
1097
	"vrndscaleps",
1098
	"vrndscalesd",
1099
	"vrndscaless",
1100
	"vrsqrt14pd",
1101
	"vrsqrt14ps",
1102
	"vrsqrt14sd",
1103
	"vrsqrt14ss",
1104
	"vscalefpd",
1105
	"vscalefps",
1106
	"vscalefsd",
1107
	"vscalefss",
1108
	"vscatterdpd",
1109
	"vscatterdps",
1110
	"vscatterqpd",
1111
	"vscatterqps",
1112
	"vshuff32x4",
1113
	"vshuff64x2",
1114
	"vshufi32x4",
1115
	"vshufi64x2",
1116
	"vtestpd",
1117
	"vtestps",
1118
	"vzeroall",
1119
	"vzeroupper",
1120
	"wait",
1121
	"wbinvd",
1122
	"wrfsbase",
1123
	"wrgsbase",
1124
	"wrmsr",
1125
	"wrpkru",
1126
	"xabort",
1127
	"xacquire",
1128
	"xadd",
1129
	"xbegin",
1130
	"xchg",
1131
	"xend",
1132
	"xgetbv",
1133
	"xlat",
1134
	"xlatb",
1135
	"xor",
1136
	"xorpd",
1137
	"xorps",
1138
	"xrelease",
1139
	"xrstor",
1140
	"xrstors",
1141
	"xsave",
1142
	"xsavec",
1143
	"xsaveopt",
1144
	"xsaves",
1145
	"xsetbv",
1146
	"xtest"
1147
]
1148
 
1149
fasm_types = [
1150
	"db", "rb",
1151
	"dw", "rw",
1152
	"dd", "rd",
1153
	"dp", "rp",
1154
	"df", "rf",
1155
	"dq", "rq",
1156
	"dt", "rt",
1157
	"du",
1158
]
1159
 
8855 Boppan 1160
# Warning list
1161
warnings = ""
1162
 
8837 Boppan 1163
# Parse arguments
1164
parser = argparse.ArgumentParser()
1165
parser.add_argument("-o", help="Doxygen output folder")
1166
parser.add_argument("--clean", help="Remove generated files", action="store_true")
1167
parser.add_argument("--dump", help="Dump all defined symbols", action="store_true")
1168
parser.add_argument("--stats", help="Print symbol stats", action="store_true")
8855 Boppan 1169
parser.add_argument("--nowarn", help="Do not write warnings file", action="store_true")
8837 Boppan 1170
args = parser.parse_args()
1171
doxygen_src_path = args.o if args.o else 'docs/doxygen'
1172
clean_generated_stuff = args.clean
1173
dump_symbols = args.dump
1174
print_stats = args.stats
8855 Boppan 1175
enable_warnings = not args.nowarn
8837 Boppan 1176
 
8957 Boppan 1177
# Variables, functions, labels, macros, structure types
1178
elements = []
1179
# Names of macroses
1180
macro_names = []
1181
# Names of structs
1182
struct_names = []
1183
# Equated constant names (name = value)
1184
equated_constant_names = []
1185
# Literally equated constant names (name equ value)
1186
equ_names = []
8825 Boppan 1187
 
8957 Boppan 1188
class LegacyAsmReader:
1189
	def __init__(self, file):
1190
		self.file = file
1191
		self.lines = open(file, "r", encoding="utf-8").readlines()
1192
		self.line_idx = 0
1193
		self.i = 0
1194
 
1195
	def curr(self):
1196
		try: return self.lines[self.line_idx][self.i]
1197
		except: return ''
1198
 
1199
	def step(self):
1200
		c = self.curr()
1201
		self.i += 1
1202
		# Wrap the line if '\\' followed by whitespaces and/or comment
1203
		while self.curr() == '\\':
1204
			i_of_backslash = self.i
1205
			self.i += 1
1206
			while self.curr().isspace():
1207
				self.i += 1
1208
			if self.curr() == ';' or self.curr() == '':
1209
				self.line_idx += 1
1210
				self.i = 0
1211
			else:
1212
				# There's something other than a comment after the backslash
1213
				# So don't interpret the backslash as a line wrap
1214
				self.i = i_of_backslash
1215
				break
1216
		return c
1217
 
1218
	def nextline(self):
1219
		c = self.curr()
1220
		while c != '':
1221
			c = self.step()
1222
		self.line_idx += 1
1223
		self.i = 0
1224
 
1225
	def no_lines(self):
1226
		if self.line_idx >= len(self.lines):
1227
			return True
1228
		return False
1229
 
1230
	def location(self):
1231
		return f"{self.file}:{self.line_idx + 1}"
1232
 
1233
	def skip_spaces(self):
1234
		while self.curr().isspace():
1235
			self.step()
1236
 
1237
class AsmReaderRecognizingStrings(LegacyAsmReader):
1238
	def __init__(self, file):
1239
		super().__init__(file)
1240
		self.in_string = None
1241
		self.should_recognize_strings = True
1242
 
1243
	def step(self):
1244
		c = super().step()
1245
		if self.should_recognize_strings and (c == '"' or c == "'"):
1246
			# If just now we was at the double or single quotation mark
1247
			# and we aren't in a string yet
1248
			# then say "we are in a string openned with this quotation mark now"
1249
			if self.in_string == None:
1250
				self.in_string = c
1251
			# If just now we was at the double or single quotation mark
1252
			# and we are in the string entered with the same quotation mark
1253
			# then say "we aren't in a string anymore"
1254
			elif self.in_string == c:
1255
				self.in_string = None
1256
		return c
1257
 
1258
class AsmReaderReadingComments(AsmReaderRecognizingStrings):
1259
	def __init__(self, file):
1260
		super().__init__(file)
1261
		self.status = dict()
1262
		self.status_reset()
1263
		self.comment = ''
1264
 
1265
	def status_reset(self):
1266
		# If the line has non-comment code
1267
		self.status['has_code'] = False
1268
		# If the line has a comment at the end
1269
		self.status['has_comment'] = False
1270
		# Let it recognize strings further, we are definitely out of a comment
1271
		self.should_recognize_strings = True
1272
 
1273
	def status_set_has_comment(self):
1274
		self.status['has_comment'] = True
1275
		# Don't let it recognize strings cause we are in a comment now
1276
		self.should_recognize_strings = False
1277
 
1278
	def status_set_has_code(self):
1279
		self.status['has_code'] = True
1280
 
1281
	def status_has_comment(self):
1282
		return self.status['has_comment']
1283
 
1284
	def status_has_code(self):
1285
		return self.status['has_code']
1286
 
1287
	def update_status(self):
1288
		# If we aren't in a comment and we aren't in a string - say we are now in a comment if ';' met
1289
		if not self.status_has_comment() and not self.in_string and self.curr() == ';':
1290
			self.status_set_has_comment()
1291
		# Else if we are in a comment - collect the comment
1292
		elif self.status_has_comment():
1293
			self.comment += self.curr()
1294
		# Else if there's some non-whitespace character out of a comment
1295
		# then the line has code
1296
		elif not self.status_has_comment() and not self.curr().isspace():
1297
			self.status_set_has_code()
1298
 
1299
	def step(self):
1300
		# Get to the next character
1301
		c = super().step()
1302
		# Update status of the line according to the next character
1303
		self.update_status()
1304
		return c
1305
 
1306
	def nextline(self):
1307
		super().nextline()
1308
		# If the line we leave was not a comment-only line
1309
		# then forget the collected comment
1310
		# Otherwise the collected comment should be complemented by comment from next line in step()
1311
		if self.status_has_code():
1312
			self.comment = ''
1313
		# Reset the line status (now it's the status of the new line)
1314
		self.status_reset()
1315
		# Set new status for this line according to the first character in the line
1316
		self.update_status()
1317
 
1318
	def get_comment(self):
1319
		return self.comment
1320
 
8963 Boppan 1321
class AsmReaderFetchingIdentifiers(AsmReaderReadingComments):
8957 Boppan 1322
	def __init__(self, file):
1323
		super().__init__(file)
1324
 
8963 Boppan 1325
	def fetch_identifier(self):
1326
		self.skip_spaces()
1327
		result = ''
1328
		while is_id(self.curr()):
1329
			result += self.step()
1330
		return result
1331
 
1332
class AsmReader(AsmReaderFetchingIdentifiers):
1333
	def __init__(self, file):
1334
		super().__init__(file)
1335
 
8957 Boppan 1336
created_files = []
1337
 
1338
class AsmElement:
1339
	def __init__(self, location, name, comment):
1340
		self.location = location
1341
		self.file = self.location.split(':')[0].replace('\\', '/')
1342
		self.line = self.location.split(':')[1]
8855 Boppan 1343
		self.name = name
8957 Boppan 1344
		self.comment = comment
1345
 
1346
	def dump(self):
1347
		print(f"{self.comment}")
1348
		print(f"{self.location}: {self.name}")
1349
 
1350
	def emit(self, dest, doxycomment = '', declaration = ''):
1351
		global warnings
1352
		# Redefine default declaration
1353
		if declaration == '':
1354
			declaration = f'#define {self.name}'
1355
		# Check doxycomment
1356
		if not doxycomment.endswith('\n'):
1357
			doxycomment += '\n'
1358
		if doxycomment.split('@brief ')[1][0].islower():
1359
			warnings += f"{self.location}: Brief comment starting from lowercase\n"
1360
		# Build contents to emit
1361
		contents = ''
1362
		contents += '/**\n'
1363
		contents += doxycomment
1364
		contents += (f"@par Source\n" +
1365
		             f"{self.file}:{self.line}\n")
1366
		contents += '*/\n'
1367
		contents += declaration
1368
		contents += '\n\n'
1369
		# Get path to file to emit this
1370
		full_path = dest + '/' + self.file
1371
		# Remove the file on first access if it was created by previous generation
1372
		if full_path not in created_files:
1373
			if os.path.isfile(full_path):
1374
				os.remove(full_path)
1375
			created_files.append(full_path)
1376
		# Create directories need for the file
1377
		os.makedirs(os.path.dirname(full_path), exist_ok=True)
1378
		f = open(full_path, "a")
1379
		contents = ''.join([i if ord(i) < 128 else '?' for i in contents])
1380
		f.write(contents)
1381
		f.close()
1382
 
1383
class AsmVariable(AsmElement):
1384
	def __init__(self, location, name, comment, type, init):
1385
		super().__init__(location, name, comment)
8855 Boppan 1386
		self.type = type
1387
		self.init = init
1388
 
8957 Boppan 1389
	def dump(self):
1390
		super().dump()
1391
		print(f"Variable")
8855 Boppan 1392
 
8957 Boppan 1393
	def emit(self, dest):
1394
		# Build doxycomment specific for the variable
1395
		doxycomment = ''
1396
		doxycomment += self.comment
1397
		if '@brief' not in doxycomment:
1398
			doxycomment = '@brief ' + doxycomment
1399
		doxycomment += (f"@par Initial value\n" +
1400
		                f"{self.init}\n")
1401
		# Build the declaration
1402
		name = self.name.replace(".", "_")
1403
		var_type = self.type.replace(".", "_")
1404
		declaration = f"{var_type} {name};"
1405
		# Emit this
1406
		super().emit(dest, doxycomment, declaration)
8855 Boppan 1407
 
8957 Boppan 1408
class AsmFunction(AsmElement):
8963 Boppan 1409
	def __init__(self, location, name, comment, calling_convention, args, used_regs):
8957 Boppan 1410
		super().__init__(location, name, comment)
8963 Boppan 1411
		self.calling_convention = calling_convention
1412
		self.args = args
1413
		self.used_regs = used_regs
8855 Boppan 1414
 
8957 Boppan 1415
	def dump(self):
1416
		super().dump()
1417
		print(f"Function")
8855 Boppan 1418
 
8957 Boppan 1419
	def emit(self, dest):
1420
		# Build doxycomment specific for the variable
1421
		doxycomment = ''
1422
		doxycomment += self.comment
1423
		if '@brief' not in doxycomment:
1424
			doxycomment = '@brief ' + doxycomment
8963 Boppan 1425
		# Build the arg list for declaration
1426
		arg_list = '('
1427
		if len(self.args) > 0:
1428
			argc = 0
1429
			for arg in self.args:
1430
				if argc != 0:
1431
					arg_list += ", "
1432
				arg_list += f"{arg[1]} {arg[0]}"
1433
				argc += 1
1434
		arg_list += ')'
8957 Boppan 1435
		# Build the declaration
1436
		name = self.name.replace(".", "_")
8963 Boppan 1437
		declaration = f"void {name}{arg_list};"
8957 Boppan 1438
		# Emit this
1439
		super().emit(dest, doxycomment, declaration)
8855 Boppan 1440
 
8957 Boppan 1441
class AsmLabel(AsmElement):
1442
	def __init__(self, location, name, comment):
1443
		super().__init__(location, name, comment)
8855 Boppan 1444
 
8957 Boppan 1445
	def dump(self):
1446
		super().dump()
1447
		print(f"Label")
8855 Boppan 1448
 
8957 Boppan 1449
	def emit(self, dest):
1450
		# Build doxycomment specific for the variable
1451
		doxycomment = ''
1452
		doxycomment += self.comment
1453
		if '@brief' not in doxycomment:
1454
			doxycomment = '@brief ' + doxycomment
1455
		# Build the declaration
1456
		name = self.name.replace(".", "_")
1457
		declaration = f"label {name};"
1458
		# Emit this
1459
		super().emit(dest, doxycomment, declaration)
8855 Boppan 1460
 
8957 Boppan 1461
class AsmMacro(AsmElement):
1462
	def __init__(self, location, name, comment, args):
1463
		super().__init__(location, name, comment)
1464
		self.args = args
8855 Boppan 1465
 
8957 Boppan 1466
	def dump(self):
1467
		super().dump()
1468
		print(f"Macro")
1469
		print(f"Parameters: {self.args}")
8855 Boppan 1470
 
8957 Boppan 1471
	def emit(self, dest):
1472
		# Construct arg list without '['s, ']'s and '*'s
1473
		args = [arg for arg in self.args if arg not in "[]*"]
1474
		# Construct C-like arg list
1475
		arg_list = ""
1476
		if len(args) > 0:
1477
			arg_list += '('
1478
			argc = 0
1479
			for arg in args:
1480
				if argc != 0:
1481
					arg_list += ", "
1482
				arg_list += arg
1483
				argc += 1
1484
			arg_list += ')'
1485
		# Build doxycomment
1486
		doxycomment = ''
1487
		doxycomment += self.comment
1488
		if '@brief' not in doxycomment:
1489
			doxycomment = '@brief ' + doxycomment
1490
		# Build declaration
1491
		declaration = f"#define {self.name}{arg_list}"
1492
		# Emit this
1493
		super().emit(dest, doxycomment, declaration)
8855 Boppan 1494
 
8957 Boppan 1495
class AsmStruct(AsmElement):
1496
	def __init__(self, location, name, comment, members):
1497
		super().__init__(location, name, comment)
1498
		self.members = members
8855 Boppan 1499
 
8957 Boppan 1500
	def dump(self):
1501
		super().dump()
1502
		print(f"Struct")
8855 Boppan 1503
 
8957 Boppan 1504
	def emit(self, dest):
1505
		# Build doxycomment
1506
		doxycomment = ''
1507
		doxycomment += self.comment
1508
		if '@brief' not in doxycomment:
1509
			doxycomment = '@brief ' + doxycomment
8958 Boppan 1510
		doxycomment += '\n'
8957 Boppan 1511
		# Build declaration
8958 Boppan 1512
		declaration = f"struct {self.name}" + " {\n"
1513
		for member in self.members:
1514
			if type(member) == AsmVariable:
1515
				declaration += f'\t{member.type} {member.name}; /**< {member.comment} */\n'
1516
		declaration += '};'
8957 Boppan 1517
		# Emit this
1518
		super().emit(dest, doxycomment, declaration)
8855 Boppan 1519
 
8957 Boppan 1520
class AsmUnion(AsmElement):
1521
	def __init__(self, location, name, comment, members):
1522
		super().__init__(location, name, comment)
1523
		self.members = members
8855 Boppan 1524
 
8957 Boppan 1525
	def dump(self):
1526
		super().dump()
1527
		print(f"Union")
8855 Boppan 1528
 
8957 Boppan 1529
	def emit(self, dest):
1530
		# Build doxycomment
1531
		doxycomment = ''
1532
		doxycomment += self.comment
1533
		if '@brief' not in doxycomment:
1534
			doxycomment = '@brief ' + doxycomment
1535
		# Build declaration
1536
		declaration = f"union {self.name}" + " {};"
1537
		# Emit this
1538
		super().emit(dest, doxycomment, declaration)
8855 Boppan 1539
 
8957 Boppan 1540
class VariableNameIsMacroName:
1541
	def __init__(self, name):
1542
		self.name = name
8855 Boppan 1543
 
8957 Boppan 1544
def is_id(c):
1545
	return c.isprintable() and c not in "+-/*=<>()[]{};:,|&~#`'\" \n\r\t\v"
8855 Boppan 1546
 
8957 Boppan 1547
def is_starts_as_id(s):
1548
	return not s[0].isdigit()
1549
 
1550
def parse_after_macro(r):
1551
	location = r.location()
1552
 
1553
	# Skip spaces after the "macro" keyword
1554
	r.skip_spaces()
8855 Boppan 1555
	# Read macro name
1556
	name = ""
8957 Boppan 1557
	while is_id(r.curr()) or r.curr() == '#':
1558
		name += r.step()
8855 Boppan 1559
	# Skip spaces after macro name
8957 Boppan 1560
	r.skip_spaces()
8855 Boppan 1561
	# Find all arguments
1562
	args = []
1563
	arg = ''
8957 Boppan 1564
	while r.curr() and r.curr() != ';' and r.curr() != '{':
8855 Boppan 1565
		# Collect identifier
8957 Boppan 1566
		if is_id(r.curr()):
1567
			arg += r.step()
8855 Boppan 1568
		# Save the collected identifier
8957 Boppan 1569
		elif r.curr() == ',':
8855 Boppan 1570
			args.append(arg)
1571
			arg = ''
8957 Boppan 1572
			r.step()
8855 Boppan 1573
		# Just push the '['
8957 Boppan 1574
		elif r.curr() == '[':
1575
			args.append(r.step())
8855 Boppan 1576
		# Just push the identifier and get ']' ready to be pushed on next comma
8957 Boppan 1577
		elif r.curr() == ']':
8855 Boppan 1578
			args.append(arg)
8957 Boppan 1579
			arg = r.step()
8855 Boppan 1580
		# Just push the identifier and get '*' ready to be pushed on next comma
8957 Boppan 1581
		elif r.curr() == '*':
8855 Boppan 1582
			args.append(arg)
8957 Boppan 1583
			arg = r.step()
8855 Boppan 1584
		# Just skip whitespaces
8957 Boppan 1585
		elif r.curr().isspace():
1586
			r.step()
8855 Boppan 1587
		# Something unexpected
1588
		else:
8957 Boppan 1589
			raise Exception(f"Unexpected symbol '{r.curr()}' at index #{r.i} " +
1590
			                f"in the macro declaration at {location} " +
1591
			                f"(line: {r.lines[r.line_idx]})\n''")
1592
	# Append the last argument
8855 Boppan 1593
	if arg != '':
1594
		args.append(arg)
8957 Boppan 1595
	# Skip t spaces after the argument list
1596
	r.skip_spaces()
1597
	# Get a comment if it is: read till the end of the line and get the comment from the reader
1598
	while r.curr() != '':
1599
		r.step()
1600
	comment = r.comment
8855 Boppan 1601
	# Find end of the macro
8957 Boppan 1602
	prev = ''
1603
	while True:
1604
		if r.curr() == '}' and prev != '\\':
1605
			break
1606
		elif r.curr() == '':
1607
			prev = ''
1608
			r.nextline()
1609
			continue
1610
		prev = r.step()
8855 Boppan 1611
	# Build the output
8957 Boppan 1612
	return AsmMacro(location, name, comment, args)
8855 Boppan 1613
 
8957 Boppan 1614
def parse_variable(r, first_word = None):
1615
	global warnings
1616
	location = r.location()
8825 Boppan 1617
 
8957 Boppan 1618
	# Skip spaces before variable name
1619
	r.skip_spaces()
1620
	# Get variable name
1621
	name = ""
1622
	# Read it if it was not supplied
1623
	if first_word == None:
1624
		while is_id(r.curr()):
1625
			name += r.step()
1626
	# Or use the supplied one instead
1627
	else:
1628
		name = first_word
1629
	# Check the name
1630
	# If it's 0 len, that means threr's something else than an identifier at the beginning
1631
	if len(name) == 0:
1632
		return None
1633
	# If it starts from digit or othervice illegally it's illegal
1634
	if not is_starts_as_id(name):
1635
		return None
1636
	# If it's a keyword, that's not a variable declaration
1637
	if name in keywords:
1638
		return None
1639
	# If it's a macro name, that's not a variable declaration
1640
	if name in macro_names:
1641
		return VariableNameIsMacroName(name)
1642
	# If it's a datatype or a structure name that's not a variable declaration: that's just a data
1643
	# don't document just a data for now
1644
	if name in struct_names or name in fasm_types:
1645
		return None
1646
	# Skip spaces before type name
1647
	r.skip_spaces()
1648
	# Read type name
1649
	var_type = ""
1650
	while is_id(r.curr()):
1651
		var_type += r.step()
1652
	# Check the type name
1653
	if len(var_type) == 0:
1654
		# If there's no type identifier after the name
1655
		# maybe the name is something meaningful for the next parser
1656
		# return it
1657
		return name
1658
	# If it starts from digit or othervice illegally it's illegal
1659
	if not is_starts_as_id(var_type):
1660
		return None
1661
	# If it's a keyword, that's not a variable declaration
1662
	# return the two words of the lexical structure
1663
	if var_type in keywords:
1664
		return (name, var_type)
1665
	# Skip spaces before the value
1666
	r.skip_spaces()
1667
	# Read the value until the comment or end of the line
1668
	value = ""
1669
	while r.curr() != ';' and r.curr() != '' and r.curr() != '\n':
1670
		value += r.step()
1671
	# Skip spaces after the value
1672
	r.skip_spaces()
8961 Boppan 1673
	# Read till end of the line to get a comment from the reader
1674
	while r.curr() != '':
8957 Boppan 1675
		r.step()
8961 Boppan 1676
	# Build the result
8957 Boppan 1677
	return AsmVariable(location, name, r.comment, var_type, value)
8825 Boppan 1678
 
8957 Boppan 1679
def parse_after_struct(r, as_union = True):
1680
	global warnings
1681
	location = r.location()
8825 Boppan 1682
 
8957 Boppan 1683
	# Skip spaces after "struct" keyword
1684
	r.skip_spaces()
1685
	# Read struct name
1686
	name = ""
1687
	while is_id(r.curr()):
1688
		name += r.step()
1689
	# Read till end of the line and get the comment from the reader
1690
	while r.curr() != '':
1691
		r.step()
1692
	comment = r.comment
1693
	# Get to the next line to parse struct members
1694
	r.nextline()
1695
	# Parse struct members
1696
	members = []
1697
	while True:
1698
		r.skip_spaces()
1699
		var = parse_variable(r)
1700
		if type(var) == AsmVariable:
1701
			members.append(var)
1702
		elif type(var) == str:
1703
			if var == 'union':
1704
				# Parse the union as a struct
1705
				union = parse_after_struct(r, as_union = True)
1706
				members.append(union)
1707
				# Skip the ends of the union
1708
				r.nextline()
1709
			elif r.curr() == ':':
1710
				warnings += f"{r.location()}: Skept the label in the struct\n"
1711
			else:
1712
				raise Exception(f"Garbage in struct member at {location} (got '{var}' identifier)")
1713
		elif type(var) == VariableNameIsMacroName:
1714
			if var.name == 'ends':
1715
				break
1716
		r.nextline()
1717
	# Return the result
1718
	if as_union:
1719
		return AsmStruct(location, name, comment, members)
1720
	else:
1721
		return AsmUnion(location, name, comment, members)
8825 Boppan 1722
 
8963 Boppan 1723
def parse_after_proc(r):
1724
	# Get proc name
1725
	name = r.fetch_identifier()
1726
	# Next identifier after the proc name
1727
	identifier = r.fetch_identifier()
1728
	# Check if the id is 'stdcall' or 'c' (calling convention specifier)
1729
	# and if so - save the convention and lookup the next identifier
1730
	calling_convention = ''
1731
	if identifier == 'stdcall' or identifier == 'c':
1732
		calling_convention = identifier
1733
		# If next is a comma, just skip it
1734
		if r.curr() == ',':
1735
			r.step()
1736
		# Read the next identifier
1737
		identifier = r.fetch_identifier()
1738
	# Check if the id is 'uses' (used register list specifier)
1739
	# and if so save the used register list
1740
	used_regs = []
1741
	if identifier == 'uses':
1742
		# Read the registers
1743
		while True:
1744
			reg_name = r.fetch_identifier()
1745
			if reg_name != '':
1746
				used_regs.append(reg_name)
1747
			else:
1748
				break
1749
		# If next is a comma, just skip it
1750
		if r.curr() == ',':
1751
			r.step()
1752
		# Read the next identifier
1753
		identifier = r.fetch_identifier()
1754
	# Check if there are argument identifiers
1755
	args = []
1756
	while identifier != '':
1757
		arg_name = identifier
1758
		arg_type = 'arg_t'
1759
		# Skip spaces after argument name
1760
		r.skip_spaces()
1761
		# If there's a ':' after the name - the next identifier is type
1762
		if r.curr() == ':':
1763
			r.step()
1764
			arg_type = r.fetch_identifier()
1765
		# If there's a comma - there's one more argument
1766
		# else no arguments anymore
1767
		if r.curr() == ',':
1768
			r.step()
1769
			identifier = r.fetch_identifier()
1770
		else:
1771
			identifier = ''
1772
		args.append((arg_name, arg_type))
1773
	# Get to the end of the line and get a comment from the reader
1774
	while r.curr() != '':
1775
		r.step()
1776
	comment = r.get_comment()
1777
	# Build the element
1778
	return AsmFunction(r.location(), name, comment, calling_convention, args, used_regs)
1779
 
8957 Boppan 1780
def get_declarations(asm_file_contents, asm_file_name):
1781
	r = AsmReader(asm_file_name)
8825 Boppan 1782
 
8957 Boppan 1783
	while not r.no_lines():
1784
		# Skip leading spaces
1785
		r.skip_spaces()
1786
		# Skip the line if it's starting with a comment
1787
		if r.curr() == ';':
1788
			r.nextline()
8825 Boppan 1789
			continue
8957 Boppan 1790
		# Get first word
1791
		first_word = ""
1792
		while is_id(r.curr()):
1793
			first_word += r.step()
1794
		# Match macro declaration
1795
		if first_word == "macro":
1796
			macro = parse_after_macro(r)
1797
			elements.append(macro)
1798
			macro_names.append(macro.name)
1799
		# Match structure declaration
1800
		elif first_word == "struct":
1801
			struct = parse_after_struct(r)
1802
			elements.append(struct)
1803
			struct_names.append(struct.name)
1804
		# Match function definition
1805
		elif first_word == "proc":
8963 Boppan 1806
			proc = parse_after_proc(r)
1807
			elements.append(proc)
8957 Boppan 1808
		elif first_word == 'format':
1809
			# Skip the format directive
1810
			pass
1811
		elif first_word == 'include':
1812
			# Skip the include directive
1813
			pass
1814
		elif first_word == 'if':
1815
			# Skip the conditional directive
1816
			pass
1817
		elif first_word == 'repeat':
1818
			# Skip the repeat directive
1819
			pass
1820
		elif first_word == 'purge':
1821
			while True:
1822
				# Skip spaces after the 'purge' keyword or after the comma what separated the previous macro name
1823
				r.skip_spaces()
1824
				# Get the purged macro name
1825
				name = ''
1826
				while is_id(r.curr()):
1827
					name += r.step()
1828
				# Remove the purged macro from the macro names list
1829
				try:
1830
					macro_names.remove(name)
1831
				except:
1832
					pass
1833
				# Skip spaces after the name
1834
				r.skip_spaces()
1835
				# If it's comma (',') after then that's not the last purged macro, continue purging
1836
				if r.curr() == ',':
1837
					r.step()
1838
					continue
1839
				# Here we purged all the macros should be purged
1840
				break
1841
		# Match label or a variable
1842
		elif len(first_word) != 0:
1843
			# Skip spaces after the identifier
1844
			r.skip_spaces()
1845
			# Match a variable
1846
			var = parse_variable(r, first_word)
1847
			if type(var) == AsmVariable:
1848
				elements.append(var)
1849
			# If it wasn't a variable but there was an identifier
1850
			# Maybe that's a label and the identifier is the label name
1851
			# The parse_variable returns the first found or supplied identifier
1852
			# In this case it returns the first_word which is supplied
1853
			# If it didn't match a type identifier after the word
1854
			elif type(var) == str:
1855
				name = var
1856
				# Match label beginning (':' after name)
1857
				if r.curr() == ':':
1858
					# Get to the end of the line and get the coment from the reader
1859
					while r.curr() != '':
1860
						r.step()
1861
					comment = r.comment
1862
					# Only handle non-local labels
1863
					if name[0] != '.' and name != "@@" and name != "$Revision":
1864
						elements.append(AsmLabel(r.location(), name, comment))
1865
				elif r.curr() == '=':
1866
					# Add the equated constant (name = value) to equated constants list
1867
					equated_constant_names.append(first_word)
1868
			elif type(var) == tuple:
1869
				(word_one, word_two) = var
1870
				if word_two == 'equ':
1871
					# Add the name to equ names list
1872
					equ_names.append(word_one)
1873
		r.nextline()
8825 Boppan 1874
 
8966 Boppan 1875
def it_neds_to_be_parsed(source_file):
1876
	dest = doxygen_src_path + '/' + source_file
1877
	# If there's no the doxygen file it should be compiled to
1878
	# then yes, we should compile it to doxygen
1879
	if not os.path.isfile(dest):
1880
		return True
1881
	source_change_time = os.path.getmtime(source_file)
1882
	dest_change_file = os.path.getmtime(dest)
1883
	# If the source is newer than the doxygen it was compiled to
1884
	# then the source should be recompiled (existing doxygen is old)
1885
	if source_change_time > dest_change_file:
1886
		return True
1887
	return False
1888
 
8834 Boppan 1889
def handle_file(handled_files, asm_file_name, subdir = "."):
8966 Boppan 1890
	# Canonicalize the file path and get it relative to cwd
1891
	cwd = os.path.abspath(os.path.dirname(sys.argv[0]))
1892
	asm_file_name = os.path.realpath(asm_file_name)
1893
	asm_file_name = asm_file_name[len(cwd) + 1:]
1894
	# If it's lang.inc - skip it
1895
	if asm_file_name == 'lang.inc':
8967 Boppan 1896
		return
1897
	# If the file was handled in this execution before - skip it
1898
	if asm_file_name in handled_files:
1899
		return
1900
	# Say that the file was handled in this execution
1901
	handled_files.append(asm_file_name)
8966 Boppan 1902
	# Check if the file should be parsed (if it was modified or wasn't parsed yet)
1903
	should_get_declarations = True
1904
	if not it_neds_to_be_parsed(asm_file_name):
1905
		print(f"Skipping {asm_file_name} (already newest)")
1906
		should_get_declarations = False
1907
	else:
1908
		print(f"Parsing {asm_file_name}")
1909
	# Read the source
1910
	asm_file_contents = open(asm_file_name, "r", encoding="utf-8").read()
1911
	# Find includes, fix their paths and handle em recoursively
1912
	includes = re.findall(r'^include (["\'])(.*)\1', asm_file_contents, flags=re.MULTILINE)
8825 Boppan 1913
	for include in includes:
8957 Boppan 1914
		include = include[1].replace('\\', '/');
8825 Boppan 1915
		full_path = subdir + '/' + include;
8966 Boppan 1916
		# If the path isn't valid, maybe that's not relative path
1917
		if not os.path.isfile(full_path):
1918
			full_path = include
8967 Boppan 1919
		new_subdir = full_path.rsplit('/', 1)[0]
1920
		handle_file(handled_files, full_path, new_subdir)
8966 Boppan 1921
	# Only collect declarations from the file if it wasn't parsed before
1922
	if should_get_declarations:
1923
		get_declarations(asm_file_contents, asm_file_name)
8825 Boppan 1924
 
1925
kernel_files = []
1926
 
8834 Boppan 1927
handle_file(kernel_files, "./kernel.asm");
8825 Boppan 1928
 
8834 Boppan 1929
if dump_symbols:
8957 Boppan 1930
	for asm_element in elements:
1931
		asm_element.dump()
8825 Boppan 1932
 
8834 Boppan 1933
if print_stats:
8957 Boppan 1934
	print("--stats is not nimplmented")
8825 Boppan 1935
 
8967 Boppan 1936
if clean_generated_stuff:
1937
	kernel_files_set = set(kernel_files)
1938
	for file in kernel_files:
1939
		doxygen_file = f"{doxygen_src_path}/{file}"
1940
		if (os.path.isfile(doxygen_file)):
1941
			print(f"Removing {file}... ", end = '')
1942
			os.remove(doxygen_file)
1943
			print("Done.")
1944
else:
1945
	print(f"Writing doumented sources to {doxygen_src_path}")
8834 Boppan 1946
 
8967 Boppan 1947
	i = 0
1948
	for element in elements:
1949
		print(f"[{i + 1}/{len(elements)}] Emitting {element.name} from {element.location}")
1950
		element.emit(doxygen_src_path)
1951
		i += 1
8855 Boppan 1952
 
1953
if enable_warnings:
1954
	open('asmxygen.txt', "w", encoding = "utf-8").write(warnings)