Subversion Repositories Kolibri OS

Rev

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

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