DEFINITION MODULE Lower; (* AST -> QBE walk for the two-phase frontend (docs/plan-lower.md). Test-only: after a normal parse has built the AST and emitted the legacy image, CanLower gates whether the unit is in the supported subset; LowerUnit then re-emits it into a fresh QbeGen state, writing gen_ssa/L.ssa for a byte-compare against the legacy image. Symbol resolution is self-contained (zero SymTab surface): the grammar records each declaration's kind/type and each procedure's signature in the tables below while the scope is open, so the walk can resolve names after SymTab has popped their scopes. *) IMPORT AST, SymTab, QbeGen; PROCEDURE CanLower (unit: AST.Node): BOOLEAN; PROCEDURE LowerUnit (unit: AST.Node); PROCEDURE LowerSession (units: ARRAY OF AST.Node; n: CARDINAL; progName: ARRAY OF CHAR); PROCEDURE BeginSession (progName: ARRAY OF CHAR); PROCEDURE BeginUnit; PROCEDURE LowerUnitNow (unit: AST.Node; isProg: BOOLEAN); PROCEDURE EndSession; (* The expression/statement/declaration walkers are mutually recursive. gm2's link pass rejects FORWARD and V3 has no whole-module pass, so they are declared here (definition-visible throughout the implementation) instead of being forward-declared. *) PROCEDURE CanExpr (n: AST.Node): BOOLEAN; PROCEDURE CanDecls (seq: AST.Node): BOOLEAN; PROCEDURE CanProc (proc: AST.Node): BOOLEAN; PROCEDURE IsBuiltin (nm: ARRAY OF CHAR): BOOLEAN; PROCEDURE LowerExpr (n: AST.Node; VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal); PROCEDURE LowerStmt (seq: AST.Node); PROCEDURE LowerDecls (seq: AST.Node); PROCEDURE Reset; PROCEDURE NoteVar (name: ARRAY OF CHAR; kind: INTEGER; t: SymTab.TypeIndex); PROCEDURE NoteConstVal (val: ARRAY OF CHAR); PROCEDURE ScopeEnter; PROCEDURE ScopeLeave; PROCEDURE NoteProc (name: ARRAY OF CHAR; uid: CARDINAL; res: SymTab.TypeIndex; depth: CARDINAL; ext: BOOLEAN); PROCEDURE MarkProcExternal; PROCEDURE NoteProcNode (n: AST.Node); PROCEDURE SetProcRes (t: SymTab.TypeIndex); PROCEDURE NoteParam (name: ARRAY OF CHAR; t: SymTab.TypeIndex; isVar: BOOLEAN); END Lower.