Subversion Repositories Kolibri OS

Rev

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")