DEFINITION MODULE SymTab; (* Symbol table with static type checking for SimpleMod2 (simplified Modula-2 without procedures). - flat scopes with levels: globals at level 0, WITH statement bodies push the record's fields as an inner scope (shadowing allowed, duplicates within one level rejected) - every symbol carries a type descriptor index (InvalidType if unknown, e.g. imported names); unknown types suppress follow-on errors to avoid cascades - type descriptors: aliases (one per TYPE declaration, so self-references such as POINTER TO Person resolve), subranges, enumerations, arrays, records (with field lists), sets, pointers, predefined types, string literals - INTEGER, CARDINAL and subranges thereof form one lenient "integer family"; mixed INTEGER/REAL arithmetic is rejected *) CONST MaxSyms = 256; InvalidType = -1; (* symbol kinds *) KindConst = 0; KindType = 1; KindVar = 2; KindImport = 3; KindModule = 4; KindPredef = 5; KindField = 6; (* type classes returned by ClassOf *) ClInvalid = 0; ClInt = 1; ClReal = 2; ClChar = 3; ClBool = 4; ClEnum = 5; ClArray = 6; ClRecord = 7; ClSet = 8; ClPtr = 9; ClStr = 10; (* operator codes for RelCheck *) OpEq = 0; OpNeq1 = 1; OpNeq2 = 2; OpLt = 3; OpLe = 4; OpGt = 5; OpGe = 6; OpIn = 7; (* operator codes for AddOp / MulOp *) OpAdd = 0; OpSub = 1; OpOr = 2; OpTimes = 0; OpSlash = 1; OpDiv = 2; OpMod = 3; OpAnd = 4; TYPE Name = ARRAY [0 .. 63] OF CHAR; TypeIndex = INTEGER; (* ---------------- symbols and scopes ---------------- *) PROCEDURE Init; (* Clears the table and enters predefined identifiers (INTEGER, CARDINAL, SHORTINT, LONGINT, REAL, LONGREAL, CHAR, BOOLEAN, TRUE, FALSE, NIL). *) PROCEDURE Enter (name: ARRAY OF CHAR; kind: INTEGER): BOOLEAN; (* Enters name at the current scope level (type InvalidType). Returns FALSE on duplicate within the same level. *) PROCEDURE EnterPending (name: ARRAY OF CHAR; kind: INTEGER): BOOLEAN; (* Like Enter, but remembers the entry for a later FixPending call (used for VAR identifier lists whose type is parsed afterwards). Returns FALSE on duplicate (entry not recorded). *) PROCEDURE FixPending (t: TypeIndex); (* Assigns type t to all pending entries, clears the buffer. *) PROCEDURE PendCount (): CARDINAL; (* Number of entries currently waiting for FixPending. *) PROCEDURE PendName (i: CARDINAL; VAR n: Name); (* Name of the i-th pending entry (empty string if out of range). Used by the QBE backend to emit storage for VAR lists whose type is parsed after the identifiers. *) PROCEDURE FieldPending (rec: TypeIndex; name: ARRAY OF CHAR): BOOLEAN; (* Records a field name for record descriptor rec (type fixed later with FixPendingF). Returns FALSE on duplicate field. *) PROCEDURE FixPendingF (rec: TypeIndex; t: TypeIndex); (* Assigns type t to pending fields owned by rec. *) PROCEDURE Lookup (name: ARRAY OF CHAR): BOOLEAN; (* TRUE if name is visible (innermost scope wins). *) PROCEDURE SymType (name: ARRAY OF CHAR): TypeIndex; (* Type of innermost visible entry, InvalidType if absent. *) PROCEDURE SetSymType (name: ARRAY OF CHAR; t: TypeIndex); (* Sets type of innermost visible entry. *) PROCEDURE SymKind (name: ARRAY OF CHAR): INTEGER; (* Kind of innermost visible entry, -1 if absent. *) PROCEDURE Equal (a, b: ARRAY OF CHAR): BOOLEAN; PROCEDURE PushScope; PROCEDURE PopScope; (* WITH statement support: PushRecord pushes a record's fields. *) PROCEDURE PushRecord (t: TypeIndex): BOOLEAN; (* Pushes a scope containing t's fields (as KindField). FALSE if t is not a record type (or invalid). Caller must PopScope after. *) PROCEDURE PrintTable; (* ---------------- type descriptors ---------------- *) PROCEDURE NewAlias (): TypeIndex; PROCEDURE NewSub (base: TypeIndex): TypeIndex; PROCEDURE NewEnum (): TypeIndex; PROCEDURE NewArray (elem: TypeIndex): TypeIndex; PROCEDURE NewRecord (): TypeIndex; PROCEDURE NewSet (base: TypeIndex): TypeIndex; PROCEDURE NewPtr (base: TypeIndex): TypeIndex; PROCEDURE NewStr (): TypeIndex; (* Fresh descriptors; base/elem may be InvalidType. InvalidType is returned when the table is full. *) PROCEDURE SetTarget (t, base: TypeIndex); (* Sets an alias target (TYPE declaration completion). *) PROCEDURE IntType (): TypeIndex; PROCEDURE RealType (): TypeIndex; PROCEDURE CharType (): TypeIndex; PROCEDURE BoolType (): TypeIndex; PROCEDURE ClassOf (t: TypeIndex): INTEGER; (* Resolves aliases; InvalidType maps to ClInvalid. *) PROCEDURE IsIntFamily (t: TypeIndex): BOOLEAN; (* INTEGER, CARDINAL or subrange thereof (Invalid suppresses). *) PROCEDURE SameType (a, b: TypeIndex): BOOLEAN; (* Same resolved descriptor (Invalid suppresses). *) PROCEDURE FieldExists (rec: TypeIndex; name: ARRAY OF CHAR): BOOLEAN; PROCEDURE FieldType (rec: TypeIndex; name: ARRAY OF CHAR): TypeIndex; PROCEDURE ArrayElem (t: TypeIndex): TypeIndex; PROCEDURE PtrBase (t: TypeIndex): TypeIndex; (* ---------------- predicates used by grammar checks ---------------- *) (* All return TRUE if either operand is InvalidType (no cascades). *) PROCEDURE Assignable (src, dst: TypeIndex): BOOLEAN; (* Assignment compatibility (210). *) PROCEDURE ArithCheck (l, r: TypeIndex; divmod: BOOLEAN; VAR res: TypeIndex): BOOLEAN; (* + - * / (divmod FALSE) or DIV MOD (TRUE); res is result type (211). *) PROCEDURE UnaryCheck (t: TypeIndex; VAR res: TypeIndex): BOOLEAN; (* Unary + - (part of 211). *) PROCEDURE BoolCheck (t: TypeIndex): BOOLEAN; (* BOOLEAN required: NOT/AND/OR operands (212), conditions (214). *) PROCEDURE RelCheck (l, r: TypeIndex; op: INTEGER): BOOLEAN; (* = # <> < <= > >= IN (213/222 chosen by caller via op). *) PROCEDURE EqCheck (l, r: TypeIndex): BOOLEAN; (* = # compatibility, also reused for CASE label matching. *) PROCEDURE InCheck (l, set: TypeIndex): BOOLEAN; PROCEDURE SetElemCheck (first, elem: TypeIndex): BOOLEAN; PROCEDURE SetFor (elem: TypeIndex): TypeIndex; (* Fresh SET OF elem descriptor for set literals. *) PROCEDURE StrLen (s: ARRAY OF CHAR): CARDINAL; END SymTab.