Subversion Repositories Kolibri OS

Rev

Rev 9028 | Rev 9033 | 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):
9030 Boppan 1375
		print(f"\n{self.location}: {self.name}")
8957 Boppan 1376
		print(f"{self.comment}")
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()
9030 Boppan 1423
		print(f"(Variable)\n---")
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()
9030 Boppan 1449
		print(f"(Function)\n---")
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
9028 Boppan 1457
		# If there was no arguments, maybe that's just a label
1458
		# then parse parameters from its comment
1459
		if len(self.args) == 0 and '@param' in self.comment:
1460
			i = 0
1461
			while '@param' in self.comment[i:]:
1462
				i = self.comment.index('@param', i)
1463
				# Skip '@param'
1464
				i += len('@param')
1465
				# Skip spaces after '@param'
1466
				while self.comment[i].isspace():
1467
					i += 1
1468
				# Get the parameter name
1469
				name = ''
1470
				while is_id(self.comment[i]):
1471
					name += self.comment[i]
1472
					i += 1
1473
				# Save the parameter
1474
				self.args.append((name, 'arg_t'))
8963 Boppan 1475
		# Build the arg list for declaration
1476
		arg_list = '('
1477
		if len(self.args) > 0:
1478
			argc = 0
1479
			for arg in self.args:
1480
				if argc != 0:
1481
					arg_list += ", "
1482
				arg_list += f"{arg[1]} {arg[0]}"
1483
				argc += 1
1484
		arg_list += ')'
8957 Boppan 1485
		# Build the declaration
1486
		name = self.name.replace(".", "_")
8963 Boppan 1487
		declaration = f"void {name}{arg_list};"
8957 Boppan 1488
		# Emit this
1489
		super().emit(dest, doxycomment, declaration)
8855 Boppan 1490
 
8957 Boppan 1491
class AsmLabel(AsmElement):
1492
	def __init__(self, location, name, comment):
1493
		super().__init__(location, name, comment)
8855 Boppan 1494
 
8957 Boppan 1495
	def dump(self):
1496
		super().dump()
9030 Boppan 1497
		print(f"(Label)\n---")
8855 Boppan 1498
 
8957 Boppan 1499
	def emit(self, dest):
1500
		# Build doxycomment specific for the variable
1501
		doxycomment = ''
1502
		doxycomment += self.comment
1503
		if '@brief' not in doxycomment:
1504
			doxycomment = '@brief ' + doxycomment
1505
		# Build the declaration
1506
		name = self.name.replace(".", "_")
1507
		declaration = f"label {name};"
1508
		# Emit this
1509
		super().emit(dest, doxycomment, declaration)
8855 Boppan 1510
 
8957 Boppan 1511
class AsmMacro(AsmElement):
1512
	def __init__(self, location, name, comment, args):
1513
		super().__init__(location, name, comment)
1514
		self.args = args
8855 Boppan 1515
 
8957 Boppan 1516
	def dump(self):
1517
		super().dump()
9030 Boppan 1518
		print(f"(Macro)\n---")
8855 Boppan 1519
 
8957 Boppan 1520
	def emit(self, dest):
1521
		# Construct arg list without '['s, ']'s and '*'s
1522
		args = [arg for arg in self.args if arg not in "[]*"]
1523
		# Construct C-like arg list
1524
		arg_list = ""
1525
		if len(args) > 0:
1526
			arg_list += '('
1527
			argc = 0
1528
			for arg in args:
1529
				if argc != 0:
1530
					arg_list += ", "
1531
				arg_list += arg
1532
				argc += 1
1533
			arg_list += ')'
1534
		# Build doxycomment
1535
		doxycomment = ''
1536
		doxycomment += self.comment
1537
		if '@brief' not in doxycomment:
1538
			doxycomment = '@brief ' + doxycomment
1539
		# Build declaration
1540
		declaration = f"#define {self.name}{arg_list}"
1541
		# Emit this
1542
		super().emit(dest, doxycomment, declaration)
