Subversion Repositories Kolibri OS

Rev

Rev 9407 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 9407 Rev 9408
1
import re
1
import re
2
import os
2
import os
3
import argparse
3
import argparse
4
import sys
4
import sys
5
import pickle
5
import pickle
6
import hashlib
6
import hashlib
7
import difflib
7
import difflib
8
 
8
 
9
# fasm keywords
9
# fasm keywords
10
keywords = [
10
keywords = [
11
    "align", "equ", "org", "while", "load", "store", "times", "repeat", 
11
    "align", "equ", "org", "while", "load", "store", "times", "repeat",
12
    "display", "err", "assert", "if", "aaa", "aad", "aam", "aas", "adc", 
12
    "display", "err", "assert", "if", "aaa", "aad", "aam", "aas", "adc",
13
    "add", "addpd", "addps", "addsd", "addss", "addsubpd", "addsubps", "adox", 
13
    "add", "addpd", "addps", "addsd", "addss", "addsubpd", "addsubps", "adox",
14
    "aesdeclast", "aesenc", "aesenclast", "aesimc", "aeskeygenassist", "and", 
14
    "aesdeclast", "aesenc", "aesenclast", "aesimc", "aeskeygenassist", "and",
15
    "andnpd", "andnps", "andpd", "andps", "arpl", "bextr", "blendpd", 
15
    "andnpd", "andnps", "andpd", "andps", "arpl", "bextr", "blendpd",
16
    "blendvpd", "blendvps", "blsi", "blsmsk", "blsr", "bndcl", "bndcn", 
16
    "blendvpd", "blendvps", "blsi", "blsmsk", "blsr", "bndcl", "bndcn",
17
    "bndldx", "bndmk", "bndmov", "bndstx", "bound", "bsf", "bsr", "bswap", 
17
    "bndldx", "bndmk", "bndmov", "bndstx", "bound", "bsf", "bsr", "bswap",
18
    "btc", "btr", "bts", "bzhi", "call", "cbw", "cdq", "cdqe", "clac", "clc", 
18
    "btc", "btr", "bts", "bzhi", "call", "cbw", "cdq", "cdqe", "clac", "clc",
19
    "cldemote", "clflush", "clflushopt", "cli", "clts", "clwb", "cmc", "cmova", 
19
    "cldemote", "clflush", "clflushopt", "cli", "clts", "clwb", "cmc", "cmova",
20
    "cmovb", "cmovbe", "cmovc", "cmove", "cmovg", "cmovge", "cmovl", "cmovle", 
20
    "cmovb", "cmovbe", "cmovc", "cmove", "cmovg", "cmovge", "cmovl", "cmovle",
21
    "cmovnae", "cmovnb", "cmovnbe", "cmovnc", "cmovne", "cmovng", "cmovnge", 
21
    "cmovnae", "cmovnb", "cmovnbe", "cmovnc", "cmovne", "cmovng", "cmovnge",
22
    "cmovnle", "cmovno", "cmovnp", "cmovns", "cmovnz", "cmovo", "cmovp", 
22
    "cmovnle", "cmovno", "cmovnp", "cmovns", "cmovnz", "cmovo", "cmovp",
23
    "cmovpo", "cmovs", "cmovz", "cmp", "cmppd", "cmpps", "cmps", "cmpsb", 
23
    "cmovpo", "cmovs", "cmovz", "cmp", "cmppd", "cmpps", "cmps", "cmpsb",
24
    "cmpsd", "cmpsq", "cmpss", "cmpsw", "cmpxchg", "cmpxchg16b", "cmpxchg8b", 
24
    "cmpsd", "cmpsq", "cmpss", "cmpsw", "cmpxchg", "cmpxchg16b", "cmpxchg8b",
25
    "comiss", "cpuid", "cqo", "crc32", "cvtdq2pd", "cvtdq2ps", "cvtpd2dq", 
25
    "comiss", "cpuid", "cqo", "crc32", "cvtdq2pd", "cvtdq2ps", "cvtpd2dq",
26
    "cvtpd2ps", "cvtpi2pd", "cvtpi2ps", "cvtps2dq", "cvtps2pd", "cvtps2pi", 
26
    "cvtpd2ps", "cvtpi2pd", "cvtpi2ps", "cvtps2dq", "cvtps2pd", "cvtps2pi",
27
    "cvtsd2ss", "cvtsi2sd", "cvtsi2ss", "cvtss2sd", "cvtss2si", "cvttpd2dq", 
27
    "cvtsd2ss", "cvtsi2sd", "cvtsi2ss", "cvtss2sd", "cvtss2si", "cvttpd2dq",
28
    "cvttps2dq", "cvttps2pi", "cvttsd2si", "cvttss2si", "cwd", "cwde", "daa", 
28
    "cvttps2dq", "cvttps2pi", "cvttsd2si", "cvttss2si", "cwd", "cwde", "daa",
29
    "dec", "div", "divpd", "divps", "divsd", "divss", "dppd", "dpps", "emms", 
29
    "dec", "div", "divpd", "divps", "divsd", "divss", "dppd", "dpps", "emms",
30
    "extractps", "f2xm1", "fabs", "fadd", "faddp", "fbld", "fbstp", "fchs", 
30
    "extractps", "f2xm1", "fabs", "fadd", "faddp", "fbld", "fbstp", "fchs",
31
    "fcmova", "fcmovae", "fcmovb", "fcmovbe", "fcmovc", "fcmove", "fcmovg", 
31
    "fcmova", "fcmovae", "fcmovb", "fcmovbe", "fcmovc", "fcmove", "fcmovg",
32
    "fcmovl", "fcmovle", "fcmovna", "fcmovnae", "fcmovnb", "fcmovnbe", 
32
    "fcmovl", "fcmovle", "fcmovna", "fcmovnae", "fcmovnb", "fcmovnbe",
33
    "fcmovne", "fcmovng", "fcmovnge", "fcmovnl", "fcmovnle", "fcmovno", 
33
    "fcmovne", "fcmovng", "fcmovnge", "fcmovnl", "fcmovnle", "fcmovno",
34
    "fcmovns", "fcmovnz", "fcmovo", "fcmovp", "fcmovpe", "fcmovpo", "fcmovs", 
34
    "fcmovns", "fcmovnz", "fcmovo", "fcmovp", "fcmovpe", "fcmovpo", "fcmovs",
35
    "fcom", "fcomi", "fcomip", "fcomp", "fcompp", "fcos", "fdecstp", "fdiv", 
35
    "fcom", "fcomi", "fcomip", "fcomp", "fcompp", "fcos", "fdecstp", "fdiv",
36
    "fdivr", "fdivrp", "ffree", "fiadd", "ficom", "ficomp", "fidiv", "fidivr", 
36
    "fdivr", "fdivrp", "ffree", "fiadd", "ficom", "ficomp", "fidiv", "fidivr",
37
    "fimul", "fincstp", "finit", "fist", "fistp", "fisttp", "fisub", "fisubr", 
37
    "fimul", "fincstp", "finit", "fist", "fistp", "fisttp", "fisub", "fisubr",
38
    "fld1", "fldcw", "fldenv", "fldl2e", "fldl2t", "fldlg2", "fldln2", "fldpi", 
38
    "fld1", "fldcw", "fldenv", "fldl2e", "fldl2t", "fldlg2", "fldln2", "fldpi",
39
    "fmul", "fmulp", "fnclex", "fninit", "fnop", "fnsave", "fnstcw", "fnstenv", 
39
    "fmul", "fmulp", "fnclex", "fninit", "fnop", "fnsave", "fnstcw", "fnstenv",
40
    "fpatan", "fprem", "fprem1", "fptan", "frndint", "frstor", "fsave", 
40
    "fpatan", "fprem", "fprem1", "fptan", "frndint", "frstor", "fsave",
41
    "fsin", "fsincos", "fsqrt", "fst", "fstcw", "fstenv", "fstp", "fstsw", 
41
    "fsin", "fsincos", "fsqrt", "fst", "fstcw", "fstenv", "fstp", "fstsw",
42
    "fsubp", "fsubr", "fsubrp", "ftst", "fucom", "fucomi", "fucomip", "fucomp", 
42
    "fsubp", "fsubr", "fsubrp", "ftst", "fucom", "fucomi", "fucomip", "fucomp",
43
    "fwait", "fxam", "fxch", "fxrstor", "fxsave", "fxtract", "fyl2x", 
43
    "fwait", "fxam", "fxch", "fxrstor", "fxsave", "fxtract", "fyl2x",
44
    "gf2p8affineinvqb", "gf2p8affineqb", "gf2p8mulb", "haddpd", "haddps", 
44
    "gf2p8affineinvqb", "gf2p8affineqb", "gf2p8mulb", "haddpd", "haddps",
45
    "hsubpd", "hsubps", "idiv", "imul", "in", "inc", "ins", "insb", "insd", 
45
    "hsubpd", "hsubps", "idiv", "imul", "in", "inc", "ins", "insb", "insd",
46
    "insw", "int", "int1", "int3", "into", "invd", "invlpg", "invpcid", "iret", 
46
    "insw", "int", "int1", "int3", "into", "invd", "invlpg", "invpcid", "iret",
47
    "jmp", "ja", "jae", "jb", "jbe", "jc", "jcxz", "jecxz", "je", "jg", "jge", 
47
    "jmp", "ja", "jae", "jb", "jbe", "jc", "jcxz", "jecxz", "je", "jg", "jge",
48
    "jle", "jna", "jnae", "jnb", "jnbe", "jnc", "jne", "jng", "jnge", "jnl", 
48
    "jle", "jna", "jnae", "jnb", "jnbe", "jnc", "jne", "jng", "jnge", "jnl",
49
    "jno", "jnp", "jns", "jnz", "jo", "jp", "jpe", "jpo", "js", "jz", "kaddb", 
49
    "jno", "jnp", "jns", "jnz", "jo", "jp", "jpe", "jpo", "js", "jz", "kaddb",
50
    "kaddq", "kaddw", "kandb", "kandd", "kandnb", "kandnd", "kandnq", "kandnw", 
50
    "kaddq", "kaddw", "kandb", "kandd", "kandnb", "kandnd", "kandnq", "kandnw",
51
    "kandw", "kmovb", "kmovd", "kmovq", "kmovw", "knotb", "knotd", "knotq", 
51
    "kandw", "kmovb", "kmovd", "kmovq", "kmovw", "knotb", "knotd", "knotq",
52
    "korb", "kord", "korq", "kortestb", "kortestd", "kortestq", "kortestw", 
52
    "korb", "kord", "korq", "kortestb", "kortestd", "kortestq", "kortestw",
53
    "kshiftlb", "kshiftld", "kshiftlq", "kshiftlw", "kshiftrb", "kshiftrd", 
53
    "kshiftlb", "kshiftld", "kshiftlq", "kshiftlw", "kshiftrb", "kshiftrd",
54
    "kshiftrw", "ktestb", "ktestd", "ktestq", "ktestw", "kunpckbw", "kunpckdq", 
54
    "kshiftrw", "ktestb", "ktestd", "ktestq", "ktestw", "kunpckbw", "kunpckdq",
55
    "kxnorb", "kxnord", "kxnorq", "kxnorw", "kxorb", "kxord", "kxorq", "kxorw", 
55
    "kxnorb", "kxnord", "kxnorq", "kxnorw", "kxorb", "kxord", "kxorq", "kxorw",
56
    "lar", "lddqu", "ldmxcsr", "lds", "lea", "leave", "les", "lfence", "lfs", 
56
    "lar", "lddqu", "ldmxcsr", "lds", "lea", "leave", "les", "lfence", "lfs",
57
    "lgs", "lidt", "lldt", "lmsw", "lock", "lods", "lodsb", "lodsd", "lodsq", 
57
    "lgs", "lidt", "lldt", "lmsw", "lock", "lods", "lodsb", "lodsd", "lodsq",
58
    "loop", "loopa", "loopae", "loopb", "loopbe", "loopc", "loope", "loopg", 
58
    "loop", "loopa", "loopae", "loopb", "loopbe", "loopc", "loope", "loopg",
59
    "loopl", "loople", "loopna", "loopnae", "loopnb", "loopnbe", "loopnc", 
59
    "loopl", "loople", "loopna", "loopnae", "loopnb", "loopnbe", "loopnc",
60
    "loopng", "loopnge", "loopnl", "loopnle", "loopno", "loopnp", "loopns", 
60
    "loopng", "loopnge", "loopnl", "loopnle", "loopno", "loopnp", "loopns",
61
    "loopo", "loopp", "looppe", "looppo", "loops", "loopz", "lsl", "lss", 
61
    "loopo", "loopp", "looppe", "looppo", "loops", "loopz", "lsl", "lss",
62
    "lzcnt", "maskmovdqu", "maskmovq", "maxpd", "maxps", "maxsd", "maxss", 
62
    "lzcnt", "maskmovdqu", "maskmovq", "maxpd", "maxps", "maxsd", "maxss",
63
    "minpd", "minps", "minsd", "minss", "monitor", "mov", "movapd", "movaps", 
63
    "minpd", "minps", "minsd", "minss", "monitor", "mov", "movapd", "movaps",
64
    "movd", "movddup", "movdir64b", "movdiri", "movdq2q", "movdqa", "movdqu", 
64
    "movd", "movddup", "movdir64b", "movdiri", "movdq2q", "movdqa", "movdqu",
65
    "movhpd", "movhps", "movlhps", "movlpd", "movlps", "movmskpd", "movmskps", 
65
    "movhpd", "movhps", "movlhps", "movlpd", "movlps", "movmskpd", "movmskps",
66
    "movntdqa", "movnti", "movntpd", "movntps", "movntq", "movq", "movq", 
66
    "movntdqa", "movnti", "movntpd", "movntps", "movntq", "movq", "movq",
67
    "movs", "movsb", "movsd", "movsd", "movshdup", "movsldup", "movsq", 
67
    "movs", "movsb", "movsd", "movsd", "movshdup", "movsldup", "movsq",
68
    "movsw", "movsx", "movsxd", "movupd", "movups", "movzx", "mpsadbw", "mul", 
68
    "movsw", "movsx", "movsxd", "movupd", "movups", "movzx", "mpsadbw", "mul",
69
    "mulps", "mulsd", "mulss", "mulx", "mwait", "neg", "nop", "not", "or", 
69
    "mulps", "mulsd", "mulss", "mulx", "mwait", "neg", "nop", "not", "or",
70
    "orps", "out", "outs", "outsb", "outsd", "outsw", "pabsb", "pabsd", 
70
    "orps", "out", "outs", "outsb", "outsd", "outsw", "pabsb", "pabsd",
71
    "pabsw", "packssdw", "packsswb", "packusdw", "packuswb", "paddb", "paddd", 
71
    "pabsw", "packssdw", "packsswb", "packusdw", "packuswb", "paddb", "paddd",
72
    "paddsb", "paddsw", "paddusb", "paddusw", "paddw", "palignr", "pand", 
72
    "paddsb", "paddsw", "paddusb", "paddusw", "paddw", "palignr", "pand",
73
    "pause", "pavgb", "pavgw", "pblendvb", "pblendw", "pclmulqdq", "pcmpeqb", 
73
    "pause", "pavgb", "pavgw", "pblendvb", "pblendw", "pclmulqdq", "pcmpeqb",
74
    "pcmpeqq", "pcmpeqw", "pcmpestri", "pcmpestrm", "pcmpgtb", "pcmpgtd", 
74
    "pcmpeqq", "pcmpeqw", "pcmpestri", "pcmpestrm", "pcmpgtb", "pcmpgtd",
75
    "pcmpgtw", "pcmpistri", "pcmpistrm", "pdep", "pext", "pextrb", "pextrd", 
75
    "pcmpgtw", "pcmpistri", "pcmpistrm", "pdep", "pext", "pextrb", "pextrd",
76
    "pextrw", "phaddd", "phaddsw", "phaddw", "phminposuw", "phsubd", "phsubsw", 
76
    "pextrw", "phaddd", "phaddsw", "phaddw", "phminposuw", "phsubd", "phsubsw",
77
    "pinsrb", "pinsrd", "pinsrq", "pinsrw", "pmaddubsw", "pmaddwd", "pmaxsb", 
77
    "pinsrb", "pinsrd", "pinsrq", "pinsrw", "pmaddubsw", "pmaddwd", "pmaxsb",
78
    "pmaxsq", "pmaxsw", "pmaxub", "pmaxud", "pmaxuq", "pmaxuw", "pminsb", 
78
    "pmaxsq", "pmaxsw", "pmaxub", "pmaxud", "pmaxuq", "pmaxuw", "pminsb",
79
    "pminsq", "pminsw", "pminub", "pminud", "pminuq", "pminuw", "pmovmskb", 
79
    "pminsq", "pminsw", "pminub", "pminud", "pminuq", "pminuw", "pmovmskb",
80
    "pmovzx", "pmuldq", "pmulhrsw", "pmulhuw", "pmulhw", "pmulld", "pmullq", 
80
    "pmovzx", "pmuldq", "pmulhrsw", "pmulhuw", "pmulhw", "pmulld", "pmullq",
81
    "pmuludq", "pop", "popa", "popad", "popcnt", "popf", "popfd", "popfq", 
81
    "pmuludq", "pop", "popa", "popad", "popcnt", "popf", "popfd", "popfq",
82
    "prefetchw", "prefetchh", "psadbw", "pshufb", "pshufd", "pshufhw", 
82
    "prefetchw", "prefetchh", "psadbw", "pshufb", "pshufd", "pshufhw",
83
    "pshufw", "psignb", "psignd", "psignw", "pslld", "pslldq", "psllq", 
83
    "pshufw", "psignb", "psignd", "psignw", "pslld", "pslldq", "psllq",
84
    "psrad", "psraq", "psraw", "psrld", "psrldq", "psrlq", "psrlw", "psubb", 
84
    "psrad", "psraq", "psraw", "psrld", "psrldq", "psrlq", "psrlw", "psubb",
85
    "psubq", "psubsb", "psubsw", "psubusb", "psubusw", "psubw", "ptest", 
85
    "psubq", "psubsb", "psubsw", "psubusb", "psubusw", "psubw", "ptest",
86
    "punpckhbw", "punpckhdq", "punpckhqdq", "punpckhwd", "punpcklbw", 
86
    "punpckhbw", "punpckhdq", "punpckhqdq", "punpckhwd", "punpcklbw",
87
    "punpcklqdq", "punpcklwd", "push", "pushw", "pushd", "pusha", "pushad", 
87
    "punpcklqdq", "punpcklwd", "push", "pushw", "pushd", "pusha", "pushad",
88
    "pushfd", "pushfq", "pxor", "rcl", "rcpps", "rcpss", "rcr", "rdfsbase", 
88
    "pushfd", "pushfq", "pxor", "rcl", "rcpps", "rcpss", "rcr", "rdfsbase",
89
    "rdmsr", "rdpid", "rdpkru", "rdpmc", "rdrand", "rdseed", "rdtsc", "rdtscp", 
89
    "rdmsr", "rdpid", "rdpkru", "rdpmc", "rdrand", "rdseed", "rdtsc", "rdtscp",
90
    "repe", "repne", "repnz", "repz", "ret", "rol", "ror", "rorx", "roundpd", 
90
    "repe", "repne", "repnz", "repz", "ret", "rol", "ror", "rorx", "roundpd",
91
    "roundsd", "roundss", "rsm", "rsqrtps", "rsqrtss", "sahf", "sal", "sar", 
91
    "roundsd", "roundss", "rsm", "rsqrtps", "rsqrtss", "sahf", "sal", "sar",
92
    "sbb", "scas", "scasb", "scasd", "scasw", "seta", "setae", "setb", "setbe", 
92
    "sbb", "scas", "scasb", "scasd", "scasw", "seta", "setae", "setb", "setbe",
93
    "sete", "setg", "setge", "setl", "setle", "setna", "setnae", "setnb", 
93
    "sete", "setg", "setge", "setl", "setle", "setna", "setnae", "setnb",
94
    "setnc", "setne", "setng", "setnge", "setnl", "setnle", "setno", "setnp", 
94
    "setnc", "setne", "setng", "setnge", "setnl", "setnle", "setno", "setnp",
95
    "setnz", "seto", "setp", "setpe", "setpo", "sets", "setz", "sfence", 
95
    "setnz", "seto", "setp", "setpe", "setpo", "sets", "setz", "sfence",
96
    "sha1msg1", "sha1msg2", "sha1nexte", "sha1rnds4", "sha256msg1", 
96
    "sha1msg1", "sha1msg2", "sha1nexte", "sha1rnds4", "sha256msg1",
97
    "sha256rnds2", "shl", "shld", "shlx", "shr", "shrd", "shrx", "shufpd", 
97
    "sha256rnds2", "shl", "shld", "shlx", "shr", "shrd", "shrx", "shufpd",
98
    "sidt", "sldt", "smsw", "sqrtpd", "sqrtps", "sqrtsd", "sqrtss", "stac", 
98
    "sidt", "sldt", "smsw", "sqrtpd", "sqrtps", "sqrtsd", "sqrtss", "stac",
99
    "std", "sti", "stmxcsr", "stos", "stosb", "stosd", "stosq", "stosw", "str", 
99
    "std", "sti", "stmxcsr", "stos", "stosb", "stosd", "stosq", "stosw", "str",
100
    "subpd", "subps", "subsd", "subss", "swapgs", "syscall", "sysenter", 
100
    "subpd", "subps", "subsd", "subss", "swapgs", "syscall", "sysenter",
101
    "sysret", "test", "tpause", "tzcnt", "ucomisd", "ucomiss", "ud", 
101
    "sysret", "test", "tpause", "tzcnt", "ucomisd", "ucomiss", "ud",
102
    "umwait", "unpckhpd", "unpckhps", "unpcklpd", "unpcklps", "valignd", 
102
    "umwait", "unpckhpd", "unpckhps", "unpcklpd", "unpcklps", "valignd",
103
    "vblendmpd", "vblendmps", "vbroadcast", "vcompresspd", "vcompressps", 
103
    "vblendmpd", "vblendmps", "vbroadcast", "vcompresspd", "vcompressps",
104
    "vcvtpd2udq", "vcvtpd2uqq", "vcvtph2ps", "vcvtps2ph", "vcvtps2qq", 
104
    "vcvtpd2udq", "vcvtpd2uqq", "vcvtph2ps", "vcvtps2ph", "vcvtps2qq",
105
    "vcvtps2uqq", "vcvtqq2pd", "vcvtqq2ps", "vcvtsd2usi", "vcvtss2usi", 
105
    "vcvtps2uqq", "vcvtqq2pd", "vcvtqq2ps", "vcvtsd2usi", "vcvtss2usi",
106
    "vcvttpd2udq", "vcvttpd2uqq", "vcvttps2qq", "vcvttps2udq", "vcvttps2uqq", 
106
    "vcvttpd2udq", "vcvttpd2uqq", "vcvttps2qq", "vcvttps2udq", "vcvttps2uqq",
107
    "vcvttss2usi", "vcvtudq2pd", "vcvtudq2ps", "vcvtuqq2pd", "vcvtuqq2ps", 
107
    "vcvttss2usi", "vcvtudq2pd", "vcvtudq2ps", "vcvtuqq2pd", "vcvtuqq2ps",
108
    "vcvtusi2ss", "vdbpsadbw", "verr", "verw", "vexpandpd", "vexpandps", 
108
    "vcvtusi2ss", "vdbpsadbw", "verr", "verw", "vexpandpd", "vexpandps",
109
    "vextractf32x4", "vextractf32x8", "vextractf64x2", "vextractf64x4", 
109
    "vextractf32x4", "vextractf32x8", "vextractf64x2", "vextractf64x4",
110
    "vextracti32x4", "vextracti32x8", "vextracti64x2", "vextracti64x4", 
110
    "vextracti32x4", "vextracti32x8", "vextracti64x2", "vextracti64x4",
111
    "vfixupimmps", "vfixupimmsd", "vfixupimmss", "vfmadd132pd", "vfmadd132ps", 
111
    "vfixupimmps", "vfixupimmsd", "vfixupimmss", "vfmadd132pd", "vfmadd132ps",
112
    "vfmadd132ss", "vfmadd213pd", "vfmadd213ps", "vfmadd213sd", "vfmadd213ss", 
112
    "vfmadd132ss", "vfmadd213pd", "vfmadd213ps", "vfmadd213sd", "vfmadd213ss",
113
    "vfmadd231ps", "vfmadd231sd", "vfmadd231ss", "vfmaddsub132pd", 
113
    "vfmadd231ps", "vfmadd231sd", "vfmadd231ss", "vfmaddsub132pd",
114
    "vfmaddsub213pd", "vfmaddsub213ps", "vfmaddsub231pd", "vfmaddsub231ps", 
114
    "vfmaddsub213pd", "vfmaddsub213ps", "vfmaddsub231pd", "vfmaddsub231ps",
115
    "vfmsub132ps", "vfmsub132sd", "vfmsub132ss", "vfmsub213pd", "vfmsub213ps", 
115
    "vfmsub132ps", "vfmsub132sd", "vfmsub132ss", "vfmsub213pd", "vfmsub213ps",
116
    "vfmsub213ss", "vfmsub231pd", "vfmsub231ps", "vfmsub231sd", "vfmsub231ss", 
116
    "vfmsub213ss", "vfmsub231pd", "vfmsub231ps", "vfmsub231sd", "vfmsub231ss",
117
    "vfmsubadd132ps", "vfmsubadd213pd", "vfmsubadd213ps", "vfmsubadd231pd", 
117
    "vfmsubadd132ps", "vfmsubadd213pd", "vfmsubadd213ps", "vfmsubadd231pd",
118
    "vfnmadd132pd", "vfnmadd132ps", "vfnmadd132sd", "vfnmadd132ss", 
118
    "vfnmadd132pd", "vfnmadd132ps", "vfnmadd132sd", "vfnmadd132ss",
119
    "vfnmadd213ps", "vfnmadd213sd", "vfnmadd213ss", "vfnmadd231pd", 
119
    "vfnmadd213ps", "vfnmadd213sd", "vfnmadd213ss", "vfnmadd231pd",
120
    "vfnmadd231sd", "vfnmadd231ss", "vfnmsub132pd", "vfnmsub132ps", 
120
    "vfnmadd231sd", "vfnmadd231ss", "vfnmsub132pd", "vfnmsub132ps",
121
    "vfnmsub132ss", "vfnmsub213pd", "vfnmsub213ps", "vfnmsub213sd", 
121
    "vfnmsub132ss", "vfnmsub213pd", "vfnmsub213ps", "vfnmsub213sd",
122
    "vfnmsub231pd", "vfnmsub231ps", "vfnmsub231sd", "vfnmsub231ss", 
122
    "vfnmsub231pd", "vfnmsub231ps", "vfnmsub231sd", "vfnmsub231ss",
123
    "vfpclassps", "vfpclasssd", "vfpclassss", "vgatherdpd", "vgatherdpd", 
123
    "vfpclassps", "vfpclasssd", "vfpclassss", "vgatherdpd", "vgatherdpd",
124
    "vgatherdps", "vgatherqpd", "vgatherqpd", "vgatherqps", "vgatherqps", 
124
    "vgatherdps", "vgatherqpd", "vgatherqpd", "vgatherqps", "vgatherqps",
125
    "vgetexpps", "vgetexpsd", "vgetexpss", "vgetmantpd", "vgetmantps", 
125
    "vgetexpps", "vgetexpsd", "vgetexpss", "vgetmantpd", "vgetmantps",
126
    "vgetmantss", "vinsertf128", "vinsertf32x4", "vinsertf32x8", 
126
    "vgetmantss", "vinsertf128", "vinsertf32x4", "vinsertf32x8",
127
    "vinsertf64x4", "vinserti128", "vinserti32x4", "vinserti32x8", 
127
    "vinsertf64x4", "vinserti128", "vinserti32x4", "vinserti32x8",
128
    "vinserti64x4", "vmaskmov", "vmovdqa32", "vmovdqa64", "vmovdqu16", 
128
    "vinserti64x4", "vmaskmov", "vmovdqa32", "vmovdqa64", "vmovdqu16",
129
    "vmovdqu64", "vmovdqu8", "vpblendd", "vpblendmb", "vpblendmd", "vpblendmq", 
129
    "vmovdqu64", "vmovdqu8", "vpblendd", "vpblendmb", "vpblendmd", "vpblendmq",
130
    "vpbroadcast", "vpbroadcastb", "vpbroadcastd", "vpbroadcastm", 
130
    "vpbroadcast", "vpbroadcastb", "vpbroadcastd", "vpbroadcastm",
131
    "vpbroadcastw", "vpcmpb", "vpcmpd", "vpcmpq", "vpcmpub", "vpcmpud", 
131
    "vpbroadcastw", "vpcmpb", "vpcmpd", "vpcmpq", "vpcmpub", "vpcmpud",
132
    "vpcmpuw", "vpcmpw", "vpcompressd", "vpcompressq", "vpconflictd", 
132
    "vpcmpuw", "vpcmpw", "vpcompressd", "vpcompressq", "vpconflictd",
133
    "vperm2f128", "vperm2i128", "vpermb", "vpermd", "vpermi2b", "vpermi2d", 
133
    "vperm2f128", "vperm2i128", "vpermb", "vpermd", "vpermi2b", "vpermi2d",
134
    "vpermi2ps", "vpermi2q", "vpermi2w", "vpermilpd", "vpermilps", "vpermpd", 
134
    "vpermi2ps", "vpermi2q", "vpermi2w", "vpermilpd", "vpermilps", "vpermpd",
135
    "vpermq", "vpermt2b", "vpermt2d", "vpermt2pd", "vpermt2ps", "vpermt2q", 
135
    "vpermq", "vpermt2b", "vpermt2d", "vpermt2pd", "vpermt2ps", "vpermt2q",
136
    "vpermw", "vpexpandd", "vpexpandq", "vpgatherdd", "vpgatherdd", 
136
    "vpermw", "vpexpandd", "vpexpandq", "vpgatherdd", "vpgatherdd",
137
    "vpgatherdq", "vpgatherqd", "vpgatherqd", "vpgatherqq", "vpgatherqq", 
137
    "vpgatherdq", "vpgatherqd", "vpgatherqd", "vpgatherqq", "vpgatherqq",
138
    "vplzcntq", "vpmadd52huq", "vpmadd52luq", "vpmaskmov", "vpmovb2m", 
138
    "vplzcntq", "vpmadd52huq", "vpmadd52luq", "vpmaskmov", "vpmovb2m",
139
    "vpmovdb", "vpmovdw", "vpmovm2b", "vpmovm2d", "vpmovm2q", "vpmovm2w", 
139
    "vpmovdb", "vpmovdw", "vpmovm2b", "vpmovm2d", "vpmovm2q", "vpmovm2w",
140
    "vpmovqb", "vpmovqd", "vpmovqw", "vpmovsdb", "vpmovsdw", "vpmovsqb", 
140
    "vpmovqb", "vpmovqd", "vpmovqw", "vpmovsdb", "vpmovsdw", "vpmovsqb",
141
    "vpmovsqw", "vpmovswb", "vpmovusdb", "vpmovusdw", "vpmovusqb", "vpmovusqd", 
141
    "vpmovsqw", "vpmovswb", "vpmovusdb", "vpmovusdw", "vpmovusqb", "vpmovusqd",
142
    "vpmovuswb", "vpmovw2m", "vpmovwb", "vpmultishiftqb", "vprold", "vprolq", 
142
    "vpmovuswb", "vpmovw2m", "vpmovwb", "vpmultishiftqb", "vprold", "vprolq",
143
    "vprolvq", "vprord", "vprorq", "vprorvd", "vprorvq", "vpscatterdd", 
143
    "vprolvq", "vprord", "vprorq", "vprorvd", "vprorvq", "vpscatterdd",
144
    "vpscatterqd", "vpscatterqq", "vpsllvd", "vpsllvq", "vpsllvw", "vpsravd", 
144
    "vpscatterqd", "vpscatterqq", "vpsllvd", "vpsllvq", "vpsllvw", "vpsravd",
145
    "vpsravw", "vpsrlvd", "vpsrlvq", "vpsrlvw", "vpternlogd", "vpternlogq", 
145
    "vpsravw", "vpsrlvd", "vpsrlvq", "vpsrlvw", "vpternlogd", "vpternlogq",
146
    "vptestmd", "vptestmq", "vptestmw", "vptestnmb", "vptestnmd", "vptestnmq", 
146
    "vptestmd", "vptestmq", "vptestmw", "vptestnmb", "vptestnmd", "vptestnmq",
147
    "vrangepd", "vrangeps", "vrangesd", "vrangess", "vrcp14pd", "vrcp14ps", 
147
    "vrangepd", "vrangeps", "vrangesd", "vrangess", "vrcp14pd", "vrcp14ps",
148
    "vrcp14ss", "vreducepd", "vreduceps", "vreducesd", "vreducess", 
148
    "vrcp14ss", "vreducepd", "vreduceps", "vreducesd", "vreducess",
149
    "vrndscaleps", "vrndscalesd", "vrndscaless", "vrsqrt14pd", "vrsqrt14ps", 
149
    "vrndscaleps", "vrndscalesd", "vrndscaless", "vrsqrt14pd", "vrsqrt14ps",
150
    "vrsqrt14ss", "vscalefpd", "vscalefps", "vscalefsd", "vscalefss", 
150
    "vrsqrt14ss", "vscalefpd", "vscalefps", "vscalefsd", "vscalefss",
151
    "vscatterdps", "vscatterqpd", "vscatterqps", "vshuff32x4", "vshuff64x2", 
151
    "vscatterdps", "vscatterqpd", "vscatterqps", "vshuff32x4", "vshuff64x2",
152
    "vshufi64x2", "vtestpd", "vtestps", "vzeroall", "vzeroupper", "wait", 
152
    "vshufi64x2", "vtestpd", "vtestps", "vzeroall", "vzeroupper", "wait",
153
    "wrfsbase", "wrgsbase", "wrmsr", "wrpkru", "xabort", "xacquire", "xadd", 
153
    "wrfsbase", "wrgsbase", "wrmsr", "wrpkru", "xabort", "xacquire", "xadd",
154
    "xchg", "xend", "xgetbv", "xlat", "xlatb", "xor", "xorpd", "xorps", 
154
    "xchg", "xend", "xgetbv", "xlat", "xlatb", "xor", "xorpd", "xorps",
155
    "xrstor", "xrstors", "xsave", "xsavec", "xsaveopt", "xsaves", "xsetbv",
155
    "xrstor", "xrstors", "xsave", "xsavec", "xsaveopt", "xsaves", "xsetbv",
156
]
156
]
157
 
