Removes both separate-compilation limitations from step 5.4/5.5. Suite 97/97 (54 run — incl. 4 trap-aborts, 7 sessions, 3 session-output, 2 session-input, 1 unit — + 43 reject). LL(1)-clean, zero gm2 warnings.
Module-level VAR/CONST data now emits as $<mod>_<name>
(previously $<name>), so two modules with a global of the same
name no longer collide at link time. QbeGen.SetModule (called by
each unit's Begin*) supplies the module; DeclVar/DeclConst
prefix it. Real-const startup flushes and the ExitCode load use
the same qualified name.
L.x / L.P no longer flatten-clone under the plain name (which
let one library's export shadow another's). New
SymTab.MaterializeAlias(mod, name, alias) clones under a
per-module key <mod>$<name> ($ can't appear in identifiers), and
the symbol node keeps:
sym — the base symbol name (for QBE mangling/global names), andmod — the defining module.SymBase and GlobalRef read those back; QbeGen.Mangled now
mangles via SymBase (drops any alias prefix) and SymRef builds
$<mod>_<sym> for data access. All other lookups
(type/kind/uid/params/result/external/depth) work unchanged because
they only need Find(alias).
ClashProg → 60: two modules ClashA/ClashB each with a global
count and a procedure Get; the program uses both
qualified. Image shows $ClashA_count/$ClashB_count and
Get_0/Get_1.MixProg → prints 7: TextIO.WriteInt (console) and
Files.WriteInt (file) in one program — the exact case that
failed before this pass.FROM A IMPORT x followed by FROM B IMPORT x is still
first-wins (Materialize returns the existing node) — genuinely
ambiguous by name; callers should use qualified access or distinct
names. Qualified access is fully per-module.
Storage/SYSTEM (ADDRESS, generic pointers) and the step-7
syslib port: SYSTEM/Storage/Trap can now be ordinary modules
whose internals bind externals without symbol collisions.