# Step 3 — Procedures (tag: `step3`) Commit `c0f1924` — "step3: procedures — nested, params, recursion, FORWARD, RETURN; 49/49 tests green" (91 files, +2730/−548). ## Goal Procedures (Phase 2 of the plan): declarations incl. nesting, value and VAR parameters, functions, `RETURN`, recursion, forward declarations; frames per spec §5.2; calls via ED/EC/EE. ## What was built - `SymTab`: frame slots (`SymSlot`), proc depths (`SymDepth`/`CurDepth`), proc records numbered 1..64, forward + define signatures with `VerifyProc`, return-type stack (`CurRet`/`InFunction`), new kinds `Proc/Param/VarPar`. - `MGen`: N-entry proc table (print helper moved to last slot), `ProcEntry`/`Leave`, calls via `ED` (global), `EC` (directly nested), `EE` + display walk (`11H`); actuals evaluated left-to-right into temps, pushed reversed (nested-call-safe frame stack in `ActBegin/Value/End`, which also own arity/type/ VAR-actual checks); frame-aware loads/stores/addresses. - `M2c.atg`: `ProcedureDecl` (nested, `FORWARD;` form verified against gm2 — caret form rejected), `Design` split into `Head`+`Tail` with `AssignOrCall`, `CallTail`, `ReturnStat`, `v/vn` attributes threading "is plain variable" for VAR-actual checks. - Codes 231 (forward mismatch/missing body), 232 (bad RETURN), 233 (invalid call); proc `END`-name reuse 202 (text widened to "module/procedure name mismatch"). ## Tests — 49/49 (25 step-2 regressions + 24 new) 14 run: proper/value-params (incl. 6 params)/functions/factorial/ fib/VAR-swap/nested display/forward mutual recursion/early RETURN/ shadowing/nested calls/dropped results/VAR chains/empty bodies/ REAL functions. 10 rejections, each exactly one error: non-proc call, arity, actual type, proper-in-expression, 3× RETURN misuse, forward mismatch, missing body, undeclared callee. ## Bugs found and fixed 1. `FORWARD;` double-semicolon — the branch must not consume `;` (it belongs to `Declaration`). 2. Bare `P;` calls need no parens — empty-call branch in statements (expressions still require parens). 3. `2EH` pops an address off the stack — same-frame indirect access must go through `2CH`+`60H`; deleted `LoadStk`. 4. Dead callee value on expression calls (`Double(10)+Double(11)` → 22) — `CallTail` drops it on entry. ## Research notes - Forward syntax confirmed empirically (`PROCEDURE P(...); FORWARD;` compiles under gm2; `^` and heading-alone do not). - Decoder-verified before use: `2E/3E` unsigned (outer locals need the `41H/51H` path), `11H np=0` valid, `EC/EE/ED` semantics. - Limits: 64 procedures, 64 actuals/call, 16 names per FP-section, 8-deep nested calls; truncating DIV/MOD and eager AND/OR carry over from step 2.