157
 
158
fasm_types = [
158
fasm_types = [
159
    "db", "rb",
159
    "db", "rb",
160
    "dw", "rw",
160
    "dw", "rw",
161
    "dd", "rd",
161
    "dd", "rd",
162
    "dp", "rp",
162
    "dp", "rp",
163
    "df", "rf",
163
    "df", "rf",
164
    "dq", "rq",
164
    "dq", "rq",
165
    "dt", "rt",
165
    "dt", "rt",
166
    "du",
166
    "du",
167
]
167
]
-
 
168
 
168
 
169
 
169
# Add kind flag to identifier in id2kind
170
# Add kind flag to identifier in id2kind
170
def id_add_kind(identifier, kind):
171
def id_add_kind(identifier, kind):
171
    if identifier not in id2kind:
172
    if identifier not in id2kind:
172
        id2kind[identifier] = ''
173
        id2kind[identifier] = ''
173
    id2kind[identifier] += kind
174
    id2kind[identifier] += kind
-
 
175
 
174
 
176
 
175
# Remove kind flag of identifier in id2kind
177
# Remove kind flag of identifier in id2kind
176
def id_remove_kind(identifier, kind):
178
def id_remove_kind(identifier, kind):
177
    if identifier in id2kind:
179
    if identifier in id2kind:
