DEFINITION MODULE MGen; (* MC64 image emitter for the M2c scalar subset (see M2c.atg). Buffers a single-module MC64 image and writes ".MC4" (current directory) at EndModule. The image satisfies the reference loader (Loader2): magic "MC64", descriptor with name, TOINIT flag, global sizes (one 8-byte slot per variable), two procedures (0 = user code, 1 = decimal print helper), relative procedure-table cells, and the checksum rule. Lowered: scalar globals (INTEGER/CARDINAL/CHAR/BOOLEAN/enums as 32-bit ops on slots, REAL as binary64), CONST initializers that are plain literals (emitted as startup stores), full scalar expressions on the stack machine, IF/CASE/WHILE/REPEAT/LOOP+EXIT/ FOR via E0/E1 jumps with fixups. Everything else is reported by the parser (error 230); this module only needs structurally valid placeholders for those cases. Test convention (no I/O in the language): if the source declares VAR ExitCode : INTEGER; (int family, VAR kind) the epilogue prints its value as decimal + CRLF through the embedded print procedure; otherwise the program just ends. Step 3 adds procedures: user procedures take table entries 1..N (0 = module body), run with ENTER frames, and are called via ED (global), EC (directly nested) or EE (display walk). *) TYPE LitStr = ARRAY [0 .. 63] OF CHAR; (* Literal text: "42", "-5", "0FFH", "3.14", "'a'", "TRUE". "" means "not a plain literal". *) PROCEDURE OpenModule (name: ARRAY OF CHAR); (* Resets all state; reserves slots 0..3 for the print helper. *) PROCEDURE DeclVar (name: ARRAY OF CHAR); (* Assigns the next global slot to name (any type; one slot). *) PROCEDURE DeclConst (name: ARRAY OF CHAR; lit: LitStr; t: INTEGER); (* Assigns a slot and buffers a startup initializer from the literal text (t is a SymTab.TypeIndex). Empty lit buffers a 0. *) PROCEDURE DeclConstInt (name: ARRAY OF CHAR; v: INTEGER); (* Assigns a slot with an INTEGER startup value (enum literals). *) PROCEDURE BeginBody; (* Flushes buffered CONST initializers as startup stores. *) PROCEDURE EndModule; (* Emits the epilogue, the print procedure, the procedure table, the descriptor, the checksum, and writes the .MC4 file. *) PROCEDURE LoadVar (name: ARRAY OF CHAR); (* Pushes the global (placeholder push-0 if unknown). *) PROCEDURE StoreVar (name: ARRAY OF CHAR); (* Pops into the global (dropped if unknown). *) PROCEDURE PushVar (name: ARRAY OF CHAR); (* Pushes a variable's value, frame-aware: globals via the global table, same-frame locals/params direct, outer frames via the display, VAR params indirect. Placeholder push-0 if unknown. *) PROCEDURE LoadTemp (t: INTEGER); PROCEDURE StoreTemp (t: INTEGER); (* Direct slot access for compiler temporaries. *) PROCEDURE TempGlobal (): INTEGER; (* Allocates a fresh hidden global slot, returns its index. *) PROCEDURE PushInt (v: INTEGER); (* Small encodings for 0..15; negatives via 0,mag,sub. *) PROCEDURE PushBits (b: LONGCARD); (* 8E + 8 bytes: CARDINAL values and REAL bit patterns. *) PROCEDURE ParseInt (s: ARRAY OF CHAR; VAR v: INTEGER): BOOLEAN; (* Decimal, H-suffixed hex, optional leading '-'. *) PROCEDURE ParseCard (s: ARRAY OF CHAR; VAR v: CARDINAL): BOOLEAN; (* Decimal or H-suffixed hex (for literals past MAXINT). *) PROCEDURE ParseReal (s: ARRAY OF CHAR; VAR b: LONGCARD): BOOLEAN; (* Decimal with optional fraction/exponent/sign to IEEE bits. *) PROCEDURE CharOrd (s: ARRAY OF CHAR): INTEGER; (* ORD of a 1-character literal such as 'a'. *) PROCEDURE NegFold (a: ARRAY OF CHAR; VAR q: LitStr); (* Folds a unary minus into literal text ("5" -> "-5"). *) PROCEDURE IsLit (s: ARRAY OF CHAR): BOOLEAN; (* TRUE for non-empty literal text. *) (* ---- stack operators (one opcode each, see mc64-spec.md §11) ---- *) PROCEDURE Add; PROCEDURE Sub; PROCEDURE MulU; PROCEDURE DivU; PROCEDURE ModU; PROCEDURE MulI; PROCEDURE DivI; PROCEDURE ModI (t: INTEGER); (* Signed a MOD b with truncation semantics via temp slot t: a - (a DIV b) * b. Caller passes TempGlobal(). *) PROCEDURE RealAdd; PROCEDURE RealSub; PROCEDURE RealMul; PROCEDURE RealDiv; PROCEDURE And; PROCEDURE Or; PROCEDURE Not; PROCEDURE Power2; (* Push (1 << pop) for set element masks. *) PROCEDURE FieldMask; (* (1<= 3). Same-frame VAR-param slots hold addresses: read them with LoadLocal, then LoadIndir0. *) PROCEDURE LoadIndir0; PROCEDURE StoreIndir0; (* 60H/70H slot-0 indirect (through VAR-param addresses). *) PROCEDURE FrameAddr (sl: INTEGER; np: CARDINAL); (* Pushes (display-frame(np) + slot*8) as a byte address. *) PROCEDURE LoadIndir; PROCEDURE StoreIndir; (* 41H/51H through a computed address. *) PROCEDURE LocalAddr (sl: INTEGER); (* 80H address of a same-frame slot. *) PROCEDURE GlobalAddr (name: ARRAY OF CHAR); (* 81H address of a global (push-0 if unknown). *) PROCEDURE PushAddr (name: ARRAY OF CHAR); (* Pushes a VAR-actual address: slot addresses for plain variables, slot contents for VAR params; display-aware. Push-0 if unknown. *) PROCEDURE StoreSetup (name: ARRAY OF CHAR); (* Emits an early store address (VAR-param or outer-frame targets) before the value expression; nothing for direct targets. *) PROCEDURE StoreFinish (name: ARRAY OF CHAR); (* Emits the store for a storable variable (global, param, local, VAR-param, outer frame). *) (* ---- procedures (see §5.2) ---- *) PROCEDURE ProcEntry (num: INTEGER; nLoc: CARDINAL); (* Records the procedure address and emits ENTER for nLoc locals. *) PROCEDURE CallProc (num: INTEGER); (* ED: call a global procedure (OFP = NIL). *) PROCEDURE CallNested (num: INTEGER); (* EC: call a directly nested procedure (OFP = FP). *) PROCEDURE CallDisplay (num: INTEGER; np: CARDINAL); (* 11H np display walk, then EE call with that frame. *) PROCEDURE Leave (nPar: CARDINAL; func: BOOLEAN); (* 84H (proper) or 85H (function) procedure leave. *) (* ---- actual parameters (nested-call-safe frame stack) ---- *) PROCEDURE ActBegin (pn: ARRAY OF CHAR); (* Opens an actual-parameter frame for a call to pn. *) PROCEDURE ActValue (t: INTEGER; v: BOOLEAN; vn: ARRAY OF CHAR): INTEGER; (* Checks one actual against its formal (0 = ok): VAR formals need a plain variable of identical type (address pushed), value formals need assignment compatibility (INTEGER widens to REAL). Always consumes the value (temp store). 1 means error 233. *) PROCEDURE ActEnd (pn: ARRAY OF CHAR; sfx, inExpr: BOOLEAN): INTEGER; (* Verifies arity and callee kind, reloads actuals reversed and emits the depth-correct call (0 = ok, 1 = error 233). *) (* ---- control flow (E0/E1 with fixups) ---- *) PROCEDURE NewLabel (): INTEGER; PROCEDURE DefLabel (id: INTEGER); PROCEDURE Jmp (id: INTEGER); PROCEDURE Jz (id: INTEGER); (* Jump if false (pops the condition). *) PROCEDURE PushLoop (exit: INTEGER); PROCEDURE PopLoop; PROCEDURE TopLoop (VAR exit: INTEGER): BOOLEAN; (* Innermost LOOP exit label; FALSE outside any LOOP. *) PROCEDURE NoSupEnter; PROCEDURE NoSupExit; PROCEDURE CopyName (s: ARRAY OF CHAR; VAR d: ARRAY OF CHAR); (* Copies zero-terminated strings between any char arrays. *) PROCEDURE NoEmitEnter; PROCEDURE NoEmitExit; (* Suppresses code emission (not literal capture) in declarative contexts such as CONST initializers and subrange bounds. *) PROCEDURE NoSup (): BOOLEAN; (* Guard depth for unsupported constructs: while > 0 the grammar suppresses follow-on 230 errors to avoid cascades. *) END MGen.