Rev 8846 | Rev 8856 | 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 |
8855 | Boppan | 14 | # Do not write warnings file: --nowarn |
15 | enable_warnings = True |
||
8825 | Boppan | 16 | |
8837 | Boppan | 17 | # Constants |
18 | link_root = "http://websvn.kolibrios.org/filedetails.php?repname=Kolibri+OS&path=/kernel/trunk" |
||
19 | |||
8855 | Boppan | 20 | # Warning list |
21 | warnings = "" |
||
22 | |||
8837 | Boppan | 23 | # Parse arguments |
24 | parser = argparse.ArgumentParser() |
||
25 | parser.add_argument("-o", help="Doxygen output folder") |
||
26 | parser.add_argument("--clean", help="Remove generated files", action="store_true") |
||
27 | parser.add_argument("--dump", help="Dump all defined symbols", action="store_true") |
||
28 | parser.add_argument("--stats", help="Print symbol stats", action="store_true") |
||
8855 | Boppan | 29 | parser.add_argument("--nowarn", help="Do not write warnings file", action="store_true") |
8837 | Boppan | 30 | args = parser.parse_args() |
31 | doxygen_src_path = args.o if args.o else 'docs/doxygen' |
||
32 | clean_generated_stuff = args.clean |
||
33 | dump_symbols = args.dump |
||
34 | print_stats = args.stats |
||
8855 | Boppan | 35 | enable_warnings = not args.nowarn |
8837 | Boppan | 36 | |
8825 | Boppan | 37 | # kernel_structure["filename"] = { |
38 | # [ [], # [0] Variables - [ line, name ] |
||
39 | # [], # [1] Macros - [ line, name ] |
||
40 | # [], # [2] Procedures - [ line, name ] |
||
41 | # [], # [3] Labels - [ line, name ] |
||
42 | # [] ] } # [4] Structures - [ line, name ] |
||
43 | VARIABLES = 0 |
||
44 | MACROS = 1 |
||
45 | PROCEDURES = 2 |
||
46 | LABELS = 3 |
||
47 | STRUCTURES = 4 |
||
48 | kernel_structure = {} |
||
49 | |||
8855 | Boppan | 50 | class AsmVariable: |
51 | def __init__(self, line, name, type, init, comment, line_span): |
||
52 | self.line = line |
||
53 | self.name = name |
||
54 | self.type = type |
||
55 | self.init = init |
||
56 | self.comment = comment # Comment after the definition (a dd 0 ; Comment) |
||
57 | self.line_span = line_span # How much .asm lines its definition takes |
||
58 | |||
59 | class AsmFunction: |
||
60 | def __init__(self, line, name): |
||
61 | self.line = line |
||
62 | self.name = name |
||
63 | |||
64 | class AsmLabel: |
||
65 | def __init__(self, line, name): |
||
66 | self.line = line |
||
67 | self.name = name |
||
68 | |||
69 | class AsmMacro: |
||
70 | def __init__(self, line, name, comment, args): |
||
71 | self.line = line |
||
72 | self.name = name |
||
73 | self.comment = comment |
||
74 | self.args = args |
||
75 | |||
76 | class AsmStruct: |
||
77 | def __init__(self, line, name): |
||
78 | self.line = line |
||
79 | self.name = name |
||
80 | |||
81 | def parse_variable(asm_file_name, lines, line_idx): |
||
82 | global warnings |
||
83 | |||
84 | def curr(): |
||
85 | try: return line[i] |
||
86 | except: return '' |
||
87 | |||
88 | # Returns current and then increments current index |
||
89 | def step(): |
||
90 | nonlocal i |
||
91 | c = curr() |
||
92 | i += 1 |
||
93 | return c |
||
94 | |||
95 | line = lines[line_idx] |
||
96 | i = 0 |
||
97 | # Skip first spaces |
||
98 | while curr().isspace(): step() |
||
99 | # Get name |
||
100 | name = "" |
||
101 | while curr().isalnum() or curr() == '_' or curr() == '.': name += step() |
||
102 | # Skip spaces after variable name |
||
103 | while curr().isspace(): step() |
||
104 | # Get type specifier (db, dd, etc.) |
||
105 | type = "" |
||
106 | while curr().isalnum() or curr() == '_': type += step() |
||
107 | # Skip spaces after type specifier |
||
108 | while curr().isspace(): step() |
||
109 | # Get initial value (everything up to end of the line or comment) |
||
110 | init = "" |
||
111 | while curr() and curr() != ';': init += step() |
||
112 | # Get comment |
||
113 | comment = "" |
||
114 | if curr() == ';': |
||
115 | step() # Skip ';' |
||
116 | while curr(): comment += step() |
||
117 | # Process type |
||
118 | if type == "db": type = "byte" |
||
119 | elif type == "dw": type = "word" |
||
120 | elif type == "dd": type = "dword" |
||
121 | elif type == "dq": type = "qword" |
||
122 | else: raise Exception(f"Unexpected type: '{type}' (i = {i})") |
||
123 | # Process comment |
||
124 | if comment == "": comment = "Undocumented" |
||
125 | else: |
||
126 | comment = comment.lstrip() |
||
127 | if (len(comment) == 0): |
||
128 | comment = "!!! EMPTY_COMMENT" |
||
129 | warnings += f"{asm_file_name}:{line_idx + 1}: Empty comment in\n" |
||
130 | if comment[0].islower(): |
||
131 | warnings += f"{asm_file_name}:{line_idx + 1}: Сomment sarting with lowercase\n" |
||
132 | # Build the result |
||
133 | result = AsmVariable(line_idx + 1, name, type, init, comment, 1) |
||
134 | return (1, result) |
||
135 | |||
136 | def is_id(c): |
||
137 | return c.isprintable() and c not in "+-/*=<>()[]{}:,|&~#`'\" \n\r\t\v" |
||
138 | |||
139 | def get_comment_begin(line): |
||
140 | result = len(line) |
||
141 | in_str = False |
||
142 | for i in range(len(line)): |
||
143 | if in_str: |
||
144 | if line[i] == in_str: in_str = False |
||
145 | i += 1 |
||
146 | elif line[i] == '\'' or line[i] == '\"': |
||
147 | in_str = line[i] |
||
148 | i += 1 |
||
149 | elif line[i] == ';': |
||
150 | result = i |
||
151 | break |
||
152 | else: |
||
153 | i += 1 |
||
154 | return result |
||
155 | |||
156 | def get_comment(line): |
||
157 | return line[get_comment_begin(line):] |
||
158 | |||
159 | def remove_comment(line): |
||
160 | return line[0:get_comment_begin(line)] |
||
161 | |||
162 | def insert_comment(line, comment): |
||
163 | comment_begin = get_comment_begin(line) |
||
164 | line_left = line[:get_comment_begin(line)] |
||
165 | line_right = line[get_comment_begin(line):] |
||
166 | return line_left + comment + line_right |
||
167 | |||
168 | def has_line_wrap(line): |
||
169 | if remove_comment(line).rstrip()[-1] == '\\': |
||
170 | return True |
||
171 | return False |
||
172 | |||
173 | def remove_line_wrap(line): |
||
174 | if remove_comment(line).rstrip()[-1] == '\\': |
||
175 | return remove_comment(line).rstrip()[:-1] |
||
176 | return line |
||
177 | |||
178 | def parse_macro(asm_file_name, lines, line_idx): |
||
179 | line_idx_orig = line_idx |
||
180 | global warnings |
||
181 | |||
182 | def curr(): |
||
183 | try: return line[i] |
||
184 | except: return '' |
||
185 | |||
186 | # Returns current and then increments current index |
||
187 | def step(): |
||
188 | nonlocal i |
||
189 | c = curr() |
||
190 | i += 1 |
||
191 | return c |
||
192 | |||
193 | line = lines[line_idx] |
||
194 | # Handle line wraps ('\' at the end) |
||
195 | while has_line_wrap(line): |
||
196 | next_line = lines[line_idx + 1] |
||
197 | prev_line_comment = get_comment(line) |
||
198 | line = remove_line_wrap(line) + insert_comment(next_line, prev_line_comment) |
||
199 | line_idx += 1 |
||
200 | |||
201 | i = 0 |
||
202 | # Skip first spaces |
||
203 | while curr().isspace(): step() |
||
204 | # Read "macro" keyword |
||
205 | keyword = "" |
||
206 | while is_id(curr()): keyword += step() |
||
207 | if keyword != "macro": raise Exception(f"Not a macro: {line}") |
||
208 | # Skip spaces after "macro" |
||
209 | while curr().isspace(): step() |
||
210 | # Read macro name |
||
211 | name = "" |
||
212 | while curr() and not curr().isspace(): name += step() |
||
213 | # Skip spaces after macro name |
||
214 | while curr().isspace(): step() |
||
215 | # Find all arguments |
||
216 | args = [] |
||
217 | arg = '' |
||
218 | while curr() and curr() != ';' and curr() != '{': |
||
219 | # Collect identifier |
||
220 | if is_id(curr()): |
||
221 | arg += step() |
||
222 | # Save the collected identifier |
||
223 | elif curr() == ',': |
||
224 | args.append(arg) |
||
225 | arg = '' |
||
226 | step() |
||
227 | # Just push the '[' |
||
228 | elif curr() == '[': |
||
229 | args.append(step()) |
||
230 | # Just push the identifier and get ']' ready to be pushed on next comma |
||
231 | elif curr() == ']': |
||
232 | args.append(arg) |
||
233 | arg = step() |
||
234 | # Just push the identifier and get '*' ready to be pushed on next comma |
||
235 | elif curr() == '*': |
||
236 | args.append(arg) |
||
237 | arg = step() |
||
238 | # Just skip whitespaces |
||
239 | elif curr().isspace(): |
||
240 | step() |
||
241 | # Something unexpected |
||
242 | else: |
||
243 | raise Exception(f"Unexpected symbol '{curr()}' at index #{i} " + |
||
244 | f"in the macro declaration:\n'{line}'") |
||
245 | if arg != '': |
||
246 | args.append(arg) |
||
247 | if len(args) > 0: |
||
248 | print(line, args) |
||
249 | # Find a comment if any |
||
250 | comment = "" |
||
251 | while curr() and curr() != ';': step() |
||
252 | if curr() == ';': |
||
253 | step() |
||
254 | while curr(): comment += step() |
||
255 | # Find end of the macro |
||
256 | end_of_macro = False |
||
257 | while not end_of_macro: |
||
258 | line = lines[line_idx] |
||
259 | rbraces = re.finditer('}', line) |
||
260 | for rbrace_match in rbraces: |
||
261 | rbrace_idx = rbrace_match.start() |
||
262 | if line[rbrace_idx - 1] != '\\': |
||
263 | end_of_macro = True |
||
264 | line_idx += 1 |
||
265 | # Process comment |
||
266 | if comment != "": |
||
267 | comment = comment.lstrip() |
||
268 | if (len(comment) == 0): |
||
269 | comment = "!!! EMPTY_COMMENT" |
||
270 | warnings += f"{asm_file_name}:{line_idx + 1}: Empty comment in\n" |
||
271 | if comment[0].islower(): |
||
272 | warnings += f"{asm_file_name}:{line_idx + 1}: Сomment sarting with lowercase\n" |
||
273 | # Build the output |
||
274 | line_span = line_idx - line_idx_orig + 1 |
||
275 | result = AsmMacro(line_idx_orig, name, comment, args) |
||
276 | return (line_span, result) |
||
277 | |||
8825 | Boppan | 278 | def get_declarations(asm_file_contents, asm_file_name): |
8842 | Boppan | 279 | asm_file_name = asm_file_name.replace("./", "") |
8825 | Boppan | 280 | kernel_structure[asm_file_name] = [ [], [], [], [], [] ] |
281 | |||
8855 | Boppan | 282 | variable_pattern = re.compile(r'^\s*[\w\.]+\s+d[bwdq]\s+.*') |
8825 | Boppan | 283 | macro_pattern = re.compile(r'^\s*macro\s+([\w]+).*') |
284 | proc_pattern = re.compile(r'^\s*proc\s+([\w\.]+).*') |
||
285 | label_pattern = re.compile(r'^(?!;)\s*([\w\.]+):.*') |
||
286 | struct_pattern = re.compile(r'^\s*struct\s+([\w]+).*') |
||
287 | |||
288 | line_idx = 0 |
||
289 | lines = asm_file_contents.splitlines() |
||
290 | while line_idx < len(lines): |
||
291 | line = lines[line_idx] |
||
292 | |||
8855 | Boppan | 293 | if variable_pattern.match(line): |
294 | (skip_lines, var) = parse_variable(asm_file_name, lines, line_idx) |
||
295 | kernel_structure[asm_file_name][VARIABLES].append(var) |
||
296 | line_idx += skip_lines |
||
8825 | Boppan | 297 | continue |
298 | |||
299 | match = macro_pattern.findall(line) |
||
300 | if len(match) > 0: |
||
8855 | Boppan | 301 | (skip_lines, macro) = parse_macro(asm_file_name, lines, line_idx) |
302 | kernel_structure[asm_file_name][MACROS].append(macro) |
||
303 | line_idx += skip_lines |
||
8825 | Boppan | 304 | continue |
305 | |||
306 | match = proc_pattern.findall(line) |
||
307 | if len(match) > 0: |
||
308 | proc_name = match[0] |
||
8855 | Boppan | 309 | kernel_structure[asm_file_name][PROCEDURES].append(AsmFunction(line_idx + 1, proc_name)) |
8825 | Boppan | 310 | line_idx += 1 |
311 | continue |
||
312 | |||
313 | match = label_pattern.findall(line) |
||
314 | if len(match) > 0: |
||
315 | label_name = match[0] |
||
316 | # Don't count local labels |
||
317 | if label_name[0] != '.': |
||
8855 | Boppan | 318 | kernel_structure[asm_file_name][LABELS].append(AsmLabel(line_idx + 1, label_name)) |
8825 | Boppan | 319 | line_idx += 1 |
320 | continue |
||
321 | |||
322 | match = struct_pattern.findall(line) |
||
323 | if len(match) > 0: |
||
324 | struct_name = match[0] |
||
8855 | Boppan | 325 | kernel_structure[asm_file_name][STRUCTURES].append(AsmStruct(line_idx + 1, struct_name)) |
8825 | Boppan | 326 | end_of_struct = False |
327 | while not end_of_struct: |
||
328 | line = lines[line_idx] |
||
329 | if re.match(r"^ends$", line) != None: |
||
330 | end_of_struct = True |
||
331 | line_idx += 1 |
||
332 | continue |
||
333 | |||
334 | line_idx += 1 |
||
335 | |||
8834 | Boppan | 336 | def handle_file(handled_files, asm_file_name, subdir = "."): |
8841 | Boppan | 337 | if dump_symbols: |
338 | print(f"Handling {asm_file_name}") |
||
8825 | Boppan | 339 | handled_files.append(asm_file_name) |
340 | try: |
||
341 | asm_file_contents = open(asm_file_name, "r", encoding="utf-8").read() |
||
342 | except: |
||
343 | return |
||
344 | get_declarations(asm_file_contents, asm_file_name) |
||
345 | include_directive_pattern_1 = re.compile(r'include "(.*)"') |
||
346 | include_directive_pattern_2 = re.compile(r'include \'(.*)\'') |
||
347 | includes = include_directive_pattern_1.findall(asm_file_contents) |
||
348 | includes += include_directive_pattern_2.findall(asm_file_contents) |
||
349 | for include in includes: |
||
350 | include = include.replace('\\', '/'); |
||
351 | full_path = subdir + '/' + include; |
||
352 | if full_path not in handled_files: |
||
353 | new_subdir = full_path.rsplit('/', 1)[0] |
||
8834 | Boppan | 354 | handle_file(handled_files, full_path, new_subdir) |
8825 | Boppan | 355 | return handled_files |
356 | |||
357 | kernel_files = [] |
||
358 | |||
8834 | Boppan | 359 | handle_file(kernel_files, "./kernel.asm"); |
8825 | Boppan | 360 | |
8834 | Boppan | 361 | if dump_symbols: |
362 | for source in kernel_structure: |
||
363 | print(f"File: {source}") |
||
364 | if len(kernel_structure[source][VARIABLES]) > 0: |
||
365 | print(" Variables:") |
||
366 | for variable in kernel_structure[source][VARIABLES]: |
||
8855 | Boppan | 367 | print(f" {variable.line}: {variable.name}") |
8834 | Boppan | 368 | if len(kernel_structure[source][PROCEDURES]) > 0: |
369 | print(" Procedures:") |
||
370 | for procedure in kernel_structure[source][PROCEDURES]: |
||
8855 | Boppan | 371 | print(f" {procedure.line}: {procedure.name}") |
8834 | Boppan | 372 | if len(kernel_structure[source][LABELS]) > 0: |
373 | print(" Global labels:") |
||
374 | for label in kernel_structure[source][LABELS]: |
||
8855 | Boppan | 375 | print(f" {label.line}: {label.name}") |
8834 | Boppan | 376 | if len(kernel_structure[source][MACROS]) > 0: |
377 | print(" Macroses:") |
||
378 | for macro in kernel_structure[source][MACROS]: |
||
8855 | Boppan | 379 | print(f" {macro.line}: {macro.name}") |
8834 | Boppan | 380 | if len(kernel_structure[source][STRUCTURES]) > 0: |
381 | print(" Structures:") |
||
382 | for struct in kernel_structure[source][STRUCTURES]: |
||
8855 | Boppan | 383 | print(f" {struct.line}: {struct.name}") |
8825 | Boppan | 384 | |
8834 | Boppan | 385 | if print_stats: |
386 | # Collect stats |
||
387 | var_count = 0 |
||
388 | proc_count = 0 |
||
389 | label_count = 0 |
||
390 | macro_count = 0 |
||
391 | struct_count = 0 |
||
8825 | Boppan | 392 | |
8834 | Boppan | 393 | for source in kernel_structure: |
394 | var_count += len(kernel_structure[source][VARIABLES]) |
||
395 | proc_count += len(kernel_structure[source][PROCEDURES]) |
||
396 | label_count += len(kernel_structure[source][LABELS]) |
||
397 | macro_count += len(kernel_structure[source][MACROS]) |
||
398 | struct_count += len(kernel_structure[source][STRUCTURES]) |
||
8825 | Boppan | 399 | |
8841 | Boppan | 400 | print(f"File count: {len(kernel_structure)}") |
8834 | Boppan | 401 | print(f"Variable count: {var_count}") |
402 | print(f"Procedures count: {proc_count}") |
||
403 | print(f"Global labels count: {label_count}") |
||
404 | print(f"Macroses count: {macro_count}") |
||
405 | print(f"Structures count: {struct_count}") |
||
8825 | Boppan | 406 | |
8834 | Boppan | 407 | print(f"Writing doumented sources to {doxygen_src_path}") |
408 | |||
409 | created_files = [] |
||
410 | |||
8842 | Boppan | 411 | def write_something(source, somehing): |
8834 | Boppan | 412 | full_path = doxygen_src_path + '/' + source |
413 | # Remove the file on first access if it was created by previous generation |
||
414 | if full_path not in created_files: |
||
415 | if os.path.isfile(full_path): |
||
416 | os.remove(full_path) |
||
417 | created_files.append(full_path) |
||
418 | # Only remove the file on 'clean_generated_stuff' flag (removed above, just return) |
||
419 | if clean_generated_stuff: return |
||
420 | # Create directories need for the file |
||
421 | os.makedirs(os.path.dirname(full_path), exist_ok=True) |
||
422 | f = open(full_path, "a") |
||
8842 | Boppan | 423 | f.write(somehing) |
8834 | Boppan | 424 | f.close() |
425 | |||
8855 | Boppan | 426 | def write_variable(source, variable): |
427 | line = variable.line |
||
428 | type = variable.type |
||
429 | init = variable.init |
||
430 | brief = variable.comment |
||
431 | name = variable.name.replace(".", "_") |
||
8842 | Boppan | 432 | something = (f"/**\n" + |
433 | f" * @brief {brief}\n" + |
||
434 | f" * @par Initial value\n" + |
||
435 | f" * {init}\n" + |
||
436 | f" * @par Source\n" + |
||
437 | f" * {source}:{line}\n" + |
||
438 | f" */\n" + |
||
439 | f"{type} {name};\n\n") |
||
440 | write_something(source, something) |
||
441 | |||
442 | def write_procedure(source, line, name, brief = "Undocumented"): |
||
443 | name = name.replace(".", "_") |
||
444 | something = (f"/**\n" + |
||
445 | f" * @brief {brief}\n" + |
||
446 | f" * @par Source\n" + |
||
447 | f" * {source}:{line}\n" + |
||
448 | f" */\n" + |
||
449 | f"void {name}();\n\n") |
||
450 | write_something(source, something) |
||
451 | |||
8844 | Boppan | 452 | def write_label(source, line, name, brief = "Undocumented"): |
453 | name = name.replace(".", "_") |
||
454 | something = (f"/**\n" + |
||
455 | f" * @brief {brief}\n" + |
||
456 | f" * @par Source\n" + |
||
457 | f" * {source}:{line}\n" + |
||
458 | f" */\n" + |
||
459 | f"void {name}();\n\n") |
||
460 | write_something(source, something) |
||
461 | |||
8855 | Boppan | 462 | def write_macro(source, macro): |
463 | if macro.comment == "": brief = "Undocumented" |
||
464 | else: brief = macro.comment |
||
465 | line = macro.line |
||
466 | name = macro.name.replace(".", "_").replace("@", "_") |
||
467 | # Construct arg list without '['s, ']'s and '*'s |
||
468 | args = [arg for arg in macro.args if arg not in "[]*"] |
||
469 | # Construct C-like arg list |
||
470 | arg_list = "" |
||
471 | if len(args) > 0: |
||
472 | arg_list += '(' |
||
473 | argc = 0 |
||
474 | for arg in args: |
||
475 | if argc != 0: |
||
476 | arg_list += ", " |
||
477 | arg_list += arg |
||
478 | argc += 1 |
||
479 | arg_list += ')' |
||
480 | |||
8846 | Boppan | 481 | something = (f"/**\n" + |
482 | f" * @def {name}\n" + |
||
483 | f" * @brief {brief}\n" + |
||
484 | f" * @par Source\n" + |
||
485 | f" * {source}:{line}\n" + |
||
8855 | Boppan | 486 | f" */\n#define {name}{arg_list}\n\n") |
8846 | Boppan | 487 | write_something(source, something) |
488 | |||
489 | def write_structure(source, line, name, brief = "Undocumented"): |
||
490 | name = name.replace(".", "_") |
||
491 | something = (f"/**\n" + |
||
492 | f" * @struct {name}\n" + |
||
493 | f" * @brief {brief}\n" + |
||
494 | f" * @par Source\n" + |
||
495 | f" * {source}:{line}\n" + |
||
496 | f" */\nstruct {name}" + " {};\n\n") |
||
497 | write_something(source, something) |
||
498 | |||
8834 | Boppan | 499 | i = 1 |
500 | for source in kernel_structure: |
||
501 | # Print progress: current/total |
||
502 | print(f"{i}/{len(kernel_structure)} Writing {source}") |
||
503 | # Write variables doxygen of the source file |
||
504 | if len(kernel_structure[source][VARIABLES]) > 0: |
||
505 | for variable in kernel_structure[source][VARIABLES]: |
||
8855 | Boppan | 506 | write_variable(source, variable) |
8842 | Boppan | 507 | if len(kernel_structure[source][PROCEDURES]) > 0: |
508 | for procedure in kernel_structure[source][PROCEDURES]: |
||
8855 | Boppan | 509 | write_procedure(source, procedure.line, procedure.name) |
8844 | Boppan | 510 | if len(kernel_structure[source][LABELS]) > 0: |
511 | for label in kernel_structure[source][LABELS]: |
||
8855 | Boppan | 512 | write_label(source, label.line, label.name) |
8846 | Boppan | 513 | if len(kernel_structure[source][MACROS]) > 0: |
514 | for macro in kernel_structure[source][MACROS]: |
||
8855 | Boppan | 515 | write_macro(source, macro) |
8846 | Boppan | 516 | if len(kernel_structure[source][STRUCTURES]) > 0: |
517 | for structure in kernel_structure[source][STRUCTURES]: |
||
8855 | Boppan | 518 | write_structure(source, structure.line, structure.name) |
8834 | Boppan | 519 | i += 1 |
8855 | Boppan | 520 | |
521 | if enable_warnings: |
||
522 | open('asmxygen.txt', "w", encoding = "utf-8").write(warnings)>> |