Subversion Repositories Kolibri OS

Rev

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