8855 Boppan 1543
 
8957 Boppan 1544
class AsmStruct(AsmElement):
1545
	def __init__(self, location, name, comment, members):
1546
		super().__init__(location, name, comment)
1547
		self.members = members
8855 Boppan 1548
 
8957 Boppan 1549
	def dump(self):
1550
		super().dump()
9030 Boppan 1551
		print(f"(Struct)\n---")
8855 Boppan 1552
 
8957 Boppan 1553
	def emit(self, dest):
1554
		# Build doxycomment
1555
		doxycomment = ''
1556
		doxycomment += self.comment
1557
		if '@brief' not in doxycomment:
1558
			doxycomment = '@brief ' + doxycomment
8958 Boppan 1559
		doxycomment += '\n'
8957 Boppan 1560
		# Build declaration
8958 Boppan 1561
		declaration = f"struct {self.name}" + " {\n"
1562
		for member in self.members:
1563
			if type(member) == AsmVariable:
1564
				declaration += f'\t{member.type} {member.name}; /**< {member.comment} */\n'
1565
		declaration += '};'
8957 Boppan 1566
		# Emit this
1567
		super().emit(dest, doxycomment, declaration)
8855 Boppan 1568
 
8957 Boppan 1569
class AsmUnion(AsmElement):
1570
	def __init__(self, location, name, comment, members):
1571
		super().__init__(location, name, comment)
1572
		self.members = members
8855 Boppan 1573
 
8957 Boppan 1574
	def dump(self):
1575
		super().dump()
9030 Boppan 1576
		print(f"(Union)\n---")
8855 Boppan 1577
 
8957 Boppan 1578
	def emit(self, dest):
1579
		# Build doxycomment
1580
		doxycomment = ''
1581
		doxycomment += self.comment
1582
		if '@brief' not in doxycomment:
1583
			doxycomment = '@brief ' + doxycomment
1584
		# Build declaration
1585
		declaration = f"union {self.name}" + " {};"
1586
		# Emit this
1587
		super().emit(dest, doxycomment, declaration)
8855 Boppan 1588
 
8957 Boppan 1589
class VariableNameIsMacroName:
1590
	def __init__(self, name):
1591
		self.name = name
8855 Boppan 1592
 
8957 Boppan 1593
def is_id(c):
1594
	return c.isprintable() and c not in "+-/*=<>()[]{};:,|&~#`'\" \n\r\t\v"
8855 Boppan 1595
 
8957 Boppan 1596
def is_starts_as_id(s):
1597
	return not s[0].isdigit()
1598
 
1599
def parse_after_macro(r):
1600
	location = r.location()
1601
 
1602
	# Skip spaces after the "macro" keyword
1603
	r.skip_spaces()
8855 Boppan 1604
	# Read macro name
1605
	name = ""
8957 Boppan 1606
	while is_id(r.curr()) or r.curr() == '#':
1607
		name += r.step()
8855 Boppan 1608
	# Skip spaces after macro name
8957 Boppan 1609
	r.skip_spaces()
8855 Boppan 1610
	# Find all arguments
1611
	args = []
1612
	arg = ''
8957 Boppan 1613
	while r.curr() and r.curr() != ';' and r.curr() != '{':
8855 Boppan 1614
		# Collect identifier
8957 Boppan 1615
		if is_id(r.curr()):
1616
			arg += r.step()
8855 Boppan 1617
		# Save the collected identifier
8957 Boppan 1618
		elif r.curr() == ',':
8855 Boppan 1619
			args.append(arg)
1620
			arg = ''
8957 Boppan 1621
			r.step()
8855 Boppan 1622
		# Just push the '['
8957 Boppan 1623
		elif r.curr() == '[':
1624
			args.append(r.step())
8855 Boppan 1625
		# Just push the identifier and get ']' ready to be pushed on next comma
8957 Boppan 1626
		elif r.curr() == ']':
8855 Boppan 1627
			args.append(arg)
8957 Boppan 1628
			arg = r.step()
