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")>>> |