178
        if kind in id2kind[identifier]:
180
        if kind in id2kind[identifier]:
179
            id2kind[identifier] = id2kind[identifier].replace(kind, '')
181
            id2kind[identifier] = id2kind[identifier].replace(kind, '')
-
 
182
 
180
 
183
 
181
# Get kind of an identifier
184
# Get kind of an identifier
182
def id_get_kind(identifier):
185
def id_get_kind(identifier):
183
    if identifier in id2kind:
186
    if identifier in id2kind:
184
        return id2kind[identifier]
187
        return id2kind[identifier]
185
    else:
188
    else:
186
        return ''
189
        return ''
-
 
190
 
187
 
191
 
188
class LegacyAsmReader:
192
class LegacyAsmReader:
189
    def __init__(self, file):
193
    def __init__(self, file):
190
        self.file = file
194
        self.file = file
191
        self.lines = open(file, "r", encoding="utf-8").readlines()
195
        self.lines = open(file, "r", encoding="utf-8").readlines()
192
        self.line_idx = 0
196
        self.line_idx = 0
193
        self.i = 0
197
        self.i = 0
194
 
198
 
195
    def currline(self):
199
    def currline(self):
196
        return self.lines[self.line_idx]
200
        return self.lines[self.line_idx]
197
 
201
 
198
    def curr(self):
202
    def curr(self):
-
 
203
        try:
199
        try: return self.lines[self.line_idx][self.i]
204
            return self.lines[self.line_idx][self.i]
-
 
205
        except:
200
        except: return ''
206
            return ''
201
 
207
 
202
    def step(self):
208
    def step(self):
203
        c = self.curr()
209
        c = self.curr()
204
        self.i += 1
210
        self.i += 1
205
        # Wrap the line if '\\' followed by whitespaces and/or comment
211
        # Wrap the line if '\\' followed by whitespaces and/or comment
206
        while self.curr() == '\\':
212
        while self.curr() == '\\':
207
            i_of_backslash = self.i
213
            i_of_backslash = self.i
208
            self.i += 1
214
            self.i += 1
209
            while self.curr().isspace():
215
            while self.curr().isspace():
210
                self.i += 1
216
                self.i += 1
211
            if self.curr() == ';' or self.curr() == '':
217
            if self.curr() == ';' or self.curr() == '':
212
                self.line_idx += 1
218
                self.line_idx += 1
213
                self.i = 0
219
                self.i = 0
214
            else:
220
            else:
215
                # There's something other than a comment after the backslash
221
                # There's something other than a comment after the backslash
216
                # So don't interpret the backslash as a line wrap
222
                # So don't interpret the backslash as a line wrap
217
                self.i = i_of_backslash
223
                self.i = i_of_backslash
218
                break
224
                break
219
        return c
225
        return c
220
 
226
 
221
    def nextline(self):
227
    def nextline(self):
222
        c = self.curr()
228
        c = self.curr()
223
        while c != '':
229
        while c != '':
224
            c = self.step()
230
            c = self.step()
225
        self.line_idx += 1
231
        self.line_idx += 1
226
        self.i = 0
232
        self.i = 0
227
 
233
 
228
    def no_lines(self):
234
    def no_lines(self):
229
        if self.line_idx >= len(self.lines):
235
        if self.line_idx >= len(self.lines):
230
            return True
236
            return True
231
        return False
237
        return False
232
 
238
 
233
    def location(self): 
239
    def location(self):
234
        return f"{self.file}:{self.line_idx + 1}"
240
        return f"{self.file}:{self.line_idx + 1}"
235
 
241
 
236
    def skip_spaces(self):
242
    def skip_spaces(self):
237
        while self.curr().isspace():
243
        while self.curr().isspace():
238
            self.step()
244
            self.step()
-
 
245
 
239
 
246
 
240
class AsmReaderRecognizingStrings(LegacyAsmReader):
247
class AsmReaderRecognizingStrings(LegacyAsmReader):
241
    def __init__(self, file):
248
    def __init__(self, file):
242
        super().__init__(file)
249
        super().__init__(file)
243
        self.in_string = None
250
        self.in_string = None
244
        self.should_recognize_strings = True
251
        self.should_recognize_strings = True
245
 
252
 
246
    def step(self):
253
    def step(self):
247
        c = super().step()
254
        c = super().step()
248
        if self.should_recognize_strings and (c == '"' or c == "'"):
255
        if self.should_recognize_strings and (c == '"' or c == "'"):
249
            # If just now we was at the double or single quotation mark
256
            # If just now we was at the double or single quotation mark
250
            # and we aren't in a string yet
