Subversion Repositories Kolibri OS

Rev

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