# V3 step 3.6 — pointers: vars, NIL, deref, NEW/DISPOSE (done 2026-09-20) Composites complete. Suite 64/64 (30 run — incl. 3 trap-aborts — + 34 reject). LL(1)-clean (only the known-benign TypeBlock warning). ## NIL as a real type (the key decision) `NIL` was `InvalidType` piggy-backing on error suppression, which made `p := NIL` silently emit nothing and `p = NIL` fold false. Now `FNil`/`ClNil`/`dNil`: `NIL` assigns to pointers (210 elsewhere — `i := NIL` finally errors instead of vanishing), compares with pointers via `ceql/cnel` (213 against the rest), and is rejected everywhere else through existing predicates (211/212/214/222/230 all automatic). Named `CONST X = NIL` flows identically. No new error codes needed. ## Grammar (`M2.atg`) - `PointerType` (`POINTER TO`, never open inside); `^` suffix with sfx discipline (address flows, load at use; chains compose: `pa^[i]`, `pr^.f`, `pp^^`); `< > <= >=` on pointers are 213. - `NEW`/`DISPOSE` as builtin statements (no call syntax until step 4): plain vars via name, suffixed designators via address; 210 on non-vars, 219 on non-pointers. - `Design` root loads pointers (`LoadPtr`); `Assign` stores them (`StorePtr`); `VarDecl` accepts them (`{ l 0 }` data). - `DISPOSE` nils afterwards — deviates from Wirth-undefined (testable postcondition, safer); `DISPOSE` is shallow (nested objects leak — documented); nil-deref is raw (no check). ## Backend (`QbeGen`, all probed first) `LoadPtr/StorePtr`, `CmpL`, `DataLineL`, `NewHeap` (extern `malloc`, size from descriptors) + recursive `InitHeap` (static counts stored, nested objects allocated unrolled, members otherwise garbage). Single-arg extern calls and store-immediates (`storel 0, $p`) verified by probe before use. ## SymTab (additive only) `FNil/ClNil/dNil`, `Assignable` nil→ptr rule, `EqCheck` nil rules. `NewPtr/PtrBase` (Test2 heritage) finally wired. ## Tests `t_pointer` → 42 (NEW/deref/alias/both NIL directions/DISPOSE/ nil-after), `t_ptrarray` → 15 (heap sizing, `^`-index chains), `t_ptrrec` → 15 (record heap objects, `pr^.f` chains), `t_ptrnest` → 10 (recursive heap allocation), `t_opaqueptr` (pointer-to-opaque descriptors — the step-4 ADT hook), `t_bad_deref`/`t_bad_new` → 219. Total 64. Deferred: recursive `DISPOSE`, nil-deref trap, `HIGH`/`LEN` (step 4 calls), class lowering, procedure-type calls.