257
            # and we aren't in a string yet then say
251
            # then say "we are in a string openned with this quotation mark now"
258
            # "we are in a string openned with this quotation mark now"
252
            if self.in_string == None:
259
            if self.in_string is None:
253
                self.in_string = c
260
                self.in_string = c
254
            # If just now we was at the double or single quotation mark
261
            # If just now we was at the double or single quotation mark
255
            # and we are in the string entered with the same quotation mark
262
            # and we are in the string entered with the same quotation mark
256
            # then say "we aren't in a string anymore"
263
            # then say "we aren't in a string anymore"
257
            elif self.in_string == c:
264
            elif self.in_string == c:
258
                self.in_string = None
265
                self.in_string = None
259
        return c
266
        return c
-
 
267
 
260
 
268
 
261
class AsmReaderReadingComments(AsmReaderRecognizingStrings):
269
class AsmReaderReadingComments(AsmReaderRecognizingStrings):
262
    def __init__(self, file):
270
    def __init__(self, file):
263
        super().__init__(file)
271
        super().__init__(file)
264
        self.status = dict()
272
        self.status = dict()
265
        self.status_reset()
273
        self.status_reset()
266
        self.comment = ''
274
        self.comment = ''
267
 
275
 
268
    def status_reset(self):
276
    def status_reset(self):
269
        # If the line has non-comment code
277
        # If the line has non-comment code
270
        self.status_has_code = False
278
        self.status_has_code = False
271
        # If the line has a comment at the end
279
        # If the line has a comment at the end
272
        self.status_has_comment = False
280
        self.status_has_comment = False
273
        # Let it recognize strings further, we are definitely out of a comment
281
        # Let it recognize strings further, we are definitely out of a comment
274
        self.should_recognize_strings = True
282
        self.should_recognize_strings = True
275
 
283
 
276
    def status_set_has_comment(self):
284
    def status_set_has_comment(self):
277
        self.status_has_comment = True
285
        self.status_has_comment = True
278
        # Don't let it recognize strings cause we are in a comment now
286
        # Don't let it recognize strings cause we are in a comment now
279
        self.should_recognize_strings = False
287
        self.should_recognize_strings = False
280
 
288
 
281
    def status_set_has_code(self):
289
    def status_set_has_code(self):
282
        self.status_has_code = True
290
        self.status_has_code = True
283
 
291
 
284
    def update_status(self):
292
    def update_status(self):
285
        # If we aren't in a comment and we aren't in a string - say we are now in a comment if ';' met
293
        # If we aren't in a comment and we aren't in a string -
-
 
294
        # say we are now in a comment if ';' met
286
        if not self.status_has_comment and not self.in_string and self.curr() == ';':
295
        if (not self.status_has_comment and
-
 
296
            not self.in_string and
-
 
297
            self.curr() == ';'):
287
            self.status_set_has_comment()
298
            self.status_set_has_comment()
288
        # Else if we are in a comment - collect the comment
299
        # Else if we are in a comment - collect the comment
289
        elif self.status_has_comment:
300
        elif self.status_has_comment:
290
            self.comment += self.curr()
301
            self.comment += self.curr()
291
        # Else if there's some non-whitespace character out of a comment
302
        # Else if there's some non-whitespace character out of a comment
292
        # then the line has code
303
        # then the line has code
293
        elif not self.status_has_comment and not self.curr().isspace():
304
        elif not self.status_has_comment and not self.curr().isspace():
294
            self.status_set_has_code()
305
            self.status_set_has_code()
295
 
306
 
296
    def step(self):
307
    def step(self):
297
        # Get to the next character
308
        # Get to the next character
298
        c = super().step()
309
        c = super().step()
299
        # Update status of the line according to the next character
310
        # Update status of the line according to the next character
300
        self.update_status()
311
        self.update_status()
301
        return c
312
        return c
302
 
313
 
303
    def nextline(self):
314
    def nextline(self):
304
        prev_line = self.currline()
315
        prev_line = self.currline()
305
        super().nextline()
316
        super().nextline()
306
        # If the line we leave was not a comment-only line
317
        # If the line we leave was not a comment-only line
307
        # then forget the collected comment
318
        # then forget the collected comment
308
        # Otherwise the collected comment should be complemented by comment from next line in step()
319
        # Otherwise the collected comment should be complemented by
-
 
320
        # comment from next line in step()
309
        if self.status_has_code:
321
        if self.status_has_code:
310
            # But we should preserve comment for the next line
322
            # But we should preserve comment for the next line
311
            # If previous line set align (cause many functions re documented
323
            # If previous line set align (cause many functions re documented
312
            # right before align set, not before their labels)
324
            # right before align set, not before their labels)
313
            if not prev_line.startswith("align "):
325
            if not prev_line.startswith("align "):
314
                self.comment = ''
326
                self.comment = ''
315
        # Reset the line status (now it's the status of the new line)
327
        # Reset the line status (now it's the status of the new line)
316
        self.status_reset()
328
        self.status_reset()
317
        # Set new status for this line according to the first character in the line
329
        # Set new status for this line according to the
-
 
330
        # first character in the line
318
        self.update_status()
331
        self.update_status()
-
 
332
 
319
 
333
 
320
class AsmReaderFetchingIdentifiers(AsmReaderReadingComments):
334
class AsmReaderFetchingIdentifiers(AsmReaderReadingComments):
321
    def __init__(self, file):
335
    def __init__(self, file):
322
        super().__init__(file)
336
        super().__init__(file)
323
 
337
 
324
    def fetch_identifier(self):
338
    def fetch_identifier(self):
325
        self.skip_spaces()
339
        self.skip_spaces()
326
        result = ''
340
        result = ''
327
        while is_id(self.curr()):
341
        while is_id(self.curr()):
328
            result += self.step()
342
            result += self.step()
329
        return result
343
        return result
-
 
344
 
330
 
345
 
331
class AsmReader(AsmReaderFetchingIdentifiers):
346
class AsmReader(AsmReaderFetchingIdentifiers):
332
    def __init__(self, file):
347
    def __init__(self, file):
333
        super().__init__(file)
348
        super().__init__(file)
-
 
349
 
334
 
350
 
335
def append_file(full_path, contents):
351
def append_file(full_path, contents):
336
    if debug_mode:
352
    if debug_mode:
337
        if full_path not in output_files:
353
        if full_path not in output_files:
338
            output_files[full_path] = ""
354
            output_files[full_path] = ""
339
        output_files[full_path] += contents
355
        output_files[full_path] += contents
340
    else:
356
    else:
341
        f = open(full_path, "a")
357
        f = open(full_path, "a")
342
        f.write(contents)
358
        f.write(contents)
343
        f.close()
359
        f.close()
-
 
360
 
344
 
361
 
345
class AsmElement:
362
class AsmElement:
346
    def __init__(self, location, name, comment):
363
    def __init__(self, location, name, comment):
347
        global warnings
364
        global warnings
348
 
365
 
-
 
366
        # If the element was constructed during this execution then
349
        # If the element was constructed during this execution then the element is new
367
        # the element is new
350
        self.new = True
368
        self.new = True
351
        self.location = location
369
        self.location = location
352
        self.file = self.location.split(':')[0].replace('\\', '/')
370
        self.file = self.location.split(':')[0].replace('\\', '/')
353
        self.line = self.location.split(':')[1]
371
        self.line = self.location.split(':')[1]
354
        self.name = name
372
        self.name = name
355
        self.comment = comment
373
        self.comment = comment
356
 
374
 
357
        if self.comment == '':
375
        if self.comment == '':
358
            warnings += f'{self.location}: Undocumented element\n'
376
            warnings += f'{self.location}: Undocumented element\n'
359
 
377
 
360
    def dump(self):
378
    def dump(self):
361
        print(f"\n{self.location}: {self.name}")
379
        print(f"\n{self.location}: {self.name}")
362
        print(f"{self.comment}")
380
        print(f"{self.comment}")
363
 
381
 
364
    def emit(self, dest, doxycomment = '', declaration = ''):
382
    def emit(self, dest, doxycomment='', declaration=''):
365
        # Do not emit anything if the symbol is marked as hidden in its comment
383
        # Do not emit anything if the symbol is marked as hidden in its comment
366
        if '@dont_give_a_doxygen' in self.comment:
384
        if '@dont_give_a_doxygen' in self.comment:
367
            return
385
            return
368
 
386
 
369
        global warnings
387
        global warnings
370
        # Redefine default declaration
388
        # Redefine default declaration
371
        if declaration == '':
389
        if declaration == '':
372
            declaration = f'#define {self.name}'
390
            declaration = f'#define {self.name}'
373
        # Check doxycomment
391
        # Check doxycomment
374
        if not doxycomment.endswith('\n'):
392
        if not doxycomment.endswith('\n'):
375
            doxycomment += '\n'
393
            doxycomment += '\n'
376
        if doxycomment.split('@brief ')[1][0].islower():
394
        if doxycomment.split('@brief ')[1][0].islower():
377
            warnings += f"{self.location}: Brief comment starting from lowercase\n"
395
            warnings += (f"{self.location}: Brief comment starting from " +
-
 
396
                         "lowercase\n")
378
        # Build contents to emit
397
        # Build contents to emit
379
        contents = ''
398
        contents = ''
380
        contents += '/**\n'
399
        contents += '/**\n'
381
        contents += doxycomment
400
        contents += doxycomment
382
        contents += (f"@par Source\n" +
401
        contents += (f"@par Source\n" +
-
 
402
                     f"{self.file}:{self.line}\n")
403
                     f"#line-{self.line}'>{self.file}:{self.line}\n")
384
        contents += '*/\n'
404
        contents += '*/\n'
385
        contents += declaration
405
        contents += declaration
386
        contents += '\n\n'
406
        contents += '\n\n'
387
        # Get path to file to emit this
407
        # Get path to file to emit this
388
        full_path = dest + '/' + self.file
408
        full_path = dest + '/' + self.file
389
        # Remove the file on first access if it was created by previous generation
409
        # Remove the file on first access if it was
-
 
410
        # created by previous generation
390
        if full_path not in created_files:
411
        if full_path not in created_files:
391
            if os.path.isfile(full_path):
412
            if os.path.isfile(full_path):
392
                os.remove(full_path)
413
                os.remove(full_path)
393
            created_files.append(full_path)
414
            created_files.append(full_path)
394
        # Create directories need for the file
415
        # Create directories need for the file
395
        os.makedirs(os.path.dirname(full_path), exist_ok=True)
416
        os.makedirs(os.path.dirname(full_path), exist_ok=True)
396
        contents = ''.join([i if ord(i) < 128 else '?' for i in contents])
417
        contents = ''.join([i if ord(i) < 128 else '?' for i in contents])
397
 
418
 
398
        append_file(full_path, contents)
419
        append_file(full_path, contents)
-
 
420
 
399
 
421
 
400
class AsmVariable(AsmElement):
422
class AsmVariable(AsmElement):
401
    def __init__(self, location, name, comment, type, init):
423
    def __init__(self, location, name, comment, type, init):
402
        super().__init__(location, name, comment)
424
        super().__init__(location, name, comment)
403
        self.type = type
425
        self.type = type
404
        self.init = init
426
        self.init = init
405
 
427
 
406
    def dump(self):
428
    def dump(self):
407
        super().dump()
429
        super().dump()
408
        print(f"(Variable)\n---")
430
        print(f"(Variable)\n---")
409
 
431
 
410
    def emit(self, dest):
432
    def emit(self, dest):
411
        # Build doxycomment specific for the variable
433
        # Build doxycomment specific for the variable
412
        doxycomment = ''
434
        doxycomment = ''
413
        doxycomment += self.comment
435
        doxycomment += self.comment
414
        if '@brief' not in doxycomment:
436
        if '@brief' not in doxycomment:
415
            doxycomment = '@brief ' + doxycomment
437
            doxycomment = '@brief ' + doxycomment
416
        doxycomment += (f"@par Initial value\n" +
438
        doxycomment += (f"@par Initial value\n" +
417
                        f"{self.init}\n")
439
                        f"{self.init}\n")
418
        # Build the declaration
440
        # Build the declaration
419
        name = self.name.replace(".", "_")
441
        name = self.name.replace(".", "_")
420
        var_type = self.type.replace(".", "_")
442
        var_type = self.type.replace(".", "_")
421
        declaration = f"{var_type} {name};"
443
        declaration = f"{var_type} {name};"
422
        # Emit this
444
        # Emit this
423
        super().emit(dest, doxycomment, declaration)
445
        super().emit(dest, doxycomment, declaration)
-
 
446
 
424
 
447
 
425
class AsmFunction(AsmElement):
448
class AsmFunction(AsmElement):
-
 
449
    def __init__(self, location, name, comment, calling_convention,
426
    def __init__(self, location, name, comment, calling_convention, args, used_regs):
450
                 args, used_regs):
427
        super().__init__(location, name, comment)
451
        super().__init__(location, name, comment)
428
        self.calling_convention = calling_convention
452
        self.calling_convention = calling_convention
429
        self.args = args
453
        self.args = args
430
        self.used_regs = used_regs
454
        self.used_regs = used_regs
431
 
455
 
432
    def dump(self):
456
    def dump(self):
433
        super().dump()
457
        super().dump()
434
        print(f"(Function)\n---")
458
        print(f"(Function)\n---")
435
 
459
 
436
    def emit(self, dest):
460
    def emit(self, dest):
437
        # Build doxycomment specific for the variable
461
        # Build doxycomment specific for the variable
438
        doxycomment = ''
462
        doxycomment = ''
439
        doxycomment += self.comment
463
        doxycomment += self.comment
440
        if '@brief' not in doxycomment:
