#!/usr/bin/env python3 import os import re import sys from pathlib import Path def strip_c_comments(text): def replacer(match): s = match.group(0) if s.startswith("/"): return " " else: return s pattern = re.compile( r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', re.DOTALL | re.MULTILINE, ) return re.sub(pattern, replacer, text) c_func_pattern = re.compile(r"^(static\s+)?[^\s]+\s+([^\s(]+)\(([^;)]*)\)[^;]+{", re.MULTILINE) def funcs_in_c(text): return (match.group(2) for match in c_func_pattern.finditer(text)) asm_func_pattern = re.compile(r"INCLUDE_ASM\([^,]+, [^,]+, ([^,)]+)", re.MULTILINE) def include_asms_in_c(text): return (match.group(1) for match in asm_func_pattern.finditer(text)) def stuff(version): DIR = os.path.dirname(__file__) NONMATCHINGS_DIR = Path(os.path.join(DIR, "ver", version, "asm", "nonmatchings")) C_FILES = Path(os.path.join(DIR, "src")).rglob("*.c") ASM_FILES = NONMATCHINGS_DIR.rglob("*.s") matched = [] asm = [] for filename in C_FILES: with open(filename, "r") as file: text = strip_c_comments(file.read()) matched.extend((m for m in funcs_in_c(text) if not m in matched)) asm.extend((m for m in include_asms_in_c(text) if not m in asm)) non_matched = [os.path.splitext(os.path.basename(filename))[0] for filename in ASM_FILES] partial_matched = [f for f in matched if f in asm] matched = [f for f in matched if not f in partial_matched] matched_but_undeleted_asm = set([f for f in matched if f in non_matched and not f in partial_matched]) orphan_asm = set(non_matched) - set(asm) - matched_but_undeleted_asm to_delete = matched_but_undeleted_asm | orphan_asm if __name__ == "__main__": if "--help" in sys.argv: print("--fail-undeleted exit with error code 1 if obsolete .s functions exist") print("--delete delete obsolete .s functions without asking") exit() if len(to_delete) > 0: print(f"The following functions can be deleted: {to_delete}") if "--fail-undeleted" in sys.argv: exit(1) elif "--delete" in sys.argv or input("Delete them [y/N]? ").upper() == "Y": for func in to_delete: f = next(NONMATCHINGS_DIR.rglob(func + ".s")) os.remove(f) # Remove empty directories for folder in list(os.walk(NONMATCHINGS_DIR)): if not os.listdir(folder[0]): os.removedirs(folder[0]) stuff("jp") stuff("us") stuff("pal") stuff("ique")