"""Parser for FBNeo source files to extract BIOS sets and ROM definitions. Parses BurnRomInfo structs (static ROM arrays) and BurnDriver structs (driver registration) from FBNeo C source files. BIOS sets are identified by the BDF_BOARDROM flag in BurnDriver definitions. """ from __future__ import annotations import os import re from pathlib import Path _ROM_ENTRY_RE = re.compile( r'\{\s*"([^"]+)"\s*,\s*(0x[\da-fA-F]+)\s*,\s*(0x[\da-fA-F]+)\s*,\s*([^}]+)\}', ) _BURN_DRIVER_RE = re.compile( r"struct\s+BurnDriver\s+BurnDrv(\w+)\s*=\s*\{(.*?)\};", re.DOTALL, ) _ROM_DESC_RE = re.compile( r"static\s+struct\s+BurnRomInfo\s+(\w+)RomDesc\s*\[\s*\]\s*=\s*\{(.*?)\};", re.DOTALL, ) def find_bios_sets(source: str, filename: str) -> dict[str, dict]: """Find BDF_BOARDROM drivers in source code. Returns a dict mapping set name to metadata: {set_name: {"source_file": str, "source_line": int}} """ results: dict[str, dict] = {} for match in _BURN_DRIVER_RE.finditer(source): body = match.group(2) if "BDF_BOARDROM" not in body: continue # Set name is the first quoted string in the struct body name_match = re.search(r'"([^"]+)"', body) if not name_match: continue set_name = name_match.group(1) line_num = source[: match.start()].count("\n") + 1 results[set_name] = { "source_file": filename, "source_line": line_num, } return results def parse_rom_info(source: str, set_name: str) -> list[dict]: """Parse a BurnRomInfo array for the given set name. Returns a list of dicts with keys: name, size, crc32. Sentinel entries (empty name) are skipped. """ pattern = re.compile( r"static\s+struct\s+BurnRomInfo\s+" + re.escape(set_name) + r"RomDesc\s*\[\s*\]\s*=\s*\{(.*?)\};", re.DOTALL, ) match = pattern.search(source) if not match: return [] body = match.group(1) roms: list[dict] = [] for entry in _ROM_ENTRY_RE.finditer(body): name = entry.group(1) if not name: continue size = int(entry.group(2), 16) crc32 = format(int(entry.group(3), 16), "08x") roms.append( { "name": name, "size": size, "crc32": crc32, } ) return roms def parse_fbneo_source_tree(base_path: str) -> dict[str, dict]: """Walk the FBNeo driver source tree and extract all BIOS sets. Scans .cpp files under src/burn/drv/ for BDF_BOARDROM drivers, then parses their associated BurnRomInfo arrays. Returns a dict mapping set name to: {source_file, source_line, roms: [{name, size, crc32}, ...]} """ drv_path = Path(base_path) / "src" / "burn" / "drv" if not drv_path.is_dir(): return {} results: dict[str, dict] = {} for root, _dirs, files in os.walk(drv_path): for fname in files: if not fname.endswith(".cpp"): continue filepath = Path(root) / fname source = filepath.read_text(encoding="utf-8", errors="replace") rel_path = str(filepath.relative_to(base_path)) bios_sets = find_bios_sets(source, rel_path) for set_name, meta in bios_sets.items(): roms = parse_rom_info(source, set_name) results[set_name] = { "source_file": meta["source_file"], "source_line": meta["source_line"], "roms": roms, } return results