Subversion Repositories Kolibri OS

Rev

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