fix(phase-26): scope_data_externs ANSI-brace fix + wire §8d into family_sweep --hseq; 780-class diagnosed

- _body_open_brace only matched a `{` on its own line (the K&R shape), so fix() SILENTLY NO-OP'D on
  every ANSI draft — the same silent-skip disease as the four catalogued in §40/§8d, caught because
  the h_seq re-sweep banked 0/780. Now brace-scans forward from the signature (ANSI same-line,
  ANSI own-line, and K&R all work). Load-bearing for func_80178D40's upcoming ×134 bank.
- family_sweep --hseq now applies the §8d scoped stage at staging time.
- HONEST RESULT: still 0/780 — the substantial-band h_seq rejections are a DIFFERENT (sibling) class,
  now fully diagnosed against the bytes:
    gcc-2.7.2 decl-conflict semantics: a VISIBLE file-scope decl + a conflicting later decl (file OR
    block) is a HARD ERROR; a limbo-only block decl (scope closed) + a conflicting later decl is a
    warning. The h_seq drafts carry the EXEMPLAR TU's spellings; sibling TUs legitimately spell the
    same symbol differently (loose typing), and the visible decl is often MACRO-INJECTED — a
    DEFINE_func_* leading extern (§8c), invisible to any col-0 scan (e.g. D_80115158's `short` decl
    enters ov_SC01_000.c via DEFINE_func_8014168C() @4637; the draft carries ov077's
    `unsigned short` -> conflicting types at ANY scope).
  Sub-class (a) no-visible-decl -> §8d demotion (the jr class, proven x133). Sub-class (b) visible
  decl, different spelling -> needs reconcile-to-TU-VISIBLE (rewrite the draft decl to the TU-visible
  spelling + byte-neutral access cast; oracle = col-0 decls above the stub + engine_core.h macro
  externs for the DEFINE_ invocations above). Parked as a designed follow-up task; the 780 members
  are mechanical-recovery fodder once the tool exists.
This commit is contained in:
Drew T
2026-07-13 21:49:22 -06:00
parent b8a525bb98
commit a0e7ff7f6f
2 changed files with 25 additions and 5 deletions
+14
View File
@@ -20,6 +20,7 @@ import json, glob, re, subprocess, os, sys, shutil, collections, argparse
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import family_remap as FR
import canon_sig_reconcile as CSR # v3.2 (Phase-25 T7-M2 per-sibling re-reconcile, Q5-proven)
from scope_data_externs import fix as scope_data_fix # §8d (Phase-26 session 8)
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
PY = ".venv/bin/python"
@@ -244,6 +245,19 @@ def hseq_sweep(a):
skip[r[:24]] += 1; continue
if re.search(r'__asm__\s*\(\s*"\$', draft): # hard-reg pin (§42e): ×1-only, cc1-crashes
skip["pinned-exemplar"] += 1; continue # sibling TUs → skip the family, don't bisect-storm
# §8d — place the carried DATA externs at a scope this sibling's TU can accept.
# `remap_hseq` (via gather_externs) prepends them at FILE scope; for a per-location symbol the
# sibling declares only at BLOCK scope inside its own later functions, that ESTABLISHES A GLOBAL
# THE TU NEVER HAD and every later block-scope extern must now agree with it — loose typing ⇒ they
# don't ⇒ `conflicting types for D_80115128`. Byte-proven to be the dominant gate-rejection class
# here (as it was for the jr sweeps). Demoting is byte-neutral and never worse than raw, and the
# whole-binary gate remains the sole arbiter (G3/P9).
to_func = f"func_{to_addr:08X}"
tu_path = os.path.join(REPO, src_rel)
tu = open(tu_path).read()
mstub = re.search(rf'INCLUDE_ASM\("[^"]*",\s*{to_func}\);', tu)
if mstub:
draft, _moved = scope_data_fix(draft, tu, mstub.start(), to_func)
d = os.path.join(REPO, SWEEP, ov)
os.makedirs(d, exist_ok=True)
open(os.path.join(d, f"func_{to_addr:08X}.c"), "w").write(draft + "\n")
+11 -5
View File
@@ -72,14 +72,20 @@ def _file_scope_data_syms(text):
def _body_open_brace(body, func):
"""Index of the newline ending the line that opens `func`'s body — i.e. where block-scope decls go.
Handles both the ANSI form and the K&R form (mandatory whenever a zero-arg engine_core.h thunk calls
the function), whose param decls sit between the signature and the `{`."""
r"""Index just past the `{` that opens `func`'s body — i.e. where block-scope decls go. Scans forward
from the signature to the first `{` at depth 0 of the *statement* (so it handles the ANSI form with
the brace on the signature line, the ANSI form with the brace on its own line, AND the K&R form whose
param decls sit between the signature and the `{`). The first cut of this used `^\s*\{\s*$` — own-line
braces only — and silently no-op'd on every ANSI draft (the same silent-skip disease as the four
catalogued in §40/§8d; caught because the h_seq re-sweep banked 0/780)."""
sig = re.search(rf'^[^\n]*\b{re.escape(func)}\s*\(', body, re.M)
if not sig:
return None
brace = re.compile(r'^\s*\{\s*$', re.M).search(body, sig.end())
return brace.end() if brace else None
i = body.find('{', sig.end())
if i < 0:
return None
j = body.find('\n', i)
return (j + 1) if j >= 0 else (i + 1)
def fix(body, tu_text, insert_pos, func):