Subversion Repositories Kolibri OS

Rev

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