464
        if '@brief' not in doxycomment:
441
            doxycomment = '@brief ' + doxycomment
465
            doxycomment = '@brief ' + doxycomment
442
        # If there was no arguments, maybe that's just a label
466
        # If there was no arguments, maybe that's just a label
443
        # then parse parameters from its comment
467
        # then parse parameters from its comment
444
        if len(self.args) == 0 and '@param' in self.comment:
468
        if len(self.args) == 0 and '@param' in self.comment:
445
            i = 0
469
            i = 0
446
            while '@param' in self.comment[i:]:
470
            while '@param' in self.comment[i:]:
447
                i = self.comment.index('@param', i)
471
                i = self.comment.index('@param', i)
448
                # Skip '@param'
472
                # Skip '@param'
449
                i += len('@param')
473
                i += len('@param')
450
                # Skip spaces after '@param'
474
                # Skip spaces after '@param'
451
                while self.comment[i].isspace():
475
                while self.comment[i].isspace():
452
                    i += 1
476
                    i += 1
453
                # Get the parameter name
477
                # Get the parameter name
454
                name = ''
478
                name = ''
455
                while is_id(self.comment[i]):
479
                while is_id(self.comment[i]):
456
                    name += self.comment[i]
480
                    name += self.comment[i]
457
                    i += 1
481
                    i += 1
458
                # Save the parameter
482
                # Save the parameter
459
                self.args.append((name, 'arg_t'))
483
                self.args.append((name, 'arg_t'))
460
        # Build the arg list for declaration
484
        # Build the arg list for declaration
461
        arg_list = '('
485
        arg_list = '('
462
        if len(self.args) > 0:
486
        if len(self.args) > 0:
463
            argc = 0
487
            argc = 0
464
            for arg in self.args:
488
            for arg in self.args:
465
                if argc != 0:
489
                if argc != 0:
466
                    arg_list += ", "
490
                    arg_list += ", "
467
                arg_list += f"{arg[1]} {arg[0]}"
491
                arg_list += f"{arg[1]} {arg[0]}"
468
                argc += 1
492
                argc += 1
469
        arg_list += ')'
493
        arg_list += ')'
470
        # Build the declaration
494
        # Build the declaration
471
        name = self.name.replace(".", "_")
495
        name = self.name.replace(".", "_")
472
        declaration = f"void {name}{arg_list};"
496
        declaration = f"void {name}{arg_list};"
473
        # Emit this
497
        # Emit this
474
        super().emit(dest, doxycomment, declaration)
498
        super().emit(dest, doxycomment, declaration)
-
 
499
 
475
 
500
 
476
class AsmLabel(AsmElement):
501
class AsmLabel(AsmElement):
477
    def __init__(self, location, name, comment):
502
    def __init__(self, location, name, comment):
478
        super().__init__(location, name, comment)
503
        super().__init__(location, name, comment)
479
 
504
 
480
    def dump(self):
505
    def dump(self):
481
        super().dump()
506
        super().dump()
482
        print(f"(Label)\n---")
507
        print(f"(Label)\n---")
483
 
508
 
484
    def emit(self, dest):
509
    def emit(self, dest):
485
        # Build doxycomment specific for the variable
510
        # Build doxycomment specific for the variable
486
        doxycomment = ''
511
        doxycomment = ''
487
        doxycomment += self.comment
512
        doxycomment += self.comment
488
        if '@brief' not in doxycomment:
513
        if '@brief' not in doxycomment:
489
            doxycomment = '@brief ' + doxycomment
514
            doxycomment = '@brief ' + doxycomment
490
        # Build the declaration
515
        # Build the declaration
491
        name = self.name.replace(".", "_")
516
        name = self.name.replace(".", "_")
492
        declaration = f"label {name};"
517
        declaration = f"label {name};"
493
        # Emit this
518
        # Emit this
494
        super().emit(dest, doxycomment, declaration)
519
        super().emit(dest, doxycomment, declaration)
-
 
520
 
495
 
521
 
496
class AsmMacro(AsmElement):
522
class AsmMacro(AsmElement):
497
    def __init__(self, location, name, comment, args):
523
    def __init__(self, location, name, comment, args):
498
        super().__init__(location, name, comment)
524
        super().__init__(location, name, comment)
499
        self.args = args
525
        self.args = args
500
 
526
 
501
    def dump(self):
527
    def dump(self):
502
        super().dump()
528
        super().dump()
503
        print(f"(Macro)\n---")
529
        print(f"(Macro)\n---")
504
 
530
 
505
    def emit(self, dest):
531
    def emit(self, dest):
506
        # Construct arg list without '['s, ']'s and '*'s
532
        # Construct arg list without '['s, ']'s and '*'s
507
        args = [arg for arg in self.args if arg not in "[]*"]
533
        args = [arg for arg in self.args if arg not in "[]*"]
508
        # Construct C-like arg list
534
        # Construct C-like arg list
509
        arg_list = ""
535
        arg_list = ""
510
        if len(args) > 0:
536
        if len(args) > 0:
511
            arg_list += '('
537
            arg_list += '('
512
            argc = 0
538
            argc = 0
513
            for arg in args:
539
            for arg in args:
514
                if argc != 0:
540
                if argc != 0:
515
                    arg_list += ", "
541
                    arg_list += ", "
516
                arg_list += arg
542
                arg_list += arg
517
                argc += 1
543
                argc += 1
518
            arg_list += ')'
544
            arg_list += ')'
519
        # Build doxycomment
545
        # Build doxycomment
520
        doxycomment = ''
546
        doxycomment = ''
521
        doxycomment += self.comment
547
        doxycomment += self.comment
522
        if '@brief' not in doxycomment:
548
        if '@brief' not in doxycomment:
523
            doxycomment = '@brief ' + doxycomment
549
            doxycomment = '@brief ' + doxycomment
524
        # Build declaration
550
        # Build declaration
525
        declaration = f"#define {self.name}{arg_list}"
551
        declaration = f"#define {self.name}{arg_list}"
526
        # Emit this
552
        # Emit this
527
        super().emit(dest, doxycomment, declaration)
553
        super().emit(dest, doxycomment, declaration)
-
 
554
 
528
 
555
 
529
class AsmStruct(AsmElement):
556
class AsmStruct(AsmElement):
530
    def __init__(self, location, name, comment, members):
557
    def __init__(self, location, name, comment, members):
531
        super().__init__(location, name, comment)
558
        super().__init__(location, name, comment)
532
        self.members = members
559
        self.members = members
533
 
560
 
534
    def dump(self):
561
    def dump(self):
535
        super().dump()
562
        super().dump()
536
        print(f"(Struct)\n---")
563
        print(f"(Struct)\n---")
537
 
564
 
538
    def emit(self, dest):
565
    def emit(self, dest):
539
        # Build doxycomment
566
        # Build doxycomment
540
        doxycomment = ''
567
        doxycomment = ''
541
        doxycomment += self.comment
568
        doxycomment += self.comment
542
        if '@brief' not in doxycomment:
569
        if '@brief' not in doxycomment:
543
            doxycomment = '@brief ' + doxycomment
570
            doxycomment = '@brief ' + doxycomment
544
        doxycomment += '\n'
571
        doxycomment += '\n'
545
        # Build declaration
572
        # Build declaration
546
        declaration = f"struct {self.name}" + " {\n"
573
        declaration = f"struct {self.name}" + " {\n"
547
        for member in self.members:
574
        for member in self.members:
548
            if type(member) == AsmVariable:
575
            if type(member) == AsmVariable:
549
                declaration += f'\t{member.type} {member.name}; /**< {member.comment} */\n'
576
                declaration += (f'\t{member.type} {member.name}; ' +
-
 
577
                                f'/**< {member.comment} */\n')
550
        declaration += '};'
578
        declaration += '};'
551
        # Emit this
579
        # Emit this
552
        super().emit(dest, doxycomment, declaration)
580
        super().emit(dest, doxycomment, declaration)
-
 
581
 
553
 
582
 
554
class AsmUnion(AsmElement):
583
class AsmUnion(AsmElement):
555
    def __init__(self, location, name, comment, members):
584
    def __init__(self, location, name, comment, members):
556
        super().__init__(location, name, comment)
585
        super().__init__(location, name, comment)
557
        self.members = members
586
        self.members = members
558
 
587
 
559
    def dump(self):
588
    def dump(self):
560
        super().dump()
589
        super().dump()
561
        print(f"(Union)\n---")
590
        print(f"(Union)\n---")
562
 
591
 
563
    def emit(self, dest):
592
    def emit(self, dest):
564
        # Build doxycomment
593
        # Build doxycomment
565
        doxycomment = ''
594
        doxycomment = ''
566
        doxycomment += self.comment
595
        doxycomment += self.comment
567
        if '@brief' not in doxycomment:
596
        if '@brief' not in doxycomment:
568
            doxycomment = '@brief ' + doxycomment
597
            doxycomment = '@brief ' + doxycomment
569
        # Build declaration
598
        # Build declaration
570
        declaration = f"union {self.name}" + " {};"
599
        declaration = f"union {self.name}" + " {};"
571
        # Emit this
600
        # Emit this
572
        super().emit(dest, doxycomment, declaration)
601
        super().emit(dest, doxycomment, declaration)
-
 
602
 
573
 
603
 
574
class VariableNameIsMacroName:
604
class VariableNameIsMacroName:
575
    def __init__(self, name):
605
    def __init__(self, name):
576
        self.name = name
606
        self.name = name
-
 
607
 
577
 
608
 
578
def is_id(c):
609
def is_id(c):
579
    return c.isprintable() and c not in "+-/*=<>()[]{};:,|&~#`'\" \n\r\t\v"
610
    return c.isprintable() and c not in "+-/*=<>()[]{};:,|&~#`'\" \n\r\t\v"
-
 
611
 
580
 
612
 
581
def is_starts_as_id(s):
613
def is_starts_as_id(s):
582
    return not s[0].isdigit()
614
    return not s[0].isdigit()
-
 
615
 
583
 
616
 
584
def parse_after_macro(r):
617
def parse_after_macro(r):
585
    location = r.location()
618
    location = r.location()
586
 
619
 
587
    # Skip spaces after the "macro" keyword
620
    # Skip spaces after the "macro" keyword
588
    r.skip_spaces()
621
    r.skip_spaces()
589
    # Read macro name
622
    # Read macro name
590
    name = ""
623
    name = ""
591
    while is_id(r.curr()) or r.curr() == '#':
624
    while is_id(r.curr()) or r.curr() == '#':
592
        name += r.step()
625
        name += r.step()
593
    # Skip spaces after macro name
626
    # Skip spaces after macro name
594
    r.skip_spaces()
627
    r.skip_spaces()
595
    # Find all arguments
628
    # Find all arguments
596
    args = []
629
    args = []
597
    arg = ''
630
    arg = ''
598
    while r.curr() and r.curr() != ';' and r.curr() != '{':
631
    while r.curr() and r.curr() != ';' and r.curr() != '{':
599
        # Collect identifier
632
        # Collect identifier
600
        if is_id(r.curr()):
633
        if is_id(r.curr()):
601
            arg += r.step()
634
            arg += r.step()
602
        # Save the collected identifier
635
        # Save the collected identifier
603
        elif r.curr() == ',':
636
        elif r.curr() == ',':
604
            args.append(arg)
637
            args.append(arg)
605
            arg = ''
638
            arg = ''
606
            r.step()
639
            r.step()
607
        # Just push the '['
640
        # Just push the '['
608
        elif r.curr() == '[':
641
        elif r.curr() == '[':
609
            args.append(r.step())
642
            args.append(r.step())
610
        # Just push the identifier and get ']' ready to be pushed on next comma
643
        # Just push the identifier and get ']' ready to be pushed on next comma
611
        elif r.curr() == ']':
644
        elif r.curr() == ']':
612
            args.append(arg)
645
            args.append(arg)
613
            arg = r.step()
646
            arg = r.step()
614
        # Just push the identifier and get '*' ready to be pushed on next comma
647
        # Just push the identifier and get '*' ready to be pushed on next comma
615
        elif r.curr() == '*':
648
        elif r.curr() == '*':
616
            args.append(arg)
649
            args.append(arg)
617
            arg = r.step()
650
            arg = r.step()
618
        # Just skip whitespaces
651
        # Just skip whitespaces
619
        elif r.curr().isspace():
652
        elif r.curr().isspace():
620
            r.step()
653
            r.step()
621
        # Something unexpected
654
        # Something unexpected
622
        else:
655
        else:
623
            raise Exception(f"Unexpected symbol '{r.curr()}' at index #{r.i} " + 
656
            raise Exception(f"Unexpected symbol '{r.curr()}' " +
624
                            f"in the macro declaration at {location} " +
657
                            f"at index #{r.i} in the macro declaration " +
-
 
658
                            f"at {location} " +
625
                            f"(line: {r.lines[r.line_idx]})\n''")
659
                            f"(line: {r.lines[r.line_idx]})\n''")
626
    # Append the last argument
660
    # Append the last argument
627
    if arg != '':
661
    if arg != '':
628
        args.append(arg)
662
        args.append(arg)
629
    # Skip t spaces after the argument list
663
    # Skip t spaces after the argument list
630
    r.skip_spaces()
664
    r.skip_spaces()
631
    # Get a comment if it is: read till the end of the line and get the comment from the reader
665
    # Get a comment if it is: read till the end of the line and
-
 
666
    # get the comment from the reader
632
    while r.curr() != '':
667
    while r.curr() != '':
633
        r.step()
668
        r.step()
634
    comment = r.comment
669
    comment = r.comment
635
    # Find end of the macro
