summary_step3.6.md 2.3 KB

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.