comparison-PIM4-gm2-V3.md 8.4 KB

PIM4 vs GNU Modula-2 vs V3 — feature comparison

Date: 2026-10-22 · V3 state: v3-sysclock (suite 258/258, self-hosting fixpoint OK 4,007,769 bytes, corpus 505/612, 0 crashes).

Scope. PIM4 is Wirth's Programming in Modula-2, 4th edition (the language specification, not a compiler). GNU Modula-2 (gm2) is the GCC front end: its PIM and ISO modes plus the extensions common in its testsuite. V3 is this compiler: a PIM/ISO subset plus the gm2 compatibility it deliberately chose.

Legend: ✅ supported / standard · 🔄 partial or caveated · ❌ absent · ⚠️ non-standard extension · n/a not applicable.

The tables describe the common/default behaviour; the exact flags and modes of gm2 can change individual cells. V3's deliberate deviations are listed at the end.

Standards & dialect

Feature PIM4 GNU Modula-2 V3
PIM base language ✅ (definition) ✅ (PIM 2/3/4 modes) ✅ (PIM/ISO subset)
ISO 10514-1 base ❌ (predates ISO) ✅ 🔄 mostly; see missing ISO rows below
ISO 10514-2 generics ❌ ✅ ✅ (refinement form)
ISO 10514-3 OO ❌ ❌ ❌ (CLASS is Clarion-form, not ISO OO)
Declaration before use ✅ strict 🔄 multi-pass, accepts forward refs ✅ strict for data; 🔄 forward procedure calls allowed
FORWARD declarations ✅ ✅ ✅
EXPORT QUALIFIED / UNQUALIFIED ❌ (PIM export list only) ✅ ✅
Foreign modules (DEFINITION MODULE FOR "C") ❌ ✅ ✅

Lexical

Feature PIM4 GNU Modula-2 V3
Identifiers with _ ❌ (classic names) ✅ ✅
Numeric bases ✅ octal B, hex H ✅ B/H (and more) ❌ (0x/0X only; 012H/666B rejected)
Nested (* *) comments ✅ ✅ ✅
'…' and "…" strings ✅ ✅ ✅
Unicode UCHAR/UString ❌ ❌ ✅ (extension: U'a', U"…", UCHR, UORD)

Types