670
    # Find end of the macro
636
    prev = ''
671
    prev = ''
637
    while True:
672
    while True:
638
        if r.curr() == '}' and prev != '\\':
673
        if r.curr() == '}' and prev != '\\':
639
            break
674
            break
640
        elif r.curr() == '':
675
        elif r.curr() == '':
641
            prev = ''
676
            prev = ''
642
            r.nextline()
677
            r.nextline()
643
            continue
678
            continue
644
        prev = r.step()
679
        prev = r.step()
645
    # Build the output
680
    # Build the output
646
    return AsmMacro(location, name, comment, args)
681
    return AsmMacro(location, name, comment, args)
-
 
682
 
647
 
683
 
648
def parse_variable(r, first_word = None):
684
def parse_variable(r, first_word=None):
649
    global warnings
685
    global warnings
650
    location = r.location()
686
    location = r.location()
651
 
687
 
652
    # Skip spaces before variable name
688
    # Skip spaces before variable name
653
    r.skip_spaces()
689
    r.skip_spaces()
654
    # Get variable name
690
    # Get variable name
655
    name = ""
691
    name = ""
656
    # Read it if it was not supplied
692
    # Read it if it was not supplied
657
    if first_word == None:
693
    if first_word is None:
658
        while is_id(r.curr()):
694
        while is_id(r.curr()):
659
            name += r.step()
695
            name += r.step()
660
    # Or use the supplied one instead
696
    # Or use the supplied one instead
661
    else:
697
    else:
662
        name = first_word
698
        name = first_word
663
    # Check the name
699
    # Check the name
664
    # If it's 0 len, that means threr's something else than an identifier at the beginning
700
    # If it's 0 len, that means threr's something else than an
-
 
701
    # identifier at the beginning
665
    if len(name) == 0:
702
    if len(name) == 0:
666
        return None
703
        return None
667
    # If it starts from digit or othervice illegally it's illegal
704
    # If it starts from digit or othervice illegally it's illegal
668
    if not is_starts_as_id(name):
705
    if not is_starts_as_id(name):
669
        return None
706
        return None
670
    # Get kind of the identifier from id2kind table
707
    # Get kind of the identifier from id2kind table
671
    kind = id_get_kind(name)
708
    kind = id_get_kind(name)
672
    # If it's a keyword, that's not a variable declaration
709
    # If it's a keyword, that's not a variable declaration
673
    if ID_KIND_KEYWORD in kind:
710
    if ID_KIND_KEYWORD in kind:
674
        return None
711
        return None
675
    # If it's a macro name, that's not a variable declaration
712
    # If it's a macro name, that's not a variable declaration
676
    if ID_KIND_MACRO_NAME in kind:
713
    if ID_KIND_MACRO_NAME in kind:
677
        return VariableNameIsMacroName(name)
714
        return VariableNameIsMacroName(name)
678
    # If it's a datatype or a structure name that's not a variable declaration: that's just a data
715
    # If it's a datatype or a structure name that's not a
-
 
716
    # variable declaration: that's just a data
679
    # don't document just a data for now
717
    # don't document just a data for now
680
    if ID_KIND_STRUCT_NAME in kind or ID_KIND_FASM_TYPE in kind:
718
    if ID_KIND_STRUCT_NAME in kind or ID_KIND_FASM_TYPE in kind:
681
        return None
719
        return None
682
    # Skip spaces before type name
720
    # Skip spaces before type name
683
    r.skip_spaces()
721
    r.skip_spaces()
684
    # Read type name
722
    # Read type name
685
    var_type = ""
723
    var_type = ""
686
    while is_id(r.curr()):
724
    while is_id(r.curr()):
687
        var_type += r.step()
725
        var_type += r.step()
688
    # Check the type name
726
    # Check the type name
689
    if len(var_type) == 0:
727
    if len(var_type) == 0:
690
        # If there's no type identifier after the name
728
        # If there's no type identifier after the name
691
        # maybe the name is something meaningful for the next parser
729
        # maybe the name is something meaningful for the next parser
692
        # return it
730
        # return it
693
        return name
731
        return name
694
    # If it starts from digit or othervice illegally it's illegal
732
    # If it starts from digit or othervice illegally it's illegal
695
    if not is_starts_as_id(var_type):
733
    if not is_starts_as_id(var_type):
696
        return None
734
        return None
697
    # Get kind of type identifier
735
    # Get kind of type identifier
698
    type_kind = id_get_kind(var_type)
736
    type_kind = id_get_kind(var_type)
699
    # If it's a keyword, that's not a variable declaration
737
    # If it's a keyword, that's not a variable declaration
700
    # return the two words of the lexical structure
738
    # return the two words of the lexical structure
701
    if ID_KIND_KEYWORD in type_kind:
739
    if ID_KIND_KEYWORD in type_kind:
702
        return (name, var_type)
740
        return (name, var_type)
703
    # Skip spaces before the value
741
    # Skip spaces before the value
704
    r.skip_spaces()
742
    r.skip_spaces()
705
    # Read the value until the comment or end of the line
743
    # Read the value until the comment or end of the line
706
    value = ""
744
    value = ""
707
    while r.curr() != ';' and r.curr() != '' and r.curr() != '\n':
745
    while r.curr() != ';' and r.curr() != '' and r.curr() != '\n':
708
        value += r.step()
746
        value += r.step()
709
    # Skip spaces after the value
747
    # Skip spaces after the value
710
    r.skip_spaces()
748
    r.skip_spaces()
711
    # Read till end of the line to get a comment from the reader
749
    # Read till end of the line to get a comment from the reader
712
    while r.curr() != '':
750
    while r.curr() != '':
713
        r.step()
751
        r.step()
714
    # Build the result
752
    # Build the result
715
    return AsmVariable(location, name, r.comment, var_type, value)
753
    return AsmVariable(location, name, r.comment, var_type, value)
-
 
754
 
716
 
755
 
717
def parse_after_struct(r, as_union = True):
756
def parse_after_struct(r, as_union=True):
718
    global warnings
757
    global warnings
719
    location = r.location()
758
    location = r.location()
720
 
759
 
721
    # Skip spaces after "struct" keyword
760
    # Skip spaces after "struct" keyword
722
    r.skip_spaces()
761
    r.skip_spaces()
723
    # Read struct name
762
    # Read struct name
724
    name = ""
763
    name = ""
725
    while is_id(r.curr()):
764
    while is_id(r.curr()):
726
        name += r.step()
765
        name += r.step()
727
    # Read till end of the line and get the comment from the reader
766
    # Read till end of the line and get the comment from the reader
728
    while r.curr() != '':
767
    while r.curr() != '':
729
        r.step()
768
        r.step()
730
    comment = r.comment
769
    comment = r.comment
731
    # Get to the next line to parse struct members
770
    # Get to the next line to parse struct members
732
    r.nextline()
771
    r.nextline()
733
    # Parse struct members
772
    # Parse struct members
734
    members = []
773
    members = []
735
    while True:
774
    while True:
736
        r.skip_spaces()
775
        r.skip_spaces()
737
        var = parse_variable(r)
776
        var = parse_variable(r)
738
        if type(var) == AsmVariable:
777
        if type(var) == AsmVariable:
739
            members.append(var)
778
            members.append(var)
740
        elif type(var) == str:
779
        elif type(var) == str:
741
            if var == 'union':
780
            if var == 'union':
742
                # Parse the union as a struct
781
                # Parse the union as a struct
743
                union = parse_after_struct(r, as_union = True)
782
                union = parse_after_struct(r, as_union=True)
744
                members.append(union)
783
                members.append(union)
745
                # Skip the ends of the union
784
                # Skip the ends of the union
746
                r.nextline()
785
                r.nextline()
747
            elif r.curr() == ':':
786
            elif r.curr() == ':':
748
                warnings += f"{r.location()}: Skept the label in the struct\n"
787
                warnings += f"{r.location()}: Skept the label in the struct\n"
749
            else:
788
            else:
750
                raise Exception(f"Garbage in struct member at {location} (got '{var}' identifier)")
789
                raise Exception(f"Garbage in struct member at {location} " +
-
 
790
                                f" (got '{var}' identifier)")
751
        elif type(var) == VariableNameIsMacroName:
791
        elif type(var) == VariableNameIsMacroName:
752
            if var.name == 'ends':
792
            if var.name == 'ends':
753
                break
793
                break
754
        r.nextline()
794
        r.nextline()
755
    # Return the result
795
    # Return the result
756
    if as_union:
796
    if as_union:
757
        return AsmStruct(location, name, comment, members)
797
        return AsmStruct(location, name, comment, members)
758
    else:
798
    else:
759
        return AsmUnion(location, name, comment, members)
799
        return AsmUnion(location, name, comment, members)
-
 
800
 
760
 
801
 
761
def parse_after_proc(r):
802
def parse_after_proc(r):
762
    # Get proc name
803
    # Get proc name
763
    name = r.fetch_identifier()
804
    name = r.fetch_identifier()
764
    # Next identifier after the proc name
805
    # Next identifier after the proc name
765
    identifier = r.fetch_identifier()
806
    identifier = r.fetch_identifier()
766
    # Check if the id is 'stdcall' or 'c' (calling convention specifier)
807
    # Check if the id is 'stdcall' or 'c' (calling convention specifier)
767
    # and if so - save the convention and lookup the next identifier
808
    # and if so - save the convention and lookup the next identifier
768
    calling_convention = ''
809
    calling_convention = ''
769
    if identifier == 'stdcall' or identifier == 'c':
810
    if identifier == 'stdcall' or identifier == 'c':
770
        calling_convention = identifier
811
        calling_convention = identifier
771
        # If next is a comma, just skip it
812
        # If next is a comma, just skip it
772
        if r.curr() == ',':
813
        if r.curr() == ',':
773
            r.step()
814
            r.step()
774
        # Read the next identifier
815
        # Read the next identifier
775
        identifier = r.fetch_identifier()
816
        identifier = r.fetch_identifier()
776
    # Check if the id is 'uses' (used register list specifier)
817
    # Check if the id is 'uses' (used register list specifier)
777
    # and if so save the used register list
818
    # and if so save the used register list
778
    used_regs = []
819
    used_regs = []
779
    if identifier == 'uses':
820
    if identifier == 'uses':
780
        # Read the registers
821
        # Read the registers
781
        while True:
822
        while True:
782
            reg_name = r.fetch_identifier()
823
            reg_name = r.fetch_identifier()
783
            if reg_name != '':
824
            if reg_name != '':
784
                used_regs.append(reg_name)
825
                used_regs.append(reg_name)
785
            else:
826
            else:
786
                break
827
                break
787
        # If next is a comma, just skip it
828
        # If next is a comma, just skip it
788
        if r.curr() == ',':
829
        if r.curr() == ',':
789
            r.step()
830
            r.step()
790
        # Read the next identifier
831
        # Read the next identifier
791
        identifier = r.fetch_identifier()
832
        identifier = r.fetch_identifier()
792
    # Check if there are argument identifiers
833
    # Check if there are argument identifiers
793
    args = []
834
    args = []
794
    while identifier != '':
835
    while identifier != '':
795
        arg_name = identifier
836
        arg_name = identifier
796
        arg_type = 'arg_t'
837
        arg_type = 'arg_t'
797
        # Skip spaces after argument name
838
        # Skip spaces after argument name
798
        r.skip_spaces()
839
        r.skip_spaces()
799
        # If there's a ':' after the name - the next identifier is type
840
        # If there's a ':' after the name - the next identifier is type
800
        if r.curr() == ':':
841
        if r.curr() == ':':
801
            r.step()
842
            r.step()
802
            arg_type = r.fetch_identifier()
843
            arg_type = r.fetch_identifier()
803
        # If there's a comma - there's one more argument
844
        # If there's a comma - there's one more argument
804
        # else no arguments anymore
845
        # else no arguments anymore
805
        if r.curr() == ',':
846
        if r.curr() == ',':
806
            r.step()
847
            r.step()
807
            identifier = r.fetch_identifier()
848
            identifier = r.fetch_identifier()
808
        else:
849
        else:
809
            identifier = ''
850
            identifier = ''
810
        args.append((arg_name, arg_type))
851
        args.append((arg_name, arg_type))
811
    # Get to the end of the line and get a comment from the reader
852
    # Get to the end of the line and get a comment from the reader
812
    while r.curr() != '':
853
    while r.curr() != '':
813
        r.step()
854
        r.step()
814
    comment = r.comment
855
    comment = r.comment
815
    # Build the element
856
    # Build the element
816
    return AsmFunction(r.location(), name, comment, calling_convention, args, used_regs)
857
    return AsmFunction(r.location(), name, comment, calling_convention,
-
 
858
                       args, used_regs)
-
 
859
 
817
 
860
 
818
def get_declarations(asm_file_contents, asm_file_name):
861
def get_declarations(asm_file_contents, asm_file_name):
819
    r = AsmReader(asm_file_name)
862
    r = AsmReader(asm_file_name)
820
 
863
 
821
    while not r.no_lines():
864
    while not r.no_lines():
822
        # Skip leading spaces
865
        # Skip leading spaces
823
        r.skip_spaces()
866
        r.skip_spaces()
824
        # Skip the line if it's starting with a comment
867
        # Skip the line if it's starting with a comment
825
        if r.curr() == ';':
868
        if r.curr() == ';':
826
            r.nextline()
869
            r.nextline()
827
            continue
870
            continue
828
        # Get first word
871
        # Get first word
829
        first_word = ""
872
        first_word = ""
830
        while is_id(r.curr()):
873
        while is_id(r.curr()):
831
            first_word += r.step()
