Files
BFM-decomp/tools/sunset/gen_engine_decls.py
T
Drew T 827295e241 tools+docs(phase-33.5): task 13.5 — the tools audit + the two dictionaries: tools/tool_census.py (two agreeing enumerations of 327 tool files; docstring/SETUP row/consumers/class derived from the tree; the authored half in config/tool_dictionary.tsv — phase · portability · the NEED each tool answers · what · adapts · verdict — with coverage asserted both ways) → docs/tool-index.md (need-keyed, KEEP-GEN, Reference-index row, wiki + how-to pointers), the kit's tools/MANIFEST.md regenerated (header states live 293 + superseded 28 = 321 rows), and the two verbatim corpora in-tree (Drew, confirmed S91): decomp-architect/corpus/tools/<phase>/ (302 copies + 28 superseded pointers + INDEX) and corpus/cookbook/ (the cookbook, its symptom index, the codegen map, a front page stating what transfers per compiler) — sha1-equal to their sources by tool_census --check in tools-health, regenerated by make kit-corpus; kit_lint exempts the corpus dirs (verbatim evidence) but syntax-checks them; G66 (consult the tool dictionary first) + G67 (translate an inherited idiom through its pass) + two memory seeds (34 at install); SETUP Step 6 installs docs/knowledge-corpus.md and checks the manifest against its own stated total; the ops-setup dictionary rows; the intake's Phase 7 cites G66/G67 and Phase 10 + Part C name the raw-cast → declared-symbol step; templates/layout-contract.md (the five-tool probe, a draft for the split). The review under Drew's criterion: 93 no-consumer tools (one Opus agent's draft, verified: 0 defects, every successor live, 0 live consumers, 0 collisions; four one-off verdicts overturned to STILL-NEEDED) → 34 retired by git mv to tools/sunset/ (28 superseded, 6 one-offs; README review table; SETUP rows moved; Archive-index group). Run 4 (fresh throwaway, the final kit): stopped on my Step-6 check (321 vs the live 293) → both sides derived → resumed → PASS 10/10, manifest 56 == 56, 4 commits, guardrails held (the one foreign path was the timeline regenerated by the detached tools-health). tools-health OK; doc_links --strict rc 0; audit_public OK over 6,842 paths; the purge probe PASSED (Phase 34's gate open). decision-log "P33.5 S91" + accelerators "P33.5 S91" banked; log + checkpoint (NEXT = task 14, xHigh, fresh session)
2026-09-07 22:09:15 -06:00

105 lines
4.6 KiB
Python

#!/usr/bin/env python3
"""gen_engine_decls.py — the canonical-decls header (Phase 16, Drew's "lever 1", cookbook §14c-c).
Declare EVERY engine function (from its definition signature) and EVERY data symbol ONCE, canonically,
in src/shared/engine_decls.h. The overlay .c includes it; harvest drafts then strip ALL their own
declarations -> a draft can NEVER conflict with engine_core.h's definitions or another draft's guess.
This dissolves the dominant whole-binary gate-failure (`conflicting types for func_X`) on call-heavy
functions, which m2c declares with a guessed signature (and without `extern`, so sig_unify misses them).
python3 tools/gen_engine_decls.py # regenerate src/shared/engine_decls.h
"""
import os, re
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
ECORE = os.path.join(REPO, "src/shared/engine_core.h")
OVC = os.path.join(REPO, "src/ov_SC01_077/ov_SC01_077.c")
OUT = os.path.join(REPO, "src/shared/engine_decls.h")
# a function DEFINITION signature: `<ret> func_XXXX(<params>) {` (in an engine_core.h macro or inline)
DEF_RE = re.compile(r"\b([A-Za-z_][\w \*]*\bfunc_[0-9A-Fa-f]+\s*\([^){;]*\))\s*\{")
DATA_RE = re.compile(r"extern\s+([A-Za-z_][\w\s\*]*?\bD_[0-9A-Fa-f]+\s*(?:\[\s*\])?)\s*;")
SCALARS = {"void", "u8", "u16", "u32", "s8", "s16", "s32", "u64", "s64", "f32", "f64", "char",
"int", "short", "long", "unsigned", "signed", "float", "double",
"M2C_UNK", "M2C_UNK8", "M2C_UNK16", "M2C_UNK32", "M2C_UNK64"}
def known_structs():
"""struct names declared in engine_types.h (forward decls + defs)."""
names = set()
p = os.path.join(REPO, "src/shared/engine_types.h")
if os.path.exists(p):
for m in re.finditer(r"\b(?:struct|union)\s+([A-Za-z_]\w*)", open(p).read()):
names.add(m.group(1))
return names
def resolvable(sig, structs):
"""True iff every type token in the signature is a scalar or a known shared struct/union."""
s = re.sub(r"\bfunc_[0-9A-Fa-f]+\b", "", sig) # drop the function name
s = re.sub(r"\b[a-z_]\w*\s*(?=[,)])", "", s) # drop param names (lowercase, before , or ))
for m in re.finditer(r"\b(struct|union)\s+([A-Za-z_]\w*)", s):
if m.group(2) not in structs:
return False
s2 = re.sub(r"\b(struct|union)\s+\w+", "", s) # remove resolved struct refs
for tok in re.findall(r"\b([A-Za-z_]\w*)\b", s2):
if tok not in SCALARS:
return False
return True
def def_sigs(path, structs):
"""addr -> canonical prototype string, from every RESOLVABLE function DEFINITION in `path`."""
out = {}
if not os.path.exists(path):
return out
for m in DEF_RE.finditer(open(path).read()):
sig = re.sub(r"\s+", " ", m.group(1)).strip().rstrip("\\").strip()
if not resolvable(sig, structs):
continue
a = int(re.search(r"func_([0-9A-Fa-f]+)", sig).group(1), 16)
out.setdefault(a, sig) # first definition wins (engine_core.h is authoritative)
return out
def data_decls(paths):
out = {}
for p in paths:
if not os.path.exists(p):
continue
for m in DATA_RE.finditer(open(p).read()):
decl = re.sub(r"\s+", " ", m.group(1)).strip()
sym = re.search(r"D_[0-9A-Fa-f]+", decl).group(0)
out.setdefault(sym, decl)
return out
def main():
structs = known_structs()
funcs = {}
funcs.update(def_sigs(ECORE, structs)) # engine_core.h macro defs (authoritative)
for a, s in def_sigs(OVC, structs).items(): # + inline 077-local defs
funcs.setdefault(a, s)
data = {k: v for k, v in data_decls([ECORE, OVC]).items() if resolvable(v, structs)}
lines = ["#ifndef BFM_ENGINE_DECLS_H", "#define BFM_ENGINE_DECLS_H",
"/* src/shared/engine_decls.h — GENERATED by tools/gen_engine_decls.py (Phase 16 lever 1).",
" * Canonical declaration of every engine function + data symbol, so harvest drafts strip",
" * their own decls and can never `conflicting types`. Regenerate after new matches land. */",
'#include "common.h"', '#include "engine_types.h"', ""]
lines.append(f"/* {len(funcs)} function prototypes */")
for a in sorted(funcs):
lines.append(funcs[a] + ";")
lines.append("")
lines.append(f"/* {len(data)} data symbols */")
for sym in sorted(data):
lines.append(f"extern {data[sym]};")
lines += ["", "#endif"]
open(OUT, "w").write("\n".join(lines) + "\n")
print(f"wrote {OUT}: {len(funcs)} func protos + {len(data)} data decls")
if __name__ == "__main__":
main()