SymTab.mod 36 KB

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