Subversion Repositories Kolibri OS

Rev

Rev 8982 | Blame | Last modification | View Log | Download | RSS feed

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