diff --git a/kernel/trunk/asmxygen.py b/kernel/trunk/asmxygen.py
index da7c657ba1..da21f33207 100644
--- a/kernel/trunk/asmxygen.py
+++ b/kernel/trunk/asmxygen.py
@@ -156,974 +156,974 @@ keywords = [
]
fasm_types = [
- "db", "rb",
- "dw", "rw",
- "dd", "rd",
- "dp", "rp",
- "df", "rf",
- "dq", "rq",
- "dt", "rt",
- "du",
+ "db", "rb",
+ "dw", "rw",
+ "dd", "rd",
+ "dp", "rp",
+ "df", "rf",
+ "dq", "rq",
+ "dt", "rt",
+ "du",
]
# Add kind flag to identifier in id2kind
def id_add_kind(identifier, kind):
- if identifier not in id2kind:
- id2kind[identifier] = ''
- id2kind[identifier] += kind
+ if identifier not in id2kind:
+ id2kind[identifier] = ''
+ id2kind[identifier] += kind
# Remove kind flag of identifier in id2kind
def id_remove_kind(identifier, kind):
- if identifier in id2kind:
- if kind in id2kind[identifier]:
- id2kind[identifier] = id2kind[identifier].replace(kind, '')
+ if identifier in id2kind:
+ if kind in id2kind[identifier]:
+ id2kind[identifier] = id2kind[identifier].replace(kind, '')
# Get kind of an identifier
def id_get_kind(identifier):
- if identifier in id2kind:
- return id2kind[identifier]
- else:
- return ''
+ if identifier in id2kind:
+ return id2kind[identifier]
+ else:
+ return ''
class LegacyAsmReader:
- def __init__(self, file):
- self.file = file
- self.lines = open(file, "r", encoding="utf-8").readlines()
- self.line_idx = 0
- self.i = 0
+ def __init__(self, file):
+ self.file = file
+ self.lines = open(file, "r", encoding="utf-8").readlines()
+ self.line_idx = 0
+ self.i = 0
- def currline(self):
- return self.lines[self.line_idx]
+ def currline(self):
+ return self.lines[self.line_idx]
- def curr(self):
- try: return self.lines[self.line_idx][self.i]
- except: return ''
+ def curr(self):
+ try: return self.lines[self.line_idx][self.i]
+ except: return ''
- def step(self):
- c = self.curr()
- self.i += 1
- # Wrap the line if '\\' followed by whitespaces and/or comment
- while self.curr() == '\\':
- i_of_backslash = self.i
- self.i += 1
- while self.curr().isspace():
- self.i += 1
- if self.curr() == ';' or self.curr() == '':
- self.line_idx += 1
- self.i = 0
- else:
- # There's something other than a comment after the backslash
- # So don't interpret the backslash as a line wrap
- self.i = i_of_backslash
- break
- return c
+ def step(self):
+ c = self.curr()
+ self.i += 1
+ # Wrap the line if '\\' followed by whitespaces and/or comment
+ while self.curr() == '\\':
+ i_of_backslash = self.i
+ self.i += 1
+ while self.curr().isspace():
+ self.i += 1
+ if self.curr() == ';' or self.curr() == '':
+ self.line_idx += 1
+ self.i = 0
+ else:
+ # There's something other than a comment after the backslash
+ # So don't interpret the backslash as a line wrap
+ self.i = i_of_backslash
+ break
+ return c
- def nextline(self):
- c = self.curr()
- while c != '':
- c = self.step()
- self.line_idx += 1
- self.i = 0
+ def nextline(self):
+ c = self.curr()
+ while c != '':
+ c = self.step()
+ self.line_idx += 1
+ self.i = 0
- def no_lines(self):
- if self.line_idx >= len(self.lines):
- return True
- return False
+ def no_lines(self):
+ if self.line_idx >= len(self.lines):
+ return True
+ return False
- def location(self):
- return f"{self.file}:{self.line_idx + 1}"
+ def location(self):
+ return f"{self.file}:{self.line_idx + 1}"
- def skip_spaces(self):
- while self.curr().isspace():
- self.step()
+ def skip_spaces(self):
+ while self.curr().isspace():
+ self.step()
class AsmReaderRecognizingStrings(LegacyAsmReader):
- def __init__(self, file):
- super().__init__(file)
- self.in_string = None
- self.should_recognize_strings = True
+ def __init__(self, file):
+ super().__init__(file)
+ self.in_string = None
+ self.should_recognize_strings = True
- def step(self):
- c = super().step()
- if self.should_recognize_strings and (c == '"' or c == "'"):
- # If just now we was at the double or single quotation mark
- # and we aren't in a string yet
- # then say "we are in a string openned with this quotation mark now"
- if self.in_string == None:
- self.in_string = c
- # If just now we was at the double or single quotation mark
- # and we are in the string entered with the same quotation mark
- # then say "we aren't in a string anymore"
- elif self.in_string == c:
- self.in_string = None
- return c
+ def step(self):
+ c = super().step()
+ if self.should_recognize_strings and (c == '"' or c == "'"):
+ # If just now we was at the double or single quotation mark
+ # and we aren't in a string yet
+ # then say "we are in a string openned with this quotation mark now"
+ if self.in_string == None:
+ self.in_string = c
+ # If just now we was at the double or single quotation mark
+ # and we are in the string entered with the same quotation mark
+ # then say "we aren't in a string anymore"
+ elif self.in_string == c:
+ self.in_string = None
+ return c
class AsmReaderReadingComments(AsmReaderRecognizingStrings):
- def __init__(self, file):
- super().__init__(file)
- self.status = dict()
- self.status_reset()
- self.comment = ''
+ def __init__(self, file):
+ super().__init__(file)
+ self.status = dict()
+ self.status_reset()
+ self.comment = ''
- def status_reset(self):
- # If the line has non-comment code
- self.status_has_code = False
- # If the line has a comment at the end
- self.status_has_comment = False
- # Let it recognize strings further, we are definitely out of a comment
- self.should_recognize_strings = True
+ def status_reset(self):
+ # If the line has non-comment code
+ self.status_has_code = False
+ # If the line has a comment at the end
+ self.status_has_comment = False
+ # Let it recognize strings further, we are definitely out of a comment
+ self.should_recognize_strings = True
- def status_set_has_comment(self):
- self.status_has_comment = True
- # Don't let it recognize strings cause we are in a comment now
- self.should_recognize_strings = False
+ def status_set_has_comment(self):
+ self.status_has_comment = True
+ # Don't let it recognize strings cause we are in a comment now
+ self.should_recognize_strings = False
- def status_set_has_code(self):
- self.status_has_code = True
+ def status_set_has_code(self):
+ self.status_has_code = True
- def update_status(self):
- # If we aren't in a comment and we aren't in a string - say we are now in a comment if ';' met
- if not self.status_has_comment and not self.in_string and self.curr() == ';':
- self.status_set_has_comment()
- # Else if we are in a comment - collect the comment
- elif self.status_has_comment:
- self.comment += self.curr()
- # Else if there's some non-whitespace character out of a comment
- # then the line has code
- elif not self.status_has_comment and not self.curr().isspace():
- self.status_set_has_code()
+ def update_status(self):
+ # If we aren't in a comment and we aren't in a string - say we are now in a comment if ';' met
+ if not self.status_has_comment and not self.in_string and self.curr() == ';':
+ self.status_set_has_comment()
+ # Else if we are in a comment - collect the comment
+ elif self.status_has_comment:
+ self.comment += self.curr()
+ # Else if there's some non-whitespace character out of a comment
+ # then the line has code
+ elif not self.status_has_comment and not self.curr().isspace():
+ self.status_set_has_code()
- def step(self):
- # Get to the next character
- c = super().step()
- # Update status of the line according to the next character
- self.update_status()
- return c
+ def step(self):
+ # Get to the next character
+ c = super().step()
+ # Update status of the line according to the next character
+ self.update_status()
+ return c
- def nextline(self):
- prev_line = self.currline()
- super().nextline()
- # If the line we leave was not a comment-only line
- # then forget the collected comment
- # Otherwise the collected comment should be complemented by comment from next line in step()
- if self.status_has_code:
- # But we should preserve comment for the next line
- # If previous line set align (cause many functions re documented
- # right before align set, not before their labels)
- if not prev_line.startswith("align "):
- self.comment = ''
- # Reset the line status (now it's the status of the new line)
- self.status_reset()
- # Set new status for this line according to the first character in the line
- self.update_status()
+ def nextline(self):
+ prev_line = self.currline()
+ super().nextline()
+ # If the line we leave was not a comment-only line
+ # then forget the collected comment
+ # Otherwise the collected comment should be complemented by comment from next line in step()
+ if self.status_has_code:
+ # But we should preserve comment for the next line
+ # If previous line set align (cause many functions re documented
+ # right before align set, not before their labels)
+ if not prev_line.startswith("align "):
+ self.comment = ''
+ # Reset the line status (now it's the status of the new line)
+ self.status_reset()
+ # Set new status for this line according to the first character in the line
+ self.update_status()
class AsmReaderFetchingIdentifiers(AsmReaderReadingComments):
- def __init__(self, file):
- super().__init__(file)
+ def __init__(self, file):
+ super().__init__(file)
- def fetch_identifier(self):
- self.skip_spaces()
- result = ''
- while is_id(self.curr()):
- result += self.step()
- return result
+ def fetch_identifier(self):
+ self.skip_spaces()
+ result = ''
+ while is_id(self.curr()):
+ result += self.step()
+ return result
class AsmReader(AsmReaderFetchingIdentifiers):
- def __init__(self, file):
- super().__init__(file)
+ def __init__(self, file):
+ super().__init__(file)
def append_file(full_path, contents):
- if debug_mode:
- if full_path not in output_files:
- output_files[full_path] = ""
- output_files[full_path] += contents
- else:
- f = open(full_path, "a")
- f.write(contents)
- f.close()
+ if debug_mode:
+ if full_path not in output_files:
+ output_files[full_path] = ""
+ output_files[full_path] += contents
+ else:
+ f = open(full_path, "a")
+ f.write(contents)
+ f.close()
class AsmElement:
- def __init__(self, location, name, comment):
- global warnings
+ def __init__(self, location, name, comment):
+ global warnings
- # If the element was constructed during this execution then the element is new
- self.new = True
- self.location = location
- self.file = self.location.split(':')[0].replace('\\', '/')
- self.line = self.location.split(':')[1]
- self.name = name
- self.comment = comment
+ # If the element was constructed during this execution then the element is new
+ self.new = True
+ self.location = location
+ self.file = self.location.split(':')[0].replace('\\', '/')
+ self.line = self.location.split(':')[1]
+ self.name = name
+ self.comment = comment
- if self.comment == '':
- warnings += f'{self.location}: Undocumented element\n'
+ if self.comment == '':
+ warnings += f'{self.location}: Undocumented element\n'
- def dump(self):
- print(f"\n{self.location}: {self.name}")
- print(f"{self.comment}")
+ def dump(self):
+ print(f"\n{self.location}: {self.name}")
+ print(f"{self.comment}")
- def emit(self, dest, doxycomment = '', declaration = ''):
- # Do not emit anything if the symbol is marked as hidden in its comment
- if '@dont_give_a_doxygen' in self.comment:
- return
+ def emit(self, dest, doxycomment = '', declaration = ''):
+ # Do not emit anything if the symbol is marked as hidden in its comment
+ if '@dont_give_a_doxygen' in self.comment:
+ return
- global warnings
- # Redefine default declaration
- if declaration == '':
- declaration = f'#define {self.name}'
- # Check doxycomment
- if not doxycomment.endswith('\n'):
- doxycomment += '\n'
- if doxycomment.split('@brief ')[1][0].islower():
- warnings += f"{self.location}: Brief comment starting from lowercase\n"
- # Build contents to emit
- contents = ''
- contents += '/**\n'
- contents += doxycomment
- contents += (f"@par Source\n" +
- f"{self.file}:{self.line}\n")
- contents += '*/\n'
- contents += declaration
- contents += '\n\n'
- # Get path to file to emit this
- full_path = dest + '/' + self.file
- # Remove the file on first access if it was created by previous generation
- if full_path not in created_files:
- if os.path.isfile(full_path):
- os.remove(full_path)
- created_files.append(full_path)
- # Create directories need for the file
- os.makedirs(os.path.dirname(full_path), exist_ok=True)
- contents = ''.join([i if ord(i) < 128 else '?' for i in contents])
+ global warnings
+ # Redefine default declaration
+ if declaration == '':
+ declaration = f'#define {self.name}'
+ # Check doxycomment
+ if not doxycomment.endswith('\n'):
+ doxycomment += '\n'
+ if doxycomment.split('@brief ')[1][0].islower():
+ warnings += f"{self.location}: Brief comment starting from lowercase\n"
+ # Build contents to emit
+ contents = ''
+ contents += '/**\n'
+ contents += doxycomment
+ contents += (f"@par Source\n" +
+ f"{self.file}:{self.line}\n")
+ contents += '*/\n'
+ contents += declaration
+ contents += '\n\n'
+ # Get path to file to emit this
+ full_path = dest + '/' + self.file
+ # Remove the file on first access if it was created by previous generation
+ if full_path not in created_files:
+ if os.path.isfile(full_path):
+ os.remove(full_path)
+ created_files.append(full_path)
+ # Create directories need for the file
+ os.makedirs(os.path.dirname(full_path), exist_ok=True)
+ contents = ''.join([i if ord(i) < 128 else '?' for i in contents])
- append_file(full_path, contents)
+ append_file(full_path, contents)
class AsmVariable(AsmElement):
- def __init__(self, location, name, comment, type, init):
- super().__init__(location, name, comment)
- self.type = type
- self.init = init
+ def __init__(self, location, name, comment, type, init):
+ super().__init__(location, name, comment)
+ self.type = type
+ self.init = init
- def dump(self):
- super().dump()
- print(f"(Variable)\n---")
+ def dump(self):
+ super().dump()
+ print(f"(Variable)\n---")
- def emit(self, dest):
- # Build doxycomment specific for the variable
- doxycomment = ''
- doxycomment += self.comment
- if '@brief' not in doxycomment:
- doxycomment = '@brief ' + doxycomment
- doxycomment += (f"@par Initial value\n" +
- f"{self.init}\n")
- # Build the declaration
- name = self.name.replace(".", "_")
- var_type = self.type.replace(".", "_")
- declaration = f"{var_type} {name};"
- # Emit this
- super().emit(dest, doxycomment, declaration)
+ def emit(self, dest):
+ # Build doxycomment specific for the variable
+ doxycomment = ''
+ doxycomment += self.comment
+ if '@brief' not in doxycomment:
+ doxycomment = '@brief ' + doxycomment
+ doxycomment += (f"@par Initial value\n" +
+ f"{self.init}\n")
+ # Build the declaration
+ name = self.name.replace(".", "_")
+ var_type = self.type.replace(".", "_")
+ declaration = f"{var_type} {name};"
+ # Emit this
+ super().emit(dest, doxycomment, declaration)
class AsmFunction(AsmElement):
- def __init__(self, location, name, comment, calling_convention, args, used_regs):
- super().__init__(location, name, comment)
- self.calling_convention = calling_convention
- self.args = args
- self.used_regs = used_regs
+ def __init__(self, location, name, comment, calling_convention, args, used_regs):
+ super().__init__(location, name, comment)
+ self.calling_convention = calling_convention
+ self.args = args
+ self.used_regs = used_regs
- def dump(self):
- super().dump()
- print(f"(Function)\n---")
+ def dump(self):
+ super().dump()
+ print(f"(Function)\n---")
- def emit(self, dest):
- # Build doxycomment specific for the variable
- doxycomment = ''
- doxycomment += self.comment
- if '@brief' not in doxycomment:
- doxycomment = '@brief ' + doxycomment
- # If there was no arguments, maybe that's just a label
- # then parse parameters from its comment
- if len(self.args) == 0 and '@param' in self.comment:
- i = 0
- while '@param' in self.comment[i:]:
- i = self.comment.index('@param', i)
- # Skip '@param'
- i += len('@param')
- # Skip spaces after '@param'
- while self.comment[i].isspace():
- i += 1
- # Get the parameter name
- name = ''
- while is_id(self.comment[i]):
- name += self.comment[i]
- i += 1
- # Save the parameter
- self.args.append((name, 'arg_t'))
- # Build the arg list for declaration
- arg_list = '('
- if len(self.args) > 0:
- argc = 0
- for arg in self.args:
- if argc != 0:
- arg_list += ", "
- arg_list += f"{arg[1]} {arg[0]}"
- argc += 1
- arg_list += ')'
- # Build the declaration
- name = self.name.replace(".", "_")
- declaration = f"void {name}{arg_list};"
- # Emit this
- super().emit(dest, doxycomment, declaration)
+ def emit(self, dest):
+ # Build doxycomment specific for the variable
+ doxycomment = ''
+ doxycomment += self.comment
+ if '@brief' not in doxycomment:
+ doxycomment = '@brief ' + doxycomment
+ # If there was no arguments, maybe that's just a label
+ # then parse parameters from its comment
+ if len(self.args) == 0 and '@param' in self.comment:
+ i = 0
+ while '@param' in self.comment[i:]:
+ i = self.comment.index('@param', i)
+ # Skip '@param'
+ i += len('@param')
+ # Skip spaces after '@param'
+ while self.comment[i].isspace():
+ i += 1
+ # Get the parameter name
+ name = ''
+ while is_id(self.comment[i]):
+ name += self.comment[i]
+ i += 1
+ # Save the parameter
+ self.args.append((name, 'arg_t'))
+ # Build the arg list for declaration
+ arg_list = '('
+ if len(self.args) > 0:
+ argc = 0
+ for arg in self.args:
+ if argc != 0:
+ arg_list += ", "
+ arg_list += f"{arg[1]} {arg[0]}"
+ argc += 1
+ arg_list += ')'
+ # Build the declaration
+ name = self.name.replace(".", "_")
+ declaration = f"void {name}{arg_list};"
+ # Emit this
+ super().emit(dest, doxycomment, declaration)
class AsmLabel(AsmElement):
- def __init__(self, location, name, comment):
- super().__init__(location, name, comment)
+ def __init__(self, location, name, comment):
+ super().__init__(location, name, comment)
- def dump(self):
- super().dump()
- print(f"(Label)\n---")
+ def dump(self):
+ super().dump()
+ print(f"(Label)\n---")
- def emit(self, dest):
- # Build doxycomment specific for the variable
- doxycomment = ''
- doxycomment += self.comment
- if '@brief' not in doxycomment:
- doxycomment = '@brief ' + doxycomment
- # Build the declaration
- name = self.name.replace(".", "_")
- declaration = f"label {name};"
- # Emit this
- super().emit(dest, doxycomment, declaration)
+ def emit(self, dest):
+ # Build doxycomment specific for the variable
+ doxycomment = ''
+ doxycomment += self.comment
+ if '@brief' not in doxycomment:
+ doxycomment = '@brief ' + doxycomment
+ # Build the declaration
+ name = self.name.replace(".", "_")
+ declaration = f"label {name};"
+ # Emit this
+ super().emit(dest, doxycomment, declaration)
class AsmMacro(AsmElement):
- def __init__(self, location, name, comment, args):
- super().__init__(location, name, comment)
- self.args = args
+ def __init__(self, location, name, comment, args):
+ super().__init__(location, name, comment)
+ self.args = args
- def dump(self):
- super().dump()
- print(f"(Macro)\n---")
+ def dump(self):
+ super().dump()
+ print(f"(Macro)\n---")
- def emit(self, dest):
- # Construct arg list without '['s, ']'s and '*'s
- args = [arg for arg in self.args if arg not in "[]*"]
- # Construct C-like arg list
- arg_list = ""
- if len(args) > 0:
- arg_list += '('
- argc = 0
- for arg in args:
- if argc != 0:
- arg_list += ", "
- arg_list += arg
- argc += 1
- arg_list += ')'
- # Build doxycomment
- doxycomment = ''
- doxycomment += self.comment
- if '@brief' not in doxycomment:
- doxycomment = '@brief ' + doxycomment
- # Build declaration
- declaration = f"#define {self.name}{arg_list}"
- # Emit this
- super().emit(dest, doxycomment, declaration)
+ def emit(self, dest):
+ # Construct arg list without '['s, ']'s and '*'s
+ args = [arg for arg in self.args if arg not in "[]*"]
+ # Construct C-like arg list
+ arg_list = ""
+ if len(args) > 0:
+ arg_list += '('
+ argc = 0
+ for arg in args:
+ if argc != 0:
+ arg_list += ", "
+ arg_list += arg
+ argc += 1
+ arg_list += ')'
+ # Build doxycomment
+ doxycomment = ''
+ doxycomment += self.comment
+ if '@brief' not in doxycomment:
+ doxycomment = '@brief ' + doxycomment
+ # Build declaration
+ declaration = f"#define {self.name}{arg_list}"
+ # Emit this
+ super().emit(dest, doxycomment, declaration)
class AsmStruct(AsmElement):
- def __init__(self, location, name, comment, members):
- super().__init__(location, name, comment)
- self.members = members
+ def __init__(self, location, name, comment, members):
+ super().__init__(location, name, comment)
+ self.members = members
- def dump(self):
- super().dump()
- print(f"(Struct)\n---")
+ def dump(self):
+ super().dump()
+ print(f"(Struct)\n---")
- def emit(self, dest):
- # Build doxycomment
- doxycomment = ''
- doxycomment += self.comment
- if '@brief' not in doxycomment:
- doxycomment = '@brief ' + doxycomment
- doxycomment += '\n'
- # Build declaration
- declaration = f"struct {self.name}" + " {\n"
- for member in self.members:
- if type(member) == AsmVariable:
- declaration += f'\t{member.type} {member.name}; /**< {member.comment} */\n'
- declaration += '};'
- # Emit this
- super().emit(dest, doxycomment, declaration)
+ def emit(self, dest):
+ # Build doxycomment
+ doxycomment = ''
+ doxycomment += self.comment
+ if '@brief' not in doxycomment:
+ doxycomment = '@brief ' + doxycomment
+ doxycomment += '\n'
+ # Build declaration
+ declaration = f"struct {self.name}" + " {\n"
+ for member in self.members:
+ if type(member) == AsmVariable:
+ declaration += f'\t{member.type} {member.name}; /**< {member.comment} */\n'
+ declaration += '};'
+ # Emit this
+ super().emit(dest, doxycomment, declaration)
class AsmUnion(AsmElement):
- def __init__(self, location, name, comment, members):
- super().__init__(location, name, comment)
- self.members = members
+ def __init__(self, location, name, comment, members):
+ super().__init__(location, name, comment)
+ self.members = members
- def dump(self):
- super().dump()
- print(f"(Union)\n---")
+ def dump(self):
+ super().dump()
+ print(f"(Union)\n---")
- def emit(self, dest):
- # Build doxycomment
- doxycomment = ''
- doxycomment += self.comment
- if '@brief' not in doxycomment:
- doxycomment = '@brief ' + doxycomment
- # Build declaration
- declaration = f"union {self.name}" + " {};"
- # Emit this
- super().emit(dest, doxycomment, declaration)
+ def emit(self, dest):
+ # Build doxycomment
+ doxycomment = ''
+ doxycomment += self.comment
+ if '@brief' not in doxycomment:
+ doxycomment = '@brief ' + doxycomment
+ # Build declaration
+ declaration = f"union {self.name}" + " {};"
+ # Emit this
+ super().emit(dest, doxycomment, declaration)
class VariableNameIsMacroName:
- def __init__(self, name):
- self.name = name
+ def __init__(self, name):
+ self.name = name
def is_id(c):
- return c.isprintable() and c not in "+-/*=<>()[]{};:,|&~#`'\" \n\r\t\v"
+ return c.isprintable() and c not in "+-/*=<>()[]{};:,|&~#`'\" \n\r\t\v"
def is_starts_as_id(s):
- return not s[0].isdigit()
+ return not s[0].isdigit()
def parse_after_macro(r):
- location = r.location()
+ location = r.location()
- # Skip spaces after the "macro" keyword
- r.skip_spaces()
- # Read macro name
- name = ""
- while is_id(r.curr()) or r.curr() == '#':
- name += r.step()
- # Skip spaces after macro name
- r.skip_spaces()
- # Find all arguments
- args = []
- arg = ''
- while r.curr() and r.curr() != ';' and r.curr() != '{':
- # Collect identifier
- if is_id(r.curr()):
- arg += r.step()
- # Save the collected identifier
- elif r.curr() == ',':
- args.append(arg)
- arg = ''
- r.step()
- # Just push the '['
- elif r.curr() == '[':
- args.append(r.step())
- # Just push the identifier and get ']' ready to be pushed on next comma
- elif r.curr() == ']':
- args.append(arg)
- arg = r.step()
- # Just push the identifier and get '*' ready to be pushed on next comma
- elif r.curr() == '*':
- args.append(arg)
- arg = r.step()
- # Just skip whitespaces
- elif r.curr().isspace():
- r.step()
- # Something unexpected
- else:
- raise Exception(f"Unexpected symbol '{r.curr()}' at index #{r.i} " +
- f"in the macro declaration at {location} " +
- f"(line: {r.lines[r.line_idx]})\n''")
- # Append the last argument
- if arg != '':
- args.append(arg)
- # Skip t spaces after the argument list
- r.skip_spaces()
- # Get a comment if it is: read till the end of the line and get the comment from the reader
- while r.curr() != '':
- r.step()
- comment = r.comment
- # Find end of the macro
- prev = ''
- while True:
- if r.curr() == '}' and prev != '\\':
- break
- elif r.curr() == '':
- prev = ''
- r.nextline()
- continue
- prev = r.step()
- # Build the output
- return AsmMacro(location, name, comment, args)
+ # Skip spaces after the "macro" keyword
+ r.skip_spaces()
+ # Read macro name
+ name = ""
+ while is_id(r.curr()) or r.curr() == '#':
+ name += r.step()
+ # Skip spaces after macro name
+ r.skip_spaces()
+ # Find all arguments
+ args = []
+ arg = ''
+ while r.curr() and r.curr() != ';' and r.curr() != '{':
+ # Collect identifier
+ if is_id(r.curr()):
+ arg += r.step()
+ # Save the collected identifier
+ elif r.curr() == ',':
+ args.append(arg)
+ arg = ''
+ r.step()
+ # Just push the '['
+ elif r.curr() == '[':
+ args.append(r.step())
+ # Just push the identifier and get ']' ready to be pushed on next comma
+ elif r.curr() == ']':
+ args.append(arg)
+ arg = r.step()
+ # Just push the identifier and get '*' ready to be pushed on next comma
+ elif r.curr() == '*':
+ args.append(arg)
+ arg = r.step()
+ # Just skip whitespaces
+ elif r.curr().isspace():
+ r.step()
+ # Something unexpected
+ else:
+ raise Exception(f"Unexpected symbol '{r.curr()}' at index #{r.i} " +
+ f"in the macro declaration at {location} " +
+ f"(line: {r.lines[r.line_idx]})\n''")
+ # Append the last argument
+ if arg != '':
+ args.append(arg)
+ # Skip t spaces after the argument list
+ r.skip_spaces()
+ # Get a comment if it is: read till the end of the line and get the comment from the reader
+ while r.curr() != '':
+ r.step()
+ comment = r.comment
+ # Find end of the macro
+ prev = ''
+ while True:
+ if r.curr() == '}' and prev != '\\':
+ break
+ elif r.curr() == '':
+ prev = ''
+ r.nextline()
+ continue
+ prev = r.step()
+ # Build the output
+ return AsmMacro(location, name, comment, args)
def parse_variable(r, first_word = None):
- global warnings
- location = r.location()
+ global warnings
+ location = r.location()
- # Skip spaces before variable name
- r.skip_spaces()
- # Get variable name
- name = ""
- # Read it if it was not supplied
- if first_word == None:
- while is_id(r.curr()):
- name += r.step()
- # Or use the supplied one instead
- else:
- name = first_word
- # Check the name
- # If it's 0 len, that means threr's something else than an identifier at the beginning
- if len(name) == 0:
- return None
- # If it starts from digit or othervice illegally it's illegal
- if not is_starts_as_id(name):
- return None
- # Get kind of the identifier from id2kind table
- kind = id_get_kind(name)
- # If it's a keyword, that's not a variable declaration
- if ID_KIND_KEYWORD in kind:
- return None
- # If it's a macro name, that's not a variable declaration
- if ID_KIND_MACRO_NAME in kind:
- return VariableNameIsMacroName(name)
- # If it's a datatype or a structure name that's not a variable declaration: that's just a data
- # don't document just a data for now
- if ID_KIND_STRUCT_NAME in kind or ID_KIND_FASM_TYPE in kind:
- return None
- # Skip spaces before type name
- r.skip_spaces()
- # Read type name
- var_type = ""
- while is_id(r.curr()):
- var_type += r.step()
- # Check the type name
- if len(var_type) == 0:
- # If there's no type identifier after the name
- # maybe the name is something meaningful for the next parser
- # return it
- return name
- # If it starts from digit or othervice illegally it's illegal
- if not is_starts_as_id(var_type):
- return None
- # Get kind of type identifier
- type_kind = id_get_kind(var_type)
- # If it's a keyword, that's not a variable declaration
- # return the two words of the lexical structure
- if ID_KIND_KEYWORD in type_kind:
- return (name, var_type)
- # Skip spaces before the value
- r.skip_spaces()
- # Read the value until the comment or end of the line
- value = ""
- while r.curr() != ';' and r.curr() != '' and r.curr() != '\n':
- value += r.step()
- # Skip spaces after the value
- r.skip_spaces()
- # Read till end of the line to get a comment from the reader
- while r.curr() != '':
- r.step()
- # Build the result
- return AsmVariable(location, name, r.comment, var_type, value)
+ # Skip spaces before variable name
+ r.skip_spaces()
+ # Get variable name
+ name = ""
+ # Read it if it was not supplied
+ if first_word == None:
+ while is_id(r.curr()):
+ name += r.step()
+ # Or use the supplied one instead
+ else:
+ name = first_word
+ # Check the name
+ # If it's 0 len, that means threr's something else than an identifier at the beginning
+ if len(name) == 0:
+ return None
+ # If it starts from digit or othervice illegally it's illegal
+ if not is_starts_as_id(name):
+ return None
+ # Get kind of the identifier from id2kind table
+ kind = id_get_kind(name)
+ # If it's a keyword, that's not a variable declaration
+ if ID_KIND_KEYWORD in kind:
+ return None
+ # If it's a macro name, that's not a variable declaration
+ if ID_KIND_MACRO_NAME in kind:
+ return VariableNameIsMacroName(name)
+ # If it's a datatype or a structure name that's not a variable declaration: that's just a data
+ # don't document just a data for now
+ if ID_KIND_STRUCT_NAME in kind or ID_KIND_FASM_TYPE in kind:
+ return None
+ # Skip spaces before type name
+ r.skip_spaces()
+ # Read type name
+ var_type = ""
+ while is_id(r.curr()):
+ var_type += r.step()
+ # Check the type name
+ if len(var_type) == 0:
+ # If there's no type identifier after the name
+ # maybe the name is something meaningful for the next parser
+ # return it
+ return name
+ # If it starts from digit or othervice illegally it's illegal
+ if not is_starts_as_id(var_type):
+ return None
+ # Get kind of type identifier
+ type_kind = id_get_kind(var_type)
+ # If it's a keyword, that's not a variable declaration
+ # return the two words of the lexical structure
+ if ID_KIND_KEYWORD in type_kind:
+ return (name, var_type)
+ # Skip spaces before the value
+ r.skip_spaces()
+ # Read the value until the comment or end of the line
+ value = ""
+ while r.curr() != ';' and r.curr() != '' and r.curr() != '\n':
+ value += r.step()
+ # Skip spaces after the value
+ r.skip_spaces()
+ # Read till end of the line to get a comment from the reader
+ while r.curr() != '':
+ r.step()
+ # Build the result
+ return AsmVariable(location, name, r.comment, var_type, value)
def parse_after_struct(r, as_union = True):
- global warnings
- location = r.location()
+ global warnings
+ location = r.location()
- # Skip spaces after "struct" keyword
- r.skip_spaces()
- # Read struct name
- name = ""
- while is_id(r.curr()):
- name += r.step()
- # Read till end of the line and get the comment from the reader
- while r.curr() != '':
- r.step()
- comment = r.comment
- # Get to the next line to parse struct members
- r.nextline()
- # Parse struct members
- members = []
- while True:
- r.skip_spaces()
- var = parse_variable(r)
- if type(var) == AsmVariable:
- members.append(var)
- elif type(var) == str:
- if var == 'union':
- # Parse the union as a struct
- union = parse_after_struct(r, as_union = True)
- members.append(union)
- # Skip the ends of the union
- r.nextline()
- elif r.curr() == ':':
- warnings += f"{r.location()}: Skept the label in the struct\n"
- else:
- raise Exception(f"Garbage in struct member at {location} (got '{var}' identifier)")
- elif type(var) == VariableNameIsMacroName:
- if var.name == 'ends':
- break
- r.nextline()
- # Return the result
- if as_union:
- return AsmStruct(location, name, comment, members)
- else:
- return AsmUnion(location, name, comment, members)
+ # Skip spaces after "struct" keyword
+ r.skip_spaces()
+ # Read struct name
+ name = ""
+ while is_id(r.curr()):
+ name += r.step()
+ # Read till end of the line and get the comment from the reader
+ while r.curr() != '':
+ r.step()
+ comment = r.comment
+ # Get to the next line to parse struct members
+ r.nextline()
+ # Parse struct members
+ members = []
+ while True:
+ r.skip_spaces()
+ var = parse_variable(r)
+ if type(var) == AsmVariable:
+ members.append(var)
+ elif type(var) == str:
+ if var == 'union':
+ # Parse the union as a struct
+ union = parse_after_struct(r, as_union = True)
+ members.append(union)
+ # Skip the ends of the union
+ r.nextline()
+ elif r.curr() == ':':
+ warnings += f"{r.location()}: Skept the label in the struct\n"
+ else:
+ raise Exception(f"Garbage in struct member at {location} (got '{var}' identifier)")
+ elif type(var) == VariableNameIsMacroName:
+ if var.name == 'ends':
+ break
+ r.nextline()
+ # Return the result
+ if as_union:
+ return AsmStruct(location, name, comment, members)
+ else:
+ return AsmUnion(location, name, comment, members)
def parse_after_proc(r):
- # Get proc name
- name = r.fetch_identifier()
- # Next identifier after the proc name
- identifier = r.fetch_identifier()
- # Check if the id is 'stdcall' or 'c' (calling convention specifier)
- # and if so - save the convention and lookup the next identifier
- calling_convention = ''
- if identifier == 'stdcall' or identifier == 'c':
- calling_convention = identifier
- # If next is a comma, just skip it
- if r.curr() == ',':
- r.step()
- # Read the next identifier
- identifier = r.fetch_identifier()
- # Check if the id is 'uses' (used register list specifier)
- # and if so save the used register list
- used_regs = []
- if identifier == 'uses':
- # Read the registers
- while True:
- reg_name = r.fetch_identifier()
- if reg_name != '':
- used_regs.append(reg_name)
- else:
- break
- # If next is a comma, just skip it
- if r.curr() == ',':
- r.step()
- # Read the next identifier
- identifier = r.fetch_identifier()
- # Check if there are argument identifiers
- args = []
- while identifier != '':
- arg_name = identifier
- arg_type = 'arg_t'
- # Skip spaces after argument name
- r.skip_spaces()
- # If there's a ':' after the name - the next identifier is type
- if r.curr() == ':':
- r.step()
- arg_type = r.fetch_identifier()
- # If there's a comma - there's one more argument
- # else no arguments anymore
- if r.curr() == ',':
- r.step()
- identifier = r.fetch_identifier()
- else:
- identifier = ''
- args.append((arg_name, arg_type))
- # Get to the end of the line and get a comment from the reader
- while r.curr() != '':
- r.step()
- comment = r.comment
- # Build the element
- return AsmFunction(r.location(), name, comment, calling_convention, args, used_regs)
+ # Get proc name
+ name = r.fetch_identifier()
+ # Next identifier after the proc name
+ identifier = r.fetch_identifier()
+ # Check if the id is 'stdcall' or 'c' (calling convention specifier)
+ # and if so - save the convention and lookup the next identifier
+ calling_convention = ''
+ if identifier == 'stdcall' or identifier == 'c':
+ calling_convention = identifier
+ # If next is a comma, just skip it
+ if r.curr() == ',':
+ r.step()
+ # Read the next identifier
+ identifier = r.fetch_identifier()
+ # Check if the id is 'uses' (used register list specifier)
+ # and if so save the used register list
+ used_regs = []
+ if identifier == 'uses':
+ # Read the registers
+ while True:
+ reg_name = r.fetch_identifier()
+ if reg_name != '':
+ used_regs.append(reg_name)
+ else:
+ break
+ # If next is a comma, just skip it
+ if r.curr() == ',':
+ r.step()
+ # Read the next identifier
+ identifier = r.fetch_identifier()
+ # Check if there are argument identifiers
+ args = []
+ while identifier != '':
+ arg_name = identifier
+ arg_type = 'arg_t'
+ # Skip spaces after argument name
+ r.skip_spaces()
+ # If there's a ':' after the name - the next identifier is type
+ if r.curr() == ':':
+ r.step()
+ arg_type = r.fetch_identifier()
+ # If there's a comma - there's one more argument
+ # else no arguments anymore
+ if r.curr() == ',':
+ r.step()
+ identifier = r.fetch_identifier()
+ else:
+ identifier = ''
+ args.append((arg_name, arg_type))
+ # Get to the end of the line and get a comment from the reader
+ while r.curr() != '':
+ r.step()
+ comment = r.comment
+ # Build the element
+ return AsmFunction(r.location(), name, comment, calling_convention, args, used_regs)
def get_declarations(asm_file_contents, asm_file_name):
- r = AsmReader(asm_file_name)
+ r = AsmReader(asm_file_name)
- while not r.no_lines():
- # Skip leading spaces
- r.skip_spaces()
- # Skip the line if it's starting with a comment
- if r.curr() == ';':
- r.nextline()
- continue
- # Get first word
- first_word = ""
- while is_id(r.curr()):
- first_word += r.step()
- # Match macro declaration
- if first_word == "macro":
- macro = parse_after_macro(r)
- elements.append(macro)
- id_add_kind(macro.name, ID_KIND_MACRO_NAME)
- # Match structure declaration
- elif first_word == "struct":
- struct = parse_after_struct(r)
- elements.append(struct)
- id_add_kind(struct.name, ID_KIND_STRUCT_NAME)
- # Match function definition
- elif first_word == "proc":
- proc = parse_after_proc(r)
- elements.append(proc)
- elif first_word == 'format':
- # Skip the format directive
- pass
- elif first_word == 'include':
- # Skip the include directive
- pass
- elif first_word == 'if':
- # Skip the conditional directive
- pass
- elif first_word == 'repeat':
- # Skip the repeat directive
- pass
- elif first_word == 'purge':
- while True:
- # Skip spaces after the 'purge' keyword or after the comma what separated the previous macro name
- r.skip_spaces()
- # Get the purged macro name
- name = ''
- while is_id(r.curr()):
- name += r.step()
- # Remove the purged macro from the macro names list
- try:
- id_remove_kind(name, ID_KIND_MACRO_NAME)
- except:
- pass
- # Skip spaces after the name
- r.skip_spaces()
- # If it's comma (',') after then that's not the last purged macro, continue purging
- if r.curr() == ',':
- r.step()
- continue
- # Here we purged all the macros should be purged
- break
- # Match label or a variable
- elif len(first_word) != 0:
- # Skip spaces after the identifier
- r.skip_spaces()
- # Match a variable
- var = parse_variable(r, first_word)
- if type(var) == AsmVariable:
- elements.append(var)
- # If it wasn't a variable but there was an identifier
- # Maybe that's a label and the identifier is the label name
- # The parse_variable returns the first found or supplied identifier
- # In this case it returns the first_word which is supplied
- # If it didn't match a type identifier after the word
- elif type(var) == str:
- name = var
- # Match label beginning (':' after name)
- if r.curr() == ':':
- # Get to the end of the line and get the coment from the reader
- while r.curr() != '':
- r.step()
- comment = r.comment
- # Only handle non-local labels
- if name[0] != '.' and name != "@@" and name != "$Revision":
- if '@return' in comment or '@param' in comment:
- element = AsmFunction(r.location(), name, comment, '', [], [])
- else:
- element = AsmLabel(r.location(), name, comment)
- elements.append(element)
- elif r.curr() == '=':
- # Save the identifier as a set constant
- id_add_kind(first_word, ID_KIND_SET_CONSTANT)
- elif type(var) == tuple:
- (word_one, word_two) = var
- if word_two == 'equ':
- # Save the identifier as an equated constant
- id_add_kind(word_one, ID_KIND_EQUATED_CONSTANT)
- r.nextline()
+ while not r.no_lines():
+ # Skip leading spaces
+ r.skip_spaces()
+ # Skip the line if it's starting with a comment
+ if r.curr() == ';':
+ r.nextline()
+ continue
+ # Get first word
+ first_word = ""
+ while is_id(r.curr()):
+ first_word += r.step()
+ # Match macro declaration
+ if first_word == "macro":
+ macro = parse_after_macro(r)
+ elements.append(macro)
+ id_add_kind(macro.name, ID_KIND_MACRO_NAME)
+ # Match structure declaration
+ elif first_word == "struct":
+ struct = parse_after_struct(r)
+ elements.append(struct)
+ id_add_kind(struct.name, ID_KIND_STRUCT_NAME)
+ # Match function definition
+ elif first_word == "proc":
+ proc = parse_after_proc(r)
+ elements.append(proc)
+ elif first_word == 'format':
+ # Skip the format directive
+ pass
+ elif first_word == 'include':
+ # Skip the include directive
+ pass
+ elif first_word == 'if':
+ # Skip the conditional directive
+ pass
+ elif first_word == 'repeat':
+ # Skip the repeat directive
+ pass
+ elif first_word == 'purge':
+ while True:
+ # Skip spaces after the 'purge' keyword or after the comma what separated the previous macro name
+ r.skip_spaces()
+ # Get the purged macro name
+ name = ''
+ while is_id(r.curr()):
+ name += r.step()
+ # Remove the purged macro from the macro names list
+ try:
+ id_remove_kind(name, ID_KIND_MACRO_NAME)
+ except:
+ pass
+ # Skip spaces after the name
+ r.skip_spaces()
+ # If it's comma (',') after then that's not the last purged macro, continue purging
+ if r.curr() == ',':
+ r.step()
+ continue
+ # Here we purged all the macros should be purged
+ break
+ # Match label or a variable
+ elif len(first_word) != 0:
+ # Skip spaces after the identifier
+ r.skip_spaces()
+ # Match a variable
+ var = parse_variable(r, first_word)
+ if type(var) == AsmVariable:
+ elements.append(var)
+ # If it wasn't a variable but there was an identifier
+ # Maybe that's a label and the identifier is the label name
+ # The parse_variable returns the first found or supplied identifier
+ # In this case it returns the first_word which is supplied
+ # If it didn't match a type identifier after the word
+ elif type(var) == str:
+ name = var
+ # Match label beginning (':' after name)
+ if r.curr() == ':':
+ # Get to the end of the line and get the coment from the reader
+ while r.curr() != '':
+ r.step()
+ comment = r.comment
+ # Only handle non-local labels
+ if name[0] != '.' and name != "@@" and name != "$Revision":
+ if '@return' in comment or '@param' in comment:
+ element = AsmFunction(r.location(), name, comment, '', [], [])
+ else:
+ element = AsmLabel(r.location(), name, comment)
+ elements.append(element)
+ elif r.curr() == '=':
+ # Save the identifier as a set constant
+ id_add_kind(first_word, ID_KIND_SET_CONSTANT)
+ elif type(var) == tuple:
+ (word_one, word_two) = var
+ if word_two == 'equ':
+ # Save the identifier as an equated constant
+ id_add_kind(word_one, ID_KIND_EQUATED_CONSTANT)
+ r.nextline()
def it_neds_to_be_parsed(source_file):
- # If there's no symbols file saved - parse it anyway
- # cause we need to create the symbols file and use it
- # if we gonna generate proper doxygen
- if not os.path.isfile('asmxygen.elements.pickle'):
- return True
- dest = doxygen_src_path + '/' + source_file
- # If there's no the doxygen file it should be compiled to
- # then yes, we should compile it to doxygen
- if not os.path.isfile(dest):
- return True
- source_change_time = os.path.getmtime(source_file)
- dest_change_file = os.path.getmtime(dest)
- # If the source is newer than the doxygen it was compiled to
- # then the source should be recompiled (existing doxygen is old)
- if source_change_time > dest_change_file:
- return True
- return False
+ # If there's no symbols file saved - parse it anyway
+ # cause we need to create the symbols file and use it
+ # if we gonna generate proper doxygen
+ if not os.path.isfile('asmxygen.elements.pickle'):
+ return True
+ dest = doxygen_src_path + '/' + source_file
+ # If there's no the doxygen file it should be compiled to
+ # then yes, we should compile it to doxygen
+ if not os.path.isfile(dest):
+ return True
+ source_change_time = os.path.getmtime(source_file)
+ dest_change_file = os.path.getmtime(dest)
+ # If the source is newer than the doxygen it was compiled to
+ # then the source should be recompiled (existing doxygen is old)
+ if source_change_time > dest_change_file:
+ return True
+ return False
def handle_file(handled_files, asm_file_name, subdir = "."):
- global elements
- # Canonicalize the file path and get it relative to cwd
- cwd = os.path.abspath(os.path.dirname(sys.argv[0]))
- asm_file_name = os.path.realpath(asm_file_name)
- asm_file_name = asm_file_name[len(cwd) + 1:]
- # If it's lang.inc - skip it
- if asm_file_name == 'lang.inc':
- return
- # If the file was handled in this execution before - skip it
- if asm_file_name in handled_files:
- return
- # Say that the file was handled in this execution
- handled_files.append(asm_file_name)
- # Check if the file should be parsed (if it was modified or wasn't parsed yet)
- should_get_declarations = True
- if not it_neds_to_be_parsed(asm_file_name):
- print(f"Skipping {asm_file_name} (already newest)")
- should_get_declarations = False
- else:
- print(f"Handling {asm_file_name}")
- # Remove elements parsed from this file before if any
- elements_to_remove = [x for x in elements if x.location.split(':')[0] == asm_file_name]
- elements = [x for x in elements if x.location.split(':')[0] != asm_file_name]
- # Forget types of identifiers of names of the removed elements
- for element in elements_to_remove:
- if type(element) == AsmStruct:
- id_remove_kind(element.name, ID_KIND_STRUCT_NAME)
- elif type(element) == AsmMacro:
- id_remove_kind(element.name, ID_KIND_MACRO_NAME)
- # Read the source
- asm_file_contents = open(asm_file_name, "r", encoding="utf-8").read()
- # Find includes, fix their paths and handle em recoursively
- includes = re.findall(r'^include (["\'])(.*)\1', asm_file_contents, flags=re.MULTILINE)
- for include in includes:
- include = include[1].replace('\\', '/');
- full_path = subdir + '/' + include;
- # If the path isn't valid, maybe that's not relative path
- if not os.path.isfile(full_path):
- full_path = include
- new_subdir = full_path.rsplit('/', 1)[0]
- handle_file(handled_files, full_path, new_subdir)
- # Only collect declarations from the file if it wasn't parsed before
- if should_get_declarations and not clean_generated_stuff:
- get_declarations(asm_file_contents, asm_file_name)
+ global elements
+ # Canonicalize the file path and get it relative to cwd
+ cwd = os.path.abspath(os.path.dirname(sys.argv[0]))
+ asm_file_name = os.path.realpath(asm_file_name)
+ asm_file_name = asm_file_name[len(cwd) + 1:]
+ # If it's lang.inc - skip it
+ if asm_file_name == 'lang.inc':
+ return
+ # If the file was handled in this execution before - skip it
+ if asm_file_name in handled_files:
+ return
+ # Say that the file was handled in this execution
+ handled_files.append(asm_file_name)
+ # Check if the file should be parsed (if it was modified or wasn't parsed yet)
+ should_get_declarations = True
+ if not it_neds_to_be_parsed(asm_file_name):
+ print(f"Skipping {asm_file_name} (already newest)")
+ should_get_declarations = False
+ else:
+ print(f"Handling {asm_file_name}")
+ # Remove elements parsed from this file before if any
+ elements_to_remove = [x for x in elements if x.location.split(':')[0] == asm_file_name]
+ elements = [x for x in elements if x.location.split(':')[0] != asm_file_name]
+ # Forget types of identifiers of names of the removed elements
+ for element in elements_to_remove:
+ if type(element) == AsmStruct:
+ id_remove_kind(element.name, ID_KIND_STRUCT_NAME)
+ elif type(element) == AsmMacro:
+ id_remove_kind(element.name, ID_KIND_MACRO_NAME)
+ # Read the source
+ asm_file_contents = open(asm_file_name, "r", encoding="utf-8").read()
+ # Find includes, fix their paths and handle em recoursively
+ includes = re.findall(r'^include (["\'])(.*)\1', asm_file_contents, flags=re.MULTILINE)
+ for include in includes:
+ include = include[1].replace('\\', '/');
+ full_path = subdir + '/' + include;
+ # If the path isn't valid, maybe that's not relative path
+ if not os.path.isfile(full_path):
+ full_path = include
+ new_subdir = full_path.rsplit('/', 1)[0]
+ handle_file(handled_files, full_path, new_subdir)
+ # Only collect declarations from the file if it wasn't parsed before
+ if should_get_declarations and not clean_generated_stuff:
+ get_declarations(asm_file_contents, asm_file_name)
if __name__ == "__main__":
- link_root = "http://websvn.kolibrios.org/filedetails.php?repname=Kolibri+OS&path=/kernel/trunk"
+ link_root = "http://websvn.kolibrios.org/filedetails.php?repname=Kolibri+OS&path=/kernel/trunk"
- # Dict where an identifier is assicoated with a string
- # The string contains characters specifying flags
- # Available flags:
- # k - Keyword
- # m - Macro name
- # t - fasm data Type name (db, rq, etc.)
- # s - Struct type name
- # e - equated constant (name equ value)
- # = - set constants (name = value)
- ID_KIND_KEYWORD = 'k'
- ID_KIND_MACRO_NAME = 'm'
- ID_KIND_FASM_TYPE = 't'
- ID_KIND_STRUCT_NAME = 's'
- ID_KIND_EQUATED_CONSTANT = 'e'
- ID_KIND_SET_CONSTANT = '='
- id2kind = {}
+ # Dict where an identifier is assicoated with a string
+ # The string contains characters specifying flags
+ # Available flags:
+ # k - Keyword
+ # m - Macro name
+ # t - fasm data Type name (db, rq, etc.)
+ # s - Struct type name
+ # e - equated constant (name equ value)
+ # = - set constants (name = value)
+ ID_KIND_KEYWORD = 'k'
+ ID_KIND_MACRO_NAME = 'm'
+ ID_KIND_FASM_TYPE = 't'
+ ID_KIND_STRUCT_NAME = 's'
+ ID_KIND_EQUATED_CONSTANT = 'e'
+ ID_KIND_SET_CONSTANT = '='
+ id2kind = {}
- for keyword in keywords:
- id_add_kind(keyword, ID_KIND_KEYWORD)
+ for keyword in keywords:
+ id_add_kind(keyword, ID_KIND_KEYWORD)
- for fasm_type in fasm_types:
- id_add_kind(fasm_type, ID_KIND_FASM_TYPE)
+ for fasm_type in fasm_types:
+ id_add_kind(fasm_type, ID_KIND_FASM_TYPE)
- # Warning list
- warnings = ""
+ # Warning list
+ warnings = ""
- # Parameters
- # Path to doxygen folder to make doxygen files in: -o
- doxygen_src_path = 'docs/doxygen'
- # Remove generated doxygen files: --clean
- clean_generated_stuff = False
- # Dump all defined symbols: --dump
- dump_symbols = False
- # Print symbol stats: --stats
- print_stats = False
- # Do not write warnings file: --nowarn
- enable_warnings = True
+ # Parameters
+ # Path to doxygen folder to make doxygen files in: -o
+ doxygen_src_path = 'docs/doxygen'
+ # Remove generated doxygen files: --clean
+ clean_generated_stuff = False
+ # Dump all defined symbols: --dump
+ dump_symbols = False
+ # Print symbol stats: --stats
+ print_stats = False
+ # Do not write warnings file: --nowarn
+ enable_warnings = True
- # Parse arguments
- parser = argparse.ArgumentParser()
- parser.add_argument("-o", help="Doxygen output folder")
- parser.add_argument("--clean", help="Remove generated files", action="store_true")
- parser.add_argument("--dump", help="Dump all defined symbols", action="store_true")
- parser.add_argument("--stats", help="Print symbol stats", action="store_true")
- parser.add_argument("--nowarn", help="Do not write warnings file", action="store_true")
- parser.add_argument("--noemit", help="Do not emit doxygen files (for testing)", action="store_true")
- parser.add_argument("--debug", help="Show hashes of files (for testing)", action="store_true")
- args = parser.parse_args()
- doxygen_src_path = args.o if args.o else 'docs/doxygen'
- clean_generated_stuff = args.clean
- dump_symbols = args.dump
- print_stats = args.stats
- enable_warnings = not args.nowarn
- noemit = args.noemit
- debug_mode = args.debug
+ # Parse arguments
+ parser = argparse.ArgumentParser()
+ parser.add_argument("-o", help="Doxygen output folder")
+ parser.add_argument("--clean", help="Remove generated files", action="store_true")
+ parser.add_argument("--dump", help="Dump all defined symbols", action="store_true")
+ parser.add_argument("--stats", help="Print symbol stats", action="store_true")
+ parser.add_argument("--nowarn", help="Do not write warnings file", action="store_true")
+ parser.add_argument("--noemit", help="Do not emit doxygen files (for testing)", action="store_true")
+ parser.add_argument("--debug", help="Show hashes of files (for testing)", action="store_true")
+ args = parser.parse_args()
+ doxygen_src_path = args.o if args.o else 'docs/doxygen'
+ clean_generated_stuff = args.clean
+ dump_symbols = args.dump
+ print_stats = args.stats
+ enable_warnings = not args.nowarn
+ noemit = args.noemit
+ debug_mode = args.debug
- # Variables, functions, labels, macros, structure types
- elements = []
- created_files = []
- kernel_files = []
- output_files = {} # If --debug then all the files are written here
+ # Variables, functions, labels, macros, structure types
+ elements = []
+ created_files = []
+ kernel_files = []
+ output_files = {} # If --debug then all the files are written here
- # Load remembered list of symbols
- if os.path.isfile('asmxygen.elements.pickle'):
- print('Reading existing dump of symbols')
- (elements, id2kind) = pickle.load(open('asmxygen.elements.pickle', 'rb'))
+ # Load remembered list of symbols
+ if os.path.isfile('asmxygen.elements.pickle'):
+ print('Reading existing dump of symbols')
+ (elements, id2kind) = pickle.load(open('asmxygen.elements.pickle', 'rb'))
- handle_file(kernel_files, "./kernel.asm");
+ handle_file(kernel_files, "./kernel.asm");
- if dump_symbols:
- stdout = sys.stdout
- sys.stdout = open('asmxygen.dump.txt', 'w', encoding = 'utf-8')
- for asm_element in elements:
- asm_element.dump()
- sys.stdout = stdout
+ if dump_symbols:
+ stdout = sys.stdout
+ sys.stdout = open('asmxygen.dump.txt', 'w', encoding = 'utf-8')
+ for asm_element in elements:
+ asm_element.dump()
+ sys.stdout = stdout
- if clean_generated_stuff:
- kernel_files_set = set(kernel_files)
- for file in kernel_files:
- doxygen_file = f"{doxygen_src_path}/{file}"
- if (os.path.isfile(doxygen_file)):
- print(f"Removing {file}... ", end = '')
- os.remove(doxygen_file)
- print("Done.")
- elif not noemit:
- print(f"Writing doumented sources to {doxygen_src_path}")
+ if clean_generated_stuff:
+ kernel_files_set = set(kernel_files)
+ for file in kernel_files:
+ doxygen_file = f"{doxygen_src_path}/{file}"
+ if (os.path.isfile(doxygen_file)):
+ print(f"Removing {file}... ", end = '')
+ os.remove(doxygen_file)
+ print("Done.")
+ elif not noemit:
+ print(f"Writing doumented sources to {doxygen_src_path}")
- i = 0
- new_elements = [x for x in elements if x.new]
- for element in new_elements:
- print(f"[{i + 1}/{len(new_elements)}] Emitting {element.name} from {element.location}")
- element.emit(doxygen_src_path)
- i += 1
+ i = 0
+ new_elements = [x for x in elements if x.new]
+ for element in new_elements:
+ print(f"[{i + 1}/{len(new_elements)}] Emitting {element.name} from {element.location}")
+ element.emit(doxygen_src_path)
+ i += 1
- print(f"Writing dump of symbols to asmxygen.elements.pickle")
+ print(f"Writing dump of symbols to asmxygen.elements.pickle")
- # Now when the new elements already was written, there's no new elements anymore
- for element in elements:
- element.new = False
- pickle.dump((elements, id2kind), open('asmxygen.elements.pickle', 'wb'))
+ # Now when the new elements already was written, there's no new elements anymore
+ for element in elements:
+ element.new = False
+ pickle.dump((elements, id2kind), open('asmxygen.elements.pickle', 'wb'))
- if print_stats:
- var_count = 0
- mac_count = 0
- lab_count = 0
- fun_count = 0
- uni_count = 0
- str_count = 0
- for element in elements:
- if type(element) == AsmVariable:
- var_count += 1
- elif type(element) == AsmMacro:
- mac_count += 1
- elif type(element) == AsmLabel:
- lab_count += 1
- elif type(element) == AsmFunction:
- fun_count += 1
- elif type(element) == AsmUnion:
- uni_count += 1
- elif type(element) == AsmStruct:
- str_count += 1
- print(f'Parsed variable count: {var_count}')
- print(f'Parsed macro count: {mac_count}')
- print(f'Parsed label count: {lab_count}')
- print(f'Parsed function count: {fun_count}')
- print(f'Parsed union type count: {uni_count}')
- print(f'Parsed structure type count: {str_count}')
+ if print_stats:
+ var_count = 0
+ mac_count = 0
+ lab_count = 0
+ fun_count = 0
+ uni_count = 0
+ str_count = 0
+ for element in elements:
+ if type(element) == AsmVariable:
+ var_count += 1
+ elif type(element) == AsmMacro:
+ mac_count += 1
+ elif type(element) == AsmLabel:
+ lab_count += 1
+ elif type(element) == AsmFunction:
+ fun_count += 1
+ elif type(element) == AsmUnion:
+ uni_count += 1
+ elif type(element) == AsmStruct:
+ str_count += 1
+ print(f'Parsed variable count: {var_count}')
+ print(f'Parsed macro count: {mac_count}')
+ print(f'Parsed label count: {lab_count}')
+ print(f'Parsed function count: {fun_count}')
+ print(f'Parsed union type count: {uni_count}')
+ print(f'Parsed structure type count: {str_count}')
- if enable_warnings:
- open('asmxygen.txt', "w", encoding = "utf-8").write(warnings)
+ if enable_warnings:
+ open('asmxygen.txt', "w", encoding = "utf-8").write(warnings)
- if debug_mode:
- hash_per_file = ""
- for file in output_files:
- h = hashlib.sha1(bytes(output_files[file], "ascii")).hexdigest()
- hash_per_file += f"{file}: {h}\n"
- if not os.path.exists("asmxygen_hash_per_file.txt"):
- open("asmxygen_hash_per_file.txt", "w").write(hash_per_file)
- print("NEW")
- else:
- reference_hash_per_file = open("asmxygen_hash_per_file.txt").read()
- if reference_hash_per_file != hash_per_file:
- print(''.join(difflib.ndiff(reference_hash_per_file, hash_per_file)))
- else:
- print("SUCCESS")
+ if debug_mode:
+ hash_per_file = ""
+ for file in output_files:
+ h = hashlib.sha1(bytes(output_files[file], "ascii")).hexdigest()
+ hash_per_file += f"{file}: {h}\n"
+ if not os.path.exists("asmxygen_hash_per_file.txt"):
+ open("asmxygen_hash_per_file.txt", "w").write(hash_per_file)
+ print("NEW")
+ else:
+ reference_hash_per_file = open("asmxygen_hash_per_file.txt").read()
+ if reference_hash_per_file != hash_per_file:
+ print(''.join(difflib.ndiff(reference_hash_per_file, hash_per_file)))
+ else:
+ print("SUCCESS")