Rev 8844 | Rev 8855 | 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): |
||
8842 | Boppan | 44 | asm_file_name = asm_file_name.replace("./", "") |
8825 | Boppan | 45 | kernel_structure[asm_file_name] = [ [], [], [], [], [] ] |
46 | |||
8841 | Boppan | 47 | variable_pattern = re.compile(r'^\s*([\w\.]+)\s+d([bwdq])\s+([^;]*)\s*([;].*)?') |
8825 | Boppan | 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: |
||
8841 | Boppan | 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 ]) |
||
8825 | Boppan | 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 | |||
8834 | Boppan | 121 | def handle_file(handled_files, asm_file_name, subdir = "."): |
8841 | Boppan | 122 | if dump_symbols: |
123 | print(f"Handling {asm_file_name}") |
||
8825 | Boppan | 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] |
||
8834 | Boppan | 139 | handle_file(handled_files, full_path, new_subdir) |
8825 | Boppan | 140 | return handled_files |
141 | |||
142 | kernel_files = [] |
||
143 | |||
8834 | Boppan | 144 | handle_file(kernel_files, "./kernel.asm"); |
8825 | Boppan | 145 | |
8834 | Boppan | 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]}") |
||
8825 | Boppan | 169 | |
8834 | Boppan | 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 |
||
8825 | Boppan | 177 | |
8834 | Boppan | 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]) |
||
8825 | Boppan | 184 | |
8841 | Boppan | 185 | print(f"File count: {len(kernel_structure)}") |
8834 | Boppan | 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}") |
||
8825 | Boppan | 191 | |
8834 | Boppan | 192 | print(f"Writing doumented sources to {doxygen_src_path}") |
193 | |||
194 | created_files = [] |
||
195 | |||
8842 | Boppan | 196 | def write_something(source, somehing): |
8834 | Boppan | 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") |
||
8842 | Boppan | 208 | f.write(somehing) |
8834 | Boppan | 209 | f.close() |
210 | |||
8842 | Boppan | 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" * {source}:{line}\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" * {source}:{line}\n" + |
||
229 | f" */\n" + |
||
230 | f"void {name}();\n\n") |
||
231 | write_something(source, something) |
||
232 | |||
8844 | Boppan | 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" * {source}:{line}\n" + |
||
239 | f" */\n" + |
||
240 | f"void {name}();\n\n") |
||
241 | write_something(source, something) |
||
242 | |||
8846 | Boppan | 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" * {source}:{line}\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" * {source}:{line}\n" + |
||
260 | f" */\nstruct {name}" + " {};\n\n") |
||
261 | write_something(source, something) |
||
262 | |||
8834 | Boppan | 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]: |
||
8841 | Boppan | 270 | write_variable(source, variable[0], variable[1], variable[2], variable[3], variable[4]) |
8842 | Boppan | 271 | if len(kernel_structure[source][PROCEDURES]) > 0: |
272 | for procedure in kernel_structure[source][PROCEDURES]: |
||
273 | write_procedure(source, procedure[0], procedure[1]) |
||
8844 | Boppan | 274 | if len(kernel_structure[source][LABELS]) > 0: |
275 | for label in kernel_structure[source][LABELS]: |
||
276 | write_label(source, label[0], label[1]) |
||
8846 | Boppan | 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]) |
||
8834 | Boppan | 283 | i += 1> |