|
|
@@ -0,0 +1,109 @@
|
|
|
+# Handoff — finishing L3 via option 2 (next session)
|
|
|
+
|
|
|
+Branch **`ast-stage-c`**, HEAD **`e276345`**. Suite **182/182**;
|
|
|
+fixpoint **OK** (**3,147,849 bytes**). Tree clean except `toto.mod`.
|
|
|
+
|
|
|
+## Goal
|
|
|
+
|
|
|
+Finish **L3 (procedures)** for the Lower phase
|
|
|
+(`docs/plan-lower.md`, `docs/summary_two-phase-lower3-finding.md`) using
|
|
|
+**option 2 with zero `SymTab` surface**: a `Lower`-owned symbol/signature
|
|
|
+table filled by the grammar while scopes are open, so the end-of-unit
|
|
|
+walk can resolve locals/params after `SymTab` has popped their scopes —
|
|
|
+**without** touching `SymTab` (which broke self-hosting when tried).
|
|
|
+
|
|
|
+## What is already proven (rebuilt transiently, then reverted)
|
|
|
+
|
|
|
+Option 2's architecture **works** and does not break self-hosting:
|
|
|
+
|
|
|
+- `Lower` owned tables worked: `syms[]` (name/kind/ty) with a scope
|
|
|
+ save-stack (`ScopeEnter`/`ScopeLeave`), and `procs[]` (uid/res/depth/
|
|
|
+ ext/params) via `NoteProc`/`NoteParam`/`SetProcRes`. Resolution via
|
|
|
+ `FindSym`/`FindProc` (`Resolve`, `ProcInfo`, `ParamInfo`).
|
|
|
+- Grammar hooks (all inert — they only fill tables, never emit):
|
|
|
+ - root `M2`: `Lower.Reset`
|
|
|
+ - `VarDecl`: `Lower.NoteVar(nm, KindVar, t)` per pend name
|
|
|
+ - `ConstDecl`: `Lower.NoteVar(n, KindConst, t)`
|
|
|
+ - `ProcHeading`: `Lower.ScopeEnter`, `Lower.NoteProc(pn, uid, Invalid,
|
|
|
+ depth, FALSE)` after `EnterProc`; `Lower.SetProcRes(t)` at the result
|
|
|
+ - `ParamSection`: `Lower.NoteParam(nm, t, isV)` +
|
|
|
+ `Lower.NoteVar(nm, KindParam, t)` per name
|
|
|
+ - `ProcDecl`: `Lower.ScopeLeave` in all three arms (FORWARD / EXTERNAL /
|
|
|
+ body)
|
|
|
+- With the bypass of `CanLower`, the procedure **prologue emitted
|
|
|
+ correctly and byte-aligned** with the legacy image: `BeginFunc`,
|
|
|
+ `FuncParam` for each formal, `EndFuncHeader`, and the **locals did
|
|
|
+ emit** (`%t8 =l alloc4 4 ...` for a local `s`).
|
|
|
+
|
|
|
+## The one remaining bug
|
|
|
+
|
|
|
+The procedure **body** did not emit: `LowerDecls`'s `NkProcDecl` branch
|
|
|
+does
|
|
|
+
|
|
|
+```modula2
|
|
|
+LowerDecls(AST.Child(c, 2)); (* locals -- emitted OK *)
|
|
|
+LowerStmt(AST.Child(c, 1)); (* body -- emitted NOTHING *)
|
|
|
+QbeGen.EndFunc(res)
|
|
|
+```
|
|
|
+
|
|
|
+and the output jumped straight from the locals to `EndFunc`'s default
|
|
|
+`ret 0`, i.e. `LowerStmt(AST.Child(c, 1))` dispatched to nothing.
|
|
|
+
|
|
|
+**First step next session:** dump ONE `NkProcDecl`'s children to pin the
|
|
|
+body index. Add a one-off `AST.Dump(astUnit, 0)` in the root (and
|
|
|
+**remove it before committing** — an `ASTDUMP` was accidentally committed
|
|
|
+once and cost real time), compile e.g.:
|
|
|
+
|
|
|
+```modula2
|
|
|
+MODULE Proc1;
|
|
|
+VAR ExitCode : INTEGER;
|
|
|
+PROCEDURE Add(a, b : INTEGER) : INTEGER;
|
|
|
+VAR s : INTEGER;
|
|
|
+BEGIN s := a + b; RETURN s END Add;
|
|
|
+BEGIN ExitCode := Add(4, 10) END Proc1.
|
|
|
+```
|
|
|
+
|
|
|
+Expect `NkProcDecl` = `[0]=NkIdent Add, [1]=NkBlock[assign, return],
|
|
|
+[2]=locals`. If the body is elsewhere (e.g. child 1 is the locals and
|
|
|
+the block is nested), fix the dispatch in `LowerDecls`. The earlier
|
|
|
+slice-5 dump showed child 1 = the body block; the locals (child 2) now
|
|
|
+emit, so verify whether setting child 2 shifted the body.
|
|
|
+
|
|
|
+Likely fix: the body is `AST.Child(c, 1)` and `LowerStmt` handles
|
|
|
+`NkBlock` — check `LowerStmt`'s `NkBlock` branch and the assign/return
|
|
|
+cases reach it. A `QbeGen.Remark` at the top of `LowerStmt` (removed
|
|
|
+after) will show whether it is entered for the body.
|
|
|
+
|
|
|
+## Then
|
|
|
+
|
|
|
+- Enable procs in `CanLower` (it already routes `NkDecl → CanProc`; the
|
|
|
+ earlier session found `NkProcDecl` `op` defaulted to `-1` and `CanProc`
|
|
|
+ requires `0` for a normal body — **set `AST.SetOp(astNode, 0)` at node
|
|
|
+ creation** in `ProcDecl`; this was one of the two real bugs).
|
|
|
+- Add `lower_ok t_lower3.mod` to `run_tests.sh`.
|
|
|
+- Gate: `build.sh` + `run_tests.sh` (expect 183/183) + `fixpoint.sh`
|
|
|
+ (**must stay OK** — the whole point of option 2).
|
|
|
+
|
|
|
+## Two bugs already identified (re-apply with the option-2 work)
|
|
|
+
|
|
|
+1. `NkProcDecl` op defaults to `-1`; normal body must be `0`
|
|
|
+ (`CanProc` rejects otherwise). Set it at creation.
|
|
|
+2. `NkCall` child 0 is an `NkDesignator`, not a bare `NkIdent` — calls
|
|
|
+ mangled as `$_0`. `Lower.CalleeName` unwraps the designator (already
|
|
|
+ in the committed `v3-lower3-wip` `Lower.mod`; re-add for option 2).
|
|
|
+
|
|
|
+## Do NOT
|
|
|
+
|
|
|
+- Do not modify `SymTab` (that broke self-hosting).
|
|
|
+- Do not run the legacy and `L` emitters concurrently (shared
|
|
|
+ `QbeGen` buffer + counters).
|
|
|
+- Do not leave an `ASTDUMP` in `M2.atg`.
|
|
|
+
|
|
|
+## Resume
|
|
|
+
|
|
|
+```sh
|
|
|
+cd ~/Projets/Projets-Modula2/MyWork/m2compiler-V3
|
|
|
+git checkout ast-stage-c
|
|
|
+cd compiler && ./build.sh && ./run_tests.sh # 182/182
|
|
|
+cd .. && ./bootstrap/fixpoint.sh # FIXPOINT OK
|
|
|
+```
|