DEFINITION MODULE QbeGen; (* QBE backend for the scalar subset of SimpleMod2 (see SimpleQ.atg). Emits QBE SSA text to "gen_qbe/.ssa" (directory "gen_qbe" must exist). Supported: scalar globals of INTEGER / CARDINAL / SHORTINT / LONGINT / BOOLEAN / CHAR (QBE "w") and REAL / LONGREAL (QBE "d", i.e. REAL is widened to double), enumeration types with ordinal values, CONST initializers that are plain literals, full scalar expressions, and IF / CASE / WHILE / REPEAT / LOOP+EXIT / FOR statements. Anything else (ARRAY / RECORD / SET / POINTER values, string variables, WITH, IN, set literals, non-literal CONST expressions or BY steps, EXIT outside LOOP, use of imported names as values) is reported by the parser with error 230; this module only emits structurally valid placeholder code for those cases. Test convention: if the source declares a global VAR ExitCode : INTEGER; the generated "main" returns its value as the process exit code, otherwise it returns 0. This makes compiled programs observable (the language itself has no I/O). *) TYPE QVal = ARRAY [0 .. 63] OF CHAR; (* A QBE operand: either an immediate ("42", "-5", "d_3.14") or a temporary ("%t7"). Labels ("@L3") travel in plain strings. *) PROCEDURE OpenModule (name: ARRAY OF CHAR); (* Opens gen_qbe/.ssa, resets counters. *) PROCEDURE DeclVar (name: ARRAY OF CHAR; t: INTEGER); (* Emits "data $name = ..." (w for scalars, d for REAL). The second parameter is a SymTab.TypeIndex; other classes get a "w 0" placeholder so the file stays assembleable. *) PROCEDURE DeclConst (name: ARRAY OF CHAR; val: ARRAY OF CHAR; t: INTEGER); (* Like DeclVar but initialized from the literal text val ("100", "-5", "d_3.14"); non-literal val gives a 0 placeholder. NOTE: this qbe accepts only integer literals in "data", so a non-zero REAL initializer is emitted as "d 0" plus a runtime copy at function start (see BeginBody). *) PROCEDURE BeginBody; (* Emits "export function w $main() {@start" (once). *) PROCEDURE EndModule; (* Emits the return sequence (via ExitCode when present), closes the function and the file. *) PROCEDURE NewTemp (VAR t: QVal); (* Fresh "%tN" operand. *) PROCEDURE NewLabel (VAR l: QVal); (* Fresh "@LN" label. *) PROCEDURE EmitLabel (l: ARRAY OF CHAR); PROCEDURE Jmp (l: ARRAY OF CHAR); PROCEDURE Jnz (c, t, f: ARRAY OF CHAR); (* "jnz c, @t, @f". *) PROCEDURE LoadVar (name: ARRAY OF CHAR; isReal: BOOLEAN; VAR q: QVal); (* q := fresh temp holding $name. *) PROCEDURE StoreVar (name: ARRAY OF CHAR; q: ARRAY OF CHAR; isReal: BOOLEAN); (* "storew/stored q, $name". *) PROCEDURE Op3 (mn: ARRAY OF CHAR; res, l, r: ARRAY OF CHAR; isReal: BOOLEAN); (* "res =w/=d mn l, r". *) PROCEDURE Cmp (op: INTEGER; l, r: ARRAY OF CHAR; VAR q: QVal; isReal: BOOLEAN); (* Signed integer (ceqw/cnew/csltw/...) or double (ceqd/.../cled/...) comparison selected by a SymTab.OpEq..OpGe code; q := fresh w. *) PROCEDURE NegQ (a: ARRAY OF CHAR; VAR q: QVal; isReal: BOOLEAN); (* q := fresh temp holding "-a" (sub from 0). *) PROCEDURE NotQ (a: ARRAY OF CHAR; VAR q: QVal); (* q := fresh temp holding "NOT a" (xor 1, a). *) PROCEDURE ConvIR (a: ARRAY OF CHAR; VAR q: QVal); (* q := fresh double holding "swtof a" (INTEGER -> REAL). *) PROCEDURE CopyOp (s: ARRAY OF CHAR; VAR d: ARRAY OF CHAR); PROCEDURE IntStr (v: INTEGER; VAR s: QVal); PROCEDURE NormInt (s: ARRAY OF CHAR; VAR d: QVal); (* "123" -> "123"; "0FFH" -> "255". *) PROCEDURE NormReal (s: ARRAY OF CHAR; VAR d: QVal); (* "3.14" -> "d_3.14" (QBE double immediates carry a d_ prefix). *) PROCEDURE CharVal (s: ARRAY OF CHAR): INTEGER; (* ORD of a 1-character literal such as 'a'. *) PROCEDURE NegFold (a: ARRAY OF CHAR; VAR q: QVal); (* Folds a unary minus into a literal operand ("5" -> "-5"). *) PROCEDURE IsImm (s: ARRAY OF CHAR): BOOLEAN; (* TRUE for literal operands (not %temporaries). *) PROCEDURE IsNeg (s: ARRAY OF CHAR): BOOLEAN; (* TRUE for a leading '-'. *) PROCEDURE PushLoop (exit: ARRAY OF CHAR); PROCEDURE PopLoop; PROCEDURE TopLoop (VAR exit: QVal): BOOLEAN; (* Innermost LOOP exit label; FALSE when outside any LOOP. *) PROCEDURE NoQbeEnter; PROCEDURE NoQbeExit; PROCEDURE NoQbe (): BOOLEAN; (* Guard depth for unsupported constructs: while > 0 the grammar suppresses follow-on 230 errors to avoid cascades. *) PROCEDURE Remark (s: ARRAY OF CHAR); (* Emits a "# s" comment line. *) END QbeGen.