| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606 |
- IMPLEMENTATION MODULE SymTab;
- IMPORT FileIO;
- CONST
- MaxTypes = 256;
- MaxFields = 512;
- MaxPend = 64;
- MaxMarks = 16;
- 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;
- TYPE
- Symbol = RECORD
- name : Name;
- kind : INTEGER;
- typ : TypeIndex;
- lev : CARDINAL;
- END;
- Field = RECORD
- name : Name;
- typ : TypeIndex;
- owner : TypeIndex;
- next : INTEGER; (* index of next field of same owner, -1 = end *)
- END;
- VAR
- syms : ARRAY [0 .. MaxSyms - 1] OF Symbol;
- nSyms : CARDINAL;
- curLev : CARDINAL;
- marks : ARRAY [0 .. MaxMarks - 1] OF CARDINAL;
- mtop : CARDINAL;
- pend : ARRAY [0 .. MaxPend - 1] OF CARDINAL;
- nPend : CARDINAL;
- pendF : ARRAY [0 .. MaxPend - 1] OF CARDINAL;
- nPendF : CARDINAL;
- tform : ARRAY [0 .. MaxTypes - 1] OF INTEGER;
- tref : ARRAY [0 .. MaxTypes - 1] OF TypeIndex;
- nTypes : CARDINAL;
- fields : ARRAY [0 .. MaxFields - 1] OF Field;
- nFields : CARDINAL;
- dInt, dCard, dReal, dChar, dBool : TypeIndex;
- (* ---------------- 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 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;
- (* ---------------- symbols and scopes ---------------- *)
- PROCEDURE Find (name: ARRAY OF CHAR): INTEGER;
- (* innermost visible index or -1 *)
- VAR i : CARDINAL;
- BEGIN
- i := nSyms;
- WHILE i > 0 DO
- DEC(i);
- IF Equal(syms[i].name, name) THEN RETURN VAL(INTEGER, i) END
- END;
- RETURN -1
- END Find;
- PROCEDURE RawEnter (name: ARRAY OF CHAR; kind: INTEGER): INTEGER;
- (* index or -1 when full *)
- BEGIN
- IF nSyms >= MaxSyms THEN RETURN -1 END;
- Assign(syms[nSyms].name, name);
- syms[nSyms].kind := kind;
- syms[nSyms].typ := InvalidType;
- syms[nSyms].lev := curLev;
- INC(nSyms);
- RETURN VAL(INTEGER, nSyms - 1)
- END RawEnter;
- PROCEDURE DupInLevel (name: ARRAY OF CHAR): BOOLEAN;
- VAR i : CARDINAL;
- BEGIN
- i := nSyms;
- WHILE (i > 0) & (syms[i - 1].lev = curLev) DO
- DEC(i);
- IF Equal(syms[i].name, name) THEN RETURN TRUE END
- END;
- RETURN FALSE
- END DupInLevel;
- PROCEDURE Enter (name: ARRAY OF CHAR; kind: INTEGER): BOOLEAN;
- BEGIN
- IF DupInLevel(name) THEN RETURN FALSE END;
- RETURN RawEnter(name, kind) # -1
- END Enter;
- PROCEDURE EnterPending (name: ARRAY OF CHAR; kind: INTEGER): BOOLEAN;
- VAR idx : INTEGER;
- BEGIN
- IF DupInLevel(name) THEN RETURN FALSE END;
- idx := RawEnter(name, kind);
- IF (idx # -1) & (nPend < MaxPend) THEN
- pend[nPend] := VAL(CARDINAL, idx); INC(nPend)
- END;
- RETURN idx # -1
- END EnterPending;
- PROCEDURE FixPending (t: TypeIndex);
- VAR i : CARDINAL;
- BEGIN
- i := 0;
- WHILE i < nPend DO
- syms[pend[i]].typ := t; INC(i)
- END;
- nPend := 0
- END FixPending;
- PROCEDURE FindField (rec: TypeIndex; name: ARRAY OF CHAR): INTEGER;
- VAR i : INTEGER;
- BEGIN
- IF (rec < 0) OR (rec >= VAL(INTEGER, nTypes)) THEN RETURN -1 END;
- IF tform[rec] # FRecord THEN RETURN -1 END;
- i := tref[rec];
- WHILE i # -1 DO
- IF Equal(fields[i].name, name) THEN RETURN i END;
- i := fields[i].next
- END;
- RETURN -1
- END FindField;
- PROCEDURE FieldPending (rec: TypeIndex; name: ARRAY OF CHAR): BOOLEAN;
- BEGIN
- IF FindField(rec, name) # -1 THEN RETURN FALSE END;
- IF nFields >= MaxFields THEN RETURN FALSE END;
- Assign(fields[nFields].name, name);
- fields[nFields].typ := InvalidType;
- fields[nFields].owner := rec;
- fields[nFields].next := tref[rec];
- tref[rec] := VAL(INTEGER, nFields);
- IF nPendF < MaxPend THEN
- pendF[nPendF] := nFields; 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 fields[pendF[i]].owner = rec THEN
- fields[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) # -1
- END Lookup;
- PROCEDURE SymType (name: ARRAY OF CHAR): TypeIndex;
- VAR idx : INTEGER;
- BEGIN
- idx := Find(name);
- IF idx = -1 THEN RETURN InvalidType END;
- RETURN syms[idx].typ
- END SymType;
- PROCEDURE SetSymType (name: ARRAY OF CHAR; t: TypeIndex);
- VAR idx : INTEGER;
- BEGIN
- idx := Find(name);
- IF idx # -1 THEN syms[idx].typ := t END
- END SetSymType;
- PROCEDURE SymKind (name: ARRAY OF CHAR): INTEGER;
- VAR idx : INTEGER;
- BEGIN
- idx := Find(name);
- IF idx = -1 THEN RETURN -1 END;
- RETURN syms[idx].kind
- END SymKind;
- PROCEDURE PushScope;
- BEGIN
- IF mtop < MaxMarks THEN marks[mtop] := nSyms; INC(mtop) END;
- INC(curLev)
- END PushScope;
- PROCEDURE PopScope;
- BEGIN
- IF mtop > 0 THEN DEC(mtop); nSyms := marks[mtop] END;
- IF curLev > 0 THEN DEC(curLev) END
- END PopScope;
- (* ---------------- type descriptors ---------------- *)
- PROCEDURE NewDesc (form: INTEGER; ref: TypeIndex): TypeIndex;
- BEGIN
- IF nTypes >= MaxTypes THEN RETURN InvalidType END;
- tform[nTypes] := form;
- tref[nTypes] := ref;
- 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 NewEnum (): TypeIndex;
- BEGIN
- RETURN NewDesc(FEnum, InvalidType)
- END NewEnum;
- PROCEDURE NewArray (elem: TypeIndex): TypeIndex;
- BEGIN
- RETURN NewDesc(FArray, elem)
- END NewArray;
- 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 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
- | FRecord : RETURN ClRecord
- | FSet : RETURN ClSet
- | FPtr : RETURN ClPtr
- | FStr : RETURN ClStr
- | FSub : RETURN ClassOf(tref[r])
- 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) # -1
- END FieldExists;
- PROCEDURE FieldType (rec: TypeIndex; name: ARRAY OF CHAR): TypeIndex;
- VAR i : INTEGER;
- BEGIN
- i := FindField(Resolve(rec), name);
- IF i = -1 THEN RETURN InvalidType END;
- RETURN fields[i].typ
- END FieldType;
- PROCEDURE ArrayElem (t: TypeIndex): TypeIndex;
- VAR r : TypeIndex;
- BEGIN
- r := Resolve(t);
- IF (r = InvalidType) OR (tform[r] # FArray) THEN
- RETURN InvalidType
- END;
- RETURN tref[r]
- END ArrayElem;
- 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 PushRecord (t: TypeIndex): BOOLEAN;
- (* Pushes a scope with t's fields; caller must PopScope afterwards. *)
- VAR r, i : INTEGER;
- BEGIN
- r := Resolve(t);
- IF (r < 0) OR (tform[r] # FRecord) THEN RETURN FALSE END;
- PushScope;
- i := tref[r];
- WHILE i # -1 DO
- IF Enter(fields[i].name, KindField) THEN
- SetSymType(fields[i].name, fields[i].typ)
- END;
- i := fields[i].next
- END;
- RETURN TRUE
- END PushRecord;
- (* ---------------- predicates ---------------- *)
- PROCEDURE SetBasesOk (a, b: TypeIndex): BOOLEAN;
- (* base compatibility for two SET types *)
- BEGIN
- IF SameType(a, b) THEN RETURN TRUE END;
- IF IsIntFamily(a) & IsIntFamily(b) THEN RETURN TRUE END;
- IF (ClassOf(a) = ClChar) & (ClassOf(b) = ClChar) THEN
- RETURN TRUE
- END;
- RETURN FALSE
- 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) = ClInt) & (ClassOf(dst) = ClInt) THEN
- RETURN TRUE
- END;
- IF (ClassOf(src) = ClInt) & (ClassOf(dst) = ClReal) THEN
- RETURN TRUE
- END;
- IF (ClassOf(src) = ClStr) & (ClassOf(dst) = ClArray) 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 SameType(l, r) 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) = ClBool) & (ClassOf(r) = ClBool) THEN
- RETURN TRUE
- END;
- IF (ClassOf(l) = ClStr) & (ClassOf(r) = ClStr) 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;
- 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
- nSyms := 0; curLev := 0; mtop := 0;
- nPend := 0; nPendF := 0;
- nTypes := 0; nFields := 0;
- dInt := NewDesc(FInt, InvalidType);
- dCard := NewDesc(FInt, InvalidType);
- dReal := NewDesc(FReal, InvalidType);
- dChar := NewDesc(FChar, InvalidType);
- dBool := NewDesc(FBool, InvalidType);
- Predef("INTEGER", KindPredef, dInt);
- Predef("CARDINAL", KindPredef, dCard);
- Predef("SHORTINT", KindPredef, dInt);
- Predef("LONGINT", KindPredef, dInt);
- 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, InvalidType)
- 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")
- ELSE FileIO.WriteString(FileIO.StdOut, "???")
- END
- END WriteKind;
- PROCEDURE PrintTable;
- VAR i : CARDINAL;
- BEGIN
- FileIO.WriteLn(FileIO.StdOut);
- FileIO.WriteString(FileIO.StdOut, "--- Symbol table ---");
- FileIO.WriteLn(FileIO.StdOut);
- i := 0;
- WHILE i < nSyms DO
- FileIO.WriteString(FileIO.StdOut, " ");
- FileIO.WriteString(FileIO.StdOut, syms[i].name);
- FileIO.WriteString(FileIO.StdOut, " : ");
- WriteKind(syms[i].kind);
- FileIO.WriteString(FileIO.StdOut, " #");
- FileIO.WriteInt(FileIO.StdOut, syms[i].typ, 1);
- FileIO.WriteLn(FileIO.StdOut);
- INC(i)
- END
- END PrintTable;
- BEGIN
- Init
- END SymTab.
|