8855 Boppan 1629
		# Just push the identifier and get '*' ready to be pushed on next comma
8957 Boppan 1630
		elif r.curr() == '*':
8855 Boppan 1631
			args.append(arg)
8957 Boppan 1632
			arg = r.step()
8855 Boppan 1633
		# Just skip whitespaces
8957 Boppan 1634
		elif r.curr().isspace():
1635
			r.step()
8855 Boppan 1636
		# Something unexpected
1637
		else:
8957 Boppan 1638
			raise Exception(f"Unexpected symbol '{r.curr()}' at index #{r.i} " +
1639
			                f"in the macro declaration at {location} " +
1640
			                f"(line: {r.lines[r.line_idx]})\n''")
1641
	# Append the last argument
8855 Boppan 1642
	if arg != '':
1643
		args.append(arg)
8957 Boppan 1644
	# Skip t spaces after the argument list
1645
	r.skip_spaces()
1646
	# Get a comment if it is: read till the end of the line and get the comment from the reader
1647
	while r.curr() != '':
1648
		r.step()
1649
	comment = r.comment
8855 Boppan 1650
	# Find end of the macro
8957 Boppan 1651
	prev = ''
1652
	while True:
1653
		if r.curr() == '}' and prev != '\\':
1654
			break
1655
		elif r.curr() == '':
1656
			prev = ''
1657
			r.nextline()
1658
			continue
1659
		prev = r.step()
8855 Boppan 1660
	# Build the output
8957 Boppan 1661
	return AsmMacro(location, name, comment, args)
8855 Boppan 1662
 
8957 Boppan 1663
def parse_variable(r, first_word = None):
1664
	global warnings
1665
	location = r.location()
8825 Boppan 1666
 
8957 Boppan 1667
	# Skip spaces before variable name
1668
	r.skip_spaces()
1669
	# Get variable name
1670
	name = ""
1671
	# Read it if it was not supplied
1672
	if first_word == None:
1673
		while is_id(r.curr()):
1674
			name += r.step()
1675
	# Or use the supplied one instead
1676
	else:
1677
		name = first_word
1678
	# Check the name
1679
	# If it's 0 len, that means threr's something else than an identifier at the beginning
1680
	if len(name) == 0:
1681
		return None
1682
	# If it starts from digit or othervice illegally it's illegal
1683
	if not is_starts_as_id(name):
1684
		return None
8976 Boppan 1685
	# Get kind of the identifier from id2kind table
1686
	kind = id_get_kind(name)
8957 Boppan 1687
	# If it's a keyword, that's not a variable declaration
8976 Boppan 1688
	if ID_KIND_KEYWORD in kind:
8957 Boppan 1689
		return None
1690
	# If it's a macro name, that's not a variable declaration
8976 Boppan 1691
	if ID_KIND_MACRO_NAME in kind:
8957 Boppan 1692
		return VariableNameIsMacroName(name)
1693
	# If it's a datatype or a structure name that's not a variable declaration: that's just a data
1694
	# don't document just a data for now
8976 Boppan 1695
	if ID_KIND_STRUCT_NAME in kind or ID_KIND_FASM_TYPE in kind:
8957 Boppan 1696
		return None
1697
	# Skip spaces before type name
1698
	r.skip_spaces()
1699
	# Read type name
1700
	var_type = ""
1701
	while is_id(r.curr()):
1702
		var_type += r.step()
1703
	# Check the type name
1704
	if len(var_type) == 0:
1705
		# If there's no type identifier after the name
1706
		# maybe the name is something meaningful for the next parser
1707
		# return it
1708
		return name
1709
	# If it starts from digit or othervice illegally it's illegal
1710
	if not is_starts_as_id(var_type):
1711
		return None
8976 Boppan 1712
	# Get kind of type identifier
1713
	type_kind = id_get_kind(var_type)
8957 Boppan 1714
	# If it's a keyword, that's not a variable declaration
1715
	# return the two words of the lexical structure
8976 Boppan 1716
	if ID_KIND_KEYWORD in type_kind:
8957 Boppan 1717
		return (name, var_type)
1718
	# Skip spaces before the value
1719
	r.skip_spaces()
1720
	# Read the value until the comment or end of the line
1721
	value = ""
1722
	while r.curr() != ';' and r.curr() != '' and r.curr() != '\n':
1723
		value += r.step()
1724
	# Skip spaces after the value
1725
	r.skip_spaces()
8961 Boppan 1726
	# Read till end of the line to get a comment from the reader
1727
	while r.curr() != '':
8957 Boppan 1728
		r.step()
8961 Boppan 1729
	# Build the result
8957 Boppan 1730
	return AsmVariable(location, name, r.comment, var_type, value)
8825 Boppan 1731
 
8957 Boppan 1732
def parse_after_struct(r, as_union = True):
1733
	global warnings
1734
	location = r.location()
8825 Boppan 1735
 
8957 Boppan 1736
	# Skip spaces after "struct" keyword
1737
	r.skip_spaces()
1738
	# Read struct name
1739
	name = ""
1740
	while is_id(r.curr()):
1741
		name += r.step()
1742
	# Read till end of the line and get the comment from the reader
1743
	while r.curr() != '':
1744
		r.step()
1745
	comment = r.comment
1746
	# Get to the next line to parse struct members
1747
	r.nextline()
1748
	# Parse struct members
1749
	members = []
1750
	while True:
1751
		r.skip_spaces()
1752
		var = parse_variable(r)
1753
		if type(var) == AsmVariable:
1754
			members.append(var)
1755
		elif type(var) == str:
1756
			if var == 'union':
1757
				# Parse the union as a struct
1758
				union = parse_after_struct(r, as_union = True)
1759
				members.append(union)
1760
				# Skip the ends of the union
1761
				r.nextline()
1762
			elif r.curr() == ':':
1763
				warnings += f"{r.location()}: Skept the label in the struct\n"
1764
			else:
1765
				raise Exception(f"Garbage in struct member at {location} (got '{var}' identifier)")
1766
		elif type(var) == VariableNameIsMacroName:
1767
			if var.name == 'ends':
1768
				break
1769
		r.nextline()
1770
	# Return the result
1771
	if as_union:
1772
		return AsmStruct(location, name, comment, members)
1773
	else:
1774
		return AsmUnion(location, name, comment, members)
8825 Boppan 1775
 
8963 Boppan 1776
def parse_after_proc(r):
1777
	# Get proc name
1778
	name = r.fetch_identifier()
1779
	# Next identifier after the proc name
1780
	identifier = r.fetch_identifier()
1781
	# Check if the id is 'stdcall' or 'c' (calling convention specifier)
1782
	# and if so - save the convention and lookup the next identifier
1783
	calling_convention = ''
1784
	if identifier == 'stdcall' or identifier == 'c':
1785
		calling_convention = identifier
1786
		# If next is a comma, just skip it
1787
		if r.curr() == ',':
1788
			r.step()
1789
		# Read the next identifier
1790
		identifier = r.fetch_identifier()
1791
	# Check if the id is 'uses' (used register list specifier)
1792
	# and if so save the used register list
1793
	used_regs = []
1794
	if identifier == 'uses':
1795
		# Read the registers
1796
		while True:
1797
			reg_name = r.fetch_identifier()
1798
			if reg_name != '':
1799
				used_regs.append(reg_name)
1800
			else:
1801
				break
1802
		# If next is a comma, just skip it
1803
		if r.curr() == ',':
1804
			r.step()
1805
		# Read the next identifier
1806
		identifier = r.fetch_identifier()
1807
	# Check if there are argument identifiers
1808
	args = []
1809
	while identifier != '':
1810
		arg_name = identifier
1811
		arg_type = 'arg_t'
1812
		# Skip spaces after argument name
1813
		r.skip_spaces()
1814
		# If there's a ':' after the name - the next identifier is type
1815
		if r.curr() == ':':
1816
			r.step()
