| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623 |
- IMPLEMENTATION MODULE SymTab;
- IMPORT FileIO;
- FROM Storage IMPORT ALLOCATE;
- FROM SYSTEM IMPORT TSIZE;
- CONST
- MaxTypes = 256;
- MaxPend = 64;
- MaxMods = 32;
- ResDepth = 64;
- (* descriptor forms *)
- FNone = 0; FAlias = 1; FSub = 2; FEnum = 3; FArray = 4;
- FRecord = 5; FSet = 6; FPtr = 7; FStr = 8;
- FInt = 9; FReal = 10; FChar = 11; FBool = 12;
- FClass = 13; FOpenArr = 14; FNil = 15;
- TYPE
- SymPtr = POINTER TO SymNode;
- ScopePtr = POINTER TO ScopeNode;
- FieldPtr = POINTER TO FieldNode;
- SymNode = RECORD
- name : Name;
- kind : INTEGER;
- typ : TypeIndex;
- scope : ScopePtr; (* owning scope *)
- left : SymPtr; (* BST links within the owning scope *)
- right : SymPtr;
- rslt : TypeIndex; (* KindProc result type, InvalidType = none *)
- plink : SymPtr; (* next formal, positional chain *)
- isVar : BOOLEAN; (* KindParam: VAR formal *)
- fwd : BOOLEAN; (* KindProc: FORWARD body pending *)
- virt : BOOLEAN; (* KindProc: VIRTUAL method *)
- fdep : CARDINAL; (* KindProc: lexical function-nesting depth *)
- uid : CARDINAL; (* KindProc: unique id for name mangling *)
- END;
- ScopeNode = RECORD
- parent : ScopePtr; (* scope tree link *)
- root : SymPtr; (* BST root of this scope's symbols *)
- level : CARDINAL;
- link : ScopePtr; (* creation-order chain for PrintTable *)
- ofRec : TypeIndex; (* record/class whose members live here *)
- END;
- FieldNode = RECORD
- name : Name;
- typ : TypeIndex;
- owner : TypeIndex;
- next : FieldPtr; (* next field of the same owner *)
- off : INTEGER; (* declaration-order byte offset *)
- ord : CARDINAL; (* declaration rank (chain is reverse) *)
- END;
- VAR
- curScope : ScopePtr;
- scopeList : ScopePtr; (* all scopes, creation order *)
- scopeTail : ScopePtr;
- fields : FieldPtr; (* all record fields, newest first *)
- nFields : CARDINAL;
- pend : ARRAY [0 .. MaxPend - 1] OF SymPtr;
- nPend : CARDINAL;
- pendF : ARRAY [0 .. MaxPend - 1] OF FieldPtr;
- nPendF : CARDINAL;
- tform : ARRAY [0 .. MaxTypes - 1] OF INTEGER;
- tref : ARRAY [0 .. MaxTypes - 1] OF TypeIndex;
- tlo : ARRAY [0 .. MaxTypes - 1] OF INTEGER;
- thi : ARRAY [0 .. MaxTypes - 1] OF INTEGER;
- tparent : ARRAY [0 .. MaxTypes - 1] OF TypeIndex;
- tscope : ARRAY [0 .. MaxTypes - 1] OF ScopePtr;
- tdone : ARRAY [0 .. MaxTypes - 1] OF BOOLEAN;
- alo : ARRAY [0 .. MaxTypes - 1] OF INTEGER;
- ahi : ARRAY [0 .. MaxTypes - 1] OF INTEGER;
- blo : ARRAY [0 .. 7] OF INTEGER;
- bhi : ARRAY [0 .. 7] OF INTEGER;
- nBounds : CARDINAL;
- nTypes : CARDINAL;
- curProc : SymPtr; (* heading being declared *)
- curPTail : SymPtr; (* positional param chain tail *)
- procStk : ARRAY [0 .. 15] OF SymPtr;
- nProc : CARDINAL;
- nextUid : CARDINAL;
- dInt, dCard, dReal, dChar, dBool, dNil : TypeIndex;
- globScope : ScopePtr; (* the global scope (module names live here) *)
- curMod : INTEGER; (* current registry slot, -1 between units *)
- curUnit : INTEGER; (* UnitProg/Def/Impl, -1 between units *)
- nMods : CARDINAL;
- modNames : ARRAY [0 .. MaxMods - 1] OF Name;
- modScopes : ARRAY [0 .. MaxMods - 1] OF ScopePtr;
- modKind : ARRAY [0 .. MaxMods - 1] OF INTEGER;
- modImpl : ARRAY [0 .. MaxMods - 1] OF BOOLEAN;
- haveProg : BOOLEAN;
- (* ---------------- strings ---------------- *)
- PROCEDURE Assign (VAR dest: ARRAY OF CHAR; src: ARRAY OF CHAR);
- VAR i : CARDINAL;
- BEGIN
- i := 0;
- WHILE (i < HIGH(dest)) & (src[i] # 0C) DO
- dest[i] := src[i]; INC(i)
- END;
- dest[i] := 0C
- END Assign;
- PROCEDURE Equal (a, b: ARRAY OF CHAR): BOOLEAN;
- VAR i : CARDINAL;
- BEGIN
- i := 0;
- LOOP
- IF a[i] # b[i] THEN RETURN FALSE END;
- IF a[i] = 0C THEN RETURN TRUE END;
- INC(i)
- END
- END Equal;
- PROCEDURE Less (a, b: ARRAY OF CHAR): BOOLEAN;
- (* Lexicographic order on NUL-terminated strings (BST key order). *)
- VAR i : CARDINAL;
- BEGIN
- i := 0;
- LOOP
- IF a[i] # b[i] THEN RETURN ORD(a[i]) < ORD(b[i]) END;
- IF a[i] = 0C THEN RETURN FALSE END;
- INC(i)
- END
- END Less;
- PROCEDURE StrLen (s: ARRAY OF CHAR): CARDINAL;
- VAR i : CARDINAL;
- BEGIN
- i := 0;
- WHILE (i < HIGH(s)) & (s[i] # 0C) DO INC(i) END;
- RETURN i
- END StrLen;
- PROCEDURE ConstInt (q: ARRAY OF CHAR; VAR v: INTEGER): BOOLEAN;
- VAR i, d: CARDINAL;
- neg: BOOLEAN;
- BEGIN
- v := 0; i := 0; neg := FALSE;
- IF q[0] = "-" THEN neg := TRUE; i := 1 END;
- IF (i >= HIGH(q)) OR (q[i] = 0C) THEN RETURN FALSE END;
- WHILE (i < HIGH(q)) & (q[i] # 0C) DO
- d := ORD(q[i]);
- IF (d < ORD("0")) OR (d > ORD("9")) THEN RETURN FALSE END;
- v := v * 10 + VAL(INTEGER, d - ORD("0")); INC(i)
- END;
- IF neg THEN v := -v END;
- RETURN TRUE
- END ConstInt;
- (* ---------------- scope tree + per-scope BST ---------------- *)
- PROCEDURE NewScope (parent: ScopePtr; level: CARDINAL): ScopePtr;
- (* Heap-allocates a scope and appends it to the creation chain. *)
- VAR s: ScopePtr;
- BEGIN
- ALLOCATE(s, TSIZE(ScopeNode));
- s^.parent := parent;
- s^.root := NIL;
- s^.level := level;
- s^.link := NIL;
- s^.ofRec := InvalidType;
- IF scopeList = NIL THEN scopeList := s ELSE scopeTail^.link := s END;
- scopeTail := s;
- RETURN s
- END NewScope;
- PROCEDURE TreeFind (root: SymPtr; name: ARRAY OF CHAR): SymPtr;
- (* BST search within one scope; NIL if absent. *)
- BEGIN
- WHILE root # NIL DO
- IF Equal(root^.name, name) THEN RETURN root END;
- IF Less(name, root^.name) THEN root := root^.left
- ELSE root := root^.right
- END
- END;
- RETURN NIL
- END TreeFind;
- PROCEDURE TreeInsert (s: ScopePtr; node: SymPtr): BOOLEAN;
- (* BST insert of node into scope s; FALSE on duplicate. *)
- VAR cur, parent: SymPtr;
- goLeft: BOOLEAN;
- BEGIN
- cur := s^.root; parent := NIL; goLeft := FALSE;
- WHILE cur # NIL DO
- IF Equal(cur^.name, node^.name) THEN RETURN FALSE END;
- parent := cur;
- IF Less(node^.name, cur^.name) THEN
- cur := cur^.left; goLeft := TRUE
- ELSE
- cur := cur^.right; goLeft := FALSE
- END
- END;
- node^.left := NIL;
- node^.right := NIL;
- node^.scope := s;
- IF parent = NIL THEN s^.root := node
- ELSIF goLeft THEN parent^.left := node
- ELSE parent^.right := node
- END;
- RETURN TRUE
- END TreeInsert;
- PROCEDURE Find (name: ARRAY OF CHAR): SymPtr;
- (* Innermost visible node or NIL; walks the scope chain up. *)
- VAR s: ScopePtr;
- r: SymPtr;
- BEGIN
- s := curScope;
- WHILE s # NIL DO
- r := TreeFind(s^.root, name);
- IF r # NIL THEN RETURN r END;
- s := s^.parent
- END;
- RETURN NIL
- END Find;
- PROCEDURE RawEnter (name: ARRAY OF CHAR; kind: INTEGER): SymPtr;
- (* Heap-allocates a symbol and links it into the current scope's
- BST; NIL on duplicate (node released to nobody: dropped). *)
- VAR node: SymPtr;
- BEGIN
- ALLOCATE(node, TSIZE(SymNode));
- Assign(node^.name, name);
- node^.kind := kind;
- node^.typ := InvalidType;
- node^.scope := curScope;
- node^.left := NIL;
- node^.right := NIL;
- IF ~TreeInsert(curScope, node) THEN RETURN NIL END;
- RETURN node
- END RawEnter;
- PROCEDURE Enter (name: ARRAY OF CHAR; kind: INTEGER): BOOLEAN;
- BEGIN
- RETURN RawEnter(name, kind) # NIL
- END Enter;
- PROCEDURE EnterPending (name: ARRAY OF CHAR; kind: INTEGER): BOOLEAN;
- VAR node: SymPtr;
- BEGIN
- node := RawEnter(name, kind);
- IF (node # NIL) & (nPend < MaxPend) THEN
- pend[nPend] := node; INC(nPend)
- END;
- RETURN node # NIL
- END EnterPending;
- PROCEDURE FixPending (t: TypeIndex);
- VAR i: CARDINAL;
- BEGIN
- i := 0;
- WHILE i < nPend DO
- pend[i]^.typ := t; INC(i)
- END;
- nPend := 0
- END FixPending;
- PROCEDURE PendCount (): CARDINAL;
- BEGIN
- RETURN nPend
- END PendCount;
- PROCEDURE PendName (i: CARDINAL; VAR n: Name);
- BEGIN
- IF i < nPend THEN Assign(n, pend[i]^.name)
- ELSE n[0] := 0C
- END
- END PendName;
- PROCEDURE FindField (rec: TypeIndex; name: ARRAY OF CHAR): FieldPtr;
- VAR f: FieldPtr;
- BEGIN
- IF (rec < 0) OR (rec >= VAL(INTEGER, nTypes)) THEN RETURN NIL END;
- IF (tform[rec] # FRecord) & (tform[rec] # FClass) THEN RETURN NIL END;
- f := fields;
- WHILE f # NIL DO
- IF (f^.owner = rec) & Equal(f^.name, name) THEN RETURN f END;
- f := f^.next
- END;
- RETURN NIL
- END FindField;
- PROCEDURE FieldPending (rec: TypeIndex; name: ARRAY OF CHAR): BOOLEAN;
- VAR f: FieldPtr;
- BEGIN
- IF FindField(rec, name) # NIL THEN RETURN FALSE END;
- ALLOCATE(f, TSIZE(FieldNode));
- Assign(f^.name, name);
- f^.typ := InvalidType;
- f^.owner := rec;
- f^.next := fields;
- fields := f;
- IF (rec >= 0) & (rec < VAL(INTEGER, nTypes)) THEN
- tdone[rec] := FALSE
- END;
- IF nPendF < MaxPend THEN
- pendF[nPendF] := f; INC(nPendF)
- END;
- INC(nFields);
- RETURN TRUE
- END FieldPending;
- PROCEDURE FixPendingF (rec: TypeIndex; t: TypeIndex);
- VAR i, j: CARDINAL;
- BEGIN
- i := 0;
- WHILE i < nPendF DO
- IF pendF[i]^.owner = rec THEN
- pendF[i]^.typ := t;
- (* remove by swap with last *)
- j := nPendF - 1;
- pendF[i] := pendF[j];
- DEC(nPendF)
- ELSE
- INC(i)
- END
- END
- END FixPendingF;
- PROCEDURE Lookup (name: ARRAY OF CHAR): BOOLEAN;
- BEGIN
- RETURN Find(name) # NIL
- END Lookup;
- PROCEDURE SymType (name: ARRAY OF CHAR): TypeIndex;
- VAR node: SymPtr;
- BEGIN
- node := Find(name);
- IF node = NIL THEN RETURN InvalidType END;
- RETURN node^.typ
- END SymType;
- PROCEDURE SetSymType (name: ARRAY OF CHAR; t: TypeIndex);
- VAR node: SymPtr;
- BEGIN
- node := Find(name);
- IF node # NIL THEN node^.typ := t END
- END SetSymType;
- PROCEDURE SymKind (name: ARRAY OF CHAR): INTEGER;
- VAR node: SymPtr;
- BEGIN
- node := Find(name);
- IF node = NIL THEN RETURN -1 END;
- RETURN node^.kind
- END SymKind;
- PROCEDURE PushScope;
- BEGIN
- curScope := NewScope(curScope, curScope^.level + 1)
- END PushScope;
- PROCEDURE PopScope;
- BEGIN
- (* Nodes stay allocated but become unreachable via the chain. *)
- IF curScope^.parent # NIL THEN curScope := curScope^.parent END
- END PopScope;
- (* ---------------- type descriptors (unchanged) ---------------- *)
- PROCEDURE NewDesc (form: INTEGER; ref: TypeIndex): TypeIndex;
- BEGIN
- IF nTypes >= MaxTypes THEN RETURN InvalidType END;
- tform[nTypes] := form;
- tref[nTypes] := ref;
- tdone[nTypes] := FALSE;
- INC(nTypes);
- RETURN VAL(INTEGER, nTypes - 1)
- END NewDesc;
- PROCEDURE NewAlias (): TypeIndex;
- BEGIN
- RETURN NewDesc(FAlias, InvalidType)
- END NewAlias;
- PROCEDURE NewSub (base: TypeIndex): TypeIndex;
- BEGIN
- RETURN NewDesc(FSub, base)
- END NewSub;
- PROCEDURE NewSubR (lo, hi: INTEGER): TypeIndex;
- VAR t: TypeIndex;
- BEGIN
- t := NewDesc(FSub, InvalidType);
- IF t # InvalidType THEN tlo[t] := lo; thi[t] := hi END;
- RETURN t
- END NewSubR;
- PROCEDURE NewEnum (): TypeIndex;
- BEGIN
- RETURN NewDesc(FEnum, InvalidType)
- END NewEnum;
- PROCEDURE NewArrayB (elem: TypeIndex; lo, hi: INTEGER): TypeIndex;
- VAR t: TypeIndex;
- BEGIN
- t := NewDesc(FArray, elem);
- IF t # InvalidType THEN alo[t] := lo; ahi[t] := hi END;
- RETURN t
- END NewArrayB;
- PROCEDURE NewOpenArray (elem: TypeIndex): TypeIndex;
- BEGIN
- RETURN NewDesc(FOpenArr, elem)
- END NewOpenArray;
- PROCEDURE BoundBegin;
- BEGIN
- nBounds := 0
- END BoundBegin;
- PROCEDURE BoundAdd (lo, hi: INTEGER): BOOLEAN;
- BEGIN
- IF nBounds > HIGH(blo) THEN RETURN FALSE END;
- blo[nBounds] := lo; bhi[nBounds] := hi; INC(nBounds);
- RETURN TRUE
- END BoundAdd;
- PROCEDURE NestArray (elem: TypeIndex): TypeIndex;
- VAR i: CARDINAL;
- BEGIN
- i := nBounds;
- WHILE i > 0 DO
- DEC(i);
- elem := NewArrayB(elem, blo[i], bhi[i])
- END;
- RETURN elem
- END NestArray;
- PROCEDURE NewRecord (): TypeIndex;
- BEGIN
- RETURN NewDesc(FRecord, -1)
- END NewRecord;
- PROCEDURE NewSet (base: TypeIndex): TypeIndex;
- BEGIN
- RETURN NewDesc(FSet, base)
- END NewSet;
- PROCEDURE NewPtr (base: TypeIndex): TypeIndex;
- BEGIN
- RETURN NewDesc(FPtr, base)
- END NewPtr;
- PROCEDURE NewStr (): TypeIndex;
- BEGIN
- RETURN NewDesc(FStr, InvalidType)
- END NewStr;
- PROCEDURE NewClass (): TypeIndex;
- VAR t: TypeIndex;
- BEGIN
- t := NewDesc(FClass, InvalidType);
- IF t # InvalidType THEN
- tparent[t] := InvalidType; tscope[t] := NIL
- END;
- RETURN t
- END NewClass;
- PROCEDURE SetParent (t, p: TypeIndex);
- BEGIN
- IF (t >= 0) & (t < VAL(INTEGER, nTypes)) & (tform[t] = FClass) THEN
- tparent[t] := p
- END
- END SetParent;
- PROCEDURE PushClassScope (t: TypeIndex);
- VAR r: TypeIndex;
- BEGIN
- r := Resolve(t);
- IF (r = InvalidType) OR (tform[r] # FClass) THEN RETURN END;
- PushScope;
- tscope[r] := curScope
- END PushClassScope;
- PROCEDURE SetTarget (t, base: TypeIndex);
- BEGIN
- IF (t >= 0) & (t < VAL(INTEGER, nTypes)) & (tform[t] = FAlias) THEN
- tref[t] := base
- END
- END SetTarget;
- PROCEDURE Resolve (t: TypeIndex): TypeIndex;
- VAR n: CARDINAL;
- BEGIN
- n := 0;
- WHILE (n < ResDepth) & (t >= 0) & (t < VAL(INTEGER, nTypes))
- & (tform[t] = FAlias) DO
- t := tref[t]; INC(n)
- END;
- IF (t < 0) OR (t >= VAL(INTEGER, nTypes)) THEN
- RETURN InvalidType
- END;
- RETURN t
- END Resolve;
- PROCEDURE IntType (): TypeIndex;
- BEGIN RETURN dInt END IntType;
- PROCEDURE RealType (): TypeIndex;
- BEGIN RETURN dReal END RealType;
- PROCEDURE CharType (): TypeIndex;
- BEGIN RETURN dChar END CharType;
- PROCEDURE BoolType (): TypeIndex;
- BEGIN RETURN dBool END BoolType;
- PROCEDURE ClassOf (t: TypeIndex): INTEGER;
- VAR r: TypeIndex;
- BEGIN
- r := Resolve(t);
- IF r = InvalidType THEN RETURN ClInvalid END;
- CASE tform[r] OF
- FInt : RETURN ClInt
- | FReal : RETURN ClReal
- | FChar : RETURN ClChar
- | FBool : RETURN ClBool
- | FEnum : RETURN ClEnum
- | FArray : RETURN ClArray
- | FOpenArr : RETURN ClArray
- | FRecord : RETURN ClRecord
- | FSet : RETURN ClSet
- | FPtr : RETURN ClPtr
- | FStr : RETURN ClStr
- | FClass : RETURN ClClass
- | FNil : RETURN ClNil
- | FSub : IF tref[r] = InvalidType THEN RETURN ClInt
- ELSE RETURN ClassOf(tref[r]) END
- ELSE RETURN ClInvalid
- END
- END ClassOf;
- PROCEDURE IsIntFamily (t: TypeIndex): BOOLEAN;
- BEGIN
- RETURN ClassOf(t) = ClInt
- END IsIntFamily;
- PROCEDURE SameType (a, b: TypeIndex): BOOLEAN;
- BEGIN
- IF (a = InvalidType) OR (b = InvalidType) THEN RETURN TRUE END;
- RETURN Resolve(a) = Resolve(b)
- END SameType;
- PROCEDURE FieldExists (rec: TypeIndex; name: ARRAY OF CHAR): BOOLEAN;
- BEGIN
- RETURN FindField(Resolve(rec), name) # NIL
- END FieldExists;
- PROCEDURE FieldType (rec: TypeIndex; name: ARRAY OF CHAR): TypeIndex;
- VAR f: FieldPtr;
- BEGIN
- f := FindField(Resolve(rec), name);
- IF f = NIL THEN RETURN InvalidType END;
- RETURN f^.typ
- END FieldType;
- PROCEDURE ArrayElem (t: TypeIndex): TypeIndex;
- VAR r: TypeIndex;
- BEGIN
- r := Resolve(t);
- IF (r = InvalidType) OR ((tform[r] # FArray)
- & (tform[r] # FOpenArr)) THEN
- RETURN InvalidType
- END;
- RETURN tref[r]
- END ArrayElem;
- PROCEDURE IsOpenArray (t: TypeIndex): BOOLEAN;
- VAR r: TypeIndex;
- BEGIN
- r := Resolve(t);
- IF r = InvalidType THEN RETURN FALSE END;
- RETURN tform[r] = FOpenArr
- END IsOpenArray;
- PROCEDURE ArrayLo (t: TypeIndex): INTEGER;
- VAR r: TypeIndex;
- BEGIN
- r := Resolve(t);
- IF (r = InvalidType) OR (tform[r] # FArray) THEN RETURN 0 END;
- RETURN alo[r]
- END ArrayLo;
- PROCEDURE ArrayHi (t: TypeIndex): INTEGER;
- VAR r: TypeIndex;
- BEGIN
- r := Resolve(t);
- IF (r = InvalidType) OR (tform[r] # FArray) THEN RETURN 0 END;
- RETURN ahi[r]
- END ArrayHi;
- PROCEDURE ArrayLen (t: TypeIndex): CARDINAL;
- VAR r: TypeIndex;
- lo, hi: INTEGER;
- BEGIN
- r := Resolve(t);
- IF (r = InvalidType) OR (tform[r] # FArray) THEN RETURN 0 END;
- lo := alo[r]; hi := ahi[r];
- IF hi < lo THEN RETURN 0 END;
- RETURN VAL(CARDINAL, hi - lo + 1)
- END ArrayLen;
- PROCEDURE ArrayDepth (t: TypeIndex): CARDINAL;
- VAR r: TypeIndex;
- d: CARDINAL;
- BEGIN
- d := 0; r := Resolve(t);
- WHILE (r # InvalidType) & ((tform[r] = FArray)
- OR (tform[r] = FOpenArr)) DO
- INC(d); r := Resolve(tref[r])
- END;
- RETURN d
- END ArrayDepth;
- PROCEDURE SubBounds (t: TypeIndex; VAR lo, hi: INTEGER): BOOLEAN;
- VAR r: TypeIndex;
- BEGIN
- lo := 0; hi := -1;
- r := Resolve(t);
- IF (r = InvalidType) OR (tform[r] # FSub)
- OR (tref[r] # InvalidType) THEN
- RETURN FALSE
- END;
- lo := tlo[r]; hi := thi[r];
- RETURN TRUE
- END SubBounds;
- PROCEDURE SetBase (t: TypeIndex): TypeIndex;
- VAR r: TypeIndex;
- BEGIN
- r := Resolve(t);
- IF (r = InvalidType) OR (tform[r] # FSet) THEN
- RETURN InvalidType
- END;
- RETURN tref[r]
- END SetBase;
- PROCEDURE SetSpan (t: TypeIndex; VAR lo, n: INTEGER): BOOLEAN;
- (* Base span for mask sizing; FALSE when unsuitable. Internal. *)
- VAR b, r: TypeIndex;
- blo, bhi: INTEGER;
- BEGIN
- lo := 0; n := 0;
- b := SetBase(t);
- IF b = InvalidType THEN RETURN FALSE END;
- r := Resolve(b);
- IF r = InvalidType THEN RETURN FALSE END;
- IF tform[r] = FBool THEN lo := 0; n := 2; RETURN TRUE END;
- IF tform[r] = FChar THEN lo := 0; n := 256; RETURN TRUE END;
- IF (tform[r] = FSub) & (tref[r] = InvalidType)
- & SubBounds(b, blo, bhi) & (bhi >= blo)
- & (bhi - blo < 256) THEN
- lo := blo; n := bhi - blo + 1; RETURN TRUE
- END;
- RETURN FALSE
- END SetSpan;
- PROCEDURE SetWords (t: TypeIndex): CARDINAL;
- VAR lo, n: INTEGER;
- BEGIN
- IF ~SetSpan(t, lo, n) THEN RETURN 0 END;
- RETURN VAL(CARDINAL, (n + 31) DIV 32)
- END SetWords;
- PROCEDURE SetBaseLo (t: TypeIndex): INTEGER;
- VAR lo, n: INTEGER;
- BEGIN
- IF ~SetSpan(t, lo, n) THEN RETURN 0 END;
- RETURN lo
- END SetBaseLo;
- PROCEDURE SetCount (t: TypeIndex): CARDINAL;
- VAR lo, n: INTEGER;
- BEGIN
- IF ~SetSpan(t, lo, n) THEN RETURN 0 END;
- RETURN VAL(CARDINAL, n)
- END SetCount;
- PROCEDURE PtrBase (t: TypeIndex): TypeIndex;
- VAR r: TypeIndex;
- BEGIN
- r := Resolve(t);
- IF (r = InvalidType) OR (tform[r] # FPtr) THEN
- RETURN InvalidType
- END;
- RETURN tref[r]
- END PtrBase;
- PROCEDURE TypeSizeD (t: TypeIndex; depth: CARDINAL): CARDINAL;
- (* Inline footprint in bytes: scalars 4/8, sets words*4, pointers,
- open and fixed arrays 8 (descriptor address — array objects live
- separately); records sum members. Depth guards cycles (not 223). *)
- VAR r: TypeIndex;
- f: FieldPtr;
- n: CARDINAL;
- BEGIN
- IF depth > ResDepth THEN RETURN 0 END;
- r := Resolve(t);
- IF r = InvalidType THEN RETURN 0 END;
- CASE tform[r] OF
- FInt, FBool, FChar : RETURN 4
- | FReal : RETURN 8
- | FEnum, FSub : RETURN 4
- | FSet : RETURN SetWords(t) * 4
- | FPtr, FOpenArr, FArray : RETURN 8
- | FRecord, FClass :
- n := 0;
- f := fields;
- WHILE f # NIL DO
- IF f^.owner = r THEN
- n := n + TypeSizeD(f^.typ, depth + 1)
- END;
- f := f^.next
- END;
- RETURN n
- | FAlias :
- RETURN TypeSizeD(tref[r], depth + 1)
- ELSE RETURN 0
- END
- END TypeSizeD;
- PROCEDURE TypeSize (t: TypeIndex): CARDINAL;
- BEGIN
- RETURN TypeSizeD(t, 0)
- END TypeSize;
- PROCEDURE ComputeOffsets (r: TypeIndex);
- (* Declaration-order offsets over the (prepend-built, hence reverse)
- field chain, plus declaration ranks. Array fields count 8
- (pointer-sized in records, matching the locked layout). *)
- VAR f: FieldPtr;
- total: INTEGER;
- cnt, ord: CARDINAL;
- off: INTEGER;
- BEGIN
- total := 0; cnt := 0;
- f := fields;
- WHILE f # NIL DO
- IF f^.owner = r THEN
- total := total + VAL(INTEGER, TypeSize(f^.typ));
- INC(cnt)
- END;
- f := f^.next
- END;
- off := total; ord := cnt;
- f := fields;
- WHILE f # NIL DO
- IF f^.owner = r THEN
- off := off - VAL(INTEGER, TypeSize(f^.typ));
- DEC(ord);
- f^.off := off;
- f^.ord := ord
- END;
- f := f^.next
- END;
- tdone[r] := TRUE
- END ComputeOffsets;
- PROCEDURE FieldOffset (rec: TypeIndex; name: ARRAY OF CHAR): INTEGER;
- VAR r: TypeIndex;
- f: FieldPtr;
- BEGIN
- r := Resolve(rec);
- IF (r = InvalidType) OR ((tform[r] # FRecord)
- & (tform[r] # FClass)) THEN
- RETURN -1
- END;
- IF ~tdone[r] THEN ComputeOffsets(r) END;
- f := FindField(r, name);
- IF f = NIL THEN RETURN -1 END;
- RETURN f^.off
- END FieldOffset;
- PROCEDURE FieldOwner (name: ARRAY OF CHAR): TypeIndex;
- VAR node: SymPtr;
- BEGIN
- node := Find(name);
- IF (node = NIL) OR (node^.kind # KindField) THEN
- RETURN InvalidType
- END;
- IF node^.scope = NIL THEN RETURN InvalidType END;
- RETURN node^.scope^.ofRec
- END FieldOwner;
- PROCEDURE FieldCount (rec: TypeIndex): CARDINAL;
- VAR r: TypeIndex;
- f: FieldPtr;
- n: CARDINAL;
- BEGIN
- n := 0;
- r := Resolve(rec);
- IF (r = InvalidType) OR ((tform[r] # FRecord)
- & (tform[r] # FClass)) THEN
- RETURN 0
- END;
- f := fields;
- WHILE f # NIL DO
- IF f^.owner = r THEN INC(n) END;
- f := f^.next
- END;
- RETURN n
- END FieldCount;
- PROCEDURE FieldName (rec: TypeIndex; i: CARDINAL; VAR name: Name);
- (* i-th field in DECLARATION order (chain is reverse; ord ranks it). *)
- VAR r: TypeIndex;
- f: FieldPtr;
- BEGIN
- name[0] := 0C;
- r := Resolve(rec);
- IF (r = InvalidType) OR ((tform[r] # FRecord)
- & (tform[r] # FClass)) THEN
- RETURN
- END;
- IF ~tdone[r] THEN ComputeOffsets(r) END;
- f := fields;
- WHILE f # NIL DO
- IF (f^.owner = r) & (f^.ord = i) THEN
- Assign(name, f^.name); RETURN
- END;
- f := f^.next
- END
- END FieldName;
- PROCEDURE PushRecord (t: TypeIndex): BOOLEAN;
- (* Pushes a scope with t's fields; caller must PopScope afterwards.
- Classes share the field machinery (methods stay in the class
- scope itself). *)
- VAR r: TypeIndex;
- f: FieldPtr;
- BEGIN
- r := Resolve(t);
- IF (r < 0) OR ((tform[r] # FRecord) & (tform[r] # FClass)) THEN
- RETURN FALSE
- END;
- PushScope;
- curScope^.ofRec := r;
- f := fields;
- WHILE f # NIL DO
- IF f^.owner = r THEN
- IF Enter(f^.name, KindField) THEN
- SetSymType(f^.name, f^.typ)
- END
- END;
- f := f^.next
- END;
- RETURN TRUE
- END PushRecord;
- (* ---------------- classes ---------------- *)
- PROCEDURE MethodExists (t: TypeIndex; name: ARRAY OF CHAR): BOOLEAN;
- VAR r: TypeIndex;
- s: ScopePtr;
- node: SymPtr;
- BEGIN
- r := Resolve(t);
- IF (r = InvalidType) OR (tform[r] # FClass) THEN RETURN FALSE END;
- s := tscope[r];
- IF s = NIL THEN RETURN FALSE END;
- node := TreeFind(s^.root, name);
- RETURN (node # NIL) & (node^.kind = KindProc)
- END MethodExists;
- PROCEDURE PushClassMembers (t: TypeIndex): BOOLEAN;
- (* Pushes a scope with t's fields (KindField) for method bodies in
- CLASS IMPLEMENTATION. Method NAMES are deliberately not copied:
- bodies re-enter them fresh via EnterProc (copying would collide
- as duplicates); sibling-method visibility waits for step 4 calls,
- when unknown names there honestly report 201. *)
- VAR r: TypeIndex;
- s: ScopePtr;
- f: FieldPtr;
- BEGIN
- r := Resolve(t);
- IF (r = InvalidType) OR (tform[r] # FClass) THEN RETURN FALSE END;
- s := tscope[r];
- IF s = NIL THEN RETURN FALSE END;
- PushScope;
- curScope^.ofRec := r;
- f := fields;
- WHILE f # NIL DO
- IF f^.owner = r THEN
- IF Enter(f^.name, KindField) THEN
- SetSymType(f^.name, f^.typ)
- END
- END;
- f := f^.next
- END;
- RETURN TRUE
- END PushClassMembers;
- PROCEDURE MarkVirtual;
- BEGIN
- IF curProc # NIL THEN curProc^.virt := TRUE END
- END MarkVirtual;
- (* ---------------- procedures ---------------- *)
- PROCEDURE PushProc (node: SymPtr);
- BEGIN
- IF nProc <= HIGH(procStk) THEN
- procStk[nProc] := node; INC(nProc)
- END
- END PushProc;
- PROCEDURE EnterProc (name: ARRAY OF CHAR): BOOLEAN;
- VAR node: SymPtr;
- BEGIN
- node := RawEnter(name, KindProc);
- IF node = NIL THEN curProc := NIL; RETURN FALSE END;
- node^.rslt := InvalidType;
- node^.plink := NIL;
- node^.isVar := FALSE;
- node^.fwd := FALSE;
- node^.virt := FALSE;
- node^.uid := nextUid; INC(nextUid);
- node^.fdep := nProc;
- curProc := node;
- curPTail := NIL;
- PushProc(node);
- PushScope;
- RETURN TRUE
- END EnterProc;
- PROCEDURE ResumeProc (name: ARRAY OF CHAR): BOOLEAN;
- VAR node: SymPtr;
- BEGIN
- IF curUnit # UnitImpl THEN RETURN FALSE END;
- node := TreeFind(curScope^.root, name);
- IF (node = NIL) OR (node^.kind # KindProc) THEN RETURN FALSE END;
- node^.plink := NIL; (* implementation re-enters formals *)
- curProc := node;
- curPTail := NIL;
- PushProc(node);
- PushScope;
- RETURN TRUE
- END ResumeProc;
- PROCEDURE ReenterProc (name: ARRAY OF CHAR): BOOLEAN;
- VAR node: SymPtr;
- BEGIN
- node := TreeFind(curScope^.root, name);
- IF (node = NIL) OR (node^.kind # KindProc) OR ~node^.fwd THEN
- RETURN FALSE
- END;
- node^.fwd := FALSE;
- node^.plink := NIL; (* fresh signature; step 4 compares old vs new *)
- curProc := node;
- curPTail := NIL;
- PushProc(node);
- PushScope;
- RETURN TRUE
- END ReenterProc;
- PROCEDURE EnterParam (name: ARRAY OF CHAR; isVar: BOOLEAN): BOOLEAN;
- VAR node: SymPtr;
- BEGIN
- node := RawEnter(name, KindParam);
- IF node = NIL THEN RETURN FALSE END;
- node^.isVar := isVar;
- node^.plink := NIL;
- IF (nPend < MaxPend) THEN
- pend[nPend] := node; INC(nPend)
- END;
- IF curProc # NIL THEN
- IF curProc^.plink = NIL THEN curProc^.plink := node
- ELSE curPTail^.plink := node
- END;
- curPTail := node
- END;
- RETURN TRUE
- END EnterParam;
- PROCEDURE SetProcRes (t: TypeIndex);
- BEGIN
- IF curProc # NIL THEN curProc^.rslt := t END
- END SetProcRes;
- PROCEDURE ProcRes (name: ARRAY OF CHAR): TypeIndex;
- VAR node: SymPtr;
- BEGIN
- node := Find(name);
- IF (node = NIL) OR (node^.kind # KindProc) THEN
- RETURN InvalidType
- END;
- RETURN node^.rslt
- END ProcRes;
- PROCEDURE MarkFwd;
- BEGIN
- IF curProc # NIL THEN curProc^.fwd := TRUE END
- END MarkFwd;
- PROCEDURE CloseProc;
- BEGIN
- IF nProc > 0 THEN DEC(nProc) END;
- PopScope
- END CloseProc;
- PROCEDURE InProc (): BOOLEAN;
- BEGIN
- RETURN nProc > 0
- END InProc;
- PROCEDURE CurRes (): TypeIndex;
- BEGIN
- IF nProc = 0 THEN RETURN InvalidType END;
- RETURN procStk[nProc - 1]^.rslt
- END CurRes;
- PROCEDURE ProcDepth (): CARDINAL;
- BEGIN
- RETURN nProc
- END ProcDepth;
- PROCEDURE ProcDepthOf (name: ARRAY OF CHAR): CARDINAL;
- VAR node: SymPtr;
- BEGIN
- node := Find(name);
- IF (node = NIL) OR (node^.kind # KindProc) THEN RETURN 0 END;
- RETURN node^.fdep
- END ProcDepthOf;
- PROCEDURE ProcUid (name: ARRAY OF CHAR): CARDINAL;
- VAR node: SymPtr;
- BEGIN
- node := Find(name);
- IF (node = NIL) OR (node^.kind # KindProc) THEN RETURN 0 END;
- RETURN node^.uid
- END ProcUid;
- PROCEDURE NthParam (node: SymPtr; i: CARDINAL): SymPtr;
- BEGIN
- node := node^.plink;
- WHILE (i > 0) & (node # NIL) DO
- node := node^.plink; DEC(i)
- END;
- RETURN node
- END NthParam;
- PROCEDURE ProcNPar (name: ARRAY OF CHAR): CARDINAL;
- VAR node, p: SymPtr;
- n: CARDINAL;
- BEGIN
- node := Find(name);
- IF (node = NIL) OR (node^.kind # KindProc) THEN RETURN 0 END;
- n := 0; p := node^.plink;
- WHILE p # NIL DO INC(n); p := p^.plink END;
- RETURN n
- END ProcNPar;
- PROCEDURE ParamType (name: ARRAY OF CHAR; i: CARDINAL): TypeIndex;
- VAR node, p: SymPtr;
- BEGIN
- node := Find(name);
- IF (node = NIL) OR (node^.kind # KindProc) THEN
- RETURN InvalidType
- END;
- p := NthParam(node, i);
- IF p = NIL THEN RETURN InvalidType END;
- RETURN p^.typ
- END ParamType;
- PROCEDURE ParamIsVar (name: ARRAY OF CHAR; i: CARDINAL): BOOLEAN;
- VAR node, p: SymPtr;
- BEGIN
- node := Find(name);
- IF (node = NIL) OR (node^.kind # KindProc) THEN RETURN FALSE END;
- p := NthParam(node, i);
- IF p = NIL THEN RETURN FALSE END;
- RETURN p^.isVar
- END ParamIsVar;
- PROCEDURE VarParamOk (actual, formal: TypeIndex): BOOLEAN;
- (* Addressable-designator compatibility for VAR formals: same type,
- or fixed array into open array with same element type, or string
- literal into open CHAR array. *)
- VAR fa, fe: TypeIndex;
- BEGIN
- IF (actual = InvalidType) OR (formal = InvalidType) THEN
- RETURN TRUE
- END;
- IF SameType(actual, formal) THEN RETURN TRUE END;
- IF IsOpenArray(formal)
- & (ClassOf(actual) = ClArray) & (ArrayDepth(actual) = 1) THEN
- fa := ArrayElem(actual); fe := ArrayElem(formal);
- IF SameType(fa, fe) THEN RETURN TRUE END
- END;
- IF IsOpenArray(formal) & (ClassOf(actual) = ClStr) THEN
- fe := ArrayElem(formal);
- IF ClassOf(fe) = ClChar THEN RETURN TRUE END
- END;
- RETURN FALSE
- END VarParamOk;
- (* ---------------- modules / separate compilation (step 4.3) ---------------- *)
- PROCEDURE EnterIn (s: ScopePtr; name: ARRAY OF CHAR;
- kind: INTEGER): BOOLEAN;
- VAR node: SymPtr;
- BEGIN
- ALLOCATE(node, TSIZE(SymNode));
- Assign(node^.name, name);
- node^.kind := kind;
- node^.typ := InvalidType;
- node^.scope := s;
- node^.left := NIL;
- node^.right := NIL;
- node^.rslt := InvalidType;
- node^.plink := NIL;
- node^.isVar := FALSE;
- node^.fwd := FALSE;
- node^.virt := FALSE;
- node^.fdep := 0;
- node^.uid := 0;
- IF ~TreeInsert(s, node) THEN RETURN FALSE END;
- RETURN TRUE
- END EnterIn;
- PROCEDURE FindMod (name: ARRAY OF CHAR): INTEGER;
- VAR i : CARDINAL;
- BEGIN
- i := 0;
- WHILE i < nMods DO
- IF Equal(modNames[i], name) THEN RETURN VAL(INTEGER, i) END;
- INC(i)
- END;
- RETURN -1
- END FindMod;
- PROCEDURE NewMod (name: ARRAY OF CHAR; kind: INTEGER): BOOLEAN;
- VAR idx : CARDINAL;
- s : ScopePtr;
- BEGIN
- IF nMods >= MaxMods THEN RETURN FALSE END;
- IF FindMod(name) # -1 THEN RETURN FALSE END;
- idx := nMods;
- Assign(modNames[idx], name);
- s := NewScope(globScope, 1);
- modScopes[idx] := s;
- modKind[idx] := kind;
- modImpl[idx] := FALSE;
- INC(nMods);
- (* the module name lives in the global scope *)
- IF ~EnterIn(globScope, name, KindModule) THEN
- DEC(nMods); RETURN FALSE
- END;
- curMod := VAL(INTEGER, idx);
- curUnit := kind;
- curScope := s;
- RETURN TRUE
- END NewMod;
- PROCEDURE BeginDef (name: ARRAY OF CHAR): BOOLEAN;
- BEGIN
- RETURN NewMod(name, UnitDef)
- END BeginDef;
- PROCEDURE BeginImpl (name: ARRAY OF CHAR): BOOLEAN;
- VAR idx : INTEGER;
- BEGIN
- idx := FindMod(name);
- IF idx = -1 THEN RETURN FALSE END;
- IF (modKind[idx] # UnitDef) OR modImpl[idx] THEN RETURN FALSE END;
- modImpl[idx] := TRUE;
- curMod := idx;
- curUnit := UnitImpl;
- curScope := modScopes[idx];
- RETURN TRUE
- END BeginImpl;
- PROCEDURE BeginProg (name: ARRAY OF CHAR): BOOLEAN;
- VAR ok : BOOLEAN;
- BEGIN
- ok := NewMod(name, UnitProg);
- IF ok THEN haveProg := TRUE END;
- RETURN ok
- END BeginProg;
- PROCEDURE HaveProgram (): BOOLEAN;
- BEGIN
- RETURN haveProg
- END HaveProgram;
- PROCEDURE EndUnit;
- BEGIN
- curScope := globScope;
- curMod := -1;
- curUnit := -1
- END EndUnit;
- PROCEDURE CurUnit (): INTEGER;
- BEGIN
- RETURN curUnit
- END CurUnit;
- PROCEDURE CurModule (VAR name: Name);
- BEGIN
- IF curMod < 0 THEN name[0] := 0C
- ELSE Assign(name, modNames[curMod])
- END
- END CurModule;
- PROCEDURE ModKnown (name: ARRAY OF CHAR): BOOLEAN;
- BEGIN
- RETURN FindMod(name) # -1
- END ModKnown;
- PROCEDURE ModDefined (name: ARRAY OF CHAR): BOOLEAN;
- VAR i : INTEGER;
- BEGIN
- i := FindMod(name);
- RETURN (i # -1) & (modKind[i] # UnitProg)
- END ModDefined;
- PROCEDURE ModImplemented (name: ARRAY OF CHAR): BOOLEAN;
- VAR i : INTEGER;
- BEGIN
- i := FindMod(name);
- RETURN (i # -1) & modImpl[i]
- END ModImplemented;
- PROCEDURE OpaqueBase (name: ARRAY OF CHAR): TypeIndex;
- VAR node: SymPtr;
- r : TypeIndex;
- BEGIN
- node := Find(name);
- IF (node = NIL) OR (node^.kind # KindType) THEN
- RETURN InvalidType
- END;
- r := node^.typ;
- IF (r < 0) OR (r >= VAL(INTEGER, nTypes)) THEN
- RETURN InvalidType
- END;
- IF (tform[r] = FAlias) & (tref[r] = InvalidType) THEN RETURN r END;
- RETURN InvalidType
- END OpaqueBase;
- PROCEDURE QualNode (mod, name: ARRAY OF CHAR): SymPtr;
- VAR i : INTEGER;
- BEGIN
- i := FindMod(mod);
- IF i = -1 THEN RETURN NIL END;
- RETURN TreeFind(modScopes[i]^.root, name)
- END QualNode;
- PROCEDURE QualFind (mod, name: ARRAY OF CHAR): BOOLEAN;
- BEGIN
- RETURN QualNode(mod, name) # NIL
- END QualFind;
- PROCEDURE QualKind (mod, name: ARRAY OF CHAR): INTEGER;
- VAR n : SymPtr;
- BEGIN
- n := QualNode(mod, name);
- IF n = NIL THEN RETURN -1 END;
- RETURN n^.kind
- END QualKind;
- PROCEDURE QualType (mod, name: ARRAY OF CHAR): TypeIndex;
- VAR n : SymPtr;
- BEGIN
- n := QualNode(mod, name);
- IF n = NIL THEN RETURN InvalidType END;
- RETURN n^.typ
- END QualType;
- PROCEDURE QualProcUid (mod, name: ARRAY OF CHAR): CARDINAL;
- VAR n : SymPtr;
- BEGIN
- n := QualNode(mod, name);
- IF (n = NIL) OR (n^.kind # KindProc) THEN RETURN 0 END;
- RETURN n^.uid
- END QualProcUid;
- PROCEDURE QualNthParam (n: SymPtr; i: CARDINAL): SymPtr;
- BEGIN
- n := n^.plink;
- WHILE (i > 0) & (n # NIL) DO
- n := n^.plink; DEC(i)
- END;
- RETURN n
- END QualNthParam;
- PROCEDURE QualProcNPar (mod, name: ARRAY OF CHAR): CARDINAL;
- VAR n, p : SymPtr;
- c : CARDINAL;
- BEGIN
- n := QualNode(mod, name);
- IF (n = NIL) OR (n^.kind # KindProc) THEN RETURN 0 END;
- c := 0; p := n^.plink;
- WHILE p # NIL DO INC(c); p := p^.plink END;
- RETURN c
- END QualProcNPar;
- PROCEDURE QualParamType (mod, name: ARRAY OF CHAR; i: CARDINAL):
- TypeIndex;
- VAR n, p : SymPtr;
- BEGIN
- n := QualNode(mod, name);
- IF (n = NIL) OR (n^.kind # KindProc) THEN
- RETURN InvalidType
- END;
- p := QualNthParam(n, i);
- IF p = NIL THEN RETURN InvalidType END;
- RETURN p^.typ
- END QualParamType;
- PROCEDURE QualParamIsVar (mod, name: ARRAY OF CHAR; i: CARDINAL):
- BOOLEAN;
- VAR n, p : SymPtr;
- BEGIN
- n := QualNode(mod, name);
- IF (n = NIL) OR (n^.kind # KindProc) THEN RETURN FALSE END;
- p := QualNthParam(n, i);
- IF p = NIL THEN RETURN FALSE END;
- RETURN p^.isVar
- END QualParamIsVar;
- PROCEDURE QualProcRes (mod, name: ARRAY OF CHAR): TypeIndex;
- VAR n : SymPtr;
- BEGIN
- n := QualNode(mod, name);
- IF (n = NIL) OR (n^.kind # KindProc) THEN
- RETURN InvalidType
- END;
- RETURN n^.rslt
- END QualProcRes;
- PROCEDURE Materialize (mod, name: ARRAY OF CHAR): BOOLEAN;
- (* Clones mod's export into the current scope (qualified-access
- flattening and FROM-import share this). *)
- VAR src, node : SymPtr;
- BEGIN
- src := QualNode(mod, name);
- IF src = NIL THEN RETURN FALSE END;
- (* already visible (repeat L.x): nothing to do *)
- IF TreeFind(curScope^.root, name) # NIL THEN RETURN TRUE END;
- ALLOCATE(node, TSIZE(SymNode));
- node^ := src^;
- node^.left := NIL;
- node^.right := NIL;
- node^.scope := curScope;
- IF ~TreeInsert(curScope, node) THEN RETURN FALSE END;
- RETURN TRUE
- END Materialize;
- PROCEDURE ImportFrom (mod, name: ARRAY OF CHAR): BOOLEAN;
- BEGIN
- RETURN Materialize(mod, name)
- END ImportFrom;
- (* ---------------- predicates (unchanged) ---------------- *)
- PROCEDURE BaseSpanOk (b: TypeIndex): BOOLEAN;
- (* TRUE for set-suitable bases: bool, char, subranges ≤ 256 wide. *)
- VAR r: TypeIndex;
- lo, hi: INTEGER;
- BEGIN
- r := Resolve(b);
- IF r = InvalidType THEN RETURN TRUE END;
- IF tform[r] = FBool THEN RETURN TRUE END;
- IF tform[r] = FChar THEN RETURN TRUE END;
- IF (tform[r] = FSub) & (tref[r] = InvalidType)
- & SubBounds(b, lo, hi) & (hi >= lo) & (hi - lo < 256) THEN
- RETURN TRUE
- END;
- RETURN FALSE
- END BaseSpanOk;
- PROCEDURE SetBasesOk (a, b: TypeIndex): BOOLEAN;
- (* base compatibility for two SET types: same, or both suitable
- (masks compare over min words + zero-check extras) *)
- BEGIN
- IF SameType(a, b) THEN RETURN TRUE END;
- RETURN BaseSpanOk(a) & BaseSpanOk(b)
- END SetBasesOk;
- PROCEDURE Assignable (src, dst: TypeIndex): BOOLEAN;
- VAR rs, rd: TypeIndex;
- BEGIN
- IF (src = InvalidType) OR (dst = InvalidType) THEN RETURN TRUE END;
- rs := Resolve(src); rd := Resolve(dst);
- IF rs = rd THEN RETURN TRUE END;
- IF (rs = InvalidType) OR (rd = InvalidType) THEN RETURN TRUE END;
- IF (tform[rs] = FSet) & (tform[rd] = FSet) THEN
- RETURN SetBasesOk(tref[rs], tref[rd])
- END;
- IF (ClassOf(src) = ClArray) & (ClassOf(dst) = ClArray) THEN
- RETURN SameType(src, dst)
- END;
- IF (ClassOf(src) = ClStr) & (ClassOf(dst) = ClArray) THEN
- RETURN (ArrayDepth(dst) = 1)
- & (ClassOf(ArrayElem(dst)) = ClChar)
- END;
- IF ClassOf(src) = ClNil THEN
- RETURN ClassOf(dst) = ClPtr
- END;
- IF (ClassOf(src) = ClInt) & (ClassOf(dst) = ClInt) THEN
- RETURN TRUE
- END;
- IF (ClassOf(src) = ClInt) & (ClassOf(dst) = ClReal) THEN
- RETURN TRUE
- END;
- RETURN FALSE
- END Assignable;
- PROCEDURE ArithCheck (l, r: TypeIndex; divmod: BOOLEAN;
- VAR res: TypeIndex): BOOLEAN;
- BEGIN
- res := InvalidType;
- IF (l = InvalidType) OR (r = InvalidType) THEN RETURN TRUE END;
- IF IsIntFamily(l) & IsIntFamily(r) THEN
- res := dInt; RETURN TRUE
- END;
- IF ~divmod & (ClassOf(l) = ClReal) & (ClassOf(r) = ClReal) THEN
- res := dReal; RETURN TRUE
- END;
- RETURN FALSE
- END ArithCheck;
- PROCEDURE UnaryCheck (t: TypeIndex; VAR res: TypeIndex): BOOLEAN;
- BEGIN
- res := InvalidType;
- IF t = InvalidType THEN RETURN TRUE END;
- IF IsIntFamily(t) THEN res := dInt; RETURN TRUE END;
- IF ClassOf(t) = ClReal THEN res := dReal; RETURN TRUE END;
- RETURN FALSE
- END UnaryCheck;
- PROCEDURE BoolCheck (t: TypeIndex): BOOLEAN;
- BEGIN
- IF t = InvalidType THEN RETURN TRUE END;
- RETURN ClassOf(t) = ClBool
- END BoolCheck;
- PROCEDURE EqCheck (l, r: TypeIndex): BOOLEAN;
- VAR rl, rr: TypeIndex;
- BEGIN
- IF (l = InvalidType) OR (r = InvalidType) THEN RETURN TRUE END;
- IF ClassOf(l) = ClNil THEN
- RETURN (ClassOf(r) = ClNil) OR (ClassOf(r) = ClPtr)
- END;
- IF ClassOf(r) = ClNil THEN
- RETURN (ClassOf(l) = ClNil) OR (ClassOf(l) = ClPtr)
- END;
- IF SameType(l, r) THEN
- (* Whole-array, string, record and class equality are not
- built-in (213); compare member-wise instead. *)
- IF (ClassOf(l) = ClArray) OR (ClassOf(l) = ClStr)
- OR (ClassOf(l) = ClRecord) OR (ClassOf(l) = ClClass) THEN
- RETURN FALSE
- END;
- RETURN TRUE
- END;
- IF IsIntFamily(l) & IsIntFamily(r) THEN RETURN TRUE END;
- IF (ClassOf(l) = ClReal) & (ClassOf(r) = ClReal) THEN
- RETURN TRUE
- END;
- IF (ClassOf(l) = ClChar) & (ClassOf(r) = ClChar) THEN
- RETURN TRUE
- END;
- IF (ClassOf(l) = ClBool) & (ClassOf(r) = ClBool) THEN
- RETURN TRUE
- END;
- rl := Resolve(l); rr := Resolve(r);
- IF (rl = InvalidType) OR (rr = InvalidType) THEN RETURN TRUE END;
- IF (tform[rl] = FSet) & (tform[rr] = FSet) THEN
- RETURN SetBasesOk(tref[rl], tref[rr])
- END;
- RETURN FALSE
- END EqCheck;
- PROCEDURE OrdCheck (l, r: TypeIndex): BOOLEAN;
- BEGIN
- IF (l = InvalidType) OR (r = InvalidType) THEN RETURN TRUE END;
- IF IsIntFamily(l) & IsIntFamily(r) THEN RETURN TRUE END;
- IF (ClassOf(l) = ClReal) & (ClassOf(r) = ClReal) THEN
- RETURN TRUE
- END;
- IF (ClassOf(l) = ClChar) & (ClassOf(r) = ClChar) THEN
- RETURN TRUE
- END;
- IF (ClassOf(l) = ClEnum) & SameType(l, r) THEN RETURN TRUE END;
- RETURN FALSE
- END OrdCheck;
- PROCEDURE InCheck (l, set: TypeIndex): BOOLEAN;
- VAR rs, b: TypeIndex;
- BEGIN
- IF (l = InvalidType) OR (set = InvalidType) THEN RETURN TRUE END;
- rs := Resolve(set);
- IF (rs = InvalidType) OR (tform[rs] # FSet) THEN RETURN FALSE END;
- b := tref[rs];
- IF SameType(l, b) THEN RETURN TRUE END;
- IF IsIntFamily(l) & IsIntFamily(b) THEN RETURN TRUE END;
- IF (ClassOf(l) = ClChar) & (ClassOf(b) = ClChar) THEN
- RETURN TRUE
- END;
- (* lenient: small int/char/bool tested against suitable sets;
- the span trap decides out-of-range at runtime *)
- IF ((ClassOf(l) = ClInt) OR (ClassOf(l) = ClChar)
- OR (ClassOf(l) = ClBool)) & (SetWords(set) > 0) THEN
- RETURN TRUE
- END;
- RETURN FALSE
- END InCheck;
- PROCEDURE RelCheck (l, r: TypeIndex; op: INTEGER): BOOLEAN;
- BEGIN
- IF (l = InvalidType) OR (r = InvalidType) THEN RETURN TRUE END;
- IF op = OpIn THEN RETURN InCheck(l, r) END;
- IF (op = OpEq) OR (op = OpNeq1) OR (op = OpNeq2) THEN
- RETURN EqCheck(l, r)
- END;
- RETURN OrdCheck(l, r)
- END RelCheck;
- PROCEDURE SetElemCheck (first, elem: TypeIndex): BOOLEAN;
- BEGIN
- IF (first = InvalidType) OR (elem = InvalidType) THEN
- RETURN TRUE
- END;
- IF SameType(first, elem) THEN RETURN TRUE END;
- IF IsIntFamily(first) & IsIntFamily(elem) THEN RETURN TRUE END;
- RETURN FALSE
- END SetElemCheck;
- PROCEDURE SetFor (elem: TypeIndex): TypeIndex;
- VAR e: TypeIndex;
- BEGIN
- e := Resolve(elem);
- IF e = InvalidType THEN e := dInt END;
- RETURN NewSet(e)
- END SetFor;
- (* ---------------- init ---------------- *)
- PROCEDURE Predef (name: ARRAY OF CHAR; kind: INTEGER; t: TypeIndex);
- BEGIN
- IF Enter(name, kind) THEN SetSymType(name, t) END
- END Predef;
- PROCEDURE Init;
- BEGIN
- scopeList := NIL; scopeTail := NIL;
- fields := NIL; nFields := 0;
- nPend := 0; nPendF := 0;
- nTypes := 0; nProc := 0; nBounds := 0; nextUid := 0;
- curProc := NIL; curPTail := NIL;
- nMods := 0; curMod := -1; curUnit := -1; haveProg := FALSE;
- curScope := NewScope(NIL, 0);
- globScope := curScope;
- dInt := NewDesc(FInt, InvalidType);
- dCard := NewDesc(FInt, InvalidType);
- dReal := NewDesc(FReal, InvalidType);
- dChar := NewDesc(FChar, InvalidType);
- dBool := NewDesc(FBool, InvalidType);
- dNil := NewDesc(FNil, InvalidType);
- Predef("INTEGER", KindPredef, dInt);
- Predef("CARDINAL", KindPredef, dCard);
- Predef("SHORTINT", KindPredef, dInt);
- Predef("LONGINT", KindPredef, dInt);
- Predef("SHORTCARD", KindPredef, dCard);
- Predef("REAL", KindPredef, dReal);
- Predef("LONGREAL", KindPredef, dReal);
- Predef("CHAR", KindPredef, dChar);
- Predef("BOOLEAN", KindPredef, dBool);
- Predef("TRUE", KindConst, dBool);
- Predef("FALSE", KindConst, dBool);
- Predef("NIL", KindConst, dNil)
- END Init;
- (* ---------------- listing ---------------- *)
- PROCEDURE WriteKind (kind: INTEGER);
- BEGIN
- CASE kind OF
- KindConst : FileIO.WriteString(FileIO.StdOut, "CONST")
- | KindType : FileIO.WriteString(FileIO.StdOut, "TYPE")
- | KindVar : FileIO.WriteString(FileIO.StdOut, "VAR")
- | KindImport : FileIO.WriteString(FileIO.StdOut, "IMPORT")
- | KindModule : FileIO.WriteString(FileIO.StdOut, "MODULE")
- | KindPredef : FileIO.WriteString(FileIO.StdOut, "PREDEF")
- | KindField : FileIO.WriteString(FileIO.StdOut, "FIELD")
- | KindProc : FileIO.WriteString(FileIO.StdOut, "PROC")
- | KindParam : FileIO.WriteString(FileIO.StdOut, "PARAM")
- ELSE FileIO.WriteString(FileIO.StdOut, "???")
- END
- END WriteKind;
- PROCEDURE WriteNode (node: SymPtr);
- BEGIN
- IF node = NIL THEN RETURN END;
- WriteNode(node^.left);
- FileIO.WriteString(FileIO.StdOut, " ");
- FileIO.WriteString(FileIO.StdOut, node^.name);
- FileIO.WriteString(FileIO.StdOut, " : ");
- WriteKind(node^.kind);
- FileIO.WriteString(FileIO.StdOut, " #");
- FileIO.WriteInt(FileIO.StdOut, node^.typ, 1);
- FileIO.WriteLn(FileIO.StdOut);
- WriteNode(node^.right)
- END WriteNode;
- PROCEDURE PrintTable;
- VAR s: ScopePtr;
- BEGIN
- FileIO.WriteLn(FileIO.StdOut);
- FileIO.WriteString(FileIO.StdOut, "--- Symbol table ---");
- FileIO.WriteLn(FileIO.StdOut);
- s := scopeList;
- WHILE s # NIL DO
- WriteNode(s^.root);
- s := s^.link
- END
- END PrintTable;
- BEGIN
- Init
- END SymTab.
|