Rev 8837 | Rev 8842 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
8834 | Boppan | 1 | import re |
8825 | Boppan | 2 | import os |
8837 | Boppan | 3 | import argparse |
8825 | Boppan | 4 | |
8834 | Boppan | 5 | # Parameters |
8837 | Boppan | 6 | # Path to doxygen folder to make doxygen files in: -o |
8834 | Boppan | 7 | doxygen_src_path = 'docs/doxygen' |
8837 | Boppan | 8 | # Remove generated doxygen files: --clean |
9 | clean_generated_stuff = False |
||
10 | # Dump all defined symbols: --dump |
||
8834 | Boppan | 11 | dump_symbols = False |
8837 | Boppan | 12 | # Print symbol stats: --stats |
8834 | Boppan | 13 | print_stats = False |
8825 | Boppan | 14 | |
8837 | Boppan | 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 | |||
8825 | Boppan | 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 | kernel_structure[asm_file_name] = [ [], [], [], [], [] ] |
||
45 | |||
8841 | Boppan | 46 | variable_pattern = re.compile(r'^\s*([\w\.]+)\s+d([bwdq])\s+([^;]*)\s*([;].*)?') |
8825 | Boppan | 47 | macro_pattern = re.compile(r'^\s*macro\s+([\w]+).*') |
48 | proc_pattern = re.compile(r'^\s*proc\s+([\w\.]+).*') |
||
49 | label_pattern = re.compile(r'^(?!;)\s*([\w\.]+):.*') |
||
50 | struct_pattern = re.compile(r'^\s*struct\s+([\w]+).*') |
||
51 | |||
52 | line_idx = 0 |
||
53 | lines = asm_file_contents.splitlines() |
||
54 | while line_idx < len(lines): |
||
55 | line = lines[line_idx] |
||
56 | |||
57 | match = variable_pattern.findall(line) |
||
58 | if len(match) > 0: |
||
8841 | Boppan | 59 | (var_name, var_type, var_init, var_comm) = match[0] |
60 | if var_comm == "": |
||
61 | var_comm = "Undocumented" |
||
62 | else: |
||
63 | var_comm = var_comm[1:].lstrip() |
||
64 | if (len(var_comm) == 0): |
||
65 | var_comm = "!!! EMPTY_COMMENT" |
||
66 | if var_comm[0].islower(): var_comm = "!!! LOWERCASE COMMENT " + var_comm |
||
67 | if var_type == "b": var_type = "byte" |
||
68 | if var_type == "w": var_type = "word" |
||
69 | if var_type == "d": var_type = "dword" |
||
70 | if var_type == "q": var_type = "qword" |
||
71 | kernel_structure[asm_file_name][VARIABLES].append([ line_idx + 1, var_name, var_type, var_init, var_comm ]) |
||
8825 | Boppan | 72 | line_idx += 1 |
73 | continue |
||
74 | |||
75 | match = macro_pattern.findall(line) |
||
76 | if len(match) > 0: |
||
77 | macro_name = match[0] |
||
78 | kernel_structure[asm_file_name][MACROS].append([ line_idx + 1, macro_name ]) |
||
79 | end_of_macro = False |
||
80 | while not end_of_macro: |
||
81 | line = lines[line_idx] |
||
82 | rbraces = re.finditer('}', line) |
||
83 | for rbrace_match in rbraces: |
||
84 | rbrace_idx = rbrace_match.start() |
||
85 | if line[rbrace_idx - 1] != '\\': |
||
86 | end_of_macro = True |
||
87 | line_idx += 1 |
||
88 | continue |
||
89 | |||
90 | match = proc_pattern.findall(line) |
||
91 | if len(match) > 0: |
||
92 | proc_name = match[0] |
||
93 | kernel_structure[asm_file_name][PROCEDURES].append([ line_idx + 1, proc_name ]) |
||
94 | line_idx += 1 |
||
95 | continue |
||
96 | |||
97 | match = label_pattern.findall(line) |
||
98 | if len(match) > 0: |
||
99 | label_name = match[0] |
||
100 | # Don't count local labels |
||
101 | if label_name[0] != '.': |
||
102 | kernel_structure[asm_file_name][LABELS].append([ line_idx + 1, label_name ]) |
||
103 | line_idx += 1 |
||
104 | continue |
||
105 | |||
106 | match = struct_pattern.findall(line) |
||
107 | if len(match) > 0: |
||
108 | struct_name = match[0] |
||
109 | kernel_structure[asm_file_name][STRUCTURES].append([ line_idx + 1, struct_name ]) |
||
110 | end_of_struct = False |
||
111 | while not end_of_struct: |
||
112 | line = lines[line_idx] |
||
113 | if re.match(r"^ends$", line) != None: |
||
114 | end_of_struct = True |
||
115 | line_idx += 1 |
||
116 | continue |
||
117 | |||
118 | line_idx += 1 |
||
119 | |||
8834 | Boppan | 120 | def handle_file(handled_files, asm_file_name, subdir = "."): |
8841 | Boppan | 121 | if dump_symbols: |
122 | print(f"Handling {asm_file_name}") |
||
8825 | Boppan | 123 | handled_files.append(asm_file_name) |
124 | try: |
||
125 | asm_file_contents = open(asm_file_name, "r", encoding="utf-8").read() |
||
126 | except: |
||
127 | return |
||
128 | get_declarations(asm_file_contents, asm_file_name) |
||
129 | include_directive_pattern_1 = re.compile(r'include "(.*)"') |
||
130 | include_directive_pattern_2 = re.compile(r'include \'(.*)\'') |
||
131 | includes = include_directive_pattern_1.findall(asm_file_contents) |
||
132 | includes += include_directive_pattern_2.findall(asm_file_contents) |
||
133 | for include in includes: |
||
134 | include = include.replace('\\', '/'); |
||
135 | full_path = subdir + '/' + include; |
||
136 | if full_path not in handled_files: |
||
137 | new_subdir = full_path.rsplit('/', 1)[0] |
||
8834 | Boppan | 138 | handle_file(handled_files, full_path, new_subdir) |
8825 | Boppan | 139 | return handled_files |
140 | |||
141 | kernel_files = [] |
||
142 | |||
8834 | Boppan | 143 | handle_file(kernel_files, "./kernel.asm"); |
8825 | Boppan | 144 | |
8834 | Boppan | 145 | if dump_symbols: |
146 | for source in kernel_structure: |
||
147 | print(f"File: {source}") |
||
148 | if len(kernel_structure[source][VARIABLES]) > 0: |
||
149 | print(" Variables:") |
||
150 | for variable in kernel_structure[source][VARIABLES]: |
||
151 | print(f" {variable[0]}: {variable[1]}") |
||
152 | if len(kernel_structure[source][PROCEDURES]) > 0: |
||
153 | print(" Procedures:") |
||
154 | for procedure in kernel_structure[source][PROCEDURES]: |
||
155 | print(f" {procedure[0]}: {procedure[1]}") |
||
156 | if len(kernel_structure[source][LABELS]) > 0: |
||
157 | print(" Global labels:") |
||
158 | for label in kernel_structure[source][LABELS]: |
||
159 | print(f" {label[0]}: {label[1]}") |
||
160 | if len(kernel_structure[source][MACROS]) > 0: |
||
161 | print(" Macroses:") |
||
162 | for macro in kernel_structure[source][MACROS]: |
||
163 | print(f" {macro[0]}: {macro[1]}") |
||
164 | if len(kernel_structure[source][STRUCTURES]) > 0: |
||
165 | print(" Structures:") |
||
166 | for struct in kernel_structure[source][STRUCTURES]: |
||
167 | print(f" {struct[0]}: {struct[1]}") |
||
8825 | Boppan | 168 | |
8834 | Boppan | 169 | if print_stats: |
170 | # Collect stats |
||
171 | var_count = 0 |
||
172 | proc_count = 0 |
||
173 | label_count = 0 |
||
174 | macro_count = 0 |
||
175 | struct_count = 0 |
||
8825 | Boppan | 176 | |
8834 | Boppan | 177 | for source in kernel_structure: |
178 | var_count += len(kernel_structure[source][VARIABLES]) |
||
179 | proc_count += len(kernel_structure[source][PROCEDURES]) |
||
180 | label_count += len(kernel_structure[source][LABELS]) |
||
181 | macro_count += len(kernel_structure[source][MACROS]) |
||
182 | struct_count += len(kernel_structure[source][STRUCTURES]) |
||
8825 | Boppan | 183 | |
8841 | Boppan | 184 | print(f"File count: {len(kernel_structure)}") |
8834 | Boppan | 185 | print(f"Variable count: {var_count}") |
186 | print(f"Procedures count: {proc_count}") |
||
187 | print(f"Global labels count: {label_count}") |
||
188 | print(f"Macroses count: {macro_count}") |
||
189 | print(f"Structures count: {struct_count}") |
||
8825 | Boppan | 190 | |
8834 | Boppan | 191 | print(f"Writing doumented sources to {doxygen_src_path}") |
192 | |||
193 | created_files = [] |
||
194 | |||
8841 | Boppan | 195 | def write_variable(source, line, name, type, init, brief): |
8834 | Boppan | 196 | source = source.replace("./", "") |
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 | name = name.replace(".", "_") |
||
208 | f = open(full_path, "a") |
||
209 | f.write(f"/**\n") |
||
210 | f.write(f" * @brief {brief}\n") |
||
211 | f.write(f" * @par Initial value\n") |
||
212 | f.write(f" * {init}\n") |
||
213 | f.write(f" * @par Source\n") |
||
214 | f.write(f" * {source}:{line}\n") |
||
215 | f.write(f" */\n") |
||
8841 | Boppan | 216 | f.write(f"{type} {name};\n\n") |
8834 | Boppan | 217 | f.close() |
218 | |||
219 | i = 1 |
||
220 | for source in kernel_structure: |
||
221 | # Print progress: current/total |
||
222 | print(f"{i}/{len(kernel_structure)} Writing {source}") |
||
223 | # Write variables doxygen of the source file |
||
224 | if len(kernel_structure[source][VARIABLES]) > 0: |
||
225 | for variable in kernel_structure[source][VARIABLES]: |
||
8841 | Boppan | 226 | write_variable(source, variable[0], variable[1], variable[2], variable[3], variable[4]) |
8834 | Boppan | 227 | i += 1> |