1817
			arg_type = r.fetch_identifier()
1818
		# If there's a comma - there's one more argument
1819
		# else no arguments anymore
1820
		if r.curr() == ',':
1821
			r.step()
1822
			identifier = r.fetch_identifier()
1823
		else:
1824
			identifier = ''
1825
		args.append((arg_name, arg_type))
1826
	# Get to the end of the line and get a comment from the reader
1827
	while r.curr() != '':
1828
		r.step()
8973 Boppan 1829
	comment = r.comment
8963 Boppan 1830
	# Build the element
1831
	return AsmFunction(r.location(), name, comment, calling_convention, args, used_regs)
1832
 
8957 Boppan 1833
def get_declarations(asm_file_contents, asm_file_name):
1834
	r = AsmReader(asm_file_name)
8825 Boppan 1835
 
8957 Boppan 1836
	while not r.no_lines():
1837
		# Skip leading spaces
1838
		r.skip_spaces()
1839
		# Skip the line if it's starting with a comment
1840
		if r.curr() == ';':
1841
			r.nextline()
8825 Boppan 1842
			continue
8957 Boppan 1843
		# Get first word
1844
		first_word = ""
1845
		while is_id(r.curr()):
1846
			first_word += r.step()
1847
		# Match macro declaration
1848
		if first_word == "macro":
1849
			macro = parse_after_macro(r)
1850
			elements.append(macro)
8976 Boppan 1851
			id_add_kind(macro.name, ID_KIND_MACRO_NAME)
8957 Boppan 1852
		# Match structure declaration
1853
		elif first_word == "struct":
1854
			struct = parse_after_struct(r)
1855
			elements.append(struct)
8976 Boppan 1856
			id_add_kind(struct.name, ID_KIND_STRUCT_NAME)
8957 Boppan 1857
		# Match function definition
1858
		elif first_word == "proc":
8963 Boppan 1859
			proc = parse_after_proc(r)
1860
			elements.append(proc)
8957 Boppan 1861
		elif first_word == 'format':
1862
			# Skip the format directive
1863
			pass
1864
		elif first_word == 'include':
1865
			# Skip the include directive
1866
			pass
1867
		elif first_word == 'if':
1868
			# Skip the conditional directive
1869
			pass
1870
		elif first_word == 'repeat':
1871
			# Skip the repeat directive
1872
			pass
1873
		elif first_word == 'purge':
1874
			while True:
1875
				# Skip spaces after the 'purge' keyword or after the comma what separated the previous macro name
1876
				r.skip_spaces()
1877
				# Get the purged macro name
1878
				name = ''
1879
				while is_id(r.curr()):
1880
					name += r.step()
1881
				# Remove the purged macro from the macro names list
1882
				try:
8976 Boppan 1883
					id_remove_kind(name, ID_KIND_MACRO_NAME)
8957 Boppan 1884
				except:
1885
					pass
1886
				# Skip spaces after the name
1887
				r.skip_spaces()
1888
				# If it's comma (',') after then that's not the last purged macro, continue purging
1889
				if r.curr() == ',':
1890
					r.step()
1891
					continue
1892
				# Here we purged all the macros should be purged
1893
				break
1894
		# Match label or a variable
1895
		elif len(first_word) != 0:
1896
			# Skip spaces after the identifier
1897
			r.skip_spaces()
1898
			# Match a variable
1899
			var = parse_variable(r, first_word)
1900
			if type(var) == AsmVariable:
1901
				elements.append(var)
1902
			# If it wasn't a variable but there was an identifier
1903
			# Maybe that's a label and the identifier is the label name
1904
			# The parse_variable returns the first found or supplied identifier
1905
			# In this case it returns the first_word which is supplied
1906
			# If it didn't match a type identifier after the word
1907
			elif type(var) == str:
1908
				name = var
1909
				# Match label beginning (':' after name)
1910
				if r.curr() == ':':
1911
					# Get to the end of the line and get the coment from the reader
1912
					while r.curr() != '':
1913
						r.step()
