Subversion Repositories Kolibri OS

Rev

Rev 8966 | Rev 8973 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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