874
            first_word += r.step()
832
        # Match macro declaration
875
        # Match macro declaration
833
        if first_word == "macro":
876
        if first_word == "macro":
834
            macro = parse_after_macro(r)
877
            macro = parse_after_macro(r)
835
            elements.append(macro)
878
            elements.append(macro)
836
            id_add_kind(macro.name, ID_KIND_MACRO_NAME)
879
            id_add_kind(macro.name, ID_KIND_MACRO_NAME)
837
        # Match structure declaration
880
        # Match structure declaration
838
        elif first_word == "struct":
881
        elif first_word == "struct":
839
            struct = parse_after_struct(r)
882
            struct = parse_after_struct(r)
840
            elements.append(struct)
883
            elements.append(struct)
841
            id_add_kind(struct.name, ID_KIND_STRUCT_NAME)
884
            id_add_kind(struct.name, ID_KIND_STRUCT_NAME)
842
        # Match function definition
885
        # Match function definition
843
        elif first_word == "proc":
886
        elif first_word == "proc":
844
            proc = parse_after_proc(r)
887
            proc = parse_after_proc(r)
845
            elements.append(proc)
888
            elements.append(proc)
846
        elif first_word == 'format':
889
        elif first_word == 'format':
847
            # Skip the format directive
890
            # Skip the format directive
848
            pass
891
            pass
849
        elif first_word == 'include':
892
        elif first_word == 'include':
850
            # Skip the include directive
893
            # Skip the include directive
851
            pass
894
            pass
852
        elif first_word == 'if':
895
        elif first_word == 'if':
853
            # Skip the conditional directive
896
            # Skip the conditional directive
854
            pass
897
            pass
855
        elif first_word == 'repeat':
898
        elif first_word == 'repeat':
856
            # Skip the repeat directive
899
            # Skip the repeat directive
857
            pass
900
            pass
858
        elif first_word == 'purge':
901
        elif first_word == 'purge':
859
            while True:
902
            while True:
-
 
903
                # Skip spaces after the 'purge' keyword or after
860
                # Skip spaces after the 'purge' keyword or after the comma what separated the previous macro name
904
                # the comma what separated the previous macro name
861
                r.skip_spaces()
905
                r.skip_spaces()
862
                # Get the purged macro name
906
                # Get the purged macro name
863
                name = ''
907
                name = ''
864
                while is_id(r.curr()):
908
                while is_id(r.curr()):
865
                    name += r.step()
909
                    name += r.step()
866
                # Remove the purged macro from the macro names list
910
                # Remove the purged macro from the macro names list
867
                try:
911
                try:
868
                    id_remove_kind(name, ID_KIND_MACRO_NAME)
912
                    id_remove_kind(name, ID_KIND_MACRO_NAME)
869
                except:
913
                except:
870
                    pass
914
                    pass
871
                # Skip spaces after the name
915
                # Skip spaces after the name
872
                r.skip_spaces()
916
                r.skip_spaces()
873
                # If it's comma (',') after then that's not the last purged macro, continue purging
917
                # If it's comma (',') after then that's not the last purged
-
 
918
                # macro, continue purging
874
                if r.curr() == ',':
919
                if r.curr() == ',':
875
                    r.step()
920
                    r.step()
876
                    continue
921
                    continue
877
                # Here we purged all the macros should be purged
922
                # Here we purged all the macros should be purged
878
                break
923
                break
879
        # Match label or a variable
924
        # Match label or a variable
880
        elif len(first_word) != 0:
925
        elif len(first_word) != 0:
881
            # Skip spaces after the identifier
926
            # Skip spaces after the identifier
882
            r.skip_spaces()
927
            r.skip_spaces()
883
            # Match a variable
928
            # Match a variable
884
            var = parse_variable(r, first_word)
929
            var = parse_variable(r, first_word)
885
            if type(var) == AsmVariable:
930
            if type(var) == AsmVariable:
886
                elements.append(var)
931
                elements.append(var)
887
            # If it wasn't a variable but there was an identifier
932
            # If it wasn't a variable but there was an identifier
888
            # Maybe that's a label and the identifier is the label name
933
            # Maybe that's a label and the identifier is the label name
889
            # The parse_variable returns the first found or supplied identifier
934
            # The parse_variable returns the first found or supplied identifier
890
            # In this case it returns the first_word which is supplied
935
            # In this case it returns the first_word which is supplied
891
            # If it didn't match a type identifier after the word
936
            # If it didn't match a type identifier after the word
892
            elif type(var) == str:
937
            elif type(var) == str:
893
                name = var
938
                name = var
894
                # Match label beginning (':' after name)
939
                # Match label beginning (':' after name)
895
                if r.curr() == ':':
940
                if r.curr() == ':':
-
 
941
                    # Get to the end of the line and
896
                    # Get to the end of the line and get the coment from the reader
942
                    # get the coment from the reader
897
                    while r.curr() != '':
943
                    while r.curr() != '':
898
                        r.step()
944
                        r.step()
899
                    comment = r.comment
945
                    comment = r.comment
900
                    # Only handle non-local labels
946
                    # Only handle non-local labels
901
                    if name[0] != '.' and name != "@@" and name != "$Revision":
947
                    if name[0] != '.' and name != "@@" and name != "$Revision":
-
 
948
                        # Treate the label as function if there's @return or
-
 
949
                        # @param in its comment. Othervice it's just a variable
-
 
950
                        # with type `label` in generated doxygen C
902
                        if '@return' in comment or '@param' in comment:
951
                        if '@return' in comment or '@param' in comment:
903
                            element = AsmFunction(r.location(), name, comment, '', [], [])
952
                            element = AsmFunction(r.location(), name, comment,
-
 
953
                                                  '', [], [])
904
                        else:
954
                        else:
905
                            element = AsmLabel(r.location(), name, comment)
955
                            element = AsmLabel(r.location(), name, comment)
906
                        elements.append(element)
956
                        elements.append(element)
907
                elif r.curr() == '=':
957
                elif r.curr() == '=':
908
                    # Save the identifier as a set constant
958
                    # Save the identifier as a set constant
909
                    id_add_kind(first_word, ID_KIND_SET_CONSTANT)
959
                    id_add_kind(first_word, ID_KIND_SET_CONSTANT)
910
            elif type(var) == tuple:
960
            elif type(var) == tuple:
911
                (word_one, word_two) = var
961
                (word_one, word_two) = var
912
                if word_two == 'equ':
962
                if word_two == 'equ':
913
                    # Save the identifier as an equated constant
963
                    # Save the identifier as an equated constant
914
                    id_add_kind(word_one, ID_KIND_EQUATED_CONSTANT)
964
                    id_add_kind(word_one, ID_KIND_EQUATED_CONSTANT)
915
        r.nextline()
965
        r.nextline()
-
 
966
 
916
 
967
 
917
def it_neds_to_be_parsed(source_file):
968
def it_neds_to_be_parsed(source_file):
918
    # If there's no symbols file saved - parse it anyway
969
    # If there's no symbols file saved - parse it anyway
919
    # cause we need to create the symbols file and use it
970
    # cause we need to create the symbols file and use it
920
    # if we gonna generate proper doxygen
971
    # if we gonna generate proper doxygen
921
    if not os.path.isfile('asmxygen.elements.pickle'):
972
    if not os.path.isfile('asmxygen.elements.pickle'):
922
        return True
973
        return True
923
    dest = doxygen_src_path + '/' + source_file
974
    dest = doxygen_src_path + '/' + source_file
924
    # If there's no the doxygen file it should be compiled to
975
    # If there's no the doxygen file it should be compiled to
925
    # then yes, we should compile it to doxygen
976
    # then yes, we should compile it to doxygen
926
    if not os.path.isfile(dest):
977
    if not os.path.isfile(dest):
927
        return True
978
        return True
928
    source_change_time = os.path.getmtime(source_file)
979
    source_change_time = os.path.getmtime(source_file)
929
    dest_change_file = os.path.getmtime(dest)
980
    dest_change_file = os.path.getmtime(dest)
930
    # If the source is newer than the doxygen it was compiled to
981
    # If the source is newer than the doxygen it was compiled to
931
    # then the source should be recompiled (existing doxygen is old)
982
    # then the source should be recompiled (existing doxygen is old)
932
    if source_change_time > dest_change_file:
983
    if source_change_time > dest_change_file:
933
        return True
984
        return True
934
    return False
985
    return False
-
 
986
 
935
 
987
 
936
def handle_file(handled_files, asm_file_name, subdir = "."):
988
def handle_file(handled_files, asm_file_name, subdir="."):
937
    global elements
989
    global elements
938
    # Canonicalize the file path and get it relative to cwd
990
    # Canonicalize the file path and get it relative to cwd
939
    cwd = os.path.abspath(os.path.dirname(sys.argv[0]))
991
    cwd = os.path.abspath(os.path.dirname(sys.argv[0]))
940
    asm_file_name = os.path.realpath(asm_file_name)
992
    asm_file_name = os.path.realpath(asm_file_name)
941
    asm_file_name = asm_file_name[len(cwd) + 1:]
993
    asm_file_name = asm_file_name[len(cwd) + 1:]
942
    # If it's lang.inc - skip it
994
    # If it's lang.inc - skip it
943
    if asm_file_name == 'lang.inc':
995
    if asm_file_name == 'lang.inc':
944
        return
996
        return
945
    # If the file was handled in this execution before - skip it
997
    # If the file was handled in this execution before - skip it
946
    if asm_file_name in handled_files:
998
    if asm_file_name in handled_files:
947
        return
999
        return
948
    # Say that the file was handled in this execution
1000
    # Say that the file was handled in this execution
949
    handled_files.append(asm_file_name)
1001
    handled_files.append(asm_file_name)
-
 
1002
    # Check if the file should be parsed
950
    # Check if the file should be parsed (if it was modified or wasn't parsed yet)
1003
    # (if it was modified or wasn't parsed yet)
951
    should_get_declarations = True
1004
    should_get_declarations = True
952
    if not it_neds_to_be_parsed(asm_file_name):
1005
    if not it_neds_to_be_parsed(asm_file_name):
953
        print(f"Skipping {asm_file_name} (already newest)")
1006
        print(f"Skipping {asm_file_name} (already newest)")
954
        should_get_declarations = False
1007
        should_get_declarations = False
955
    else:
1008
    else:
956
        print(f"Handling {asm_file_name}")
1009
        print(f"Handling {asm_file_name}")
957
        # Remove elements parsed from this file before if any
1010
        # Remove elements parsed from this file before if any
-
 
1011
        elements_to_remove = [
958
        elements_to_remove = [x for x in elements if x.location.split(':')[0] == asm_file_name]
1012
            x for x in elements if x.location.split(':')[0] == asm_file_name
-
 
1013
        ]
-
 
1014
        elements = [
959
        elements = [x for x in elements if x.location.split(':')[0] != asm_file_name]
1015
            x for x in elements if x.location.split(':')[0] != asm_file_name
-
 
1016
        ]
960
        # Forget types of identifiers of names of the removed elements
1017
        # Forget types of identifiers of names of the removed elements
961
        for element in elements_to_remove:
1018
        for element in elements_to_remove:
962
            if type(element) == AsmStruct:
1019
            if type(element) == AsmStruct:
963
                id_remove_kind(element.name, ID_KIND_STRUCT_NAME)
1020
                id_remove_kind(element.name, ID_KIND_STRUCT_NAME)
964
            elif type(element) == AsmMacro:
1021
            elif type(element) == AsmMacro:
965
                id_remove_kind(element.name, ID_KIND_MACRO_NAME)
1022
                id_remove_kind(element.name, ID_KIND_MACRO_NAME)
966
    # Read the source
1023
    # Read the source
967
    asm_file_contents = open(asm_file_name, "r", encoding="utf-8").read()
1024
    asm_file_contents = open(asm_file_name, "r", encoding="utf-8").read()
968
    # Find includes, fix their paths and handle em recoursively
1025
    # Find includes, fix their paths and handle em recoursively
969
    includes = re.findall(r'^include (["\'])(.*)\1', asm_file_contents, flags=re.MULTILINE)
1026
    includes = re.findall(r'^include (["\'])(.*)\1', asm_file_contents,
-
 
1027
                          flags=re.MULTILINE)
970
    for include in includes:
1028
    for include in includes:
971
        include = include[1].replace('\\', '/');
1029
        include = include[1].replace('\\', '/')
972
        full_path = subdir + '/' + include;
1030
        full_path = subdir + '/' + include
973
        # If the path isn't valid, maybe that's not relative path
1031
        # If the path isn't valid, maybe that's not relative path
974
        if not os.path.isfile(full_path):
1032
        if not os.path.isfile(full_path):
975
            full_path = include
1033
            full_path = include
976
        new_subdir = full_path.rsplit('/', 1)[0]
1034
        new_subdir = full_path.rsplit('/', 1)[0]
977
        handle_file(handled_files, full_path, new_subdir)
1035
        handle_file(handled_files, full_path, new_subdir)
978
    # Only collect declarations from the file if it wasn't parsed before
1036
    # Only collect declarations from the file if it wasn't parsed before
979
    if should_get_declarations and not clean_generated_stuff:
1037
    if should_get_declarations and not clean_generated_stuff:
980
        get_declarations(asm_file_contents, asm_file_name)
1038
        get_declarations(asm_file_contents, asm_file_name)
981
 
1039
 
982
if __name__ == "__main__":
1040
if __name__ == "__main__":
983
    link_root = "http://websvn.kolibrios.org/filedetails.php?repname=Kolibri+OS&path=/kernel/trunk"
1041
    link_root = "http://websvn.kolibrios.org/filedetails.php"