1914
					comment = r.comment
1915
					# Only handle non-local labels
1916
					if name[0] != '.' and name != "@@" and name != "$Revision":
8989 Boppan 1917
						if '@return' in comment or '@param' in comment:
1918
							element = AsmFunction(r.location(), name, comment, '', [], [])
1919
						else:
1920
							element = AsmLabel(r.location(), name, comment)
1921
						elements.append(element)
8957 Boppan 1922
				elif r.curr() == '=':
8976 Boppan 1923
					# Save the identifier as a set constant
1924
					id_add_kind(first_word, ID_KIND_SET_CONSTANT)
8957 Boppan 1925
			elif type(var) == tuple:
1926
				(word_one, word_two) = var
1927
				if word_two == 'equ':
8976 Boppan 1928
					# Save the identifier as an equated constant
1929
					id_add_kind(word_one, ID_KIND_EQUATED_CONSTANT)
8957 Boppan 1930
		r.nextline()
8825 Boppan 1931
 
8966 Boppan 1932
def it_neds_to_be_parsed(source_file):
8990 Boppan 1933
	# If there's no symbols file saved - parse it anyway
1934
	# cause we need to create the symbols file and use it
1935
	# if we gonna generate proper doxygen
1936
	if not os.path.isfile('asmxygen.elements.pickle'):
1937
		return True
8966 Boppan 1938
	dest = doxygen_src_path + '/' + source_file
1939
	# If there's no the doxygen file it should be compiled to
1940
	# then yes, we should compile it to doxygen
1941
	if not os.path.isfile(dest):
1942
		return True
1943
	source_change_time = os.path.getmtime(source_file)
1944
	dest_change_file = os.path.getmtime(dest)
1945
	# If the source is newer than the doxygen it was compiled to
1946
	# then the source should be recompiled (existing doxygen is old)
1947
	if source_change_time > dest_change_file:
1948
		return True
1949
	return False
1950
 
8834 Boppan 1951
def handle_file(handled_files, asm_file_name, subdir = "."):
8990 Boppan 1952
	global elements
8966 Boppan 1953
	# Canonicalize the file path and get it relative to cwd
1954
	cwd = os.path.abspath(os.path.dirname(sys.argv[0]))
1955
	asm_file_name = os.path.realpath(asm_file_name)
1956
	asm_file_name = asm_file_name[len(cwd) + 1:]
1957
	# If it's lang.inc - skip it
1958
	if asm_file_name == 'lang.inc':
8967 Boppan 1959
		return
1960
	# If the file was handled in this execution before - skip it
1961
	if asm_file_name in handled_files:
1962
		return
1963
	# Say that the file was handled in this execution
1964
	handled_files.append(asm_file_name)
8966 Boppan 1965
	# Check if the file should be parsed (if it was modified or wasn't parsed yet)
1966
	should_get_declarations = True
1967
	if not it_neds_to_be_parsed(asm_file_name):
1968
		print(f"Skipping {asm_file_name} (already newest)")
1969
		should_get_declarations = False
1970
	else:
8975 Boppan 1971
		print(f"Handling {asm_file_name}")
8990 Boppan 1972
		# Remove elements parsed from this file before if any
1973
		elements_to_remove = [x for x in elements if x.location.split(':')[0] == asm_file_name]
1974
		elements = [x for x in elements if x.location.split(':')[0] != asm_file_name]
1975
		# Forget types of identifiers of names of the removed elements
1976
		for element in elements_to_remove:
1977
			if type(element) == AsmStruct:
1978
				id_remove_kind(element.name, ID_KIND_STRUCT_NAME)
1979
			elif type(element) == AsmMacro:
1980
				id_remove_kind(element.name, ID_KIND_MACRO_NAME)
8966 Boppan 1981
	# Read the source
1982
	asm_file_contents = open(asm_file_name, "r", encoding="utf-8").read()
1983
	# Find includes, fix their paths and handle em recoursively
