SymTab.mod 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623
  1. IMPLEMENTATION MODULE SymTab;
  2. IMPORT FileIO;
  3. FROM Storage IMPORT ALLOCATE;
  4. FROM SYSTEM IMPORT TSIZE;
  5. CONST
  6. MaxTypes = 256;
  7. MaxPend = 64;
  8. MaxMods = 32;
  9. ResDepth = 64;
  10. (* descriptor forms *)
  11. FNone = 0; FAlias = 1; FSub = 2; FEnum = 3; FArray = 4;
  12. FRecord = 5; FSet = 6; FPtr = 7; FStr = 8;
  13. FInt = 9; FReal = 10; FChar = 11; FBool = 12;
  14. FClass = 13; FOpenArr = 14; FNil = 15;
  15. TYPE
  16. SymPtr = POINTER TO SymNode;
  17. ScopePtr = POINTER TO ScopeNode;
  18. FieldPtr = POINTER TO FieldNode;
  19. SymNode = RECORD
  20. name : Name;
  21. kind : INTEGER;
  22. typ : TypeIndex;
  23. scope : ScopePtr; (* owning scope *)
  24. left : SymPtr; (* BST links within the owning scope *)
  25. right : SymPtr;
  26. rslt : TypeIndex; (* KindProc result type, InvalidType = none *)
  27. plink : SymPtr; (* next formal, positional chain *)
  28. isVar : BOOLEAN; (* KindParam: VAR formal *)
  29. fwd : BOOLEAN; (* KindProc: FORWARD body pending *)
  30. virt : BOOLEAN; (* KindProc: VIRTUAL method *)
  31. fdep : CARDINAL; (* KindProc: lexical function-nesting depth *)
  32. uid : CARDINAL; (* KindProc: unique id for name mangling *)
  33. END;
  34. ScopeNode = RECORD
  35. parent : ScopePtr; (* scope tree link *)
  36. root : SymPtr; (* BST root of this scope's symbols *)
  37. level : CARDINAL;
  38. link : ScopePtr; (* creation-order chain for PrintTable *)
  39. ofRec : TypeIndex; (* record/class whose members live here *)
  40. END;
  41. FieldNode = RECORD
  42. name : Name;
  43. typ : TypeIndex;
  44. owner : TypeIndex;
  45. next : FieldPtr; (* next field of the same owner *)
  46. off : INTEGER; (* declaration-order byte offset *)
  47. ord : CARDINAL; (* declaration rank (chain is reverse) *)
  48. END;
  49. VAR
  50. curScope : ScopePtr;
  51. scopeList : ScopePtr; (* all scopes, creation order *)
  52. scopeTail : ScopePtr;
  53. fields : FieldPtr; (* all record fields, newest first *)
  54. nFields : CARDINAL;
  55. pend : ARRAY [0 .. MaxPend - 1] OF SymPtr;
  56. nPend : CARDINAL;
  57. pendF : ARRAY [0 .. MaxPend - 1] OF FieldPtr;
  58. nPendF : CARDINAL;
  59. tform : ARRAY [0 .. MaxTypes - 1] OF INTEGER;
  60. tref : ARRAY [0 .. MaxTypes - 1] OF TypeIndex;
  61. tlo : ARRAY [0 .. MaxTypes - 1] OF INTEGER;
  62. thi : ARRAY [0 .. MaxTypes - 1] OF INTEGER;
  63. tparent : ARRAY [0 .. MaxTypes - 1] OF TypeIndex;
  64. tscope : ARRAY [0 .. MaxTypes - 1] OF ScopePtr;
  65. tdone : ARRAY [0 .. MaxTypes - 1] OF BOOLEAN;
  66. alo : ARRAY [0 .. MaxTypes - 1] OF INTEGER;
  67. ahi : ARRAY [0 .. MaxTypes - 1] OF INTEGER;
  68. blo : ARRAY [0 .. 7] OF INTEGER;
  69. bhi : ARRAY [0 .. 7] OF INTEGER;
  70. nBounds : CARDINAL;
  71. nTypes : CARDINAL;
  72. curProc : SymPtr; (* heading being declared *)
  73. curPTail : SymPtr; (* positional param chain tail *)
  74. procStk : ARRAY [0 .. 15] OF SymPtr;
  75. nProc : CARDINAL;
  76. nextUid : CARDINAL;
  77. dInt, dCard, dReal, dChar, dBool, dNil : TypeIndex;
  78. globScope : ScopePtr; (* the global scope (module names live here) *)
  79. curMod : INTEGER; (* current registry slot, -1 between units *)
  80. curUnit : INTEGER; (* UnitProg/Def/Impl, -1 between units *)
  81. nMods : CARDINAL;
  82. modNames : ARRAY [0 .. MaxMods - 1] OF Name;
  83. modScopes : ARRAY [0 .. MaxMods - 1] OF ScopePtr;
  84. modKind : ARRAY [0 .. MaxMods - 1] OF INTEGER;
  85. modImpl : ARRAY [0 .. MaxMods - 1] OF BOOLEAN;
  86. haveProg : BOOLEAN;
  87. (* ---------------- strings ---------------- *)
  88. PROCEDURE Assign (VAR dest: ARRAY OF CHAR; src: ARRAY OF CHAR);
  89. VAR i : CARDINAL;
  90. BEGIN
  91. i := 0;
  92. WHILE (i < HIGH(dest)) & (src[i] # 0C) DO
  93. dest[i] := src[i]; INC(i)
  94. END;
  95. dest[i] := 0C
  96. END Assign;
  97. PROCEDURE Equal (a, b: ARRAY OF CHAR): BOOLEAN;
  98. VAR i : CARDINAL;
  99. BEGIN
  100. i := 0;
  101. LOOP
  102. IF a[i] # b[i] THEN RETURN FALSE END;
  103. IF a[i] = 0C THEN RETURN TRUE END;
  104. INC(i)
  105. END
  106. END Equal;
  107. PROCEDURE Less (a, b: ARRAY OF CHAR): BOOLEAN;
  108. (* Lexicographic order on NUL-terminated strings (BST key order). *)
  109. VAR i : CARDINAL;
  110. BEGIN
  111. i := 0;
  112. LOOP
  113. IF a[i] # b[i] THEN RETURN ORD(a[i]) < ORD(b[i]) END;
  114. IF a[i] = 0C THEN RETURN FALSE END;
  115. INC(i)
  116. END
  117. END Less;
  118. PROCEDURE StrLen (s: ARRAY OF CHAR): CARDINAL;
  119. VAR i : CARDINAL;
  120. BEGIN
  121. i := 0;
  122. WHILE (i < HIGH(s)) & (s[i] # 0C) DO INC(i) END;
  123. RETURN i
  124. END StrLen;
  125. PROCEDURE ConstInt (q: ARRAY OF CHAR; VAR v: INTEGER): BOOLEAN;
  126. VAR i, d: CARDINAL;
  127. neg: BOOLEAN;
  128. BEGIN
  129. v := 0; i := 0; neg := FALSE;
  130. IF q[0] = "-" THEN neg := TRUE; i := 1 END;
  131. IF (i >= HIGH(q)) OR (q[i] = 0C) THEN RETURN FALSE END;
  132. WHILE (i < HIGH(q)) & (q[i] # 0C) DO
  133. d := ORD(q[i]);
  134. IF (d < ORD("0")) OR (d > ORD("9")) THEN RETURN FALSE END;
  135. v := v * 10 + VAL(INTEGER, d - ORD("0")); INC(i)
  136. END;
  137. IF neg THEN v := -v END;
  138. RETURN TRUE
  139. END ConstInt;
  140. (* ---------------- scope tree + per-scope BST ---------------- *)
  141. PROCEDURE NewScope (parent: ScopePtr; level: CARDINAL): ScopePtr;
  142. (* Heap-allocates a scope and appends it to the creation chain. *)
  143. VAR s: ScopePtr;
  144. BEGIN
  145. ALLOCATE(s, TSIZE(ScopeNode));
  146. s^.parent := parent;
  147. s^.root := NIL;
  148. s^.level := level;
  149. s^.link := NIL;
  150. s^.ofRec := InvalidType;
  151. IF scopeList = NIL THEN scopeList := s ELSE scopeTail^.link := s END;
  152. scopeTail := s;
  153. RETURN s
  154. END NewScope;
  155. PROCEDURE TreeFind (root: SymPtr; name: ARRAY OF CHAR): SymPtr;
  156. (* BST search within one scope; NIL if absent. *)
  157. BEGIN
  158. WHILE root # NIL DO
  159. IF Equal(root^.name, name) THEN RETURN root END;
  160. IF Less(name, root^.name) THEN root := root^.left
  161. ELSE root := root^.right
  162. END
  163. END;
  164. RETURN NIL
  165. END TreeFind;
  166. PROCEDURE TreeInsert (s: ScopePtr; node: SymPtr): BOOLEAN;
  167. (* BST insert of node into scope s; FALSE on duplicate. *)
  168. VAR cur, parent: SymPtr;
  169. goLeft: BOOLEAN;
  170. BEGIN
  171. cur := s^.root; parent := NIL; goLeft := FALSE;
  172. WHILE cur # NIL DO
  173. IF Equal(cur^.name, node^.name) THEN RETURN FALSE END;
  174. parent := cur;
  175. IF Less(node^.name, cur^.name) THEN
  176. cur := cur^.left; goLeft := TRUE
  177. ELSE
  178. cur := cur^.right; goLeft := FALSE
  179. END
  180. END;
  181. node^.left := NIL;
  182. node^.right := NIL;
  183. node^.scope := s;
  184. IF parent = NIL THEN s^.root := node
  185. ELSIF goLeft THEN parent^.left := node
  186. ELSE parent^.right := node
  187. END;
  188. RETURN TRUE
  189. END TreeInsert;
  190. PROCEDURE Find (name: ARRAY OF CHAR): SymPtr;
  191. (* Innermost visible node or NIL; walks the scope chain up. *)
  192. VAR s: ScopePtr;
  193. r: SymPtr;
  194. BEGIN
  195. s := curScope;
  196. WHILE s # NIL DO
  197. r := TreeFind(s^.root, name);
  198. IF r # NIL THEN RETURN r END;
  199. s := s^.parent
  200. END;
  201. RETURN NIL
  202. END Find;
  203. PROCEDURE RawEnter (name: ARRAY OF CHAR; kind: INTEGER): SymPtr;
  204. (* Heap-allocates a symbol and links it into the current scope's
  205. BST; NIL on duplicate (node released to nobody: dropped). *)
  206. VAR node: SymPtr;
  207. BEGIN
  208. ALLOCATE(node, TSIZE(SymNode));
  209. Assign(node^.name, name);
  210. node^.kind := kind;
  211. node^.typ := InvalidType;
  212. node^.scope := curScope;
  213. node^.left := NIL;
  214. node^.right := NIL;
  215. IF ~TreeInsert(curScope, node) THEN RETURN NIL END;
  216. RETURN node
  217. END RawEnter;
  218. PROCEDURE Enter (name: ARRAY OF CHAR; kind: INTEGER): BOOLEAN;
  219. BEGIN
  220. RETURN RawEnter(name, kind) # NIL
  221. END Enter;
  222. PROCEDURE EnterPending (name: ARRAY OF CHAR; kind: INTEGER): BOOLEAN;
  223. VAR node: SymPtr;
  224. BEGIN
  225. node := RawEnter(name, kind);
  226. IF (node # NIL) & (nPend < MaxPend) THEN
  227. pend[nPend] := node; INC(nPend)
  228. END;
  229. RETURN node # NIL
  230. END EnterPending;
  231. PROCEDURE FixPending (t: TypeIndex);
  232. VAR i: CARDINAL;
  233. BEGIN
  234. i := 0;
  235. WHILE i < nPend DO
  236. pend[i]^.typ := t; INC(i)
  237. END;
  238. nPend := 0
  239. END FixPending;
  240. PROCEDURE PendCount (): CARDINAL;
  241. BEGIN
  242. RETURN nPend
  243. END PendCount;
  244. PROCEDURE PendName (i: CARDINAL; VAR n: Name);
  245. BEGIN
  246. IF i < nPend THEN Assign(n, pend[i]^.name)
  247. ELSE n[0] := 0C
  248. END
  249. END PendName;
  250. PROCEDURE FindField (rec: TypeIndex; name: ARRAY OF CHAR): FieldPtr;
  251. VAR f: FieldPtr;
  252. BEGIN
  253. IF (rec < 0) OR (rec >= VAL(INTEGER, nTypes)) THEN RETURN NIL END;
  254. IF (tform[rec] # FRecord) & (tform[rec] # FClass) THEN RETURN NIL END;
  255. f := fields;
  256. WHILE f # NIL DO
  257. IF (f^.owner = rec) & Equal(f^.name, name) THEN RETURN f END;
  258. f := f^.next
  259. END;
  260. RETURN NIL
  261. END FindField;
  262. PROCEDURE FieldPending (rec: TypeIndex; name: ARRAY OF CHAR): BOOLEAN;
  263. VAR f: FieldPtr;
  264. BEGIN
  265. IF FindField(rec, name) # NIL THEN RETURN FALSE END;
  266. ALLOCATE(f, TSIZE(FieldNode));
  267. Assign(f^.name, name);
  268. f^.typ := InvalidType;
  269. f^.owner := rec;
  270. f^.next := fields;
  271. fields := f;
  272. IF (rec >= 0) & (rec < VAL(INTEGER, nTypes)) THEN
  273. tdone[rec] := FALSE
  274. END;
  275. IF nPendF < MaxPend THEN
  276. pendF[nPendF] := f; INC(nPendF)
  277. END;
  278. INC(nFields);
  279. RETURN TRUE
  280. END FieldPending;
  281. PROCEDURE FixPendingF (rec: TypeIndex; t: TypeIndex);
  282. VAR i, j: CARDINAL;
  283. BEGIN
  284. i := 0;
  285. WHILE i < nPendF DO
  286. IF pendF[i]^.owner = rec THEN
  287. pendF[i]^.typ := t;
  288. (* remove by swap with last *)
  289. j := nPendF - 1;
  290. pendF[i] := pendF[j];
  291. DEC(nPendF)
  292. ELSE
  293. INC(i)
  294. END
  295. END
  296. END FixPendingF;
  297. PROCEDURE Lookup (name: ARRAY OF CHAR): BOOLEAN;
  298. BEGIN
  299. RETURN Find(name) # NIL
  300. END Lookup;
  301. PROCEDURE SymType (name: ARRAY OF CHAR): TypeIndex;
  302. VAR node: SymPtr;
  303. BEGIN
  304. node := Find(name);
  305. IF node = NIL THEN RETURN InvalidType END;
  306. RETURN node^.typ
  307. END SymType;
  308. PROCEDURE SetSymType (name: ARRAY OF CHAR; t: TypeIndex);
  309. VAR node: SymPtr;
  310. BEGIN
  311. node := Find(name);
  312. IF node # NIL THEN node^.typ := t END
  313. END SetSymType;
  314. PROCEDURE SymKind (name: ARRAY OF CHAR): INTEGER;
  315. VAR node: SymPtr;
  316. BEGIN
  317. node := Find(name);
  318. IF node = NIL THEN RETURN -1 END;
  319. RETURN node^.kind
  320. END SymKind;
  321. PROCEDURE PushScope;
  322. BEGIN
  323. curScope := NewScope(curScope, curScope^.level + 1)
  324. END PushScope;
  325. PROCEDURE PopScope;
  326. BEGIN
  327. (* Nodes stay allocated but become unreachable via the chain. *)
  328. IF curScope^.parent # NIL THEN curScope := curScope^.parent END
  329. END PopScope;
  330. (* ---------------- type descriptors (unchanged) ---------------- *)
  331. PROCEDURE NewDesc (form: INTEGER; ref: TypeIndex): TypeIndex;
  332. BEGIN
  333. IF nTypes >= MaxTypes THEN RETURN InvalidType END;
  334. tform[nTypes] := form;
  335. tref[nTypes] := ref;
  336. tdone[nTypes] := FALSE;
  337. INC(nTypes);
  338. RETURN VAL(INTEGER, nTypes - 1)
  339. END NewDesc;
  340. PROCEDURE NewAlias (): TypeIndex;
  341. BEGIN
  342. RETURN NewDesc(FAlias, InvalidType)
  343. END NewAlias;
  344. PROCEDURE NewSub (base: TypeIndex): TypeIndex;
  345. BEGIN
  346. RETURN NewDesc(FSub, base)
  347. END NewSub;
  348. PROCEDURE NewSubR (lo, hi: INTEGER): TypeIndex;
  349. VAR t: TypeIndex;
  350. BEGIN
  351. t := NewDesc(FSub, InvalidType);
  352. IF t # InvalidType THEN tlo[t] := lo; thi[t] := hi END;
  353. RETURN t
  354. END NewSubR;
  355. PROCEDURE NewEnum (): TypeIndex;
  356. BEGIN
  357. RETURN NewDesc(FEnum, InvalidType)
  358. END NewEnum;
  359. PROCEDURE NewArrayB (elem: TypeIndex; lo, hi: INTEGER): TypeIndex;
  360. VAR t: TypeIndex;
  361. BEGIN
  362. t := NewDesc(FArray, elem);
  363. IF t # InvalidType THEN alo[t] := lo; ahi[t] := hi END;
  364. RETURN t
  365. END NewArrayB;
  366. PROCEDURE NewOpenArray (elem: TypeIndex): TypeIndex;
  367. BEGIN
  368. RETURN NewDesc(FOpenArr, elem)
  369. END NewOpenArray;
  370. PROCEDURE BoundBegin;
  371. BEGIN
  372. nBounds := 0
  373. END BoundBegin;
  374. PROCEDURE BoundAdd (lo, hi: INTEGER): BOOLEAN;
  375. BEGIN
  376. IF nBounds > HIGH(blo) THEN RETURN FALSE END;
  377. blo[nBounds] := lo; bhi[nBounds] := hi; INC(nBounds);
  378. RETURN TRUE
  379. END BoundAdd;
  380. PROCEDURE NestArray (elem: TypeIndex): TypeIndex;
  381. VAR i: CARDINAL;
  382. BEGIN
  383. i := nBounds;
  384. WHILE i > 0 DO
  385. DEC(i);
  386. elem := NewArrayB(elem, blo[i], bhi[i])
  387. END;
  388. RETURN elem
  389. END NestArray;
  390. PROCEDURE NewRecord (): TypeIndex;
  391. BEGIN
  392. RETURN NewDesc(FRecord, -1)
  393. END NewRecord;
  394. PROCEDURE NewSet (base: TypeIndex): TypeIndex;
  395. BEGIN
  396. RETURN NewDesc(FSet, base)
  397. END NewSet;
  398. PROCEDURE NewPtr (base: TypeIndex): TypeIndex;
  399. BEGIN
  400. RETURN NewDesc(FPtr, base)
  401. END NewPtr;
  402. PROCEDURE NewStr (): TypeIndex;
  403. BEGIN
  404. RETURN NewDesc(FStr, InvalidType)
  405. END NewStr;
  406. PROCEDURE NewClass (): TypeIndex;
  407. VAR t: TypeIndex;
  408. BEGIN
  409. t := NewDesc(FClass, InvalidType);
  410. IF t # InvalidType THEN
  411. tparent[t] := InvalidType; tscope[t] := NIL
  412. END;
  413. RETURN t
  414. END NewClass;
  415. PROCEDURE SetParent (t, p: TypeIndex);
  416. BEGIN
  417. IF (t >= 0) & (t < VAL(INTEGER, nTypes)) & (tform[t] = FClass) THEN
  418. tparent[t] := p
  419. END
  420. END SetParent;
  421. PROCEDURE PushClassScope (t: TypeIndex);
  422. VAR r: TypeIndex;
  423. BEGIN
  424. r := Resolve(t);
  425. IF (r = InvalidType) OR (tform[r] # FClass) THEN RETURN END;
  426. PushScope;
  427. tscope[r] := curScope
  428. END PushClassScope;
  429. PROCEDURE SetTarget (t, base: TypeIndex);
  430. BEGIN
  431. IF (t >= 0) & (t < VAL(INTEGER, nTypes)) & (tform[t] = FAlias) THEN
  432. tref[t] := base
  433. END
  434. END SetTarget;
  435. PROCEDURE Resolve (t: TypeIndex): TypeIndex;
  436. VAR n: CARDINAL;
  437. BEGIN
  438. n := 0;
  439. WHILE (n < ResDepth) & (t >= 0) & (t < VAL(INTEGER, nTypes))
  440. & (tform[t] = FAlias) DO
  441. t := tref[t]; INC(n)
  442. END;
  443. IF (t < 0) OR (t >= VAL(INTEGER, nTypes)) THEN
  444. RETURN InvalidType
  445. END;
  446. RETURN t
  447. END Resolve;
  448. PROCEDURE IntType (): TypeIndex;
  449. BEGIN RETURN dInt END IntType;
  450. PROCEDURE RealType (): TypeIndex;
  451. BEGIN RETURN dReal END RealType;
  452. PROCEDURE CharType (): TypeIndex;
  453. BEGIN RETURN dChar END CharType;
  454. PROCEDURE BoolType (): TypeIndex;
  455. BEGIN RETURN dBool END BoolType;
  456. PROCEDURE ClassOf (t: TypeIndex): INTEGER;
  457. VAR r: TypeIndex;
  458. BEGIN
  459. r := Resolve(t);
  460. IF r = InvalidType THEN RETURN ClInvalid END;
  461. CASE tform[r] OF
  462. FInt : RETURN ClInt
  463. | FReal : RETURN ClReal
  464. | FChar : RETURN ClChar
  465. | FBool : RETURN ClBool
  466. | FEnum : RETURN ClEnum
  467. | FArray : RETURN ClArray
  468. | FOpenArr : RETURN ClArray
  469. | FRecord : RETURN ClRecord
  470. | FSet : RETURN ClSet
  471. | FPtr : RETURN ClPtr
  472. | FStr : RETURN ClStr
  473. | FClass : RETURN ClClass
  474. | FNil : RETURN ClNil
  475. | FSub : IF tref[r] = InvalidType THEN RETURN ClInt
  476. ELSE RETURN ClassOf(tref[r]) END
  477. ELSE RETURN ClInvalid
  478. END
  479. END ClassOf;
  480. PROCEDURE IsIntFamily (t: TypeIndex): BOOLEAN;
  481. BEGIN
  482. RETURN ClassOf(t) = ClInt
  483. END IsIntFamily;
  484. PROCEDURE SameType (a, b: TypeIndex): BOOLEAN;
  485. BEGIN
  486. IF (a = InvalidType) OR (b = InvalidType) THEN RETURN TRUE END;
  487. RETURN Resolve(a) = Resolve(b)
  488. END SameType;
  489. PROCEDURE FieldExists (rec: TypeIndex; name: ARRAY OF CHAR): BOOLEAN;
  490. BEGIN
  491. RETURN FindField(Resolve(rec), name) # NIL
  492. END FieldExists;
  493. PROCEDURE FieldType (rec: TypeIndex; name: ARRAY OF CHAR): TypeIndex;
  494. VAR f: FieldPtr;
  495. BEGIN
  496. f := FindField(Resolve(rec), name);
  497. IF f = NIL THEN RETURN InvalidType END;
  498. RETURN f^.typ
  499. END FieldType;
  500. PROCEDURE ArrayElem (t: TypeIndex): TypeIndex;
  501. VAR r: TypeIndex;
  502. BEGIN
  503. r := Resolve(t);
  504. IF (r = InvalidType) OR ((tform[r] # FArray)
  505. & (tform[r] # FOpenArr)) THEN
  506. RETURN InvalidType
  507. END;
  508. RETURN tref[r]
  509. END ArrayElem;
  510. PROCEDURE IsOpenArray (t: TypeIndex): BOOLEAN;
  511. VAR r: TypeIndex;
  512. BEGIN
  513. r := Resolve(t);
  514. IF r = InvalidType THEN RETURN FALSE END;
  515. RETURN tform[r] = FOpenArr
  516. END IsOpenArray;
  517. PROCEDURE ArrayLo (t: TypeIndex): INTEGER;
  518. VAR r: TypeIndex;
  519. BEGIN
  520. r := Resolve(t);
  521. IF (r = InvalidType) OR (tform[r] # FArray) THEN RETURN 0 END;
  522. RETURN alo[r]
  523. END ArrayLo;
  524. PROCEDURE ArrayHi (t: TypeIndex): INTEGER;
  525. VAR r: TypeIndex;
  526. BEGIN
  527. r := Resolve(t);
  528. IF (r = InvalidType) OR (tform[r] # FArray) THEN RETURN 0 END;
  529. RETURN ahi[r]
  530. END ArrayHi;
  531. PROCEDURE ArrayLen (t: TypeIndex): CARDINAL;
  532. VAR r: TypeIndex;
  533. lo, hi: INTEGER;
  534. BEGIN
  535. r := Resolve(t);
  536. IF (r = InvalidType) OR (tform[r] # FArray) THEN RETURN 0 END;
  537. lo := alo[r]; hi := ahi[r];
  538. IF hi < lo THEN RETURN 0 END;
  539. RETURN VAL(CARDINAL, hi - lo + 1)
  540. END ArrayLen;
  541. PROCEDURE ArrayDepth (t: TypeIndex): CARDINAL;
  542. VAR r: TypeIndex;
  543. d: CARDINAL;
  544. BEGIN
  545. d := 0; r := Resolve(t);
  546. WHILE (r # InvalidType) & ((tform[r] = FArray)
  547. OR (tform[r] = FOpenArr)) DO
  548. INC(d); r := Resolve(tref[r])
  549. END;
  550. RETURN d
  551. END ArrayDepth;
  552. PROCEDURE SubBounds (t: TypeIndex; VAR lo, hi: INTEGER): BOOLEAN;
  553. VAR r: TypeIndex;
  554. BEGIN
  555. lo := 0; hi := -1;
  556. r := Resolve(t);
  557. IF (r = InvalidType) OR (tform[r] # FSub)
  558. OR (tref[r] # InvalidType) THEN
  559. RETURN FALSE
  560. END;
  561. lo := tlo[r]; hi := thi[r];
  562. RETURN TRUE
  563. END SubBounds;
  564. PROCEDURE SetBase (t: TypeIndex): TypeIndex;
  565. VAR r: TypeIndex;
  566. BEGIN
  567. r := Resolve(t);
  568. IF (r = InvalidType) OR (tform[r] # FSet) THEN
  569. RETURN InvalidType
  570. END;
  571. RETURN tref[r]
  572. END SetBase;
  573. PROCEDURE SetSpan (t: TypeIndex; VAR lo, n: INTEGER): BOOLEAN;
  574. (* Base span for mask sizing; FALSE when unsuitable. Internal. *)
  575. VAR b, r: TypeIndex;
  576. blo, bhi: INTEGER;
  577. BEGIN
  578. lo := 0; n := 0;
  579. b := SetBase(t);
  580. IF b = InvalidType THEN RETURN FALSE END;
  581. r := Resolve(b);
  582. IF r = InvalidType THEN RETURN FALSE END;
  583. IF tform[r] = FBool THEN lo := 0; n := 2; RETURN TRUE END;
  584. IF tform[r] = FChar THEN lo := 0; n := 256; RETURN TRUE END;
  585. IF (tform[r] = FSub) & (tref[r] = InvalidType)
  586. & SubBounds(b, blo, bhi) & (bhi >= blo)
  587. & (bhi - blo < 256) THEN
  588. lo := blo; n := bhi - blo + 1; RETURN TRUE
  589. END;
  590. RETURN FALSE
  591. END SetSpan;
  592. PROCEDURE SetWords (t: TypeIndex): CARDINAL;
  593. VAR lo, n: INTEGER;
  594. BEGIN
  595. IF ~SetSpan(t, lo, n) THEN RETURN 0 END;
  596. RETURN VAL(CARDINAL, (n + 31) DIV 32)
  597. END SetWords;
  598. PROCEDURE SetBaseLo (t: TypeIndex): INTEGER;
  599. VAR lo, n: INTEGER;
  600. BEGIN
  601. IF ~SetSpan(t, lo, n) THEN RETURN 0 END;
  602. RETURN lo
  603. END SetBaseLo;
  604. PROCEDURE SetCount (t: TypeIndex): CARDINAL;
  605. VAR lo, n: INTEGER;
  606. BEGIN
  607. IF ~SetSpan(t, lo, n) THEN RETURN 0 END;
  608. RETURN VAL(CARDINAL, n)
  609. END SetCount;
  610. PROCEDURE PtrBase (t: TypeIndex): TypeIndex;
  611. VAR r: TypeIndex;
  612. BEGIN
  613. r := Resolve(t);
  614. IF (r = InvalidType) OR (tform[r] # FPtr) THEN
  615. RETURN InvalidType
  616. END;
  617. RETURN tref[r]
  618. END PtrBase;
  619. PROCEDURE TypeSizeD (t: TypeIndex; depth: CARDINAL): CARDINAL;
  620. (* Inline footprint in bytes: scalars 4/8, sets words*4, pointers,
  621. open and fixed arrays 8 (descriptor address — array objects live
  622. separately); records sum members. Depth guards cycles (not 223). *)
  623. VAR r: TypeIndex;
  624. f: FieldPtr;
  625. n: CARDINAL;
  626. BEGIN
  627. IF depth > ResDepth THEN RETURN 0 END;
  628. r := Resolve(t);
  629. IF r = InvalidType THEN RETURN 0 END;
  630. CASE tform[r] OF
  631. FInt, FBool, FChar : RETURN 4
  632. | FReal : RETURN 8
  633. | FEnum, FSub : RETURN 4
  634. | FSet : RETURN SetWords(t) * 4
  635. | FPtr, FOpenArr, FArray : RETURN 8
  636. | FRecord, FClass :
  637. n := 0;
  638. f := fields;
  639. WHILE f # NIL DO
  640. IF f^.owner = r THEN
  641. n := n + TypeSizeD(f^.typ, depth + 1)
  642. END;
  643. f := f^.next
  644. END;
  645. RETURN n
  646. | FAlias :
  647. RETURN TypeSizeD(tref[r], depth + 1)
  648. ELSE RETURN 0
  649. END
  650. END TypeSizeD;
  651. PROCEDURE TypeSize (t: TypeIndex): CARDINAL;
  652. BEGIN
  653. RETURN TypeSizeD(t, 0)
  654. END TypeSize;
  655. PROCEDURE ComputeOffsets (r: TypeIndex);
  656. (* Declaration-order offsets over the (prepend-built, hence reverse)
  657. field chain, plus declaration ranks. Array fields count 8
  658. (pointer-sized in records, matching the locked layout). *)
  659. VAR f: FieldPtr;
  660. total: INTEGER;
  661. cnt, ord: CARDINAL;
  662. off: INTEGER;
  663. BEGIN
  664. total := 0; cnt := 0;
  665. f := fields;
  666. WHILE f # NIL DO
  667. IF f^.owner = r THEN
  668. total := total + VAL(INTEGER, TypeSize(f^.typ));
  669. INC(cnt)
  670. END;
  671. f := f^.next
  672. END;
  673. off := total; ord := cnt;
  674. f := fields;
  675. WHILE f # NIL DO
  676. IF f^.owner = r THEN
  677. off := off - VAL(INTEGER, TypeSize(f^.typ));
  678. DEC(ord);
  679. f^.off := off;
  680. f^.ord := ord
  681. END;
  682. f := f^.next
  683. END;
  684. tdone[r] := TRUE
  685. END ComputeOffsets;
  686. PROCEDURE FieldOffset (rec: TypeIndex; name: ARRAY OF CHAR): INTEGER;
  687. VAR r: TypeIndex;
  688. f: FieldPtr;
  689. BEGIN
  690. r := Resolve(rec);
  691. IF (r = InvalidType) OR ((tform[r] # FRecord)
  692. & (tform[r] # FClass)) THEN
  693. RETURN -1
  694. END;
  695. IF ~tdone[r] THEN ComputeOffsets(r) END;
  696. f := FindField(r, name);
  697. IF f = NIL THEN RETURN -1 END;
  698. RETURN f^.off
  699. END FieldOffset;
  700. PROCEDURE FieldOwner (name: ARRAY OF CHAR): TypeIndex;
  701. VAR node: SymPtr;
  702. BEGIN
  703. node := Find(name);
  704. IF (node = NIL) OR (node^.kind # KindField) THEN
  705. RETURN InvalidType
  706. END;
  707. IF node^.scope = NIL THEN RETURN InvalidType END;
  708. RETURN node^.scope^.ofRec
  709. END FieldOwner;
  710. PROCEDURE FieldCount (rec: TypeIndex): CARDINAL;
  711. VAR r: TypeIndex;
  712. f: FieldPtr;
  713. n: CARDINAL;
  714. BEGIN
  715. n := 0;
  716. r := Resolve(rec);
  717. IF (r = InvalidType) OR ((tform[r] # FRecord)
  718. & (tform[r] # FClass)) THEN
  719. RETURN 0
  720. END;
  721. f := fields;
  722. WHILE f # NIL DO
  723. IF f^.owner = r THEN INC(n) END;
  724. f := f^.next
  725. END;
  726. RETURN n
  727. END FieldCount;
  728. PROCEDURE FieldName (rec: TypeIndex; i: CARDINAL; VAR name: Name);
  729. (* i-th field in DECLARATION order (chain is reverse; ord ranks it). *)
  730. VAR r: TypeIndex;
  731. f: FieldPtr;
  732. BEGIN
  733. name[0] := 0C;
  734. r := Resolve(rec);
  735. IF (r = InvalidType) OR ((tform[r] # FRecord)
  736. & (tform[r] # FClass)) THEN
  737. RETURN
  738. END;
  739. IF ~tdone[r] THEN ComputeOffsets(r) END;
  740. f := fields;
  741. WHILE f # NIL DO
  742. IF (f^.owner = r) & (f^.ord = i) THEN
  743. Assign(name, f^.name); RETURN
  744. END;
  745. f := f^.next
  746. END
  747. END FieldName;
  748. PROCEDURE PushRecord (t: TypeIndex): BOOLEAN;
  749. (* Pushes a scope with t's fields; caller must PopScope afterwards.
  750. Classes share the field machinery (methods stay in the class
  751. scope itself). *)
  752. VAR r: TypeIndex;
  753. f: FieldPtr;
  754. BEGIN
  755. r := Resolve(t);
  756. IF (r < 0) OR ((tform[r] # FRecord) & (tform[r] # FClass)) THEN
  757. RETURN FALSE
  758. END;
  759. PushScope;
  760. curScope^.ofRec := r;
  761. f := fields;
  762. WHILE f # NIL DO
  763. IF f^.owner = r THEN
  764. IF Enter(f^.name, KindField) THEN
  765. SetSymType(f^.name, f^.typ)
  766. END
  767. END;
  768. f := f^.next
  769. END;
  770. RETURN TRUE
  771. END PushRecord;
  772. (* ---------------- classes ---------------- *)
  773. PROCEDURE MethodExists (t: TypeIndex; name: ARRAY OF CHAR): BOOLEAN;
  774. VAR r: TypeIndex;
  775. s: ScopePtr;
  776. node: SymPtr;
  777. BEGIN
  778. r := Resolve(t);
  779. IF (r = InvalidType) OR (tform[r] # FClass) THEN RETURN FALSE END;
  780. s := tscope[r];
  781. IF s = NIL THEN RETURN FALSE END;
  782. node := TreeFind(s^.root, name);
  783. RETURN (node # NIL) & (node^.kind = KindProc)
  784. END MethodExists;
  785. PROCEDURE PushClassMembers (t: TypeIndex): BOOLEAN;
  786. (* Pushes a scope with t's fields (KindField) for method bodies in
  787. CLASS IMPLEMENTATION. Method NAMES are deliberately not copied:
  788. bodies re-enter them fresh via EnterProc (copying would collide
  789. as duplicates); sibling-method visibility waits for step 4 calls,
  790. when unknown names there honestly report 201. *)
  791. VAR r: TypeIndex;
  792. s: ScopePtr;
  793. f: FieldPtr;
  794. BEGIN
  795. r := Resolve(t);
  796. IF (r = InvalidType) OR (tform[r] # FClass) THEN RETURN FALSE END;
  797. s := tscope[r];
  798. IF s = NIL THEN RETURN FALSE END;
  799. PushScope;
  800. curScope^.ofRec := r;
  801. f := fields;
  802. WHILE f # NIL DO
  803. IF f^.owner = r THEN
  804. IF Enter(f^.name, KindField) THEN
  805. SetSymType(f^.name, f^.typ)
  806. END
  807. END;
  808. f := f^.next
  809. END;
  810. RETURN TRUE
  811. END PushClassMembers;
  812. PROCEDURE MarkVirtual;
  813. BEGIN
  814. IF curProc # NIL THEN curProc^.virt := TRUE END
  815. END MarkVirtual;
  816. (* ---------------- procedures ---------------- *)
  817. PROCEDURE PushProc (node: SymPtr);
  818. BEGIN
  819. IF nProc <= HIGH(procStk) THEN
  820. procStk[nProc] := node; INC(nProc)
  821. END
  822. END PushProc;
  823. PROCEDURE EnterProc (name: ARRAY OF CHAR): BOOLEAN;
  824. VAR node: SymPtr;
  825. BEGIN
  826. node := RawEnter(name, KindProc);
  827. IF node = NIL THEN curProc := NIL; RETURN FALSE END;
  828. node^.rslt := InvalidType;
  829. node^.plink := NIL;
  830. node^.isVar := FALSE;
  831. node^.fwd := FALSE;
  832. node^.virt := FALSE;
  833. node^.uid := nextUid; INC(nextUid);
  834. node^.fdep := nProc;
  835. curProc := node;
  836. curPTail := NIL;
  837. PushProc(node);
  838. PushScope;
  839. RETURN TRUE
  840. END EnterProc;
  841. PROCEDURE ResumeProc (name: ARRAY OF CHAR): BOOLEAN;
  842. VAR node: SymPtr;
  843. BEGIN
  844. IF curUnit # UnitImpl THEN RETURN FALSE END;
  845. node := TreeFind(curScope^.root, name);
  846. IF (node = NIL) OR (node^.kind # KindProc) THEN RETURN FALSE END;
  847. node^.plink := NIL; (* implementation re-enters formals *)
  848. curProc := node;
  849. curPTail := NIL;
  850. PushProc(node);
  851. PushScope;
  852. RETURN TRUE
  853. END ResumeProc;
  854. PROCEDURE ReenterProc (name: ARRAY OF CHAR): BOOLEAN;
  855. VAR node: SymPtr;
  856. BEGIN
  857. node := TreeFind(curScope^.root, name);
  858. IF (node = NIL) OR (node^.kind # KindProc) OR ~node^.fwd THEN
  859. RETURN FALSE
  860. END;
  861. node^.fwd := FALSE;
  862. node^.plink := NIL; (* fresh signature; step 4 compares old vs new *)
  863. curProc := node;
  864. curPTail := NIL;
  865. PushProc(node);
  866. PushScope;
  867. RETURN TRUE
  868. END ReenterProc;
  869. PROCEDURE EnterParam (name: ARRAY OF CHAR; isVar: BOOLEAN): BOOLEAN;
  870. VAR node: SymPtr;
  871. BEGIN
  872. node := RawEnter(name, KindParam);
  873. IF node = NIL THEN RETURN FALSE END;
  874. node^.isVar := isVar;
  875. node^.plink := NIL;
  876. IF (nPend < MaxPend) THEN
  877. pend[nPend] := node; INC(nPend)
  878. END;
  879. IF curProc # NIL THEN
  880. IF curProc^.plink = NIL THEN curProc^.plink := node
  881. ELSE curPTail^.plink := node
  882. END;
  883. curPTail := node
  884. END;
  885. RETURN TRUE
  886. END EnterParam;
  887. PROCEDURE SetProcRes (t: TypeIndex);
  888. BEGIN
  889. IF curProc # NIL THEN curProc^.rslt := t END
  890. END SetProcRes;
  891. PROCEDURE ProcRes (name: ARRAY OF CHAR): TypeIndex;
  892. VAR node: SymPtr;
  893. BEGIN
  894. node := Find(name);
  895. IF (node = NIL) OR (node^.kind # KindProc) THEN
  896. RETURN InvalidType
  897. END;
  898. RETURN node^.rslt
  899. END ProcRes;
  900. PROCEDURE MarkFwd;
  901. BEGIN
  902. IF curProc # NIL THEN curProc^.fwd := TRUE END
  903. END MarkFwd;
  904. PROCEDURE CloseProc;
  905. BEGIN
  906. IF nProc > 0 THEN DEC(nProc) END;
  907. PopScope
  908. END CloseProc;
  909. PROCEDURE InProc (): BOOLEAN;
  910. BEGIN
  911. RETURN nProc > 0
  912. END InProc;
  913. PROCEDURE CurRes (): TypeIndex;
  914. BEGIN
  915. IF nProc = 0 THEN RETURN InvalidType END;
  916. RETURN procStk[nProc - 1]^.rslt
  917. END CurRes;
  918. PROCEDURE ProcDepth (): CARDINAL;
  919. BEGIN
  920. RETURN nProc
  921. END ProcDepth;
  922. PROCEDURE ProcDepthOf (name: ARRAY OF CHAR): CARDINAL;
  923. VAR node: SymPtr;
  924. BEGIN
  925. node := Find(name);
  926. IF (node = NIL) OR (node^.kind # KindProc) THEN RETURN 0 END;
  927. RETURN node^.fdep
  928. END ProcDepthOf;
  929. PROCEDURE ProcUid (name: ARRAY OF CHAR): CARDINAL;
  930. VAR node: SymPtr;
  931. BEGIN
  932. node := Find(name);
  933. IF (node = NIL) OR (node^.kind # KindProc) THEN RETURN 0 END;
  934. RETURN node^.uid
  935. END ProcUid;
  936. PROCEDURE NthParam (node: SymPtr; i: CARDINAL): SymPtr;
  937. BEGIN
  938. node := node^.plink;
  939. WHILE (i > 0) & (node # NIL) DO
  940. node := node^.plink; DEC(i)
  941. END;
  942. RETURN node
  943. END NthParam;
  944. PROCEDURE ProcNPar (name: ARRAY OF CHAR): CARDINAL;
  945. VAR node, p: SymPtr;
  946. n: CARDINAL;
  947. BEGIN
  948. node := Find(name);
  949. IF (node = NIL) OR (node^.kind # KindProc) THEN RETURN 0 END;
  950. n := 0; p := node^.plink;
  951. WHILE p # NIL DO INC(n); p := p^.plink END;
  952. RETURN n
  953. END ProcNPar;
  954. PROCEDURE ParamType (name: ARRAY OF CHAR; i: CARDINAL): TypeIndex;
  955. VAR node, p: SymPtr;
  956. BEGIN
  957. node := Find(name);
  958. IF (node = NIL) OR (node^.kind # KindProc) THEN
  959. RETURN InvalidType
  960. END;
  961. p := NthParam(node, i);
  962. IF p = NIL THEN RETURN InvalidType END;
  963. RETURN p^.typ
  964. END ParamType;
  965. PROCEDURE ParamIsVar (name: ARRAY OF CHAR; i: CARDINAL): BOOLEAN;
  966. VAR node, p: SymPtr;
  967. BEGIN
  968. node := Find(name);
  969. IF (node = NIL) OR (node^.kind # KindProc) THEN RETURN FALSE END;
  970. p := NthParam(node, i);
  971. IF p = NIL THEN RETURN FALSE END;
  972. RETURN p^.isVar
  973. END ParamIsVar;
  974. PROCEDURE VarParamOk (actual, formal: TypeIndex): BOOLEAN;
  975. (* Addressable-designator compatibility for VAR formals: same type,
  976. or fixed array into open array with same element type, or string
  977. literal into open CHAR array. *)
  978. VAR fa, fe: TypeIndex;
  979. BEGIN
  980. IF (actual = InvalidType) OR (formal = InvalidType) THEN
  981. RETURN TRUE
  982. END;
  983. IF SameType(actual, formal) THEN RETURN TRUE END;
  984. IF IsOpenArray(formal)
  985. & (ClassOf(actual) = ClArray) & (ArrayDepth(actual) = 1) THEN
  986. fa := ArrayElem(actual); fe := ArrayElem(formal);
  987. IF SameType(fa, fe) THEN RETURN TRUE END
  988. END;
  989. IF IsOpenArray(formal) & (ClassOf(actual) = ClStr) THEN
  990. fe := ArrayElem(formal);
  991. IF ClassOf(fe) = ClChar THEN RETURN TRUE END
  992. END;
  993. RETURN FALSE
  994. END VarParamOk;
  995. (* ---------------- modules / separate compilation (step 4.3) ---------------- *)
  996. PROCEDURE EnterIn (s: ScopePtr; name: ARRAY OF CHAR;
  997. kind: INTEGER): BOOLEAN;
  998. VAR node: SymPtr;
  999. BEGIN
  1000. ALLOCATE(node, TSIZE(SymNode));
  1001. Assign(node^.name, name);
  1002. node^.kind := kind;
  1003. node^.typ := InvalidType;
  1004. node^.scope := s;
  1005. node^.left := NIL;
  1006. node^.right := NIL;
  1007. node^.rslt := InvalidType;
  1008. node^.plink := NIL;
  1009. node^.isVar := FALSE;
  1010. node^.fwd := FALSE;
  1011. node^.virt := FALSE;
  1012. node^.fdep := 0;
  1013. node^.uid := 0;
  1014. IF ~TreeInsert(s, node) THEN RETURN FALSE END;
  1015. RETURN TRUE
  1016. END EnterIn;
  1017. PROCEDURE FindMod (name: ARRAY OF CHAR): INTEGER;
  1018. VAR i : CARDINAL;
  1019. BEGIN
  1020. i := 0;
  1021. WHILE i < nMods DO
  1022. IF Equal(modNames[i], name) THEN RETURN VAL(INTEGER, i) END;
  1023. INC(i)
  1024. END;
  1025. RETURN -1
  1026. END FindMod;
  1027. PROCEDURE NewMod (name: ARRAY OF CHAR; kind: INTEGER): BOOLEAN;
  1028. VAR idx : CARDINAL;
  1029. s : ScopePtr;
  1030. BEGIN
  1031. IF nMods >= MaxMods THEN RETURN FALSE END;
  1032. IF FindMod(name) # -1 THEN RETURN FALSE END;
  1033. idx := nMods;
  1034. Assign(modNames[idx], name);
  1035. s := NewScope(globScope, 1);
  1036. modScopes[idx] := s;
  1037. modKind[idx] := kind;
  1038. modImpl[idx] := FALSE;
  1039. INC(nMods);
  1040. (* the module name lives in the global scope *)
  1041. IF ~EnterIn(globScope, name, KindModule) THEN
  1042. DEC(nMods); RETURN FALSE
  1043. END;
  1044. curMod := VAL(INTEGER, idx);
  1045. curUnit := kind;
  1046. curScope := s;
  1047. RETURN TRUE
  1048. END NewMod;
  1049. PROCEDURE BeginDef (name: ARRAY OF CHAR): BOOLEAN;
  1050. BEGIN
  1051. RETURN NewMod(name, UnitDef)
  1052. END BeginDef;
  1053. PROCEDURE BeginImpl (name: ARRAY OF CHAR): BOOLEAN;
  1054. VAR idx : INTEGER;
  1055. BEGIN
  1056. idx := FindMod(name);
  1057. IF idx = -1 THEN RETURN FALSE END;
  1058. IF (modKind[idx] # UnitDef) OR modImpl[idx] THEN RETURN FALSE END;
  1059. modImpl[idx] := TRUE;
  1060. curMod := idx;
  1061. curUnit := UnitImpl;
  1062. curScope := modScopes[idx];
  1063. RETURN TRUE
  1064. END BeginImpl;
  1065. PROCEDURE BeginProg (name: ARRAY OF CHAR): BOOLEAN;
  1066. VAR ok : BOOLEAN;
  1067. BEGIN
  1068. ok := NewMod(name, UnitProg);
  1069. IF ok THEN haveProg := TRUE END;
  1070. RETURN ok
  1071. END BeginProg;
  1072. PROCEDURE HaveProgram (): BOOLEAN;
  1073. BEGIN
  1074. RETURN haveProg
  1075. END HaveProgram;
  1076. PROCEDURE EndUnit;
  1077. BEGIN
  1078. curScope := globScope;
  1079. curMod := -1;
  1080. curUnit := -1
  1081. END EndUnit;
  1082. PROCEDURE CurUnit (): INTEGER;
  1083. BEGIN
  1084. RETURN curUnit
  1085. END CurUnit;
  1086. PROCEDURE CurModule (VAR name: Name);
  1087. BEGIN
  1088. IF curMod < 0 THEN name[0] := 0C
  1089. ELSE Assign(name, modNames[curMod])
  1090. END
  1091. END CurModule;
  1092. PROCEDURE ModKnown (name: ARRAY OF CHAR): BOOLEAN;
  1093. BEGIN
  1094. RETURN FindMod(name) # -1
  1095. END ModKnown;
  1096. PROCEDURE ModDefined (name: ARRAY OF CHAR): BOOLEAN;
  1097. VAR i : INTEGER;
  1098. BEGIN
  1099. i := FindMod(name);
  1100. RETURN (i # -1) & (modKind[i] # UnitProg)
  1101. END ModDefined;
  1102. PROCEDURE ModImplemented (name: ARRAY OF CHAR): BOOLEAN;
  1103. VAR i : INTEGER;
  1104. BEGIN
  1105. i := FindMod(name);
  1106. RETURN (i # -1) & modImpl[i]
  1107. END ModImplemented;
  1108. PROCEDURE OpaqueBase (name: ARRAY OF CHAR): TypeIndex;
  1109. VAR node: SymPtr;
  1110. r : TypeIndex;
  1111. BEGIN
  1112. node := Find(name);
  1113. IF (node = NIL) OR (node^.kind # KindType) THEN
  1114. RETURN InvalidType
  1115. END;
  1116. r := node^.typ;
  1117. IF (r < 0) OR (r >= VAL(INTEGER, nTypes)) THEN
  1118. RETURN InvalidType
  1119. END;
  1120. IF (tform[r] = FAlias) & (tref[r] = InvalidType) THEN RETURN r END;
  1121. RETURN InvalidType
  1122. END OpaqueBase;
  1123. PROCEDURE QualNode (mod, name: ARRAY OF CHAR): SymPtr;
  1124. VAR i : INTEGER;
  1125. BEGIN
  1126. i := FindMod(mod);
  1127. IF i = -1 THEN RETURN NIL END;
  1128. RETURN TreeFind(modScopes[i]^.root, name)
  1129. END QualNode;
  1130. PROCEDURE QualFind (mod, name: ARRAY OF CHAR): BOOLEAN;
  1131. BEGIN
  1132. RETURN QualNode(mod, name) # NIL
  1133. END QualFind;
  1134. PROCEDURE QualKind (mod, name: ARRAY OF CHAR): INTEGER;
  1135. VAR n : SymPtr;
  1136. BEGIN
  1137. n := QualNode(mod, name);
  1138. IF n = NIL THEN RETURN -1 END;
  1139. RETURN n^.kind
  1140. END QualKind;
  1141. PROCEDURE QualType (mod, name: ARRAY OF CHAR): TypeIndex;
  1142. VAR n : SymPtr;
  1143. BEGIN
  1144. n := QualNode(mod, name);
  1145. IF n = NIL THEN RETURN InvalidType END;
  1146. RETURN n^.typ
  1147. END QualType;
  1148. PROCEDURE QualProcUid (mod, name: ARRAY OF CHAR): CARDINAL;
  1149. VAR n : SymPtr;
  1150. BEGIN
  1151. n := QualNode(mod, name);
  1152. IF (n = NIL) OR (n^.kind # KindProc) THEN RETURN 0 END;
  1153. RETURN n^.uid
  1154. END QualProcUid;
  1155. PROCEDURE QualNthParam (n: SymPtr; i: CARDINAL): SymPtr;
  1156. BEGIN
  1157. n := n^.plink;
  1158. WHILE (i > 0) & (n # NIL) DO
  1159. n := n^.plink; DEC(i)
  1160. END;
  1161. RETURN n
  1162. END QualNthParam;
  1163. PROCEDURE QualProcNPar (mod, name: ARRAY OF CHAR): CARDINAL;
  1164. VAR n, p : SymPtr;
  1165. c : CARDINAL;
  1166. BEGIN
  1167. n := QualNode(mod, name);
  1168. IF (n = NIL) OR (n^.kind # KindProc) THEN RETURN 0 END;
  1169. c := 0; p := n^.plink;
  1170. WHILE p # NIL DO INC(c); p := p^.plink END;
  1171. RETURN c
  1172. END QualProcNPar;
  1173. PROCEDURE QualParamType (mod, name: ARRAY OF CHAR; i: CARDINAL):
  1174. TypeIndex;
  1175. VAR n, p : SymPtr;
  1176. BEGIN
  1177. n := QualNode(mod, name);
  1178. IF (n = NIL) OR (n^.kind # KindProc) THEN
  1179. RETURN InvalidType
  1180. END;
  1181. p := QualNthParam(n, i);
  1182. IF p = NIL THEN RETURN InvalidType END;
  1183. RETURN p^.typ
  1184. END QualParamType;
  1185. PROCEDURE QualParamIsVar (mod, name: ARRAY OF CHAR; i: CARDINAL):
  1186. BOOLEAN;
  1187. VAR n, p : SymPtr;
  1188. BEGIN
  1189. n := QualNode(mod, name);
  1190. IF (n = NIL) OR (n^.kind # KindProc) THEN RETURN FALSE END;
  1191. p := QualNthParam(n, i);
  1192. IF p = NIL THEN RETURN FALSE END;
  1193. RETURN p^.isVar
  1194. END QualParamIsVar;
  1195. PROCEDURE QualProcRes (mod, name: ARRAY OF CHAR): TypeIndex;
  1196. VAR n : SymPtr;
  1197. BEGIN
  1198. n := QualNode(mod, name);
  1199. IF (n = NIL) OR (n^.kind # KindProc) THEN
  1200. RETURN InvalidType
  1201. END;
  1202. RETURN n^.rslt
  1203. END QualProcRes;
  1204. PROCEDURE Materialize (mod, name: ARRAY OF CHAR): BOOLEAN;
  1205. (* Clones mod's export into the current scope (qualified-access
  1206. flattening and FROM-import share this). *)
  1207. VAR src, node : SymPtr;
  1208. BEGIN
  1209. src := QualNode(mod, name);
  1210. IF src = NIL THEN RETURN FALSE END;
  1211. (* already visible (repeat L.x): nothing to do *)
  1212. IF TreeFind(curScope^.root, name) # NIL THEN RETURN TRUE END;
  1213. ALLOCATE(node, TSIZE(SymNode));
  1214. node^ := src^;
  1215. node^.left := NIL;
  1216. node^.right := NIL;
  1217. node^.scope := curScope;
  1218. IF ~TreeInsert(curScope, node) THEN RETURN FALSE END;
  1219. RETURN TRUE
  1220. END Materialize;
  1221. PROCEDURE ImportFrom (mod, name: ARRAY OF CHAR): BOOLEAN;
  1222. BEGIN
  1223. RETURN Materialize(mod, name)
  1224. END ImportFrom;
  1225. (* ---------------- predicates (unchanged) ---------------- *)
  1226. PROCEDURE BaseSpanOk (b: TypeIndex): BOOLEAN;
  1227. (* TRUE for set-suitable bases: bool, char, subranges ≤ 256 wide. *)
  1228. VAR r: TypeIndex;
  1229. lo, hi: INTEGER;
  1230. BEGIN
  1231. r := Resolve(b);
  1232. IF r = InvalidType THEN RETURN TRUE END;
  1233. IF tform[r] = FBool THEN RETURN TRUE END;
  1234. IF tform[r] = FChar THEN RETURN TRUE END;
  1235. IF (tform[r] = FSub) & (tref[r] = InvalidType)
  1236. & SubBounds(b, lo, hi) & (hi >= lo) & (hi - lo < 256) THEN
  1237. RETURN TRUE
  1238. END;
  1239. RETURN FALSE
  1240. END BaseSpanOk;
  1241. PROCEDURE SetBasesOk (a, b: TypeIndex): BOOLEAN;
  1242. (* base compatibility for two SET types: same, or both suitable
  1243. (masks compare over min words + zero-check extras) *)
  1244. BEGIN
  1245. IF SameType(a, b) THEN RETURN TRUE END;
  1246. RETURN BaseSpanOk(a) & BaseSpanOk(b)
  1247. END SetBasesOk;
  1248. PROCEDURE Assignable (src, dst: TypeIndex): BOOLEAN;
  1249. VAR rs, rd: TypeIndex;
  1250. BEGIN
  1251. IF (src = InvalidType) OR (dst = InvalidType) THEN RETURN TRUE END;
  1252. rs := Resolve(src); rd := Resolve(dst);
  1253. IF rs = rd THEN RETURN TRUE END;
  1254. IF (rs = InvalidType) OR (rd = InvalidType) THEN RETURN TRUE END;
  1255. IF (tform[rs] = FSet) & (tform[rd] = FSet) THEN
  1256. RETURN SetBasesOk(tref[rs], tref[rd])
  1257. END;
  1258. IF (ClassOf(src) = ClArray) & (ClassOf(dst) = ClArray) THEN
  1259. RETURN SameType(src, dst)
  1260. END;
  1261. IF (ClassOf(src) = ClStr) & (ClassOf(dst) = ClArray) THEN
  1262. RETURN (ArrayDepth(dst) = 1)
  1263. & (ClassOf(ArrayElem(dst)) = ClChar)
  1264. END;
  1265. IF ClassOf(src) = ClNil THEN
  1266. RETURN ClassOf(dst) = ClPtr
  1267. END;
  1268. IF (ClassOf(src) = ClInt) & (ClassOf(dst) = ClInt) THEN
  1269. RETURN TRUE
  1270. END;
  1271. IF (ClassOf(src) = ClInt) & (ClassOf(dst) = ClReal) THEN
  1272. RETURN TRUE
  1273. END;
  1274. RETURN FALSE
  1275. END Assignable;
  1276. PROCEDURE ArithCheck (l, r: TypeIndex; divmod: BOOLEAN;
  1277. VAR res: TypeIndex): BOOLEAN;
  1278. BEGIN
  1279. res := InvalidType;
  1280. IF (l = InvalidType) OR (r = InvalidType) THEN RETURN TRUE END;
  1281. IF IsIntFamily(l) & IsIntFamily(r) THEN
  1282. res := dInt; RETURN TRUE
  1283. END;
  1284. IF ~divmod & (ClassOf(l) = ClReal) & (ClassOf(r) = ClReal) THEN
  1285. res := dReal; RETURN TRUE
  1286. END;
  1287. RETURN FALSE
  1288. END ArithCheck;
  1289. PROCEDURE UnaryCheck (t: TypeIndex; VAR res: TypeIndex): BOOLEAN;
  1290. BEGIN
  1291. res := InvalidType;
  1292. IF t = InvalidType THEN RETURN TRUE END;
  1293. IF IsIntFamily(t) THEN res := dInt; RETURN TRUE END;
  1294. IF ClassOf(t) = ClReal THEN res := dReal; RETURN TRUE END;
  1295. RETURN FALSE
  1296. END UnaryCheck;
  1297. PROCEDURE BoolCheck (t: TypeIndex): BOOLEAN;
  1298. BEGIN
  1299. IF t = InvalidType THEN RETURN TRUE END;
  1300. RETURN ClassOf(t) = ClBool
  1301. END BoolCheck;
  1302. PROCEDURE EqCheck (l, r: TypeIndex): BOOLEAN;
  1303. VAR rl, rr: TypeIndex;
  1304. BEGIN
  1305. IF (l = InvalidType) OR (r = InvalidType) THEN RETURN TRUE END;
  1306. IF ClassOf(l) = ClNil THEN
  1307. RETURN (ClassOf(r) = ClNil) OR (ClassOf(r) = ClPtr)
  1308. END;
  1309. IF ClassOf(r) = ClNil THEN
  1310. RETURN (ClassOf(l) = ClNil) OR (ClassOf(l) = ClPtr)
  1311. END;
  1312. IF SameType(l, r) THEN
  1313. (* Whole-array, string, record and class equality are not
  1314. built-in (213); compare member-wise instead. *)
  1315. IF (ClassOf(l) = ClArray) OR (ClassOf(l) = ClStr)
  1316. OR (ClassOf(l) = ClRecord) OR (ClassOf(l) = ClClass) THEN
  1317. RETURN FALSE
  1318. END;
  1319. RETURN TRUE
  1320. END;
  1321. IF IsIntFamily(l) & IsIntFamily(r) THEN RETURN TRUE END;
  1322. IF (ClassOf(l) = ClReal) & (ClassOf(r) = ClReal) THEN
  1323. RETURN TRUE
  1324. END;
  1325. IF (ClassOf(l) = ClChar) & (ClassOf(r) = ClChar) THEN
  1326. RETURN TRUE
  1327. END;
  1328. IF (ClassOf(l) = ClBool) & (ClassOf(r) = ClBool) THEN
  1329. RETURN TRUE
  1330. END;
  1331. rl := Resolve(l); rr := Resolve(r);
  1332. IF (rl = InvalidType) OR (rr = InvalidType) THEN RETURN TRUE END;
  1333. IF (tform[rl] = FSet) & (tform[rr] = FSet) THEN
  1334. RETURN SetBasesOk(tref[rl], tref[rr])
  1335. END;
  1336. RETURN FALSE
  1337. END EqCheck;
  1338. PROCEDURE OrdCheck (l, r: TypeIndex): BOOLEAN;
  1339. BEGIN
  1340. IF (l = InvalidType) OR (r = InvalidType) THEN RETURN TRUE END;
  1341. IF IsIntFamily(l) & IsIntFamily(r) THEN RETURN TRUE END;
  1342. IF (ClassOf(l) = ClReal) & (ClassOf(r) = ClReal) THEN
  1343. RETURN TRUE
  1344. END;
  1345. IF (ClassOf(l) = ClChar) & (ClassOf(r) = ClChar) THEN
  1346. RETURN TRUE
  1347. END;
  1348. IF (ClassOf(l) = ClEnum) & SameType(l, r) THEN RETURN TRUE END;
  1349. RETURN FALSE
  1350. END OrdCheck;
  1351. PROCEDURE InCheck (l, set: TypeIndex): BOOLEAN;
  1352. VAR rs, b: TypeIndex;
  1353. BEGIN
  1354. IF (l = InvalidType) OR (set = InvalidType) THEN RETURN TRUE END;
  1355. rs := Resolve(set);
  1356. IF (rs = InvalidType) OR (tform[rs] # FSet) THEN RETURN FALSE END;
  1357. b := tref[rs];
  1358. IF SameType(l, b) THEN RETURN TRUE END;
  1359. IF IsIntFamily(l) & IsIntFamily(b) THEN RETURN TRUE END;
  1360. IF (ClassOf(l) = ClChar) & (ClassOf(b) = ClChar) THEN
  1361. RETURN TRUE
  1362. END;
  1363. (* lenient: small int/char/bool tested against suitable sets;
  1364. the span trap decides out-of-range at runtime *)
  1365. IF ((ClassOf(l) = ClInt) OR (ClassOf(l) = ClChar)
  1366. OR (ClassOf(l) = ClBool)) & (SetWords(set) > 0) THEN
  1367. RETURN TRUE
  1368. END;
  1369. RETURN FALSE
  1370. END InCheck;
  1371. PROCEDURE RelCheck (l, r: TypeIndex; op: INTEGER): BOOLEAN;
  1372. BEGIN
  1373. IF (l = InvalidType) OR (r = InvalidType) THEN RETURN TRUE END;
  1374. IF op = OpIn THEN RETURN InCheck(l, r) END;
  1375. IF (op = OpEq) OR (op = OpNeq1) OR (op = OpNeq2) THEN
  1376. RETURN EqCheck(l, r)
  1377. END;
  1378. RETURN OrdCheck(l, r)
  1379. END RelCheck;
  1380. PROCEDURE SetElemCheck (first, elem: TypeIndex): BOOLEAN;
  1381. BEGIN
  1382. IF (first = InvalidType) OR (elem = InvalidType) THEN
  1383. RETURN TRUE
  1384. END;
  1385. IF SameType(first, elem) THEN RETURN TRUE END;
  1386. IF IsIntFamily(first) & IsIntFamily(elem) THEN RETURN TRUE END;
  1387. RETURN FALSE
  1388. END SetElemCheck;
  1389. PROCEDURE SetFor (elem: TypeIndex): TypeIndex;
  1390. VAR e: TypeIndex;
  1391. BEGIN
  1392. e := Resolve(elem);
  1393. IF e = InvalidType THEN e := dInt END;
  1394. RETURN NewSet(e)
  1395. END SetFor;
  1396. (* ---------------- init ---------------- *)
  1397. PROCEDURE Predef (name: ARRAY OF CHAR; kind: INTEGER; t: TypeIndex);
  1398. BEGIN
  1399. IF Enter(name, kind) THEN SetSymType(name, t) END
  1400. END Predef;
  1401. PROCEDURE Init;
  1402. BEGIN
  1403. scopeList := NIL; scopeTail := NIL;
  1404. fields := NIL; nFields := 0;
  1405. nPend := 0; nPendF := 0;
  1406. nTypes := 0; nProc := 0; nBounds := 0; nextUid := 0;
  1407. curProc := NIL; curPTail := NIL;
  1408. nMods := 0; curMod := -1; curUnit := -1; haveProg := FALSE;
  1409. curScope := NewScope(NIL, 0);
  1410. globScope := curScope;
  1411. dInt := NewDesc(FInt, InvalidType);
  1412. dCard := NewDesc(FInt, InvalidType);
  1413. dReal := NewDesc(FReal, InvalidType);
  1414. dChar := NewDesc(FChar, InvalidType);
  1415. dBool := NewDesc(FBool, InvalidType);
  1416. dNil := NewDesc(FNil, InvalidType);
  1417. Predef("INTEGER", KindPredef, dInt);
  1418. Predef("CARDINAL", KindPredef, dCard);
  1419. Predef("SHORTINT", KindPredef, dInt);
  1420. Predef("LONGINT", KindPredef, dInt);
  1421. Predef("SHORTCARD", KindPredef, dCard);
  1422. Predef("REAL", KindPredef, dReal);
  1423. Predef("LONGREAL", KindPredef, dReal);
  1424. Predef("CHAR", KindPredef, dChar);
  1425. Predef("BOOLEAN", KindPredef, dBool);
  1426. Predef("TRUE", KindConst, dBool);
  1427. Predef("FALSE", KindConst, dBool);
  1428. Predef("NIL", KindConst, dNil)
  1429. END Init;
  1430. (* ---------------- listing ---------------- *)
  1431. PROCEDURE WriteKind (kind: INTEGER);
  1432. BEGIN
  1433. CASE kind OF
  1434. KindConst : FileIO.WriteString(FileIO.StdOut, "CONST")
  1435. | KindType : FileIO.WriteString(FileIO.StdOut, "TYPE")
  1436. | KindVar : FileIO.WriteString(FileIO.StdOut, "VAR")
  1437. | KindImport : FileIO.WriteString(FileIO.StdOut, "IMPORT")
  1438. | KindModule : FileIO.WriteString(FileIO.StdOut, "MODULE")
  1439. | KindPredef : FileIO.WriteString(FileIO.StdOut, "PREDEF")
  1440. | KindField : FileIO.WriteString(FileIO.StdOut, "FIELD")
  1441. | KindProc : FileIO.WriteString(FileIO.StdOut, "PROC")
  1442. | KindParam : FileIO.WriteString(FileIO.StdOut, "PARAM")
  1443. ELSE FileIO.WriteString(FileIO.StdOut, "???")
  1444. END
  1445. END WriteKind;
  1446. PROCEDURE WriteNode (node: SymPtr);
  1447. BEGIN
  1448. IF node = NIL THEN RETURN END;
  1449. WriteNode(node^.left);
  1450. FileIO.WriteString(FileIO.StdOut, " ");
  1451. FileIO.WriteString(FileIO.StdOut, node^.name);
  1452. FileIO.WriteString(FileIO.StdOut, " : ");
  1453. WriteKind(node^.kind);
  1454. FileIO.WriteString(FileIO.StdOut, " #");
  1455. FileIO.WriteInt(FileIO.StdOut, node^.typ, 1);
  1456. FileIO.WriteLn(FileIO.StdOut);
  1457. WriteNode(node^.right)
  1458. END WriteNode;
  1459. PROCEDURE PrintTable;
  1460. VAR s: ScopePtr;
  1461. BEGIN
  1462. FileIO.WriteLn(FileIO.StdOut);
  1463. FileIO.WriteString(FileIO.StdOut, "--- Symbol table ---");
  1464. FileIO.WriteLn(FileIO.StdOut);
  1465. s := scopeList;
  1466. WHILE s # NIL DO
  1467. WriteNode(s^.root);
  1468. s := s^.link
  1469. END
  1470. END PrintTable;
  1471. BEGIN
  1472. Init
  1473. END SymTab.