# Step 11 — Separate compilation units (DEFINITION/IMPLEMENTATION/IMPORT) 157/157 tests green (144 + 7 run + 6 rejection), mc64 boot + example green, Showcases unchanged (157, 83, 168), new Showcase4 prints 225 as hand-computed. ## Goal `DEFINITION`/`IMPLEMENTATION` compilation units with `IMPORT`/`FROM`, compiled from several files into a single `.MC4` image (the remaining big item from the step-10 limits). ## What was built - Driver (`compiler.frm`, the true source of generated `M2c.mod`): multi-file session `M2c lib.def libimpl.mod ... prog.mod`, one `.LST` per input, fail-fast on the first bad file (no HALT abort: a clean `EXIT` with `Incorrect source`). `SymTab.Init` and `MGen.OpenModule("")` run once; the program unit sets the image name (`MGen.SetModName`). - Grammar (`M2c.atg`): `M2c = Unit`, `Unit = DefUnit | ImplUnit | ProgUnit`. New `DEFINITION`/`IMPLEMENTATION` keywords were added in end-of-file productions so existing token numbers only shifted by position — CR regenerates `M2c.mod`'s `Msg` table from `M2c.err` (verified identical mapping); new-productions note added. - `SymTab`: definition interfaces publish to the existing export tables plus an in-memory side table (8 defs, 32 names each); `OpenImplementation` re-enters the interface into a fresh scope (slots allocated once at definition, found via the module context); procedure headings match through the forward machinery (`ReuseProc`/`VerifyProc`, 231 on mismatch); `CloseImplementation` requires every body (231). `FROM L IMPORT x` materializes real alias symbols (`EnterImpProc` shares the proc number, so call checking is unchanged; VAR/CONST aliases resolve through the new `GlobAlias` hook in `MGen.QualGlob`, the single funnel for all global use-paths). Ghosts are 201, bad kinds 221, duplicates 200. - `run_tests.sh`: `expect_run_files` / `expect_fail_files` for multi-file sessions. ## Tests — 157/157 (144 + 7 + 6) 7 run: `d_basic` 25 (FROM var/func, qualified const/var/call, `VAR` param, lib init), `d_from` 12 (exported array type, private impl helper, `VAR` composite formal), `d_multi` 82 (two libs, implementation-level `IMPORT`), `d_init` 510 (init order across files, init reading another lib via `FROM`), `d_func` 55 (recursive lib function), `d_type` 1122 (exported record, `VAR` record formal), `d_case` 25 (qualified enum `CASE` labels). 6 rejections, each exactly one error: `d_bad_nodef` 201, `d_bad_sig` 231, `d_bad_nobody` 231, `d_bad_imp` 201, `d_bad_exp` 201, `d_bad_dup` 200. ## Bugs found and fixed 1. `DefProcHead` double-semicolon: heading already consumes its own `;` (`';' expected` on the first definition). 2. `HALT` on compile failure aborts (SIGABRT, `Abandon` noise in every rejection run) — replaced with a clean loop `EXIT`. 3. Value composite formals in a test (`Sum(x : Vec)`) correctly hit the pre-existing 230 rule — test switched to `VAR` formal. 4. `M2c.mod` is REGENERATED by CR from `compiler.frm` on every build: driver edits first went to `M2c.mod` and were silently lost. Driver work belongs in `compiler.frm` (same for the `Msg` table, auto-mirrored from `M2c.err`). ## Known limits (deferred) `M.x` as a `VAR` actual is still 233 (pre-existing local-module limitation, confirmed identical on step-10 build — Showcase4 works around it via a temp); second program unit rejected (230 + follow-on 200); multi-`.MC4` images with `depCount` loading (still single image, `depCount` 0); circular imports; opaque types; `WITH`-field `VAR` actuals; `CHAR`/`BOOLEAN` tails as `VAR` actuals.