1984
	includes = re.findall(r'^include (["\'])(.*)\1', asm_file_contents, flags=re.MULTILINE)
8825 Boppan 1985
	for include in includes:
8957 Boppan 1986
		include = include[1].replace('\\', '/');
8825 Boppan 1987
		full_path = subdir + '/' + include;
8966 Boppan 1988
		# If the path isn't valid, maybe that's not relative path
1989
		if not os.path.isfile(full_path):
1990
			full_path = include
8967 Boppan 1991
		new_subdir = full_path.rsplit('/', 1)[0]
1992
		handle_file(handled_files, full_path, new_subdir)
8966 Boppan 1993
	# Only collect declarations from the file if it wasn't parsed before
8975 Boppan 1994
	if should_get_declarations and not clean_generated_stuff:
8966 Boppan 1995
		get_declarations(asm_file_contents, asm_file_name)
8825 Boppan 1996
 
1997
kernel_files = []
1998
 
8990 Boppan 1999
# Load remembered list of symbols
2000
if os.path.isfile('asmxygen.elements.pickle'):
2001
	print('Reading existing dump of symbols')
2002
	(elements, id2kind) = pickle.load(open('asmxygen.elements.pickle', 'rb'))
2003
 
8834 Boppan 2004
handle_file(kernel_files, "./kernel.asm");
8825 Boppan 2005
 
8834 Boppan 2006
if dump_symbols:
8957 Boppan 2007
	for asm_element in elements:
2008
		asm_element.dump()
8825 Boppan 2009
 
8967 Boppan 2010
if clean_generated_stuff:
2011
	kernel_files_set = set(kernel_files)
2012
	for file in kernel_files:
2013
		doxygen_file = f"{doxygen_src_path}/{file}"
2014
		if (os.path.isfile(doxygen_file)):
2015
			print(f"Removing {file}... ", end = '')
2016
			os.remove(doxygen_file)
2017
			print("Done.")
8976 Boppan 2018
elif not noemit:
8967 Boppan 2019
	print(f"Writing doumented sources to {doxygen_src_path}")
8834 Boppan 2020
 
8967 Boppan 2021
	i = 0
8990 Boppan 2022
	new_elements = [x for x in elements if x.new]
2023
	for element in new_elements:
2024
		print(f"[{i + 1}/{len(new_elements)}] Emitting {element.name} from {element.location}")
8967 Boppan 2025
		element.emit(doxygen_src_path)
2026
		i += 1
8855 Boppan 2027
 
8990 Boppan 2028
	print(f"Writing dump of symbols to asmxygen.elements.pickle")
2029
 
2030
	# Now when the new elements already was written, there's no new elements anymore
2031
	for element in elements:
2032
		element.new = False
2033
	pickle.dump((elements, id2kind), open('asmxygen.elements.pickle', 'wb'))
2034
 
8982 Boppan 2035
if print_stats:
2036
	var_count = 0
2037
	mac_count = 0
2038
	lab_count = 0
2039
	fun_count = 0
2040
	uni_count = 0
2041
	str_count = 0
2042
	for element in elements:
2043
		if type(element) == AsmVariable:
2044
			var_count += 1
2045
		elif type(element) == AsmMacro:
2046
			mac_count += 1
2047
		elif type(element) == AsmLabel:
2048
			lab_count += 1
2049
		elif type(element) == AsmFunction:
2050
			fun_count += 1
2051
		elif type(element) == AsmUnion:
2052
			uni_count += 1
2053
		elif type(element) == AsmStruct:
2054
			str_count += 1
2055
	print(f'Parsed variable count: {var_count}')
2056
	print(f'Parsed macro count: {mac_count}')
2057
	print(f'Parsed label count: {lab_count}')
2058
	print(f'Parsed function count: {fun_count}')
2059
	print(f'Parsed union type count: {uni_count}')
2060
	print(f'Parsed structure type count: {str_count}')
2061
 
8855 Boppan 2062
if enable_warnings:
2063
	open('asmxygen.txt', "w", encoding = "utf-8").write(warnings)