Modern Modula-2 syntax, Coco/R frontend, fresh QBE backend, Blaise-style
phased process, self-hosting with byte-identical .ssa fixpoint.
M2.atg → scanner/parser/driver), gm2 -fiso,
CR -m -C regeneration, two-phase gm2 -fgen-module-list link
(proven in V1/V2/Test2).QbeGen emitting QBE SSA text (.ssa), then
qbe -o .s + cc link + execute. System qbe pinned in
vendor/qbe-pin.txt.# only (no <>), NOT/AND/OR only (no ~/&), no B/C octal
literals, 0x-only hex, unary minus at expression start.
Evolved from V2 M2comp.atg (1290 lines), not pasted verbatim.
A second, fenced legacy grammar (TopSpeed-V3-M2.atg, step 1.12)
covers the historical dialect (_, <>, H/C/B) for corpus
ingestion — never merged into the modern grammar (see
docs/blaise-phases-map.md: our phase-10 sidecar).VAR ExitCode : INTEGER
selects process exit code; otherwise return 0.Blaise (graemeg/blaise) uses compiler/, runtime/, stdlib/,
tools/migration-analyser/, vendor/qbe/, docs/, per-module
target/. V3 port:
m2compiler-V3/
README.md build.sh run_tests.sh
compiler/src/ M2.atg (+ TopSpeed-V3-M2.atg legacy sidecar),
frames, FileIO, SymTab, QbeGen, generated
scanner/parser/driver (gitignored)
compiler/tests/ accept / reject (.LST) / run (exit-code) tests
runtime/syslib/ SYSTEM, Storage, SysIO, SysClock, Trap, Utf8
always-linked, self-hostable, NO gm2-only imports
stdlib/ Strings, TextIO (+U*), WholeIO, Math, Files,
Conversions, RealIO, CharClass, ProgramArgs,
IOChan
opt-in via IMPORT, classic DEFINITION+OPAQUE,
Benjamin-R10 semantics, classic syntax only
tools/redux-check/ modern-syntax enforcement helper
vendor/qbe-pin.txt
bootstrap/ stage1/ (gm2-built), stage2/, stage3/ (V3-built),
fixpoint.sh (rebuild 2x, diff -r *.ssa)
docs/ plan.md (this file), blaise-phases-map.md,
summary_stepN.md (one file per step)
Build outputs (.o, .ssa, .s, binaries) are never committed.
Benjamin/Actual/m2bsk-master/r10/stdlib/*.if
(+ blueprints/templates as semantic reference) and PDFs-master/.DEFINITION/IMPLEMENTATION + OPAQUE only.
Explicitly OUT: INTERFACE MODULE, [ProtoX]/[TMIN] attributes,
PROCEDURE [+] operator overloads, .bp/.gen.if templates.runtime/syslib vs stdlib/ split: syslib is always linked and
trivially compilable; stdlib is opt-in via IMPORT.| Step | Goal | Acceptance |
|---|---|---|
| 1 pipeline | minimal M2.atg + fresh QbeGen hello → .ssa → qbe → cc → run |
✅ done (5/5 → grown since) |
| 2 scalars | scalar type system, SymTab errors 200–224 + 230/232/233 (+234 unicode) | ✅ done (30/30: ints, bools, chars, REALs, control flow) |
| 3 composites | length-prefixed arrays/records/sets/pointers (§5) | 🔄 3.1 arrays ✅, 3.2 showcase ✅, 3.3 sets ✅, 3.4 pointers next |
| 4 modules/procs | DEFINITION/IMPLEMENTATION, opaque TYPE T;, nested/display, separate compilation |
not started (syntax parses; lowering pending) |
| 5 stdlib | Strings/TextIO/WholeIO/Math/Files per Benjamin | I/O + file tests |
| 6 harden | CASE/WITH/LOOP/EXIT/FOR-BY, conversions, traps | full-suite green |
| 7 syslib port | rewrite FileIO on SysIO+Storage only; ban Environment, FileSysOp, TextIO, RawIO, WholeIO, IOChan, SysClock, ProgramArgs via grep gate |
compiler sources syslib-clean; Stage1 still gm2-built |
| 8 fixpoint | bootstrap/fixpoint.sh: Stage1→Stage2→Stage3, diff -r all .ssa byte-identical, suite green on all stages |
SELF-HOSTED |
Full-language-first: the compiler itself may use the full language;
self-hosting is the last phase. Hygiene from step 1: deterministic
%tN/@LN counters, sorted symbol emission, no timestamps/paths in
.ssa; restricted SYSTEM use (ADR/TSIZE/BYTE only).
ARRAY value: bytes 0..7 = LONGCARD element count
(HIGH-LOW+1), QBE l; bytes 8.. = packed elements.ARRAY [lo..hi] (bounds still
checked statically AND stored at runtime). 8 bytes overhead/array.SYSTEM.TSIZE on arrays includes the header.ARRAY OF T: single l descriptor pointer; callee reads
count via loadl. No hidden length parameter.:= requires equal counts, else Trap.RangeFault
(no silent truncation — safety-perimeter principle).a[i]: base + 8 + (i-lo)*elemSize + runtime i < lo+count check.HIGH(a)/LEN(a): static for fixed, header read for open.ARRAY OF CHAR with this header; literals emitted as
data $n = { l count, b ... }. No trailing NUL; C boundary via
SysIO.ExportCStr copy.SYSTEM.BYTE buffers (FileIO, SymTab.Name) conform automatically.Status: increments 1–2 landed (see docs/summary_unicode.md).
Remaining: UString whole-string assignment to a fixed array; UString
=/+/concat.
UCHAR: 32-bit codepoint 0..1114111 (QBE w). CHAR unchanged
(8-bit, 0..255). Distinct types, no implicit mixing. ✅LONGCARD count (codepoints) + count × l codepoints
(prior header rule, element = UCHAR, 4 bytes each). 🔄 (literals
emit the descriptor; assignment/backing pending)LexUString action strict-RFC3629-decodes
(no overlongs/surrogates/>10FFFF/truncation). ✅U'..' / U".."; single codepoint U'a' → UCHAR,
longer/empty → UString. 'a' ≠ U'a'. ✅234. ✅ (reported in
.LST + console; note the image is still written, gate pending)UCHR(x:CHAR|INTEGER):UCHAR (constructor); CHR8(u:UCHAR):CHAR
traps unless u ≤ 255; ORD 8-bit; UORD(u):INTEGER.
⚠ deviation: UORD returns INTEGER, not LONGCARD (V3 has no
LONGCARD name or 64→32-bit conversion; a codepoint fits in 32
bits). ⚠ UCHR also accepts an integer family operand.runtime/syslib/Utf8 (Decode/Encode, MaxUTF8Length=4,
MaxCodePoint=1114111, cf. Benjamin Utf8.def): used by the output
libs. ⚠ the front-end decode lives in QbeGen.DeclUStr (stage 1 is
gm2-built and does not know UCHAR, so it cannot import Utf8).TextIO.UWriteChar/UWriteString/UWriteLn: encode to UTF-8, emit via
the shim. Raw WriteChar stays byte-oriented. ✅COMPILER M2 header + CHARACTERS/IGNORE/COMMENTS/TOKENS ✅
(0x, E-exponents, // decided interactively; ustring
token implemented, see §6).CONST/TYPE/VAR/ProcHeading + error codes (200–234) ✅WITH, which rides with records).IN, set ops; pointer ops with 3.4).file:line:col).Each section: proposed snippet → user approve/tweak → append to
compiler/src/M2.atg → CR -m -C syntax check before moving on.
Per-section self-host question: "can this cover the compiler's own
source idioms?".
U'..' vs U".." spelling confirmation during §1.stdlib Phase-5 subset order: SYSTEM+Strings+TextIO first?Trap exit-code conventions for run tests.