First stdlib landing: the compiler can now call the host. Suite 88/88 (45 run — incl. 4 trap-aborts, 4 sessions, 1 session-output — + 43 reject). LL(1)-clean, zero gm2 warnings.
PROCEDURE P(...); EXTERNAL; — a body-less procedure
in an implementation. MarkExternal flags the current heading;
its header/scope are discarded (AbortFunc), so no function is
emitted.ext + link on the procedure node; MarkExternal,
IsExternal, ProcLink. The flag rides the node, and the
implementation resumes the definition's node (ResumeProc), so
clients that IMPORT/FROM-import the routine also see it as
external.Mangled binds an external procedure to its link name
(default: its own name — a valid C symbol; m2write etc.).CallBegin/CallEnd gained an
isExt flag; the hidden static-link argument is omitted for
external calls (the shim signature has no link).runtime/syslib/shim.c)Small C layer that knows the compiler's memory layout. A string
(ARRAY OF CHAR) value is a descriptor { LONGCARD count, bytes };
the compiler passes its address as an l. Shim exports:
m2write(desc), m2writeln(), m2writeint(v), m2exit(code).
Linked into every session image by the harness.
tests/sysio.def + .mod)Classic DEFINITION/IMPLEMENTATION (separate compilation):
Write(VAR s : ARRAY OF CHAR), WriteLn, WriteInt(n), each a
thin Modula-2 wrapper over an EXTERNAL shim routine. This also
exercises passing a string literal as a VAR ARRAY OF CHAR
actual: literals now register their static descriptor address in
the actual-address note table.
Hello → stdout Hello, Modula-2! then 42, exit 0 — the first
V3 program with real output, checked by the new
expect_run_files_out harness (exit code + first output line).
Harness refactor: build_session (compile→qbe→cc with the shim)
shared by expect_run_files / expect_run_files_out.
SYSTEM/Storage (malloc/free wrappers), Strings,
TextIO, WholeIO, Math, Files; explicit external link names
(EXTERNAL "c_name"); string escapes (so literals are raw bytes —
newlines come from WriteLn); reading input.