Bläddra i källkod

library: NumberIO/RealInOut/FpuIO; resolve shipped libs in the harness

- corpus harness fidelity: V3_LIBS now defaults to V3's own shipped
  libraries (stdlib + runtime/syslib) and only SYSTEM/libc are treated
  as built-ins without a .def; a file importing Strings/IOChan/StrIO/...
  resolves against the real .def instead of being mislabelled LIB
  (corpus 427 -> 447).
- add the PIM/gm2 I/O family NumberIO, RealInOut, FpuIO (StrIO/InOut
  already shipped): a new shim m2writefix backs the fixed-point writers.
  Regression t_pimio (exit 42).  Corpus 447 -> 467.

Gates: suite 249/249, fixpoint OK (3,882,337 bytes), corpus 467/612,
0 crashes.
Eric Streit 3 dagar sedan
förälder
incheckning
d243d252ad

+ 1 - 0
.gitignore

@@ -8,3 +8,4 @@ tools/topspeed-grammar/build/
 
 # gap reproducers: listings
 docs/gaps/*.LST
+*.tmp

+ 9 - 0
compiler/run_tests.sh

@@ -333,6 +333,15 @@ expect_run_files TStreamFile 42 \
   ../stdlib/chanconsts.def ../stdlib/chanconsts.mod \
   ../stdlib/streamfile.def ../stdlib/streamfile.mod \
   t_streamfile.mod
+expect_run_files TPimIO 42 \
+  ../runtime/syslib/SysShim.def ../runtime/syslib/SysShim.mod \
+  ../stdlib/inout.def ../stdlib/inout.mod \
+  ../stdlib/strio.def ../stdlib/strio.mod \
+  ../stdlib/numberio.def ../stdlib/numberio.mod \
+  ../stdlib/realio.def ../stdlib/realio.mod \
+  ../stdlib/realinout.def ../stdlib/realinout.mod \
+  ../stdlib/fpuio.def ../stdlib/fpuio.mod \
+  t_pimio.mod
 expect_run_files WrapProg 42 \
   ../runtime/syslib/SysShim.def ../runtime/syslib/SysShim.mod \
   ../stdlib/iochan.def ../stdlib/iochan.mod \

+ 14 - 0
compiler/tests/t_pimio.mod

@@ -0,0 +1,14 @@
+MODULE TPimIO;
+(* PIM/gm2 I/O library family: StrIO, NumberIO, RealInOut, FpuIO. *)
+FROM StrIO IMPORT WriteString, WriteLn;
+FROM NumberIO IMPORT WriteCard;
+FROM RealInOut IMPORT WriteReal;
+FROM FpuIO IMPORT WriteLongInt;
+VAR ExitCode : INTEGER;
+BEGIN
+  WriteString("hello"); WriteLn;
+  WriteCard(42, 3); WriteLn;
+  WriteReal(1.5, 8); WriteLn;
+  WriteLongInt(7, 3); WriteLn;
+  ExitCode := 42
+END TPimIO.

+ 17 - 12
docs/STATUS.md

@@ -4,13 +4,14 @@ This answers "where are we now?".
 
 ## Numbers
 
-- Suite **248/248** (`compiler/run_tests.sh`).
+- Suite **249/249** (`compiler/run_tests.sh`).
 - Self-hosting **FIXPOINT OK** — stage2 and stage3 images are
   byte-identical (3,882,337 bytes).
-- Corpus **427 / 612** sources compile with 0 errors, **0 crashes**
-  (`tools/v3-corpus/corpus.sh` over the gm2 testsuite); the rest are
-  genuine language gaps, **gm2 leniencies V3 deliberately rejects**, or
-  unresolved imports.
+- Corpus **467 / 612** sources compile with 0 errors, **0 crashes**
+  (`tools/v3-corpus/corpus.sh` over the gm2 testsuite; the harness now
+  resolves V3's own shipped libraries); the rest are genuine language
+  gaps, **gm2 leniencies V3 deliberately rejects**, or unresolved
+  imports of gm2-only modules.
 - Branch **`master`**; tree clean.
 
 ## Architecture (current)
@@ -134,12 +135,16 @@ declarations still work (`t_fwdproc`, `t_fwdok`).
    `SymTab`'s `MaxTypes` all report `230` (implementation limit) instead
    of truncating silently.  Still weak: error recovery and message polish.
 4. **Library holes** — the channel framework grew `ChanConsts` and
-   `StreamFile` (ISO 10514-1) on top of `IOChan` (2026-10-19).  Still
-   missing: the remaining device/IO framework (`docs/wip/`).  Fixing
-   `StreamFile` also fixed a real bug: a **set CONST exported from a
-   definition module** is now emitted under its global name
-   (`<unit>_<name>`), so a client's qualified reference binds instead of
-   hitting an undefined symbol.
+   `StreamFile` (ISO 10514-1) on top of `IOChan`, and the PIM/gm2 I/O
+   family gained `NumberIO`, `RealInOut`, `FpuIO` (`StrIO`/`InOut`
+   already existed).  Also fixed the **corpus harness fidelity**: it now
+   searches V3's own shipped libraries (`stdlib`, `runtime/syslib`) via a
+   default `$V3_LIBS`, so a file importing e.g. `Strings` resolves
+   against the real `.def` instead of being mislabelled `LIB`.
+   Building `StreamFile` also fixed a real bug: a **set CONST exported
+   from a definition module** is now emitted under its global name
+   (`<unit>_<name>`), so a client's qualified reference binds.  Still
+   missing: gm2 runtime modules (`M2RTS`, `Builtins`, `Processes`, …).
 5. **Housekeeping** — `docs/INDEX.md` is the entry point; the
    unreferenced historical records are under `docs/archive/` (2026-10-19).
    `resolve-check` was merged to `master`.
@@ -149,7 +154,7 @@ declarations still work (`t_fwdproc`, `t_fwdok`).
 ```sh
 cd compiler
 ./build.sh          # M2.atg -> scanner/parser/driver -> ./M2
-./run_tests.sh      # 248/248
+./run_tests.sh      # 249/249
 cd ..
 ./bootstrap/fixpoint.sh   # FIXPOINT OK (byte-identical stage2/stage3)
 ```

+ 19 - 6
docs/handoff-2026-10-19-next.md

@@ -2,8 +2,8 @@
 
 **Branch state (2026-10-19):** work is on `master`, tree clean.
 
-**Baseline:** suite **248/248**, fixpoint **OK (3,882,337 bytes)**,
-corpus **427/612, 0 crashes**.
+**Baseline:** suite **249/249**, fixpoint **OK (3,882,337 bytes)**,
+corpus **467/612, 0 crashes**.
 
 **Policy:** follow **Modula-2**, not gm2 degradation — declaration
 before use (only a `POINTER`'s base may forward-reference).  In
@@ -121,8 +121,21 @@ message polish, and the library holes (`docs/wip/`).
 - Remaining library work: the rest of the device/IO framework
   (`docs/wip/`).
 
-**Baseline:** suite **248/248**, fixpoint **OK (3,882,337 bytes)**,
-corpus **427/612, 0 crashes**.
+## Library holes  ✅ second slice (2026-10-19)
+
+- **Harness fidelity**: `tools/v3-corpus/corpus.sh` now defaults
+  `V3_LIBS` to V3's own shipped libraries (`stdlib`, `runtime/syslib`)
+  and only treats `SYSTEM`/`libc` as built-ins-without-`.def`.  A corpus
+  file importing `Strings`/`IOChan`/`StrIO`/… now resolves against the
+  real `.def` instead of being mislabelled `LIB` (427 → 447).
+- **PIM/gm2 I/O family**: added `NumberIO`, `RealInOut`, `FpuIO`
+  (`StrIO`/`InOut` already shipped; a new `m2writefix` C formatter backs
+  the fixed-point writers).  Regression `t_pimio` (exit 42).  447 → 467.
+- Still missing: gm2 runtime modules (`M2RTS`, `Builtins`, `Processes`,
+  `Preemptive`, `M2Printf`, …).
+
+**Baseline:** suite **249/249**, fixpoint **OK (3,882,337 bytes)**,
+corpus **467/612, 0 crashes**.
 
 ## P5 — housekeeping  ✅ DONE (2026-10-19)
 
@@ -158,9 +171,9 @@ commit with a `v3-*` tag.
 ```sh
 cd .../m2compiler-V3
 git checkout master
-cd compiler && ./build.sh && ./run_tests.sh   # 248/248
+cd compiler && ./build.sh && ./run_tests.sh   # 249/249
 cd .. && TMP="$PWD/.scratch/fixpoint" ./bootstrap/fixpoint.sh
-tools/v3-corpus/corpus.sh                     # 427 OK, 0 crash
+tools/v3-corpus/corpus.sh                     # 467 OK, 0 crash
 ```
 
 **Recommendation:** P1 (two bounded wins) next, then reserve a separate

+ 14 - 0
runtime/syslib/shim.c

@@ -491,6 +491,20 @@ long m2writereal(double x)
     return m2writerealf(x, 0);
 }
 
+/* Write a REAL right-justified in `wid` with `dec` digits after the
+   point (FpuIO.WriteReal/WriteLongReal). */
+long m2writefix(double x, long wid, long dec)
+{
+    char buf[256];
+    int n;
+    if (wid <= 0) wid = 1;
+    if (dec < 0) dec = 0;
+    if (dec > 30) dec = 30;
+    n = snprintf(buf, sizeof buf, "%*.*f", (int)wid, (int)dec, x);
+    if (n > 0) write(1, buf, (size_t)n);
+    return 0;
+}
+
 /* Read a REAL from stdin. */
 double m2readreal(void)
 {

+ 12 - 0
stdlib/fpuio.def

@@ -0,0 +1,12 @@
+DEFINITION MODULE FpuIO;
+(* gm2/PIM floating-point I/O.  V3 models REAL and LONGREAL as the same
+   8-byte type, so both read/write paths are the same. *)
+
+PROCEDURE ReadReal (VAR x : LONGREAL);
+PROCEDURE ReadLongReal (VAR x : LONGREAL);
+PROCEDURE WriteReal (x : LONGREAL; width, decimals : CARDINAL);
+PROCEDURE WriteLongReal (x : LONGREAL; width, decimals : CARDINAL);
+PROCEDURE WriteLongInt (x : LONGINT; width : CARDINAL);
+PROCEDURE WriteLongCard (x : LONGCARD; width : CARDINAL);
+
+END FpuIO.

+ 33 - 0
stdlib/fpuio.mod

@@ -0,0 +1,33 @@
+IMPLEMENTATION MODULE FpuIO;
+(* Thin layer over the C runtime's float/integer printers. *)
+
+PROCEDURE m2writefix (x : REAL; wid : INTEGER; dec : INTEGER);
+  EXTERNAL;
+PROCEDURE m2writeintwidth (v : LONGINT; wid : CARDINAL);
+  EXTERNAL;
+PROCEDURE m2readreal () : REAL;
+  EXTERNAL;
+
+PROCEDURE ReadReal (VAR x : LONGREAL);
+BEGIN x := m2readreal() END ReadReal;
+
+PROCEDURE ReadLongReal (VAR x : LONGREAL);
+BEGIN x := m2readreal() END ReadLongReal;
+
+PROCEDURE WriteReal (x : LONGREAL; width, decimals : CARDINAL);
+BEGIN
+  m2writefix(x, VAL(INTEGER, width), VAL(INTEGER, decimals))
+END WriteReal;
+
+PROCEDURE WriteLongReal (x : LONGREAL; width, decimals : CARDINAL);
+BEGIN
+  m2writefix(x, VAL(INTEGER, width), VAL(INTEGER, decimals))
+END WriteLongReal;
+
+PROCEDURE WriteLongInt (x : LONGINT; width : CARDINAL);
+BEGIN m2writeintwidth(x, width) END WriteLongInt;
+
+PROCEDURE WriteLongCard (x : LONGCARD; width : CARDINAL);
+BEGIN m2writeintwidth(VAL(LONGINT, x), width) END WriteLongCard;
+
+END FpuIO.

+ 9 - 0
stdlib/numberio.def

@@ -0,0 +1,9 @@
+DEFINITION MODULE NumberIO;
+(* Classic PIM numeric I/O (gm2-compatible interface), layered on InOut. *)
+
+PROCEDURE ReadInt (VAR x : INTEGER);
+PROCEDURE ReadCard (VAR x : CARDINAL);
+PROCEDURE WriteInt (x : INTEGER; width : CARDINAL);
+PROCEDURE WriteCard (x : CARDINAL; width : CARDINAL);
+
+END NumberIO.

+ 16 - 0
stdlib/numberio.mod

@@ -0,0 +1,16 @@
+IMPLEMENTATION MODULE NumberIO;
+IMPORT InOut;
+
+PROCEDURE ReadInt (VAR x : INTEGER);
+BEGIN InOut.ReadInt(x) END ReadInt;
+
+PROCEDURE ReadCard (VAR x : CARDINAL);
+BEGIN InOut.ReadCard(x) END ReadCard;
+
+PROCEDURE WriteInt (x : INTEGER; width : CARDINAL);
+BEGIN InOut.WriteInt(x, width) END WriteInt;
+
+PROCEDURE WriteCard (x : CARDINAL; width : CARDINAL);
+BEGIN InOut.WriteCard(x, width) END WriteCard;
+
+END NumberIO.

+ 11 - 0
stdlib/realinout.def

@@ -0,0 +1,11 @@
+DEFINITION MODULE RealInOut;
+(* Classic PIM real I/O, layered on RealIO. *)
+
+VAR
+  Done   : BOOLEAN;
+  termCH : CHAR;
+
+PROCEDURE ReadReal (VAR x : REAL);
+PROCEDURE WriteReal (x : REAL; width : CARDINAL);
+
+END RealInOut.

+ 19 - 0
stdlib/realinout.mod

@@ -0,0 +1,19 @@
+IMPLEMENTATION MODULE RealInOut;
+IMPORT RealIO;
+
+PROCEDURE ReadReal (VAR x : REAL);
+BEGIN
+  RealIO.ReadReal(x);
+  Done := TRUE;
+  termCH := CHR(0)
+END ReadReal;
+
+PROCEDURE WriteReal (x : REAL; width : CARDINAL);
+BEGIN
+  RealIO.WriteRealF(x, width)
+END WriteReal;
+
+BEGIN
+  Done := TRUE;
+  termCH := CHR(0)
+END RealInOut.

+ 7 - 4
tools/v3-corpus/README.md

@@ -14,9 +14,9 @@ touches the corpus) and compiled on its own.  A file with **0 errors**
 is a pass.  Failures are split into:
 
 - **CRASH** — `M2` died (rc ≥ 128): a real compiler bug;
-- **LIB** — the file imports a module outside V3's known stdlib set
-  (gm2's `StrIO`/`NumberIO`/`STextIO`/…), so the `undeclared
-  identifier`s are expected, not a language gap;
+- **LIB** — the file imports a module V3 does **not** ship (gm2's
+  `NumberIO`/`FpuIO` are shipped; `M2RTS`/`Builtins`/`Processes`/… are
+  not), so the `undeclared identifier`s are expected, not a language gap;
 - **LANG** — otherwise: a genuine parse/semantic gap in V3.
 
 A "pass" is syntactic+semantic cleanup, not a linkable image (many
@@ -27,7 +27,10 @@ An IMPLEMENTATION file is compiled together with its sibling
 DEFINITION (same basename, `.def`/`.DEF`) when present, and with the
 DEFINITION of every module it imports, searched in the source directory
 and in the colon-separated `$V3_LIBS` directories — so cross-module
-imports resolve.  E.g.:
+imports resolve.  `$V3_LIBS` defaults to V3's **own** shipped libraries
+(`stdlib/` and `runtime/syslib/`), so a file importing e.g. `Strings`
+or `IOChan` resolves against the real `.def`; point it at an installed
+gm2 library set for a wider net, e.g.:
 
 ```sh
 G=$HOME/bin/Modula2/Gm2/lib/gcc/x86_64-pc-linux-gnu/16.0.1/m2

+ 6 - 1
tools/v3-corpus/corpus.sh

@@ -18,7 +18,12 @@ cd "$(dirname "$0")"
 ROOT="$(cd ../.. && pwd)"
 M2="$ROOT/compiler/M2"
 WORK=/tmp/opencode/v3corpus
-KNOWN="SYSTEM libc SysIO TextIO Strings Math Conversions RealIO ProgramArgs IOChan Files Storage WholeIO CharClass SysClock"
+# Library search path: the modules V3 actually ships.  A corpus file that
+# imports one of them should resolve against the real .def, not be
+# assumed present.
+V3_LIBS="${V3_LIBS:-$ROOT/stdlib:$ROOT/runtime/syslib}"
+# Modules with no .def (language/runtime built-ins).
+KNOWN="SYSTEM libc"
 [ -x "$M2" ] || { echo "compiler/M2 missing -- run compiler/build.sh"; exit 1; }
 [ "$#" -gt 0 ] || set -- \
   "$HOME/Projets/Projets-Modula2/MyWork/gcc-git/gcc/testsuite/gm2/pim/pass" \