Rev 9407 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 9407 | Rev 9408 | ||||
---|---|---|---|---|---|
Line 164... | Line 164... | ||||
164 | "dq", "rq", |
164 | "dq", "rq", |
||
165 | "dt", "rt", |
165 | "dt", "rt", |
||
166 | "du", |
166 | "du", |
||
167 | ] |
167 | ] |
||
Line -... | Line 168... | ||||
- | 168 | ||||
168 | 169 | ||||
169 | # Add kind flag to identifier in id2kind |
170 | # Add kind flag to identifier in id2kind |
||
170 | def id_add_kind(identifier, kind): |
171 | def id_add_kind(identifier, kind): |
||
171 | if identifier not in id2kind: |
172 | if identifier not in id2kind: |
||
172 | id2kind[identifier] = '' |
173 | id2kind[identifier] = '' |
||
Line -... | Line 174... | ||||
- | 174 | id2kind[identifier] += kind |
|||
173 | id2kind[identifier] += kind |
175 | |||
174 | 176 | ||||
175 | # Remove kind flag of identifier in id2kind |
177 | # Remove kind flag of identifier in id2kind |
||
176 | def id_remove_kind(identifier, kind): |
178 | def id_remove_kind(identifier, kind): |
||
177 | if identifier in id2kind: |
179 | if identifier in id2kind: |
||
Line -... | Line 180... | ||||
- | 180 | if kind in id2kind[identifier]: |
|||
178 | if kind in id2kind[identifier]: |
181 | id2kind[identifier] = id2kind[identifier].replace(kind, '') |
||
179 | id2kind[identifier] = id2kind[identifier].replace(kind, '') |
182 | |||
180 | 183 | ||||
181 | # Get kind of an identifier |
184 | # Get kind of an identifier |
||
182 | def id_get_kind(identifier): |
185 | def id_get_kind(identifier): |
||
183 | if identifier in id2kind: |
186 | if identifier in id2kind: |
||
Line -... | Line 187... | ||||
- | 187 | return id2kind[identifier] |
|||
184 | return id2kind[identifier] |
188 | else: |
||
185 | else: |
189 | return '' |
||
186 | return '' |
190 | |||
187 | 191 | ||||
188 | class LegacyAsmReader: |
192 | class LegacyAsmReader: |
||
Line 194... | Line 198... | ||||
194 | 198 | ||||
195 | def currline(self): |
199 | def currline(self): |
||
Line 196... | Line 200... | ||||
196 | return self.lines[self.line_idx] |
200 | return self.lines[self.line_idx] |
||
- | 201 | ||||
197 | 202 | def curr(self): |
|||
- | 203 | try: |
|||
198 | def curr(self): |
204 | return self.lines[self.line_idx][self.i] |
||
Line 199... | Line 205... | ||||
199 | try: return self.lines[self.line_idx][self.i] |
205 | except: |
||
200 | except: return '' |
206 | return '' |
||
201 | 207 | ||||
202 | def step(self): |
208 | def step(self): |
||
Line 235... | Line 241... | ||||
235 | 241 | ||||
236 | def skip_spaces(self): |
242 | def skip_spaces(self): |
||
237 | while self.curr().isspace(): |
243 | while self.curr().isspace(): |
||
Line -... | Line 244... | ||||
- | 244 | self.step() |
|||
238 | self.step() |
245 | |||
239 | 246 | ||||
240 | class AsmReaderRecognizingStrings(LegacyAsmReader): |
247 | class AsmReaderRecognizingStrings(LegacyAsmReader): |
||
241 | def __init__(self, file): |
248 | def __init__(self, file): |
||
242 | super().__init__(file) |
249 | super().__init__(file) |
||
Line 243... | Line 250... | ||||
243 | self.in_string = None |
250 | self.in_string = None |
||
244 | self.should_recognize_strings = True |
251 | self.should_recognize_strings = True |
||
245 | 252 | ||||
246 | def step(self): |
253 | def step(self): |
||
247 | c = super().step() |
254 | c = super().step() |
||
248 | if self.should_recognize_strings and (c == '"' or c == "'"): |
255 | if self.should_recognize_strings and (c == '"' or c == "'"): |
||
249 | # If just now we was at the double or single quotation mark |
256 | # If just now we was at the double or single quotation mark |
||
250 | # and we aren't in a string yet |
257 | # and we aren't in a string yet then say |
||
251 | # then say "we are in a string openned with this quotation mark now" |
258 | # "we are in a string openned with this quotation mark now" |
||
252 | if self.in_string == None: |
259 | if self.in_string is None: |
||
253 | self.in_string = c |
260 | self.in_string = c |
||
254 | # If just now we was at the double or single quotation mark |
261 | # If just now we was at the double or single quotation mark |
||
255 | # and we are in the string entered with the same quotation mark |
262 | # and we are in the string entered with the same quotation mark |
||
256 | # then say "we aren't in a string anymore" |
263 | # then say "we aren't in a string anymore" |
||
Line -... | Line 264... | ||||
- | 264 | elif self.in_string == c: |
|||
257 | elif self.in_string == c: |
265 | self.in_string = None |
||
258 | self.in_string = None |
266 | return c |
||
259 | return c |
267 | |||
260 | 268 | ||||
261 | class AsmReaderReadingComments(AsmReaderRecognizingStrings): |
269 | class AsmReaderReadingComments(AsmReaderRecognizingStrings): |
||
Line 280... | Line 288... | ||||
280 | 288 | ||||
281 | def status_set_has_code(self): |
289 | def status_set_has_code(self): |
||
Line 282... | Line 290... | ||||
282 | self.status_has_code = True |
290 | self.status_has_code = True |
||
283 | 291 | ||||
- | 292 | def update_status(self): |
|||
284 | def update_status(self): |
293 | # If we aren't in a comment and we aren't in a string - |
||
- | 294 | # say we are now in a comment if ';' met |
|||
- | 295 | if (not self.status_has_comment and |
|||
285 | # If we aren't in a comment and we aren't in a string - say we are now in a comment if ';' met |
296 | not self.in_string and |
||
286 | if not self.status_has_comment and not self.in_string and self.curr() == ';': |
297 | self.curr() == ';'): |
||
287 | self.status_set_has_comment() |
298 | self.status_set_has_comment() |
||
288 | # Else if we are in a comment - collect the comment |
299 | # Else if we are in a comment - collect the comment |
||
289 | elif self.status_has_comment: |
300 | elif self.status_has_comment: |
||
Line 303... | Line 314... | ||||
303 | def nextline(self): |
314 | def nextline(self): |
||
304 | prev_line = self.currline() |
315 | prev_line = self.currline() |
||
305 | super().nextline() |
316 | super().nextline() |
||
306 | # If the line we leave was not a comment-only line |
317 | # If the line we leave was not a comment-only line |
||
307 | # then forget the collected comment |
318 | # then forget the collected comment |
||
308 | # Otherwise the collected comment should be complemented by comment from next line in step() |
319 | # Otherwise the collected comment should be complemented by |
||
- | 320 | # comment from next line in step() |
|||
309 | if self.status_has_code: |
321 | if self.status_has_code: |
||
310 | # But we should preserve comment for the next line |
322 | # But we should preserve comment for the next line |
||
311 | # If previous line set align (cause many functions re documented |
323 | # If previous line set align (cause many functions re documented |
||
312 | # right before align set, not before their labels) |
324 | # right before align set, not before their labels) |
||
313 | if not prev_line.startswith("align "): |
325 | if not prev_line.startswith("align "): |
||
314 | self.comment = '' |
326 | self.comment = '' |
||
315 | # Reset the line status (now it's the status of the new line) |
327 | # Reset the line status (now it's the status of the new line) |
||
316 | self.status_reset() |
328 | self.status_reset() |
||
317 | # Set new status for this line according to the first character in the line |
329 | # Set new status for this line according to the |
||
- | 330 | # first character in the line |
|||
318 | self.update_status() |
331 | self.update_status() |
||
Line -... | Line 332... | ||||
- | 332 | ||||
319 | 333 | ||||
320 | class AsmReaderFetchingIdentifiers(AsmReaderReadingComments): |
334 | class AsmReaderFetchingIdentifiers(AsmReaderReadingComments): |
||
321 | def __init__(self, file): |
335 | def __init__(self, file): |
||
Line 322... | Line 336... | ||||
322 | super().__init__(file) |
336 | super().__init__(file) |
||
Line 326... | Line 340... | ||||
326 | result = '' |
340 | result = '' |
||
327 | while is_id(self.curr()): |
341 | while is_id(self.curr()): |
||
328 | result += self.step() |
342 | result += self.step() |
||
329 | return result |
343 | return result |
||
Line -... | Line 344... | ||||
- | 344 | ||||
330 | 345 | ||||
331 | class AsmReader(AsmReaderFetchingIdentifiers): |
346 | class AsmReader(AsmReaderFetchingIdentifiers): |
||
332 | def __init__(self, file): |
347 | def __init__(self, file): |
||
Line -... | Line 348... | ||||
- | 348 | super().__init__(file) |
|||
333 | super().__init__(file) |
349 | |||
334 | 350 | ||||
335 | def append_file(full_path, contents): |
351 | def append_file(full_path, contents): |
||
336 | if debug_mode: |
352 | if debug_mode: |
||
337 | if full_path not in output_files: |
353 | if full_path not in output_files: |
||
338 | output_files[full_path] = "" |
354 | output_files[full_path] = "" |
||
339 | output_files[full_path] += contents |
355 | output_files[full_path] += contents |
||
340 | else: |
356 | else: |
||
341 | f = open(full_path, "a") |
357 | f = open(full_path, "a") |
||
Line -... | Line 358... | ||||
- | 358 | f.write(contents) |
|||
342 | f.write(contents) |
359 | f.close() |
||
343 | f.close() |
360 | |||
344 | 361 | ||||
Line 345... | Line 362... | ||||
345 | class AsmElement: |
362 | class AsmElement: |
||
- | 363 | def __init__(self, location, name, comment): |
|||
346 | def __init__(self, location, name, comment): |
364 | global warnings |
||
347 | global warnings |
365 | |||
348 | 366 | # If the element was constructed during this execution then |
|||
349 | # If the element was constructed during this execution then the element is new |
367 | # the element is new |
||
350 | self.new = True |
368 | self.new = True |
||
Line 372... | Line 390... | ||||
372 | declaration = f'#define {self.name}' |
390 | declaration = f'#define {self.name}' |
||
373 | # Check doxycomment |
391 | # Check doxycomment |
||
374 | if not doxycomment.endswith('\n'): |
392 | if not doxycomment.endswith('\n'): |
||
375 | doxycomment += '\n' |
393 | doxycomment += '\n' |
||
376 | if doxycomment.split('@brief ')[1][0].islower(): |
394 | if doxycomment.split('@brief ')[1][0].islower(): |
||
377 | warnings += f"{self.location}: Brief comment starting from lowercase\n" |
395 | warnings += (f"{self.location}: Brief comment starting from " + |
||
- | 396 | "lowercase\n") |
|||
378 | # Build contents to emit |
397 | # Build contents to emit |
||
379 | contents = '' |
398 | contents = '' |
||
380 | contents += '/**\n' |
399 | contents += '/**\n' |
||
381 | contents += doxycomment |
400 | contents += doxycomment |
||
382 | contents += (f"@par Source\n" + |
401 | contents += (f"@par Source\n" + |
||
- | 402 | f"{self.file}:{self.line}\n") |
403 | f"#line-{self.line}'>{self.file}:{self.line}\n") |
|
384 | contents += '*/\n' |
404 | contents += '*/\n' |
||
385 | contents += declaration |
405 | contents += declaration |
||
386 | contents += '\n\n' |
406 | contents += '\n\n' |
||
387 | # Get path to file to emit this |
407 | # Get path to file to emit this |
||
388 | full_path = dest + '/' + self.file |
408 | full_path = dest + '/' + self.file |
||
389 | # Remove the file on first access if it was created by previous generation |
409 | # Remove the file on first access if it was |
||
- | 410 | # created by previous generation |
|||
390 | if full_path not in created_files: |
411 | if full_path not in created_files: |
||
391 | if os.path.isfile(full_path): |
412 | if os.path.isfile(full_path): |
||
392 | os.remove(full_path) |
413 | os.remove(full_path) |
||
393 | created_files.append(full_path) |
414 | created_files.append(full_path) |
||
394 | # Create directories need for the file |
415 | # Create directories need for the file |
||
395 | os.makedirs(os.path.dirname(full_path), exist_ok=True) |
416 | os.makedirs(os.path.dirname(full_path), exist_ok=True) |
||
396 | contents = ''.join([i if ord(i) < 128 else '?' for i in contents]) |
417 | contents = ''.join([i if ord(i) < 128 else '?' for i in contents]) |
||
Line 397... | Line 418... | ||||
397 | 418 | ||||
Line -... | Line 419... | ||||
- | 419 | append_file(full_path, contents) |
|||
398 | append_file(full_path, contents) |
420 | |||
399 | 421 | ||||
400 | class AsmVariable(AsmElement): |
422 | class AsmVariable(AsmElement): |
||
401 | def __init__(self, location, name, comment, type, init): |
423 | def __init__(self, location, name, comment, type, init): |
||
402 | super().__init__(location, name, comment) |
424 | super().__init__(location, name, comment) |
||
Line 420... | Line 442... | ||||
420 | var_type = self.type.replace(".", "_") |
442 | var_type = self.type.replace(".", "_") |
||
421 | declaration = f"{var_type} {name};" |
443 | declaration = f"{var_type} {name};" |
||
422 | # Emit this |
444 | # Emit this |
||
423 | super().emit(dest, doxycomment, declaration) |
445 | super().emit(dest, doxycomment, declaration) |
||
Line -... | Line 446... | ||||
- | 446 | ||||
424 | 447 | ||||
425 | class AsmFunction(AsmElement): |
448 | class AsmFunction(AsmElement): |
||
- | 449 | def __init__(self, location, name, comment, calling_convention, |
|||
426 | def __init__(self, location, name, comment, calling_convention, args, used_regs): |
450 | args, used_regs): |
||
427 | super().__init__(location, name, comment) |
451 | super().__init__(location, name, comment) |
||
428 | self.calling_convention = calling_convention |
452 | self.calling_convention = calling_convention |
||
429 | self.args = args |
453 | self.args = args |
||
Line 471... | Line 495... | ||||
471 | name = self.name.replace(".", "_") |
495 | name = self.name.replace(".", "_") |
||
472 | declaration = f"void {name}{arg_list};" |
496 | declaration = f"void {name}{arg_list};" |
||
473 | # Emit this |
497 | # Emit this |
||
474 | super().emit(dest, doxycomment, declaration) |
498 | super().emit(dest, doxycomment, declaration) |
||
Line -... | Line 499... | ||||
- | 499 | ||||
475 | 500 | ||||
476 | class AsmLabel(AsmElement): |
501 | class AsmLabel(AsmElement): |
||
477 | def __init__(self, location, name, comment): |
502 | def __init__(self, location, name, comment): |
||
Line 478... | Line 503... | ||||
478 | super().__init__(location, name, comment) |
503 | super().__init__(location, name, comment) |
||
Line 491... | Line 516... | ||||
491 | name = self.name.replace(".", "_") |
516 | name = self.name.replace(".", "_") |
||
492 | declaration = f"label {name};" |
517 | declaration = f"label {name};" |
||
493 | # Emit this |
518 | # Emit this |
||
494 | super().emit(dest, doxycomment, declaration) |
519 | super().emit(dest, doxycomment, declaration) |
||
Line -... | Line 520... | ||||
- | 520 | ||||
495 | 521 | ||||
496 | class AsmMacro(AsmElement): |
522 | class AsmMacro(AsmElement): |
||
497 | def __init__(self, location, name, comment, args): |
523 | def __init__(self, location, name, comment, args): |
||
498 | super().__init__(location, name, comment) |
524 | super().__init__(location, name, comment) |
||
Line 524... | Line 550... | ||||
524 | # Build declaration |
550 | # Build declaration |
||
525 | declaration = f"#define {self.name}{arg_list}" |
551 | declaration = f"#define {self.name}{arg_list}" |
||
526 | # Emit this |
552 | # Emit this |
||
527 | super().emit(dest, doxycomment, declaration) |
553 | super().emit(dest, doxycomment, declaration) |
||
Line -... | Line 554... | ||||
- | 554 | ||||
528 | 555 | ||||
529 | class AsmStruct(AsmElement): |
556 | class AsmStruct(AsmElement): |
||
530 | def __init__(self, location, name, comment, members): |
557 | def __init__(self, location, name, comment, members): |
||
531 | super().__init__(location, name, comment) |
558 | super().__init__(location, name, comment) |
||
Line 544... | Line 571... | ||||
544 | doxycomment += '\n' |
571 | doxycomment += '\n' |
||
545 | # Build declaration |
572 | # Build declaration |
||
546 | declaration = f"struct {self.name}" + " {\n" |
573 | declaration = f"struct {self.name}" + " {\n" |
||
547 | for member in self.members: |
574 | for member in self.members: |
||
548 | if type(member) == AsmVariable: |
575 | if type(member) == AsmVariable: |
||
549 | declaration += f'\t{member.type} {member.name}; /**< {member.comment} */\n' |
576 | declaration += (f'\t{member.type} {member.name}; ' + |
||
- | 577 | f'/**< {member.comment} */\n') |
|||
550 | declaration += '};' |
578 | declaration += '};' |
||
551 | # Emit this |
579 | # Emit this |
||
552 | super().emit(dest, doxycomment, declaration) |
580 | super().emit(dest, doxycomment, declaration) |
||
Line -... | Line 581... | ||||
- | 581 | ||||
553 | 582 | ||||
554 | class AsmUnion(AsmElement): |
583 | class AsmUnion(AsmElement): |
||
555 | def __init__(self, location, name, comment, members): |
584 | def __init__(self, location, name, comment, members): |
||
556 | super().__init__(location, name, comment) |
585 | super().__init__(location, name, comment) |
||
Line 569... | Line 598... | ||||
569 | # Build declaration |
598 | # Build declaration |
||
570 | declaration = f"union {self.name}" + " {};" |
599 | declaration = f"union {self.name}" + " {};" |
||
571 | # Emit this |
600 | # Emit this |
||
572 | super().emit(dest, doxycomment, declaration) |
601 | super().emit(dest, doxycomment, declaration) |
||
Line -... | Line 602... | ||||
- | 602 | ||||
573 | 603 | ||||
574 | class VariableNameIsMacroName: |
604 | class VariableNameIsMacroName: |
||
575 | def __init__(self, name): |
605 | def __init__(self, name): |
||
Line -... | Line 606... | ||||
- | 606 | self.name = name |
|||
576 | self.name = name |
607 | |||
577 | 608 | ||||
Line -... | Line 609... | ||||
- | 609 | def is_id(c): |
|||
578 | def is_id(c): |
610 | return c.isprintable() and c not in "+-/*=<>()[]{};:,|&~#`'\" \n\r\t\v" |
||
579 | return c.isprintable() and c not in "+-/*=<>()[]{};:,|&~#`'\" \n\r\t\v" |
611 | |||
Line -... | Line 612... | ||||
- | 612 | ||||
580 | 613 | def is_starts_as_id(s): |
|||
581 | def is_starts_as_id(s): |
614 | return not s[0].isdigit() |
||
Line 582... | Line 615... | ||||
582 | return not s[0].isdigit() |
615 | |||
583 | 616 | ||||
Line 618... | Line 651... | ||||
618 | # Just skip whitespaces |
651 | # Just skip whitespaces |
||
619 | elif r.curr().isspace(): |
652 | elif r.curr().isspace(): |
||
620 | r.step() |
653 | r.step() |
||
621 | # Something unexpected |
654 | # Something unexpected |
||
622 | else: |
655 | else: |
||
623 | raise Exception(f"Unexpected symbol '{r.curr()}' at index #{r.i} " + |
656 | raise Exception(f"Unexpected symbol '{r.curr()}' " + |
||
624 | f"in the macro declaration at {location} " + |
657 | f"at index #{r.i} in the macro declaration " + |
||
- | 658 | f"at {location} " + |
|||
625 | f"(line: {r.lines[r.line_idx]})\n''") |
659 | f"(line: {r.lines[r.line_idx]})\n''") |
||
626 | # Append the last argument |
660 | # Append the last argument |
||
627 | if arg != '': |
661 | if arg != '': |
||
628 | args.append(arg) |
662 | args.append(arg) |
||
629 | # Skip t spaces after the argument list |
663 | # Skip t spaces after the argument list |
||
630 | r.skip_spaces() |
664 | r.skip_spaces() |
||
631 | # Get a comment if it is: read till the end of the line and get the comment from the reader |
665 | # Get a comment if it is: read till the end of the line and |
||
- | 666 | # get the comment from the reader |
|||
632 | while r.curr() != '': |
667 | while r.curr() != '': |
||
633 | r.step() |
668 | r.step() |
||
634 | comment = r.comment |
669 | comment = r.comment |
||
635 | # Find end of the macro |
670 | # Find end of the macro |
||
636 | prev = '' |
671 | prev = '' |
||
Line 643... | Line 678... | ||||
643 | continue |
678 | continue |
||
644 | prev = r.step() |
679 | prev = r.step() |
||
645 | # Build the output |
680 | # Build the output |
||
646 | return AsmMacro(location, name, comment, args) |
681 | return AsmMacro(location, name, comment, args) |
||
Line -... | Line 682... | ||||
- | 682 | ||||
647 | 683 | ||||
648 | def parse_variable(r, first_word = None): |
684 | def parse_variable(r, first_word=None): |
||
649 | global warnings |
685 | global warnings |
||
Line 650... | Line 686... | ||||
650 | location = r.location() |
686 | location = r.location() |
||
651 | 687 | ||||
652 | # Skip spaces before variable name |
688 | # Skip spaces before variable name |
||
653 | r.skip_spaces() |
689 | r.skip_spaces() |
||
654 | # Get variable name |
690 | # Get variable name |
||
655 | name = "" |
691 | name = "" |
||
656 | # Read it if it was not supplied |
692 | # Read it if it was not supplied |
||
657 | if first_word == None: |
693 | if first_word is None: |
||
658 | while is_id(r.curr()): |
694 | while is_id(r.curr()): |
||
659 | name += r.step() |
695 | name += r.step() |
||
660 | # Or use the supplied one instead |
696 | # Or use the supplied one instead |
||
661 | else: |
697 | else: |
||
662 | name = first_word |
698 | name = first_word |
||
- | 699 | # Check the name |
|||
663 | # Check the name |
700 | # If it's 0 len, that means threr's something else than an |
||
664 | # If it's 0 len, that means threr's something else than an identifier at the beginning |
701 | # identifier at the beginning |
||
665 | if len(name) == 0: |
702 | if len(name) == 0: |
||
666 | return None |
703 | return None |
||
667 | # If it starts from digit or othervice illegally it's illegal |
704 | # If it starts from digit or othervice illegally it's illegal |
||
Line 673... | Line 710... | ||||
673 | if ID_KIND_KEYWORD in kind: |
710 | if ID_KIND_KEYWORD in kind: |
||
674 | return None |
711 | return None |
||
675 | # If it's a macro name, that's not a variable declaration |
712 | # If it's a macro name, that's not a variable declaration |
||
676 | if ID_KIND_MACRO_NAME in kind: |
713 | if ID_KIND_MACRO_NAME in kind: |
||
677 | return VariableNameIsMacroName(name) |
714 | return VariableNameIsMacroName(name) |
||
678 | # If it's a datatype or a structure name that's not a variable declaration: that's just a data |
715 | # If it's a datatype or a structure name that's not a |
||
- | 716 | # variable declaration: that's just a data |
|||
679 | # don't document just a data for now |
717 | # don't document just a data for now |
||
680 | if ID_KIND_STRUCT_NAME in kind or ID_KIND_FASM_TYPE in kind: |
718 | if ID_KIND_STRUCT_NAME in kind or ID_KIND_FASM_TYPE in kind: |
||
681 | return None |
719 | return None |
||
682 | # Skip spaces before type name |
720 | # Skip spaces before type name |
||
683 | r.skip_spaces() |
721 | r.skip_spaces() |
||
Line 712... | Line 750... | ||||
712 | while r.curr() != '': |
750 | while r.curr() != '': |
||
713 | r.step() |
751 | r.step() |
||
714 | # Build the result |
752 | # Build the result |
||
715 | return AsmVariable(location, name, r.comment, var_type, value) |
753 | return AsmVariable(location, name, r.comment, var_type, value) |
||
Line -... | Line 754... | ||||
- | 754 | ||||
716 | 755 | ||||
717 | def parse_after_struct(r, as_union = True): |
756 | def parse_after_struct(r, as_union=True): |
||
718 | global warnings |
757 | global warnings |
||
Line 719... | Line 758... | ||||
719 | location = r.location() |
758 | location = r.location() |
||
Line 745... | Line 784... | ||||
745 | # Skip the ends of the union |
784 | # Skip the ends of the union |
||
746 | r.nextline() |
785 | r.nextline() |
||
747 | elif r.curr() == ':': |
786 | elif r.curr() == ':': |
||
748 | warnings += f"{r.location()}: Skept the label in the struct\n" |
787 | warnings += f"{r.location()}: Skept the label in the struct\n" |
||
749 | else: |
788 | else: |
||
750 | raise Exception(f"Garbage in struct member at {location} (got '{var}' identifier)") |
789 | raise Exception(f"Garbage in struct member at {location} " + |
||
- | 790 | f" (got '{var}' identifier)") |
|||
751 | elif type(var) == VariableNameIsMacroName: |
791 | elif type(var) == VariableNameIsMacroName: |
||
752 | if var.name == 'ends': |
792 | if var.name == 'ends': |
||
753 | break |
793 | break |
||
754 | r.nextline() |
794 | r.nextline() |
||
755 | # Return the result |
795 | # Return the result |
||
756 | if as_union: |
796 | if as_union: |
||
757 | return AsmStruct(location, name, comment, members) |
797 | return AsmStruct(location, name, comment, members) |
||
758 | else: |
798 | else: |
||
759 | return AsmUnion(location, name, comment, members) |
799 | return AsmUnion(location, name, comment, members) |
||
Line -... | Line 800... | ||||
- | 800 | ||||
760 | 801 | ||||
761 | def parse_after_proc(r): |
802 | def parse_after_proc(r): |
||
762 | # Get proc name |
803 | # Get proc name |
||
763 | name = r.fetch_identifier() |
804 | name = r.fetch_identifier() |
||
764 | # Next identifier after the proc name |
805 | # Next identifier after the proc name |
||
Line 811... | Line 852... | ||||
811 | # Get to the end of the line and get a comment from the reader |
852 | # Get to the end of the line and get a comment from the reader |
||
812 | while r.curr() != '': |
853 | while r.curr() != '': |
||
813 | r.step() |
854 | r.step() |
||
814 | comment = r.comment |
855 | comment = r.comment |
||
815 | # Build the element |
856 | # Build the element |
||
816 | return AsmFunction(r.location(), name, comment, calling_convention, args, used_regs) |
857 | return AsmFunction(r.location(), name, comment, calling_convention, |
||
- | 858 | args, used_regs) |
|||
- | 859 | ||||
Line 817... | Line 860... | ||||
817 | 860 | ||||
818 | def get_declarations(asm_file_contents, asm_file_name): |
861 | def get_declarations(asm_file_contents, asm_file_name): |
||
Line 819... | Line 862... | ||||
819 | r = AsmReader(asm_file_name) |
862 | r = AsmReader(asm_file_name) |
||
Line 855... | Line 898... | ||||
855 | elif first_word == 'repeat': |
898 | elif first_word == 'repeat': |
||
856 | # Skip the repeat directive |
899 | # Skip the repeat directive |
||
857 | pass |
900 | pass |
||
858 | elif first_word == 'purge': |
901 | elif first_word == 'purge': |
||
859 | while True: |
902 | while True: |
||
- | 903 | # Skip spaces after the 'purge' keyword or after |
|||
860 | # Skip spaces after the 'purge' keyword or after the comma what separated the previous macro name |
904 | # the comma what separated the previous macro name |
||
861 | r.skip_spaces() |
905 | r.skip_spaces() |
||
862 | # Get the purged macro name |
906 | # Get the purged macro name |
||
863 | name = '' |
907 | name = '' |
||
864 | while is_id(r.curr()): |
908 | while is_id(r.curr()): |
||
865 | name += r.step() |
909 | name += r.step() |
||
Line 868... | Line 912... | ||||
868 | id_remove_kind(name, ID_KIND_MACRO_NAME) |
912 | id_remove_kind(name, ID_KIND_MACRO_NAME) |
||
869 | except: |
913 | except: |
||
870 | pass |
914 | pass |
||
871 | # Skip spaces after the name |
915 | # Skip spaces after the name |
||
872 | r.skip_spaces() |
916 | r.skip_spaces() |
||
873 | # If it's comma (',') after then that's not the last purged macro, continue purging |
917 | # If it's comma (',') after then that's not the last purged |
||
- | 918 | # macro, continue purging |
|||
874 | if r.curr() == ',': |
919 | if r.curr() == ',': |
||
875 | r.step() |
920 | r.step() |
||
876 | continue |
921 | continue |
||
877 | # Here we purged all the macros should be purged |
922 | # Here we purged all the macros should be purged |
||
878 | break |
923 | break |
||
Line 891... | Line 936... | ||||
891 | # If it didn't match a type identifier after the word |
936 | # If it didn't match a type identifier after the word |
||
892 | elif type(var) == str: |
937 | elif type(var) == str: |
||
893 | name = var |
938 | name = var |
||
894 | # Match label beginning (':' after name) |
939 | # Match label beginning (':' after name) |
||
895 | if r.curr() == ':': |
940 | if r.curr() == ':': |
||
- | 941 | # Get to the end of the line and |
|||
896 | # Get to the end of the line and get the coment from the reader |
942 | # get the coment from the reader |
||
897 | while r.curr() != '': |
943 | while r.curr() != '': |
||
898 | r.step() |
944 | r.step() |
||
899 | comment = r.comment |
945 | comment = r.comment |
||
900 | # Only handle non-local labels |
946 | # Only handle non-local labels |
||
901 | if name[0] != '.' and name != "@@" and name != "$Revision": |
947 | if name[0] != '.' and name != "@@" and name != "$Revision": |
||
- | 948 | # Treate the label as function if there's @return or |
|||
- | 949 | # @param in its comment. Othervice it's just a variable |
|||
- | 950 | # with type `label` in generated doxygen C |
|||
902 | if '@return' in comment or '@param' in comment: |
951 | if '@return' in comment or '@param' in comment: |
||
903 | element = AsmFunction(r.location(), name, comment, '', [], []) |
952 | element = AsmFunction(r.location(), name, comment, |
||
- | 953 | '', [], []) |
|||
904 | else: |
954 | else: |
||
905 | element = AsmLabel(r.location(), name, comment) |
955 | element = AsmLabel(r.location(), name, comment) |
||
906 | elements.append(element) |
956 | elements.append(element) |
||
907 | elif r.curr() == '=': |
957 | elif r.curr() == '=': |
||
908 | # Save the identifier as a set constant |
958 | # Save the identifier as a set constant |
||
Line 912... | Line 962... | ||||
912 | if word_two == 'equ': |
962 | if word_two == 'equ': |
||
913 | # Save the identifier as an equated constant |
963 | # Save the identifier as an equated constant |
||
914 | id_add_kind(word_one, ID_KIND_EQUATED_CONSTANT) |
964 | id_add_kind(word_one, ID_KIND_EQUATED_CONSTANT) |
||
915 | r.nextline() |
965 | r.nextline() |
||
Line -... | Line 966... | ||||
- | 966 | ||||
916 | 967 | ||||
917 | def it_neds_to_be_parsed(source_file): |
968 | def it_neds_to_be_parsed(source_file): |
||
918 | # If there's no symbols file saved - parse it anyway |
969 | # If there's no symbols file saved - parse it anyway |
||
919 | # cause we need to create the symbols file and use it |
970 | # cause we need to create the symbols file and use it |
||
920 | # if we gonna generate proper doxygen |
971 | # if we gonna generate proper doxygen |
||
Line 931... | Line 982... | ||||
931 | # then the source should be recompiled (existing doxygen is old) |
982 | # then the source should be recompiled (existing doxygen is old) |
||
932 | if source_change_time > dest_change_file: |
983 | if source_change_time > dest_change_file: |
||
933 | return True |
984 | return True |
||
934 | return False |
985 | return False |
||
Line -... | Line 986... | ||||
- | 986 | ||||
935 | 987 | ||||
936 | def handle_file(handled_files, asm_file_name, subdir = "."): |
988 | def handle_file(handled_files, asm_file_name, subdir="."): |
||
937 | global elements |
989 | global elements |
||
938 | # Canonicalize the file path and get it relative to cwd |
990 | # Canonicalize the file path and get it relative to cwd |
||
939 | cwd = os.path.abspath(os.path.dirname(sys.argv[0])) |
991 | cwd = os.path.abspath(os.path.dirname(sys.argv[0])) |
||
Line 945... | Line 997... | ||||
945 | # If the file was handled in this execution before - skip it |
997 | # If the file was handled in this execution before - skip it |
||
946 | if asm_file_name in handled_files: |
998 | if asm_file_name in handled_files: |
||
947 | return |
999 | return |
||
948 | # Say that the file was handled in this execution |
1000 | # Say that the file was handled in this execution |
||
949 | handled_files.append(asm_file_name) |
1001 | handled_files.append(asm_file_name) |
||
- | 1002 | # Check if the file should be parsed |
|||
950 | # Check if the file should be parsed (if it was modified or wasn't parsed yet) |
1003 | # (if it was modified or wasn't parsed yet) |
||
951 | should_get_declarations = True |
1004 | should_get_declarations = True |
||
952 | if not it_neds_to_be_parsed(asm_file_name): |
1005 | if not it_neds_to_be_parsed(asm_file_name): |
||
953 | print(f"Skipping {asm_file_name} (already newest)") |
1006 | print(f"Skipping {asm_file_name} (already newest)") |
||
954 | should_get_declarations = False |
1007 | should_get_declarations = False |
||
955 | else: |
1008 | else: |
||
956 | print(f"Handling {asm_file_name}") |
1009 | print(f"Handling {asm_file_name}") |
||
957 | # Remove elements parsed from this file before if any |
1010 | # Remove elements parsed from this file before if any |
||
- | 1011 | elements_to_remove = [ |
|||
958 | elements_to_remove = [x for x in elements if x.location.split(':')[0] == asm_file_name] |
1012 | x for x in elements if x.location.split(':')[0] == asm_file_name |
||
- | 1013 | ] |
|||
- | 1014 | elements = [ |
|||
959 | elements = [x for x in elements if x.location.split(':')[0] != asm_file_name] |
1015 | x for x in elements if x.location.split(':')[0] != asm_file_name |
||
- | 1016 | ] |
|||
960 | # Forget types of identifiers of names of the removed elements |
1017 | # Forget types of identifiers of names of the removed elements |
||
961 | for element in elements_to_remove: |
1018 | for element in elements_to_remove: |
||
962 | if type(element) == AsmStruct: |
1019 | if type(element) == AsmStruct: |
||
963 | id_remove_kind(element.name, ID_KIND_STRUCT_NAME) |
1020 | id_remove_kind(element.name, ID_KIND_STRUCT_NAME) |
||
964 | elif type(element) == AsmMacro: |
1021 | elif type(element) == AsmMacro: |
||
965 | id_remove_kind(element.name, ID_KIND_MACRO_NAME) |
1022 | id_remove_kind(element.name, ID_KIND_MACRO_NAME) |
||
966 | # Read the source |
1023 | # Read the source |
||
967 | asm_file_contents = open(asm_file_name, "r", encoding="utf-8").read() |
1024 | asm_file_contents = open(asm_file_name, "r", encoding="utf-8").read() |
||
968 | # Find includes, fix their paths and handle em recoursively |
1025 | # Find includes, fix their paths and handle em recoursively |
||
969 | includes = re.findall(r'^include (["\'])(.*)\1', asm_file_contents, flags=re.MULTILINE) |
1026 | includes = re.findall(r'^include (["\'])(.*)\1', asm_file_contents, |
||
- | 1027 | flags=re.MULTILINE) |
|||
970 | for include in includes: |
1028 | for include in includes: |
||
971 | include = include[1].replace('\\', '/'); |
1029 | include = include[1].replace('\\', '/') |
||
972 | full_path = subdir + '/' + include; |
1030 | full_path = subdir + '/' + include |
||
973 | # If the path isn't valid, maybe that's not relative path |
1031 | # If the path isn't valid, maybe that's not relative path |
||
974 | if not os.path.isfile(full_path): |
1032 | if not os.path.isfile(full_path): |
||
975 | full_path = include |
1033 | full_path = include |
||
976 | new_subdir = full_path.rsplit('/', 1)[0] |
1034 | new_subdir = full_path.rsplit('/', 1)[0] |
||
977 | handle_file(handled_files, full_path, new_subdir) |
1035 | handle_file(handled_files, full_path, new_subdir) |
||
978 | # Only collect declarations from the file if it wasn't parsed before |
1036 | # Only collect declarations from the file if it wasn't parsed before |
||
979 | if should_get_declarations and not clean_generated_stuff: |
1037 | if should_get_declarations and not clean_generated_stuff: |
||
980 | get_declarations(asm_file_contents, asm_file_name) |
1038 | get_declarations(asm_file_contents, asm_file_name) |
||
Line 981... | Line 1039... | ||||
981 | 1039 | ||||
982 | if __name__ == "__main__": |
1040 | if __name__ == "__main__": |
||
- | 1041 | link_root = "http://websvn.kolibrios.org/filedetails.php" |
|||
Line 983... | Line 1042... | ||||
983 | link_root = "http://websvn.kolibrios.org/filedetails.php?repname=Kolibri+OS&path=/kernel/trunk" |
1042 | link_root += "?repname=Kolibri+OS&path=/kernel/trunk" |
||
984 | 1043 | ||||
985 | # Dict where an identifier is assicoated with a string |
1044 | # Dict where an identifier is assicoated with a string |
||
986 | # The string contains characters specifying flags |
1045 | # The string contains characters specifying flags |
||
Line 1021... | Line 1080... | ||||
1021 | enable_warnings = True |
1080 | enable_warnings = True |
||
Line 1022... | Line 1081... | ||||
1022 | 1081 | ||||
1023 | # Parse arguments |
1082 | # Parse arguments |
||
1024 | parser = argparse.ArgumentParser() |
1083 | parser = argparse.ArgumentParser() |
||
- | 1084 | parser.add_argument("-o", help="Doxygen output folder") |
|||
1025 | parser.add_argument("-o", help="Doxygen output folder") |
1085 | parser.add_argument("--clean", |
||
- | 1086 | help="Remove generated files", |
|||
- | 1087 | action="store_true") |
|||
1026 | parser.add_argument("--clean", help="Remove generated files", action="store_true") |
1088 | parser.add_argument("--dump", |
||
- | 1089 | help="Dump all defined symbols", |
|||
- | 1090 | action="store_true") |
|||
1027 | parser.add_argument("--dump", help="Dump all defined symbols", action="store_true") |
1091 | parser.add_argument("--stats", |
||
- | 1092 | help="Print symbol stats", |
|||
- | 1093 | action="store_true") |
|||
1028 | parser.add_argument("--stats", help="Print symbol stats", action="store_true") |
1094 | parser.add_argument("--nowarn", |
||
- | 1095 | help="Do not write warnings file", |
|||
- | 1096 | action="store_true") |
|||
1029 | parser.add_argument("--nowarn", help="Do not write warnings file", action="store_true") |
1097 | parser.add_argument("--noemit", |
||
- | 1098 | help="Do not emit doxygen files (for testing)", |
|||
- | 1099 | action="store_true") |
|||
1030 | parser.add_argument("--noemit", help="Do not emit doxygen files (for testing)", action="store_true") |
1100 | parser.add_argument("--debug", |
||
- | 1101 | help="Show hashes of files (for testing)", |
|||
1031 | parser.add_argument("--debug", help="Show hashes of files (for testing)", action="store_true") |
1102 | action="store_true") |
||
1032 | args = parser.parse_args() |
1103 | args = parser.parse_args() |
||
1033 | doxygen_src_path = args.o if args.o else 'docs/doxygen' |
1104 | doxygen_src_path = args.o if args.o else 'docs/doxygen' |
||
1034 | clean_generated_stuff = args.clean |
1105 | clean_generated_stuff = args.clean |
||
1035 | dump_symbols = args.dump |
1106 | dump_symbols = args.dump |
||
Line 1045... | Line 1116... | ||||
1045 | output_files = {} # If --debug then all the files are written here |
1116 | output_files = {} # If --debug then all the files are written here |
||
Line 1046... | Line 1117... | ||||
1046 | 1117 | ||||
1047 | # Load remembered list of symbols |
1118 | # Load remembered list of symbols |
||
1048 | if os.path.isfile('asmxygen.elements.pickle'): |
1119 | if os.path.isfile('asmxygen.elements.pickle'): |
||
1049 | print('Reading existing dump of symbols') |
1120 | print('Reading existing dump of symbols') |
||
- | 1121 | pickle_file = open('asmxygen.elements.pickle', 'rb') |
|||
- | 1122 | (elements, id2kind) = pickle.load(pickle_file) |
|||
Line 1050... | Line 1123... | ||||
1050 | (elements, id2kind) = pickle.load(open('asmxygen.elements.pickle', 'rb')) |
1123 | pickle_file.close() |
||
Line 1051... | Line 1124... | ||||
1051 | 1124 | ||||
1052 | handle_file(kernel_files, "./kernel.asm"); |
1125 | handle_file(kernel_files, "./kernel.asm") |
||
1053 | 1126 | ||||
1054 | if dump_symbols: |
1127 | if dump_symbols: |
||
Line 1070... | Line 1143... | ||||
1070 | print(f"Writing doumented sources to {doxygen_src_path}") |
1143 | print(f"Writing doumented sources to {doxygen_src_path}") |
||
Line 1071... | Line 1144... | ||||
1071 | 1144 | ||||
1072 | i = 0 |
1145 | i = 0 |
||
1073 | new_elements = [x for x in elements if x.new] |
1146 | new_elements = [x for x in elements if x.new] |
||
- | 1147 | for element in new_elements: |
|||
1074 | for element in new_elements: |
1148 | counter = f"[{i + 1}/{len(new_elements)}]" |
||
1075 | print(f"[{i + 1}/{len(new_elements)}] Emitting {element.name} from {element.location}") |
1149 | print(f"{counter} Emitting {element.name} from {element.location}") |
||
1076 | element.emit(doxygen_src_path) |
1150 | element.emit(doxygen_src_path) |
||
Line 1077... | Line 1151... | ||||
1077 | i += 1 |
1151 | i += 1 |
||
Line 1078... | Line 1152... | ||||
1078 | 1152 | ||||
- | 1153 | print(f"Writing dump of symbols to asmxygen.elements.pickle") |
|||
1079 | print(f"Writing dump of symbols to asmxygen.elements.pickle") |
1154 | |||
1080 | 1155 | # Now when the new elements already was written, there's no new |
|||
1081 | # Now when the new elements already was written, there's no new elements anymore |
1156 | # elements anymore |
||
- | 1157 | for element in elements: |
|||
- | 1158 | element.new = False |
|||
Line 1082... | Line 1159... | ||||
1082 | for element in elements: |
1159 | pickle_file = open('asmxygen.elements.pickle', 'wb') |
||
1083 | element.new = False |
1160 | pickle.dump((elements, id2kind), pickle_file) |
||
1084 | pickle.dump((elements, id2kind), open('asmxygen.elements.pickle', 'wb')) |
1161 | pickle_file.close() |
||
1085 | 1162 | ||||
Line 1122... | Line 1199... | ||||
1122 | open("asmxygen_hash_per_file.txt", "w").write(hash_per_file) |
1199 | open("asmxygen_hash_per_file.txt", "w").write(hash_per_file) |
||
1123 | print("NEW") |
1200 | print("NEW") |
||
1124 | else: |
1201 | else: |
||
1125 | reference_hash_per_file = open("asmxygen_hash_per_file.txt").read() |
1202 | reference_hash_per_file = open("asmxygen_hash_per_file.txt").read() |
||
1126 | if reference_hash_per_file != hash_per_file: |
1203 | if reference_hash_per_file != hash_per_file: |
||
1127 | print(''.join(difflib.ndiff(reference_hash_per_file, hash_per_file))) |
1204 | diffs = difflib.ndiff(reference_hash_per_file, hash_per_file) |
||
- | 1205 | print(''.join(diffs)) |
|||
1128 | else: |
1206 | else: |
||
1129 | print("SUCCESS")>>> |
1207 | print("SUCCESS")>>> |