Feature PIM4 GNU Modula-2 V3
INTEGER/CARDINAL/SHORTINT/LONGINT, REAL/LONGREAL, BOOLEAN, CHAR ✅ ✅ ✅
Subranges ✅ ✅ ✅ (typed CHAR/enum subranges since 2026-10-22)
Enumerations ✅ ✅ ✅
Sets (SET OF) ✅ any finite ordinal (impl. limit) ✅ 🔄 bool/char/enum/small-int subrange; span ≤ 65536; no SET OF CARDINAL
PACKEDSET ❌ (ISO) ✅ ❌
Fixed arrays, multi-dimensional ✅ ARRAY [a], [b] OF ✅ ✅ both [a], [b] and [a, b]
Open arrays (1-D) ✅ ✅ ✅
Multi-dimensional open arrays ❌ (ISO addition) ✅ ❌ (V3 descriptor-per-level representation; unbounded* gaps)
Records, variant records ✅ ✅ ✅ (plus empty arms/ELSE extensions)
Pointers, NIL, opaque types ✅ ✅ ✅
Procedure types ✅ (PROCEDURE) ✅ (PROCEDURE, PROC) ✅ (PROCEDURE, PROC; comma/unnamed forms)
Complex types (COMPLEX, LONGCOMPLEX) ❌ ✅ (ISO) ❌ (COMPLEX64 is a REAL placeholder, no arithmetic)
SYSTEM sized types (WORD32, CARDINAL8, BITSET32, …) ❌ ✅ ✅ names; 8-bit and 16-bit names are real, WORD/WORD32 are 32-bit
BYTE granularity ✅ 8-bit ✅ 8-bit ✅ BYTE/SBYTE/WORD8/CARDINAL8/INTEGER8 are 8-bit (SIZE 1); ARRAY OF BYTE is a real byte buffer
SHORTREAL (32-bit) ❌ ✅ ❌ (all reals are 8 bytes)
ADDRESS arithmetic (ADDADR/SUBADR/DIFADR) ❌ ✅ ❌
Absolute variables VAR [addr]: T ❌ ✅ (extension) ❌
Set ordering (<, <=, >, >=) ❌ (=/#/IN only) ✅ (extension) ❌

Statements & procedures

Feature PIM4 GNU Modula-2 V3
IF/CASE/WHILE/REPEAT/LOOP/EXIT/WITH, RETURN, HALT ✅ ✅ ✅
FOR over any ordinal (CHAR/enum) ✅ ✅ ✅ (since 2026-10-22)
GOTO / labels ✅ ✅ ✅
INC/DEC on enumerations ❌ (integer) ✅ ❌ (integer only)
Empty string ""/'' as CHAR ❌/unclear (ISO rule) ✅ ✅ (ISO rule, since 2026-10-22)
LENGTH ❌ (ISO adds it) ✅ ✅
HIGH ✅ ✅ ✅ / 🔄 (HIGH of a string CONST still missing)
TSIZE/SIZE/ADR ✅ ✅ ✅
SHIFT/ROTATE ⚠️ implementation SYSTEM extension ✅ ✅
TBITSIZE ❌ ✅ ❌
ISO exceptions (EXCEPT, RETRY, EXCEPTIONS) ❌ ✅ ❌
Module finalization (FINALLY) ❌ ✅ ❌
__FILE__ / __LINE__ / __FUNCTION__ ❌ ✅ ✅ / ✅ / ❌
__BUILTIN__ / __ATTRIBUTE__ pragmas ❌ ✅ ✅ (parsed, ignored)
Inline ASM ❌ ✅ ❌

Modules, compilation, libraries

Feature PIM4 GNU Modula-2 V3
Definition / implementation / program modules ✅ ✅ ✅
Local modules ✅ ✅ ✅
Separate compilation ✅ ✅ (object files/archives) 🔄 one invocation compiles all units into one image; no incremental objects
Generics ❌ ✅ ✅
Object orientation ❌ ❌ 🔄 Clarion-form CLASS (single inheritance, virtual dispatch), not ISO 10514-3
PIM coroutines (PROCESS, NEWPROCESS, TRANSFER, IOTRANSFER) ✅ ✅ ✅ (IOTRANSFER degrades to a transfer)
ISO COROUTINES module ❌ ✅ ❌ (PIM interface only)
Standard library ❌ (none defined) ✅ PIM + ISO libraries 🔄 subset: ISO/PIM I/O, strings, storage, SysClock; no ISO exceptions/termination libs
Self-hosting n/a ✅ (part of GCC) ✅ (byte-identical 3-stage fixpoint)
Backend / target n/a GCC (many targets) QBE → C (amd64 SysV today)

The practical differences

  • PIM4 is the clean specification: strict declaration order, no ISO exceptions/complex numbers/PACKEDSET/generics, no standard library, no sized SYSTEM types or address arithmetic.
  • gm2 is the superset in practice: PIM and ISO modes, generics, exceptions, complex numbers, PACKEDSET, multi-dimensional open arrays, sized SYSTEM types, address arithmetic, absolute variables, ASM, pragmas, and many extensions — but deliberately permissive (multi-pass resolution accepts forward references).
  • V3 is a PIM/ISO compiler with the opposite bias: it rejects gm2 leniencies (declaration order), implements the common ISO/PIM constructs (generics, coroutines, foreign modules, ISO strings/SYSTEM/ procedure types, empty string as CHAR), and documents its chosen gm2 compatibility (__FILE__/__LINE__, scalar→ARRAY OF BYTE, same-size VAR, bare proc values, variant extensions, set CASE labels, libc prototypes). Its hard gaps are the large ISO features (exceptions, complex arithmetic, PACKEDSET, finalization/protection, multi-dimensional open arrays, ISO OO) and parts of the word model (SHORTREAL, REAL width, 16-bit types), plus a 65536-bit set span limit.

V3-specific deviations and limits

  • Strict data declaration order (PIM-conforming); forward procedure calls are allowed where strict PIM would require FORWARD.
  • Word model: BYTE/SBYTE/WORD8/CARDINAL8/INTEGER8 are true 8-bit types (SIZE 1), WORD16/CARDINAL16/INTEGER16 are true 16-bit types (SIZE 2); INTEGER/CARDINAL/WORD/WORD32 are 32-bit; LONGINT/LONGCARD are 64-bit; every REAL/SHORTREAL is 8 bytes; COMPLEX* is a placeholder.
  • Sets: bases limited to bool/char/byte/enum/small subranges; total span ≤ 65536; no SET OF CARDINAL.
  • No runtime range checks on subrange assignment (V3 is already lenient for the integer family).
  • Multi-dimensional open arrays are not supported: V3 represents an array level as its own descriptor, whereas gm2 passes a flat block — accepting the corpus files would compile but miscompile.
  • Single-invocation compilation: definition, implementation and program units are compiled together into one image; there is no incremental object/archive format.
  • OO is the Clarion-form CLASS dialect (single inheritance, virtual dispatch), not ISO 10514-3.

Sources

  • V3: docs/STATUS.md, docs/features.md, docs/gaps/README.md, docs/analysis_gaps.md, docs/summary_session-2026-10-22.md; the gates in this document were run at v3-proc-types.
  • gm2: the GCC Modula-2 testsuite and gm2-libs/gm2-libs-iso definition modules in the sibling gcc-git tree.
  • PIM4: N. Wirth, Programming in Modula-2, 4th edition.