-
 
1042
    link_root += "?repname=Kolibri+OS&path=/kernel/trunk"
984
 
1043
 
985
    # Dict where an identifier is assicoated with a string
1044
    # Dict where an identifier is assicoated with a string
986
    # The string contains characters specifying flags
1045
    # The string contains characters specifying flags
987
    # Available flags:
1046
    # Available flags:
988
    #  k - Keyword
1047
    #  k - Keyword
989
    #  m - Macro name
1048
    #  m - Macro name
990
    #  t - fasm data Type name (db, rq, etc.)
1049
    #  t - fasm data Type name (db, rq, etc.)
991
    #  s - Struct type name
1050
    #  s - Struct type name
992
    #  e - equated constant (name equ value)
1051
    #  e - equated constant (name equ value)
993
    #  = - set constants (name = value)
1052
    #  = - set constants (name = value)
994
    ID_KIND_KEYWORD = 'k'
1053
    ID_KIND_KEYWORD = 'k'
995
    ID_KIND_MACRO_NAME = 'm'
1054
    ID_KIND_MACRO_NAME = 'm'
996
    ID_KIND_FASM_TYPE = 't'
1055
    ID_KIND_FASM_TYPE = 't'
997
    ID_KIND_STRUCT_NAME = 's'
1056
    ID_KIND_STRUCT_NAME = 's'
998
    ID_KIND_EQUATED_CONSTANT = 'e'
1057
    ID_KIND_EQUATED_CONSTANT = 'e'
999
    ID_KIND_SET_CONSTANT = '='
1058
    ID_KIND_SET_CONSTANT = '='
1000
    id2kind = {}
1059
    id2kind = {}
1001
 
1060
 
1002
    for keyword in keywords:
1061
    for keyword in keywords:
1003
        id_add_kind(keyword, ID_KIND_KEYWORD)
1062
        id_add_kind(keyword, ID_KIND_KEYWORD)
1004
 
1063
 
1005
    for fasm_type in fasm_types:
1064
    for fasm_type in fasm_types:
1006
        id_add_kind(fasm_type, ID_KIND_FASM_TYPE)
1065
        id_add_kind(fasm_type, ID_KIND_FASM_TYPE)
1007
 
1066
 
1008
    # Warning list
1067
    # Warning list
1009
    warnings = ""
1068
    warnings = ""
1010
 
1069
 
1011
    # Parameters
1070
    # Parameters
1012
    # Path to doxygen folder to make doxygen files in: -o 
1071
    # Path to doxygen folder to make doxygen files in: -o 
1013
    doxygen_src_path = 'docs/doxygen'
1072
    doxygen_src_path = 'docs/doxygen'
1014
    # Remove generated doxygen files: --clean
1073
    # Remove generated doxygen files: --clean
1015
    clean_generated_stuff = False
1074
    clean_generated_stuff = False
1016
    # Dump all defined symbols: --dump
1075
    # Dump all defined symbols: --dump
1017
    dump_symbols = False
1076
    dump_symbols = False
1018
    # Print symbol stats: --stats
1077
    # Print symbol stats: --stats
1019
    print_stats = False
1078
    print_stats = False
1020
    # Do not write warnings file: --nowarn
1079
    # Do not write warnings file: --nowarn
1021
    enable_warnings = True
1080
    enable_warnings = True
1022
 
1081
 
1023
    # Parse arguments
1082
    # Parse arguments
1024
    parser = argparse.ArgumentParser()
1083
    parser = argparse.ArgumentParser()
1025
    parser.add_argument("-o", help="Doxygen output folder")
1084
    parser.add_argument("-o", help="Doxygen output folder")
-
 
1085
    parser.add_argument("--clean",
1026
    parser.add_argument("--clean", help="Remove generated files", action="store_true")
1086
                        help="Remove generated files",
-
 
1087
                        action="store_true")
-
 
1088
    parser.add_argument("--dump",
1027
    parser.add_argument("--dump", help="Dump all defined symbols", action="store_true")
1089
                        help="Dump all defined symbols",
-
 
1090
                        action="store_true")
-
 
1091
    parser.add_argument("--stats",
1028
    parser.add_argument("--stats", help="Print symbol stats", action="store_true")
1092
                        help="Print symbol stats",
-
 
1093
                        action="store_true")
-
 
1094
    parser.add_argument("--nowarn",
1029
    parser.add_argument("--nowarn", help="Do not write warnings file", action="store_true")
1095
                        help="Do not write warnings file",
-
 
1096
                        action="store_true")
-
 
1097
    parser.add_argument("--noemit",
1030
    parser.add_argument("--noemit", help="Do not emit doxygen files (for testing)", action="store_true")
1098
                        help="Do not emit doxygen files (for testing)",
-
 
1099
                        action="store_true")
-
 
1100
    parser.add_argument("--debug",
1031
    parser.add_argument("--debug", help="Show hashes of files (for testing)", action="store_true")
1101
                        help="Show hashes of files (for testing)",
-
 
1102
                        action="store_true")
1032
    args = parser.parse_args()
1103
    args = parser.parse_args()
1033
    doxygen_src_path = args.o if args.o else 'docs/doxygen'
1104
    doxygen_src_path = args.o if args.o else 'docs/doxygen'
1034
    clean_generated_stuff = args.clean
1105
    clean_generated_stuff = args.clean
1035
    dump_symbols = args.dump
1106
    dump_symbols = args.dump
1036
    print_stats = args.stats
1107
    print_stats = args.stats
1037
    enable_warnings = not args.nowarn
1108
    enable_warnings = not args.nowarn
1038
    noemit = args.noemit
1109
    noemit = args.noemit
1039
    debug_mode = args.debug
1110
    debug_mode = args.debug
1040
 
1111
 
1041
    # Variables, functions, labels, macros, structure types
1112
    # Variables, functions, labels, macros, structure types
1042
    elements = []
1113
    elements = []
1043
    created_files = []
1114
    created_files = []
1044
    kernel_files = []
1115
    kernel_files = []
1045
    output_files = {} # If --debug then all the files are written here
1116
    output_files = {}  # If --debug then all the files are written here
1046
 
1117
 
1047
    # Load remembered list of symbols
1118
    # Load remembered list of symbols
1048
    if os.path.isfile('asmxygen.elements.pickle'):
1119
    if os.path.isfile('asmxygen.elements.pickle'):
1049
        print('Reading existing dump of symbols')
1120
        print('Reading existing dump of symbols')
1050
        (elements, id2kind) = pickle.load(open('asmxygen.elements.pickle', 'rb'))
1121
        pickle_file = open('asmxygen.elements.pickle', 'rb')
-
 
1122
        (elements, id2kind) = pickle.load(pickle_file)
-
 
1123
        pickle_file.close()
1051
 
1124
 
1052
    handle_file(kernel_files, "./kernel.asm");
1125
    handle_file(kernel_files, "./kernel.asm")
1053
 
1126
 
1054
    if dump_symbols:
1127
    if dump_symbols:
1055
        stdout = sys.stdout
1128
        stdout = sys.stdout
1056
        sys.stdout = open('asmxygen.dump.txt', 'w', encoding = 'utf-8')
1129
        sys.stdout = open('asmxygen.dump.txt', 'w', encoding='utf-8')
1057
        for asm_element in elements:
1130
        for asm_element in elements:
1058
            asm_element.dump()
1131
            asm_element.dump()
1059
        sys.stdout = stdout
1132
        sys.stdout = stdout
1060
 
1133
 
1061
    if clean_generated_stuff:
1134
    if clean_generated_stuff:
1062
        kernel_files_set = set(kernel_files)
1135
        kernel_files_set = set(kernel_files)
1063
        for file in kernel_files:
1136
        for file in kernel_files:
1064
            doxygen_file = f"{doxygen_src_path}/{file}"
1137
            doxygen_file = f"{doxygen_src_path}/{file}"
1065
            if (os.path.isfile(doxygen_file)):
1138
            if (os.path.isfile(doxygen_file)):
1066
                print(f"Removing {file}... ", end = '')
1139
                print(f"Removing {file}... ", end='')
1067
                os.remove(doxygen_file)
1140
                os.remove(doxygen_file)
1068
                print("Done.")
1141
                print("Done.")
1069
    elif not noemit:
1142
    elif not noemit:
1070
        print(f"Writing doumented sources to {doxygen_src_path}")
1143
        print(f"Writing doumented sources to {doxygen_src_path}")
1071
 
1144
 
1072
        i = 0
1145
        i = 0
1073
        new_elements = [x for x in elements if x.new]
1146
        new_elements = [x for x in elements if x.new]
1074
        for element in new_elements:
1147
        for element in new_elements:
-
 
1148
            counter = f"[{i + 1}/{len(new_elements)}]"
1075
            print(f"[{i + 1}/{len(new_elements)}] Emitting {element.name} from {element.location}")
1149
            print(f"{counter} Emitting {element.name} from {element.location}")
1076
            element.emit(doxygen_src_path)
1150
            element.emit(doxygen_src_path)
1077
            i += 1
1151
            i += 1
1078
 
1152
 
1079
        print(f"Writing dump of symbols to asmxygen.elements.pickle")
1153
        print(f"Writing dump of symbols to asmxygen.elements.pickle")
1080
 
1154
 
-
 
1155
        # Now when the new elements already was written, there's no new
1081
        # Now when the new elements already was written, there's no new elements anymore
1156
        # elements anymore
1082
        for element in elements:
1157
        for element in elements:
1083
            element.new = False
1158
            element.new = False
-
 
1159
        pickle_file = open('asmxygen.elements.pickle', 'wb')
-
 
1160
        pickle.dump((elements, id2kind), pickle_file)
1084
        pickle.dump((elements, id2kind), open('asmxygen.elements.pickle', 'wb'))
1161
        pickle_file.close()
1085
 
1162
 
1086
    if print_stats:
1163
    if print_stats:
1087
        var_count = 0
1164
        var_count = 0
1088
        mac_count = 0
1165
        mac_count = 0
1089
        lab_count = 0
1166
        lab_count = 0
1090
        fun_count = 0
1167
        fun_count = 0
1091
        uni_count = 0
1168
        uni_count = 0
1092
        str_count = 0
1169
        str_count = 0
1093
        for element in elements:
1170
        for element in elements:
1094
            if type(element) == AsmVariable:
1171
            if type(element) == AsmVariable:
1095
                var_count += 1
1172
                var_count += 1
1096
            elif type(element) == AsmMacro:
1173
            elif type(element) == AsmMacro:
1097
                mac_count += 1
1174
                mac_count += 1
1098
            elif type(element) == AsmLabel:
1175
            elif type(element) == AsmLabel:
1099
                lab_count += 1
1176
                lab_count += 1
1100
            elif type(element) == AsmFunction:
1177
            elif type(element) == AsmFunction:
1101
                fun_count += 1
1178
                fun_count += 1
1102
            elif type(element) == AsmUnion:
1179
            elif type(element) == AsmUnion:
1103
                uni_count += 1
1180
                uni_count += 1
1104
            elif type(element) == AsmStruct:
1181
            elif type(element) == AsmStruct:
1105
                str_count += 1
1182
                str_count += 1
1106
        print(f'Parsed variable count: {var_count}')
1183
        print(f'Parsed variable count: {var_count}')
1107
        print(f'Parsed macro count: {mac_count}')
1184
        print(f'Parsed macro count: {mac_count}')
1108
        print(f'Parsed label count: {lab_count}')
1185
        print(f'Parsed label count: {lab_count}')
1109
        print(f'Parsed function count: {fun_count}')
1186
        print(f'Parsed function count: {fun_count}')
1110
        print(f'Parsed union type count: {uni_count}')
1187
        print(f'Parsed union type count: {uni_count}')
1111
        print(f'Parsed structure type count: {str_count}')
1188
        print(f'Parsed structure type count: {str_count}')
1112
 
1189
 
1113
    if enable_warnings:
1190
    if enable_warnings:
1114
        open('asmxygen.txt', "w", encoding = "utf-8").write(warnings)
1191
        open('asmxygen.txt', "w", encoding="utf-8").write(warnings)
1115
 
1192
 
1116
    if debug_mode:
1193
    if debug_mode:
1117
        hash_per_file = ""
1194
        hash_per_file = ""
1118
        for file in output_files:
1195
        for file in output_files:
1119
            h = hashlib.sha1(bytes(output_files[file], "ascii")).hexdigest()
1196
            h = hashlib.sha1(bytes(output_files[file], "ascii")).hexdigest()
1120
            hash_per_file += f"{file}: {h}\n"
1197
            hash_per_file += f"{file}: {h}\n"
1121
        if not os.path.exists("asmxygen_hash_per_file.txt"):
1198
        if not os.path.exists("asmxygen_hash_per_file.txt"):
1122
            open("asmxygen_hash_per_file.txt", "w").write(hash_per_file)
1199
            open("asmxygen_hash_per_file.txt", "w").write(hash_per_file)
1123
            print("NEW")
1200
            print("NEW")
1124
        else:
1201
        else:
1125
            reference_hash_per_file = open("asmxygen_hash_per_file.txt").read()
1202
            reference_hash_per_file = open("asmxygen_hash_per_file.txt").read()
1126
            if reference_hash_per_file != hash_per_file:
1203
            if reference_hash_per_file != hash_per_file:
1127
                print(''.join(difflib.ndiff(reference_hash_per_file, hash_per_file)))
1204
                diffs = difflib.ndiff(reference_hash_per_file, hash_per_file)
-
 
1205
                print(''.join(diffs))
1128
            else:
1206
            else:
1129
                print("SUCCESS")
1207
                print("SUCCESS")