Subversion Repositories Kolibri OS

Rev

Rev 8844 | Rev 8855 | 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.  
  5. # Parameters
  6. # Path to doxygen folder to make doxygen files in: -o <path>
  7. doxygen_src_path = 'docs/doxygen'
  8. # Remove generated doxygen files: --clean
  9. clean_generated_stuff = False
  10. # Dump all defined symbols: --dump
  11. dump_symbols = False
  12. # Print symbol stats: --stats
  13. print_stats = False
  14.  
  15. # Constants
  16. link_root = "http://websvn.kolibrios.org/filedetails.php?repname=Kolibri+OS&path=/kernel/trunk"
  17.  
  18. # Parse arguments
  19. parser = argparse.ArgumentParser()
  20. parser.add_argument("-o", help="Doxygen output folder")
  21. parser.add_argument("--clean", help="Remove generated files", action="store_true")
  22. parser.add_argument("--dump", help="Dump all defined symbols", action="store_true")
  23. parser.add_argument("--stats", help="Print symbol stats", action="store_true")
  24. args = parser.parse_args()
  25. doxygen_src_path = args.o if args.o else 'docs/doxygen'
  26. clean_generated_stuff = args.clean
  27. dump_symbols = args.dump
  28. print_stats = args.stats
  29.  
  30. # kernel_structure["filename"] = {
  31. #   [ [],    # [0] Variables - [ line, name ]
  32. #     [],    # [1] Macros - [ line, name ]
  33. #     [],    # [2] Procedures - [ line, name ]
  34. #     [],    # [3] Labels - [ line, name ]
  35. #     [] ] } # [4] Structures - [ line, name ]
  36. VARIABLES = 0
  37. MACROS = 1
  38. PROCEDURES = 2
  39. LABELS = 3
  40. STRUCTURES = 4
  41. kernel_structure = {}
  42.  
  43. def get_declarations(asm_file_contents, asm_file_name):
  44.         asm_file_name = asm_file_name.replace("./", "")
  45.         kernel_structure[asm_file_name] = [ [], [], [], [], [] ]
  46.  
  47.         variable_pattern = re.compile(r'^\s*([\w\.]+)\s+d([bwdq])\s+([^;]*)\s*([;].*)?')
  48.         macro_pattern = re.compile(r'^\s*macro\s+([\w]+).*')
  49.         proc_pattern = re.compile(r'^\s*proc\s+([\w\.]+).*')
  50.         label_pattern = re.compile(r'^(?!;)\s*([\w\.]+):.*')
  51.         struct_pattern = re.compile(r'^\s*struct\s+([\w]+).*')
  52.  
  53.         line_idx = 0
  54.         lines = asm_file_contents.splitlines()
  55.         while line_idx < len(lines):
  56.                 line = lines[line_idx]
  57.  
  58.                 match = variable_pattern.findall(line)
  59.                 if len(match) > 0:
  60.                         (var_name, var_type, var_init, var_comm) = match[0]
  61.                         if var_comm == "":
  62.                                 var_comm = "Undocumented"
  63.                         else:
  64.                                 var_comm = var_comm[1:].lstrip()
  65.                                 if (len(var_comm) == 0):
  66.                                         var_comm = "!!! EMPTY_COMMENT"
  67.                                 if var_comm[0].islower(): var_comm = "!!! LOWERCASE COMMENT " + var_comm
  68.                         if var_type == "b": var_type = "byte"
  69.                         if var_type == "w": var_type = "word"
  70.                         if var_type == "d": var_type = "dword"
  71.                         if var_type == "q": var_type = "qword"
  72.                         kernel_structure[asm_file_name][VARIABLES].append([ line_idx + 1, var_name, var_type, var_init, var_comm ])
  73.                         line_idx += 1
  74.                         continue
  75.  
  76.                 match = macro_pattern.findall(line)
  77.                 if len(match) > 0:
  78.                         macro_name = match[0]
  79.                         kernel_structure[asm_file_name][MACROS].append([ line_idx + 1, macro_name ])
  80.                         end_of_macro = False
  81.                         while not end_of_macro:
  82.                                 line = lines[line_idx]
  83.                                 rbraces = re.finditer('}', line)
  84.                                 for rbrace_match in rbraces:
  85.                                         rbrace_idx = rbrace_match.start()
  86.                                         if line[rbrace_idx - 1] != '\\':
  87.                                                 end_of_macro = True
  88.                                 line_idx += 1
  89.                         continue
  90.  
  91.                 match = proc_pattern.findall(line)
  92.                 if len(match) > 0:
  93.                         proc_name = match[0]
  94.                         kernel_structure[asm_file_name][PROCEDURES].append([ line_idx + 1, proc_name ])
  95.                         line_idx += 1
  96.                         continue
  97.  
  98.                 match = label_pattern.findall(line)
  99.                 if len(match) > 0:
  100.                         label_name = match[0]
  101.                         # Don't count local labels
  102.                         if label_name[0] != '.':
  103.                                 kernel_structure[asm_file_name][LABELS].append([ line_idx + 1, label_name ])
  104.                                 line_idx += 1
  105.                                 continue
  106.  
  107.                 match = struct_pattern.findall(line)
  108.                 if len(match) > 0:
  109.                         struct_name = match[0]
  110.                         kernel_structure[asm_file_name][STRUCTURES].append([ line_idx + 1, struct_name ])
  111.                         end_of_struct = False
  112.                         while not end_of_struct:
  113.                                 line = lines[line_idx]
  114.                                 if re.match(r"^ends$", line) != None:
  115.                                         end_of_struct = True
  116.                                 line_idx += 1
  117.                         continue
  118.  
  119.                 line_idx += 1
  120.  
  121. def handle_file(handled_files, asm_file_name, subdir = "."):
  122.         if dump_symbols:
  123.                 print(f"Handling {asm_file_name}")
  124.         handled_files.append(asm_file_name)
  125.         try:
  126.                 asm_file_contents = open(asm_file_name, "r", encoding="utf-8").read()
  127.         except:
  128.                 return
  129.         get_declarations(asm_file_contents, asm_file_name)
  130.         include_directive_pattern_1 = re.compile(r'include "(.*)"')
  131.         include_directive_pattern_2 = re.compile(r'include \'(.*)\'')
  132.         includes = include_directive_pattern_1.findall(asm_file_contents)
  133.         includes += include_directive_pattern_2.findall(asm_file_contents)
  134.         for include in includes:
  135.                 include = include.replace('\\', '/');
  136.                 full_path = subdir + '/' + include;
  137.                 if full_path not in handled_files:
  138.                         new_subdir = full_path.rsplit('/', 1)[0]
  139.                         handle_file(handled_files, full_path, new_subdir)
  140.         return handled_files
  141.  
  142. kernel_files = []
  143.  
  144. handle_file(kernel_files, "./kernel.asm");
  145.  
  146. if dump_symbols:
  147.         for source in kernel_structure:
  148.                 print(f"File: {source}")
  149.                 if len(kernel_structure[source][VARIABLES]) > 0:
  150.                         print(" Variables:")
  151.                         for variable in kernel_structure[source][VARIABLES]:
  152.                                 print(f"  {variable[0]}: {variable[1]}")
  153.                 if len(kernel_structure[source][PROCEDURES]) > 0:
  154.                         print(" Procedures:")
  155.                         for procedure in kernel_structure[source][PROCEDURES]:
  156.                                 print(f"  {procedure[0]}: {procedure[1]}")
  157.                 if len(kernel_structure[source][LABELS]) > 0:
  158.                         print(" Global labels:")
  159.                         for label in kernel_structure[source][LABELS]:
  160.                                 print(f"  {label[0]}: {label[1]}")
  161.                 if len(kernel_structure[source][MACROS]) > 0:
  162.                         print(" Macroses:")
  163.                         for macro in kernel_structure[source][MACROS]:
  164.                                 print(f"  {macro[0]}: {macro[1]}")
  165.                 if len(kernel_structure[source][STRUCTURES]) > 0:
  166.                         print(" Structures:")
  167.                         for struct in kernel_structure[source][STRUCTURES]:
  168.                                 print(f"  {struct[0]}: {struct[1]}")
  169.  
  170. if print_stats:
  171.         # Collect stats
  172.         var_count = 0
  173.         proc_count = 0
  174.         label_count = 0
  175.         macro_count = 0
  176.         struct_count = 0
  177.  
  178.         for source in kernel_structure:
  179.                 var_count += len(kernel_structure[source][VARIABLES])
  180.                 proc_count += len(kernel_structure[source][PROCEDURES])
  181.                 label_count += len(kernel_structure[source][LABELS])
  182.                 macro_count += len(kernel_structure[source][MACROS])
  183.                 struct_count += len(kernel_structure[source][STRUCTURES])
  184.  
  185.         print(f"File count: {len(kernel_structure)}")
  186.         print(f"Variable count: {var_count}")
  187.         print(f"Procedures count: {proc_count}")
  188.         print(f"Global labels count: {label_count}")
  189.         print(f"Macroses count: {macro_count}")
  190.         print(f"Structures count: {struct_count}")
  191.  
  192. print(f"Writing doumented sources to {doxygen_src_path}")
  193.  
  194. created_files = []
  195.  
  196. def write_something(source, somehing):
  197.         full_path = doxygen_src_path + '/' + source
  198.         # Remove the file on first access if it was created by previous generation
  199.         if full_path not in created_files:
  200.                 if os.path.isfile(full_path):
  201.                         os.remove(full_path)
  202.                 created_files.append(full_path)
  203.         # Only remove the file on 'clean_generated_stuff' flag (removed above, just return)
  204.         if clean_generated_stuff: return
  205.         # Create directories need for the file
  206.         os.makedirs(os.path.dirname(full_path), exist_ok=True)
  207.         f = open(full_path, "a")
  208.         f.write(somehing)
  209.         f.close()
  210.  
  211. def write_variable(source, line, name, type, init, brief):
  212.         name = name.replace(".", "_")
  213.         something = (f"/**\n" +
  214.                      f" * @brief {brief}\n" +
  215.                      f" * @par Initial value\n" +
  216.                      f" * {init}\n" +
  217.                      f" * @par Source\n" +
  218.                      f" * <a href='{link_root}/{source}#line-{line}'>{source}:{line}</a>\n" +
  219.                      f" */\n" +
  220.                      f"{type} {name};\n\n")
  221.         write_something(source, something)
  222.  
  223. def write_procedure(source, line, name, brief = "Undocumented"):
  224.         name = name.replace(".", "_")
  225.         something = (f"/**\n" +
  226.                      f" * @brief {brief}\n" +
  227.                      f" * @par Source\n" +
  228.                      f" * <a href='{link_root}/{source}#line-{line}'>{source}:{line}</a>\n" +
  229.                      f" */\n" +
  230.                      f"void {name}();\n\n")
  231.         write_something(source, something)
  232.  
  233. def write_label(source, line, name, brief = "Undocumented"):
  234.         name = name.replace(".", "_")
  235.         something = (f"/**\n" +
  236.                      f" * @brief {brief}\n" +
  237.                      f" * @par Source\n" +
  238.                      f" * <a href='{link_root}/{source}#line-{line}'>{source}:{line}</a>\n" +
  239.                      f" */\n" +
  240.                      f"void {name}();\n\n")
  241.         write_something(source, something)
  242.  
  243. def write_macro(source, line, name, brief = "Undocumented"):
  244.         name = name.replace(".", "_")
  245.         something = (f"/**\n" +
  246.                      f" * @def {name}\n" +
  247.                      f" * @brief {brief}\n" +
  248.                      f" * @par Source\n" +
  249.                      f" * <a href='{link_root}/{source}#line-{line}'>{source}:{line}</a>\n" +
  250.                      f" */\n#define {name}\n\n")
  251.         write_something(source, something)
  252.  
  253. def write_structure(source, line, name, brief = "Undocumented"):
  254.         name = name.replace(".", "_")
  255.         something = (f"/**\n" +
  256.                      f" * @struct {name}\n" +
  257.                      f" * @brief {brief}\n" +
  258.                      f" * @par Source\n" +
  259.                      f" * <a href='{link_root}/{source}#line-{line}'>{source}:{line}</a>\n" +
  260.                      f" */\nstruct {name}" + " {};\n\n")
  261.         write_something(source, something)
  262.  
  263. i = 1
  264. for source in kernel_structure:
  265.         # Print progress: current/total
  266.         print(f"{i}/{len(kernel_structure)} Writing {source}")
  267.         # Write variables doxygen of the source file
  268.         if len(kernel_structure[source][VARIABLES]) > 0:
  269.                 for variable in kernel_structure[source][VARIABLES]:
  270.                         write_variable(source, variable[0], variable[1], variable[2], variable[3], variable[4])
  271.         if len(kernel_structure[source][PROCEDURES]) > 0:
  272.                 for procedure in kernel_structure[source][PROCEDURES]:
  273.                         write_procedure(source, procedure[0], procedure[1])
  274.         if len(kernel_structure[source][LABELS]) > 0:
  275.                 for label in kernel_structure[source][LABELS]:
  276.                         write_label(source, label[0], label[1])
  277.         if len(kernel_structure[source][MACROS]) > 0:
  278.                 for macro in kernel_structure[source][MACROS]:
  279.                         write_macro(source, macro[0], macro[1])
  280.         if len(kernel_structure[source][STRUCTURES]) > 0:
  281.                 for structure in kernel_structure[source][STRUCTURES]:
  282.                         write_structure(source, structure[0], structure[1])
  283.         i += 1
  284.