Subversion Repositories Kolibri OS

Rev

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