SymTab.mod 93 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136
  1. IMPLEMENTATION MODULE SymTab;
  2. IMPORT FileIO;
  3. FROM Storage IMPORT ALLOCATE; (* gm2 needs this for NEW substitution *)
  4. CONST
  5. MaxTypes = 4096;
  6. MaxVt = 1024; (* total virtual-method slots across all classes *)
  7. MaxPend = 256;
  8. MaxMods = 64;
  9. ResDepth = 64;
  10. MaxPP = 1024; (* total procedure-type parameter slots *)
  11. (* descriptor forms *)
  12. FNone = 0; FAlias = 1; FSub = 2; FEnum = 3; FArray = 4;
  13. FRecord = 5; FSet = 6; FPtr = 7; FStr = 8;
  14. FInt = 9; FReal = 10; FChar = 11; FBool = 12;
  15. FClass = 13; FOpenArr = 14; FNil = 15; FLong = 16; FProc = 17;
  16. FUChar = 18; FUStr = 19;
  17. (* signatures compared by the strict 231 check are bounded to this many
  18. formals (self-hosting uses far fewer). *)
  19. MaxSnap = 16;
  20. HighSnap = MaxSnap - 1;
  21. TYPE
  22. SymPtr = POINTER TO SymNode;
  23. ScopePtr = POINTER TO ScopeNode;
  24. FieldPtr = POINTER TO FieldNode;
  25. SymNode = RECORD
  26. name : Name;
  27. kind : INTEGER;
  28. typ : TypeIndex;
  29. scope : ScopePtr; (* owning scope *)
  30. left : SymPtr; (* BST links within the owning scope *)
  31. right : SymPtr;
  32. rslt : TypeIndex; (* KindProc result type, InvalidType = none *)
  33. plink : SymPtr; (* next formal, positional chain *)
  34. isVar : BOOLEAN; (* KindParam: VAR formal *)
  35. fwd : BOOLEAN; (* KindProc: FORWARD body pending *)
  36. virt : BOOLEAN; (* KindProc: VIRTUAL method *)
  37. fdep : CARDINAL; (* KindProc: lexical function-nesting depth *)
  38. snapRes : TypeIndex; (* KindProc: DEFINITION result (ResumeProc) *)
  39. snapT : ARRAY [0 .. MaxSnap - 1] OF TypeIndex; (* DEF formal types *)
  40. snapV : ARRAY [0 .. MaxSnap - 1] OF BOOLEAN; (* DEF formal VARs *)
  41. nSnap : CARDINAL; (* KindProc: number of snapshot formals *)
  42. fsnap : BOOLEAN; (* KindProc: signature snapshotted, compare *)
  43. vslot : INTEGER; (* KindProc VIRTUAL: vtable slot (-1 = none) *)
  44. hasBody : BOOLEAN; (* KindProc: a body was resumed/emitted *)
  45. ext : BOOLEAN; (* KindProc: EXTERNAL (no body emitted) *)
  46. link : Name; (* KindProc: external link (C) name *)
  47. varargs : BOOLEAN; (* KindProc: C varargs (FROM libc IMPORT) *)
  48. sym : Name; (* base symbol name (differs from name for
  49. qualified aliases) *)
  50. mod : Name; (* defining module (for QBE global names) *)
  51. uid : CARDINAL; (* KindProc: unique id for name mangling *)
  52. val : Name; (* KindConst: literal value text, "" if none *)
  53. END;
  54. ScopeNode = RECORD
  55. parent : ScopePtr; (* scope tree link *)
  56. root : SymPtr; (* BST root of this scope's symbols *)
  57. level : CARDINAL;
  58. link : ScopePtr; (* creation-order chain for PrintTable *)
  59. ofRec : TypeIndex; (* record/class whose members live here *)
  60. END;
  61. FieldNode = RECORD
  62. name : Name;
  63. typ : TypeIndex;
  64. owner : TypeIndex;
  65. next : FieldPtr; (* next field of the same owner *)
  66. off : INTEGER; (* declaration-order byte offset *)
  67. ord : CARDINAL; (* declaration rank (chain is reverse) *)
  68. END;
  69. VAR
  70. curScope : ScopePtr;
  71. scopeList : ScopePtr; (* all scopes, creation order *)
  72. scopeTail : ScopePtr;
  73. fields : FieldPtr; (* all record fields, newest first *)
  74. nFields : CARDINAL;
  75. pend : ARRAY [0 .. MaxPend - 1] OF SymPtr;
  76. nPend : CARDINAL;
  77. pendF : ARRAY [0 .. MaxPend - 1] OF FieldPtr;
  78. nPendF : CARDINAL;
  79. tform : ARRAY [0 .. MaxTypes - 1] OF INTEGER;
  80. tref : ARRAY [0 .. MaxTypes - 1] OF TypeIndex;
  81. tlo : ARRAY [0 .. MaxTypes - 1] OF INTEGER;
  82. thi : ARRAY [0 .. MaxTypes - 1] OF INTEGER;
  83. tenum : ARRAY [0 .. MaxTypes - 1] OF CARDINAL; (* enum literal count *)
  84. (* module-level forward type references awaiting completion *)
  85. pfwdN : CARDINAL;
  86. pfwdName : ARRAY [0 .. 255] OF Name;
  87. pfwdT : ARRAY [0 .. 255] OF TypeIndex;
  88. (* forward module-level variable references from procedure bodies *)
  89. nFwdVar : CARDINAL;
  90. fwdVarName : ARRAY [0 .. 255] OF Name;
  91. fwdVarKind : ARRAY [0 .. 255] OF INTEGER; (* KindVar / KindProc *)
  92. fwdVarT : ARRAY [0 .. 255] OF TypeIndex; (* placeholder type index *)
  93. tparent : ARRAY [0 .. MaxTypes - 1] OF TypeIndex;
  94. tscope : ARRAY [0 .. MaxTypes - 1] OF ScopePtr;
  95. tdone : ARRAY [0 .. MaxTypes - 1] OF BOOLEAN;
  96. (* per-class vtables: each class owns a slice of the shared pool *)
  97. vtBase : ARRAY [0 .. MaxTypes - 1] OF CARDINAL;
  98. nVirt : ARRAY [0 .. MaxTypes - 1] OF CARDINAL;
  99. vtName : ARRAY [0 .. MaxVt - 1] OF Name; (* virtual method name *)
  100. vtUid : ARRAY [0 .. MaxVt - 1] OF CARDINAL; (* its uid *)
  101. vtTop : CARDINAL;
  102. vtBuilt : ARRAY [0 .. MaxTypes - 1] OF BOOLEAN;
  103. tvptr : ARRAY [0 .. MaxTypes - 1] OF INTEGER; (* vptr field offset, -1 none *)
  104. vtl : ARRAY [0 .. MaxTypes - 1] OF TypeIndex; (* classes with a vtable *)
  105. nVtl : CARDINAL;
  106. (* class whose CLASS IMPLEMENTATION body is currently open (nested
  107. impls stack); bare method names resolve against it *)
  108. implStk : ARRAY [0 .. 15] OF TypeIndex;
  109. nImpl : CARDINAL;
  110. tvtag : ARRAY [0 .. MaxTypes - 1] OF BOOLEAN; (* record has variants *)
  111. ttag : ARRAY [0 .. MaxTypes - 1] OF FieldPtr; (* variant CASE selector *)
  112. alo : ARRAY [0 .. MaxTypes - 1] OF INTEGER;
  113. ahi : ARRAY [0 .. MaxTypes - 1] OF INTEGER;
  114. blo : ARRAY [0 .. 7] OF INTEGER;
  115. bhi : ARRAY [0 .. 7] OF INTEGER;
  116. nBounds : CARDINAL;
  117. nTypes : CARDINAL;
  118. curProc : SymPtr; (* heading being declared *)
  119. curPTail : SymPtr; (* positional param chain tail *)
  120. snapT : ARRAY [0 .. 15] OF TypeIndex; (* signature snapshot scratch *)
  121. snapV : ARRAY [0 .. 15] OF BOOLEAN;
  122. procStk : ARRAY [0 .. 15] OF SymPtr;
  123. nProc : CARDINAL;
  124. nextUid : CARDINAL;
  125. dInt, dCard, dReal, dChar, dBool, dNil, dAddr, dLong : TypeIndex;
  126. dUChar : TypeIndex; (* UCHAR: 32-bit codepoint *)
  127. dBitset : TypeIndex; (* BITSET = SET OF [0..15] *)
  128. dProc : TypeIndex; (* PROC: parameterless procedure type *)
  129. globScope : ScopePtr; (* the global scope (module names live here) *)
  130. curMod : INTEGER; (* current registry slot, -1 between units *)
  131. curUnit : INTEGER; (* UnitProg/Def/Impl, -1 between units *)
  132. nMods : CARDINAL;
  133. modNames : ARRAY [0 .. MaxMods - 1] OF Name;
  134. modScopes : ARRAY [0 .. MaxMods - 1] OF ScopePtr;
  135. modKind : ARRAY [0 .. MaxMods - 1] OF INTEGER;
  136. modImpl : ARRAY [0 .. MaxMods - 1] OF BOOLEAN;
  137. haveProg : BOOLEAN;
  138. typeBlockDepth : CARDINAL; (* > 0 inside a TYPE block *)
  139. procp : ARRAY [0 .. MaxPP - 1] OF TypeIndex; (* proc-type params *)
  140. procvis : ARRAY [0 .. MaxPP - 1] OF BOOLEAN; (* VAR flags *)
  141. procstart : ARRAY [0 .. MaxTypes - 1] OF CARDINAL;
  142. procn : ARRAY [0 .. MaxTypes - 1] OF CARDINAL;
  143. nProcP : CARDINAL;
  144. (* ---------------- strings ---------------- *)
  145. PROCEDURE Assign (VAR dest: ARRAY OF CHAR; src: ARRAY OF CHAR);
  146. VAR i : CARDINAL;
  147. BEGIN
  148. i := 0;
  149. WHILE (i < HIGH(dest)) AND (src[i] # CHR(0)) DO
  150. dest[i] := src[i]; INC(i)
  151. END;
  152. dest[i] := CHR(0)
  153. END Assign;
  154. PROCEDURE Equal (a, b: ARRAY OF CHAR): BOOLEAN;
  155. VAR i : CARDINAL;
  156. BEGIN
  157. i := 0;
  158. LOOP
  159. IF a[i] # b[i] THEN RETURN FALSE END;
  160. IF a[i] = CHR(0) THEN RETURN TRUE END;
  161. INC(i)
  162. END
  163. END Equal;
  164. PROCEDURE Less (a, b: ARRAY OF CHAR): BOOLEAN;
  165. (* Lexicographic order on NUL-terminated strings (BST key order). *)
  166. VAR i : CARDINAL;
  167. BEGIN
  168. i := 0;
  169. LOOP
  170. IF a[i] # b[i] THEN RETURN ORD(a[i]) < ORD(b[i]) END;
  171. IF a[i] = CHR(0) THEN RETURN FALSE END;
  172. INC(i)
  173. END
  174. END Less;
  175. PROCEDURE StrLen (s: ARRAY OF CHAR): CARDINAL;
  176. VAR i : CARDINAL;
  177. BEGIN
  178. i := 0;
  179. WHILE (i < HIGH(s)) AND (s[i] # CHR(0)) DO INC(i) END;
  180. RETURN i
  181. END StrLen;
  182. PROCEDURE ConstInt (q: ARRAY OF CHAR; VAR v: INTEGER): BOOLEAN;
  183. VAR i, d: CARDINAL;
  184. neg: BOOLEAN;
  185. BEGIN
  186. v := 0; i := 0; neg := FALSE;
  187. IF q[0] = "-" THEN neg := TRUE; i := 1 END;
  188. IF (i >= HIGH(q)) OR (q[i] = CHR(0)) THEN RETURN FALSE END;
  189. WHILE (i < HIGH(q)) AND (q[i] # CHR(0)) DO
  190. d := ORD(q[i]);
  191. IF (d < ORD("0")) OR (d > ORD("9")) THEN RETURN FALSE END;
  192. v := v * 10 + VAL(INTEGER, d - ORD("0")); INC(i)
  193. END;
  194. IF neg THEN v := -v END;
  195. RETURN TRUE
  196. END ConstInt;
  197. (* ---------------- scope tree + per-scope BST ---------------- *)
  198. PROCEDURE NewScope (parent: ScopePtr; level: CARDINAL): ScopePtr;
  199. (* Heap-allocates a scope and appends it to the creation chain. *)
  200. VAR s: ScopePtr;
  201. BEGIN
  202. NEW(s);
  203. s^.parent := parent;
  204. s^.root := NIL;
  205. s^.level := level;
  206. s^.link := NIL;
  207. s^.ofRec := InvalidType;
  208. IF scopeList = NIL THEN scopeList := s ELSE scopeTail^.link := s END;
  209. scopeTail := s;
  210. RETURN s
  211. END NewScope;
  212. PROCEDURE TreeFind (root: SymPtr; name: ARRAY OF CHAR): SymPtr;
  213. (* BST search within one scope; NIL if absent. *)
  214. BEGIN
  215. WHILE root # NIL DO
  216. IF Equal(root^.name, name) THEN RETURN root END;
  217. IF Less(name, root^.name) THEN root := root^.left
  218. ELSE root := root^.right
  219. END
  220. END;
  221. RETURN NIL
  222. END TreeFind;
  223. PROCEDURE TreeInsert (s: ScopePtr; node: SymPtr): BOOLEAN;
  224. (* BST insert of node into scope s; FALSE on duplicate. *)
  225. VAR cur, parent: SymPtr;
  226. goLeft: BOOLEAN;
  227. BEGIN
  228. cur := s^.root; parent := NIL; goLeft := FALSE;
  229. WHILE cur # NIL DO
  230. IF Equal(cur^.name, node^.name) THEN RETURN FALSE END;
  231. parent := cur;
  232. IF Less(node^.name, cur^.name) THEN
  233. cur := cur^.left; goLeft := TRUE
  234. ELSE
  235. cur := cur^.right; goLeft := FALSE
  236. END
  237. END;
  238. node^.left := NIL;
  239. node^.right := NIL;
  240. node^.scope := s;
  241. IF parent = NIL THEN s^.root := node
  242. ELSIF goLeft THEN parent^.left := node
  243. ELSE parent^.right := node
  244. END;
  245. RETURN TRUE
  246. END TreeInsert;
  247. PROCEDURE Find (name: ARRAY OF CHAR): SymPtr;
  248. (* Innermost visible node or NIL; walks the scope chain up. *)
  249. VAR s: ScopePtr;
  250. r: SymPtr;
  251. BEGIN
  252. s := curScope;
  253. WHILE s # NIL DO
  254. r := TreeFind(s^.root, name);
  255. IF r # NIL THEN RETURN r END;
  256. s := s^.parent
  257. END;
  258. RETURN NIL
  259. END Find;
  260. PROCEDURE SetNodeMod (node: SymPtr);
  261. (* Records the defining module for global-symbol naming. *)
  262. BEGIN
  263. IF curMod >= 0 THEN Assign(node^.mod, modNames[curMod])
  264. ELSE node^.mod[0] := CHR(0)
  265. END
  266. END SetNodeMod;
  267. PROCEDURE RawEnter (name: ARRAY OF CHAR; kind: INTEGER): SymPtr;
  268. (* Heap-allocates a symbol and links it into the current scope's
  269. BST; NIL on duplicate (node released to nobody: dropped). *)
  270. VAR node: SymPtr;
  271. BEGIN
  272. NEW(node);
  273. Assign(node^.name, name);
  274. Assign(node^.sym, name);
  275. SetNodeMod(node);
  276. node^.kind := kind;
  277. node^.typ := InvalidType;
  278. node^.scope := curScope;
  279. node^.left := NIL;
  280. node^.right := NIL;
  281. node^.val[0] := CHR(0);
  282. node^.fsnap := FALSE; (* no DEFINITION signature snapshotted *)
  283. node^.ext := FALSE;
  284. node^.varargs := FALSE;
  285. IF NOT TreeInsert(curScope, node) THEN RETURN NIL END;
  286. RETURN node
  287. END RawEnter;
  288. PROCEDURE Enter (name: ARRAY OF CHAR; kind: INTEGER): BOOLEAN;
  289. BEGIN
  290. RETURN RawEnter(name, kind) # NIL
  291. END Enter;
  292. PROCEDURE ReenterModGlobal (name: ARRAY OF CHAR; kind: INTEGER;
  293. modName: ARRAY OF CHAR): BOOLEAN;
  294. VAR node: SymPtr;
  295. BEGIN
  296. node := RawEnter(name, kind);
  297. IF node = NIL THEN RETURN FALSE END;
  298. Assign(node^.mod, modName);
  299. RETURN TRUE
  300. END ReenterModGlobal;
  301. PROCEDURE EnterPending (name: ARRAY OF CHAR; kind: INTEGER): BOOLEAN;
  302. VAR node: SymPtr;
  303. BEGIN
  304. node := RawEnter(name, kind);
  305. IF (node # NIL) AND (nPend < MaxPend) THEN
  306. pend[nPend] := node; INC(nPend)
  307. END;
  308. RETURN node # NIL
  309. END EnterPending;
  310. PROCEDURE VarParamOk (actual, formal: TypeIndex): BOOLEAN;
  311. (* Addressable-designator compatibility for VAR formals: same type,
  312. or fixed array into open array with same element type, or string
  313. literal into open CHAR array. *)
  314. VAR fa, fe: TypeIndex;
  315. BEGIN
  316. IF (actual = InvalidType) OR (formal = InvalidType) THEN
  317. RETURN TRUE
  318. END;
  319. IF SameType(actual, formal) THEN RETURN TRUE END;
  320. (* ADDRESS is interchangeable with any pointer for VAR params
  321. (ADDRESS is a predefined alias, so ClassOf is enough here) *)
  322. IF (formal = dAddr) AND (ClassOf(actual) = ClPtr) THEN
  323. RETURN TRUE
  324. END;
  325. IF (actual = dAddr) AND (ClassOf(formal) = ClPtr) THEN
  326. RETURN TRUE
  327. END;
  328. IF IsOpenArray(formal)
  329. AND (ClassOf(actual) = ClArray) AND (ArrayDepth(actual) = 1) THEN
  330. fa := ArrayElem(actual); fe := ArrayElem(formal);
  331. IF SameType(fa, fe) THEN RETURN TRUE END
  332. END;
  333. IF IsOpenArray(formal) AND (ClassOf(actual) = ClStr) THEN
  334. fe := ArrayElem(formal);
  335. IF ClassOf(fe) = ClChar THEN RETURN TRUE END
  336. END;
  337. IF IsOpenArray(formal) AND (ClassOf(actual) = ClUStr) THEN
  338. fe := ArrayElem(formal);
  339. IF ClassOf(fe) = ClUChar THEN RETURN TRUE END
  340. END;
  341. RETURN FALSE
  342. END VarParamOk;
  343. PROCEDURE FormalOk (a, b: TypeIndex): BOOLEAN;
  344. (* Value-formal equivalence for the strict 231 check: the same type, or
  345. both integer-family (one family per the scalar model), or two
  346. string-compatible types. *)
  347. BEGIN
  348. IF (a = InvalidType) OR (b = InvalidType) THEN
  349. (* an unresolved type is not honest evidence; treat as ok so a
  350. single root 221/201 is not multiplied by 231 *)
  351. RETURN TRUE
  352. END;
  353. IF SameType(a, b) THEN RETURN TRUE END;
  354. IF IsIntFamily(a) AND IsIntFamily(b) THEN RETURN TRUE END;
  355. (* Open-array formals are structurally compatible when their element
  356. types match: each `ARRAY OF T` declaration allocates a fresh
  357. descriptor, so a DEFINITION/IMPLEMENTATION pair never shares the
  358. type index and SameType would otherwise reject it. *)
  359. IF IsOpenArray(a) AND IsOpenArray(b) THEN
  360. RETURN SameType(ArrayElem(a), ArrayElem(b))
  361. END;
  362. RETURN StrCompat(a, b)
  363. END FormalOk;
  364. PROCEDURE FixPending (t: TypeIndex) : BOOLEAN;
  365. (* Assigns type t to all pending entries, clears the buffer, and
  366. returns TRUE. When the current procedure heading resumed a
  367. DEFINITION (snapshot present), this is where a formal's type is
  368. known, so the just-typed formals are compared against the
  369. snapshot: FALSE = a strict-231 mismatch. *)
  370. VAR i, base, k, n: CARDINAL;
  371. f: SymPtr;
  372. isV, ok: BOOLEAN;
  373. BEGIN
  374. n := nPend; (* formals typed by this call *)
  375. i := 0;
  376. WHILE i < nPend DO
  377. pend[i]^.typ := t; INC(i)
  378. END;
  379. nPend := 0;
  380. IF (curProc = NIL) OR (curProc^.nSnap = 0) THEN RETURN TRUE END;
  381. (* number of formals already in the chain *)
  382. base := 0;
  383. f := curProc^.plink;
  384. WHILE f # NIL DO INC(base); f := f^.plink END;
  385. IF base > curProc^.nSnap THEN RETURN FALSE END;
  386. (* the just-typed formals are chain indexes base-n .. base-1 *)
  387. FOR k := 0 TO n - 1 DO
  388. IF base >= n THEN
  389. (* walk to index base-n+k *)
  390. f := curProc^.plink;
  391. i := 0;
  392. WHILE (i < base - n + k) AND (f # NIL) DO
  393. f := f^.plink; INC(i)
  394. END;
  395. IF f # NIL THEN
  396. isV := f^.isVar;
  397. IF isV THEN ok := VarParamOk(f^.typ, curProc^.snapT[base - n + k])
  398. ELSE ok := FormalOk(f^.typ, curProc^.snapT[base - n + k]) END;
  399. IF (isV # curProc^.snapV[base - n + k]) OR NOT ok THEN
  400. RETURN FALSE
  401. END
  402. END
  403. END
  404. END;
  405. RETURN TRUE
  406. END FixPending;
  407. PROCEDURE PendCount (): CARDINAL;
  408. BEGIN
  409. RETURN nPend
  410. END PendCount;
  411. PROCEDURE PendName (i: CARDINAL; VAR n: Name);
  412. BEGIN
  413. IF i < nPend THEN Assign(n, pend[i]^.name)
  414. ELSE n[0] := CHR(0)
  415. END
  416. END PendName;
  417. PROCEDURE Resolve (t: TypeIndex): TypeIndex;
  418. VAR n: CARDINAL;
  419. BEGIN
  420. n := 0;
  421. WHILE (n < ResDepth) AND (t >= 0) AND (t < VAL(INTEGER, nTypes))
  422. AND (tform[t] = FAlias) DO
  423. t := tref[t]; INC(n)
  424. END;
  425. IF (t < 0) OR (t >= VAL(INTEGER, nTypes)) THEN
  426. RETURN InvalidType
  427. END;
  428. RETURN t
  429. END Resolve;
  430. PROCEDURE ParentOf (t: TypeIndex): TypeIndex;
  431. (* The single parent class of t, or InvalidType. *)
  432. VAR r: TypeIndex;
  433. BEGIN
  434. r := Resolve(t);
  435. IF (r >= 0) AND (r < VAL(INTEGER, nTypes))
  436. AND (tform[r] = FClass) THEN
  437. RETURN tparent[r]
  438. END;
  439. RETURN InvalidType
  440. END ParentOf;
  441. PROCEDURE PushProc (node: SymPtr);
  442. BEGIN
  443. IF nProc <= HIGH(procStk) THEN
  444. procStk[nProc] := node; INC(nProc)
  445. END
  446. END PushProc;
  447. PROCEDURE OwnField (rec: TypeIndex; name: ARRAY OF CHAR): FieldPtr;
  448. (* A field declared directly in rec (no parent walk). *)
  449. VAR f: FieldPtr;
  450. BEGIN
  451. IF (rec < 0) OR (rec >= VAL(INTEGER, nTypes)) THEN RETURN NIL END;
  452. IF (tform[rec] # FRecord) AND (tform[rec] # FClass) THEN RETURN NIL END;
  453. f := fields;
  454. WHILE f # NIL DO
  455. IF (f^.owner = rec) AND Equal(f^.name, name) THEN RETURN f END;
  456. f := f^.next
  457. END;
  458. RETURN NIL
  459. END OwnField;
  460. PROCEDURE FindField (rec: TypeIndex; name: ARRAY OF CHAR): FieldPtr;
  461. (* Looks in rec, then up the single-inheritance chain. *)
  462. VAR f: FieldPtr;
  463. r, p: TypeIndex;
  464. guard: CARDINAL;
  465. BEGIN
  466. f := OwnField(rec, name);
  467. IF f # NIL THEN RETURN f END;
  468. r := Resolve(rec);
  469. IF (r = InvalidType) OR (tform[r] # FClass) THEN RETURN NIL END;
  470. guard := 0;
  471. p := ParentOf(r);
  472. WHILE (p # InvalidType) AND (guard < ResDepth) DO
  473. f := OwnField(p, name);
  474. IF f # NIL THEN RETURN f END;
  475. r := p;
  476. p := ParentOf(r);
  477. INC(guard)
  478. END;
  479. RETURN NIL
  480. END FindField;
  481. PROCEDURE FieldPending (rec: TypeIndex; name: ARRAY OF CHAR): BOOLEAN;
  482. VAR f: FieldPtr;
  483. BEGIN
  484. IF FindField(rec, name) # NIL THEN RETURN FALSE END;
  485. NEW(f);
  486. Assign(f^.name, name);
  487. f^.typ := InvalidType;
  488. f^.owner := rec;
  489. f^.next := fields;
  490. fields := f;
  491. IF (rec >= 0) AND (rec < VAL(INTEGER, nTypes)) THEN
  492. tdone[rec] := FALSE
  493. END;
  494. IF nPendF < MaxPend THEN
  495. pendF[nPendF] := f; INC(nPendF)
  496. END;
  497. INC(nFields);
  498. RETURN TRUE
  499. END FieldPending;
  500. PROCEDURE FixPendingF (rec: TypeIndex; t: TypeIndex);
  501. VAR i, j: CARDINAL;
  502. BEGIN
  503. i := 0;
  504. WHILE i < nPendF DO
  505. IF pendF[i]^.owner = rec THEN
  506. pendF[i]^.typ := t;
  507. (* remove by swap with last *)
  508. j := nPendF - 1;
  509. pendF[i] := pendF[j];
  510. DEC(nPendF)
  511. ELSE
  512. INC(i)
  513. END
  514. END
  515. END FixPendingF;
  516. PROCEDURE Lookup (name: ARRAY OF CHAR): BOOLEAN;
  517. BEGIN
  518. RETURN Find(name) # NIL
  519. END Lookup;
  520. PROCEDURE SymType (name: ARRAY OF CHAR): TypeIndex;
  521. VAR node: SymPtr;
  522. BEGIN
  523. node := Find(name);
  524. IF node = NIL THEN RETURN InvalidType END;
  525. RETURN node^.typ
  526. END SymType;
  527. PROCEDURE SetSymType (name: ARRAY OF CHAR; t: TypeIndex);
  528. VAR node: SymPtr;
  529. BEGIN
  530. node := Find(name);
  531. IF node # NIL THEN node^.typ := t END
  532. END SetSymType;
  533. PROCEDURE SymKind (name: ARRAY OF CHAR): INTEGER;
  534. VAR node: SymPtr;
  535. BEGIN
  536. node := Find(name);
  537. IF node = NIL THEN RETURN -1 END;
  538. RETURN node^.kind
  539. END SymKind;
  540. PROCEDURE SetSymVal (name: ARRAY OF CHAR; v: ARRAY OF CHAR);
  541. VAR node: SymPtr;
  542. BEGIN
  543. node := Find(name);
  544. IF node # NIL THEN Assign(node^.val, v) END
  545. END SetSymVal;
  546. PROCEDURE GetSymVal (name: ARRAY OF CHAR; VAR v: ARRAY OF CHAR): BOOLEAN;
  547. VAR node: SymPtr;
  548. BEGIN
  549. node := Find(name);
  550. IF node = NIL THEN
  551. v[0] := CHR(0); RETURN FALSE
  552. END;
  553. IF node^.val[0] = CHR(0) THEN
  554. v[0] := CHR(0); RETURN FALSE
  555. END;
  556. Assign(v, node^.val);
  557. RETURN TRUE
  558. END GetSymVal;
  559. PROCEDURE PushScope;
  560. BEGIN
  561. curScope := NewScope(curScope, curScope^.level + 1)
  562. END PushScope;
  563. PROCEDURE PopScope;
  564. BEGIN
  565. (* Nodes stay allocated but become unreachable via the chain. *)
  566. IF curScope^.parent # NIL THEN curScope := curScope^.parent END
  567. END PopScope;
  568. (* ---------------- type descriptors (unchanged) ---------------- *)
  569. PROCEDURE NewDesc (form: INTEGER; ref: TypeIndex): TypeIndex;
  570. BEGIN
  571. IF nTypes >= MaxTypes THEN RETURN InvalidType END;
  572. tform[nTypes] := form;
  573. tref[nTypes] := ref;
  574. tdone[nTypes] := FALSE;
  575. tvtag[nTypes] := FALSE;
  576. vtBase[nTypes] := 0;
  577. nVirt[nTypes] := 0;
  578. vtBuilt[nTypes] := FALSE;
  579. tvptr[nTypes] := -1;
  580. ttag[nTypes] := NIL;
  581. INC(nTypes);
  582. RETURN VAL(INTEGER, nTypes - 1)
  583. END NewDesc;
  584. PROCEDURE NewAlias (): TypeIndex;
  585. BEGIN
  586. RETURN NewDesc(FAlias, InvalidType)
  587. END NewAlias;
  588. PROCEDURE NewSubR (lo, hi: INTEGER): TypeIndex;
  589. VAR t: TypeIndex;
  590. BEGIN
  591. t := NewDesc(FSub, InvalidType);
  592. IF t # InvalidType THEN tlo[t] := lo; thi[t] := hi END;
  593. RETURN t
  594. END NewSubR;
  595. PROCEDURE NewEnum (): TypeIndex;
  596. BEGIN
  597. RETURN NewDesc(FEnum, InvalidType)
  598. END NewEnum;
  599. PROCEDURE SetEnumCount (t: TypeIndex; n: CARDINAL);
  600. VAR r: TypeIndex;
  601. BEGIN
  602. r := Resolve(t);
  603. IF (r # InvalidType) AND (tform[r] = FEnum) THEN tenum[r] := n END
  604. END SetEnumCount;
  605. PROCEDURE EnumCount (t: TypeIndex): CARDINAL;
  606. VAR r: TypeIndex;
  607. BEGIN
  608. r := Resolve(t);
  609. IF (r = InvalidType) OR (tform[r] # FEnum) THEN RETURN 0 END;
  610. RETURN tenum[r]
  611. END EnumCount;
  612. PROCEDURE NewArrayB (elem: TypeIndex; lo, hi: INTEGER): TypeIndex;
  613. VAR t: TypeIndex;
  614. BEGIN
  615. t := NewDesc(FArray, elem);
  616. IF t # InvalidType THEN alo[t] := lo; ahi[t] := hi END;
  617. RETURN t
  618. END NewArrayB;
  619. PROCEDURE NewOpenArray (elem: TypeIndex): TypeIndex;
  620. BEGIN
  621. RETURN NewDesc(FOpenArr, elem)
  622. END NewOpenArray;
  623. PROCEDURE BoundBegin;
  624. BEGIN
  625. nBounds := 0
  626. END BoundBegin;
  627. PROCEDURE BoundAdd (lo, hi: INTEGER): BOOLEAN;
  628. BEGIN
  629. IF nBounds > HIGH(blo) THEN RETURN FALSE END;
  630. blo[nBounds] := lo; bhi[nBounds] := hi; INC(nBounds);
  631. RETURN TRUE
  632. END BoundAdd;
  633. PROCEDURE BoundCount (): CARDINAL;
  634. BEGIN RETURN nBounds END BoundCount;
  635. PROCEDURE BoundLo (i: CARDINAL): INTEGER;
  636. BEGIN
  637. IF i < nBounds THEN RETURN blo[i] ELSE RETURN 0 END
  638. END BoundLo;
  639. PROCEDURE BoundHi (i: CARDINAL): INTEGER;
  640. BEGIN
  641. IF i < nBounds THEN RETURN bhi[i] ELSE RETURN -1 END
  642. END BoundHi;
  643. PROCEDURE NewRecord (): TypeIndex;
  644. BEGIN
  645. RETURN NewDesc(FRecord, -1)
  646. END NewRecord;
  647. PROCEDURE NewSet (base: TypeIndex): TypeIndex;
  648. BEGIN
  649. RETURN NewDesc(FSet, base)
  650. END NewSet;
  651. PROCEDURE NewPtr (base: TypeIndex): TypeIndex;
  652. BEGIN
  653. RETURN NewDesc(FPtr, base)
  654. END NewPtr;
  655. PROCEDURE NewStr (): TypeIndex;
  656. BEGIN
  657. RETURN NewDesc(FStr, InvalidType)
  658. END NewStr;
  659. PROCEDURE NewUStr (): TypeIndex;
  660. BEGIN
  661. RETURN NewDesc(FUStr, InvalidType)
  662. END NewUStr;
  663. PROCEDURE NewClass (): TypeIndex;
  664. VAR t: TypeIndex;
  665. BEGIN
  666. t := NewDesc(FClass, InvalidType);
  667. IF t # InvalidType THEN
  668. tparent[t] := InvalidType; tscope[t] := NIL
  669. END;
  670. RETURN t
  671. END NewClass;
  672. PROCEDURE SetParent (t, p: TypeIndex);
  673. BEGIN
  674. IF (t >= 0) AND (t < VAL(INTEGER, nTypes)) AND (tform[t] = FClass) THEN
  675. tparent[t] := p
  676. END
  677. END SetParent;
  678. PROCEDURE IsOrdinal (t: TypeIndex): BOOLEAN;
  679. (* An ordinal type: integer family, CHAR, UCHAR, BOOLEAN or an
  680. enumeration (drives CASE/variant selectors). *)
  681. VAR c: INTEGER;
  682. BEGIN
  683. IF Resolve(t) = InvalidType THEN RETURN FALSE END;
  684. c := ClassOf(t);
  685. RETURN (c = ClInt) OR (c = ClChar) OR (c = ClUChar)
  686. OR (c = ClBool) OR (c = ClEnum)
  687. END IsOrdinal;
  688. PROCEDURE ResetFields (rec: TypeIndex);
  689. (* Starts a fresh variant branch: drops any still-pending fields of
  690. rec (their identifiers saw no ":" yet) and clears its layout so
  691. the next branch overlays from the tag slot. Field names already
  692. committed in an earlier branch stay in the record's scope. *)
  693. VAR i: CARDINAL;
  694. r: TypeIndex;
  695. BEGIN
  696. r := Resolve(rec);
  697. i := 0;
  698. WHILE i < nPendF DO
  699. IF pendF[i]^.owner = r THEN
  700. nPendF := nPendF - 1;
  701. pendF[i] := pendF[nPendF]
  702. ELSE
  703. INC(i)
  704. END
  705. END;
  706. IF (r >= 0) AND (r < VAL(INTEGER, nTypes)) THEN
  707. tdone[r] := FALSE
  708. END
  709. END ResetFields;
  710. PROCEDURE SetVariantTag (rec: TypeIndex; name: ARRAY OF CHAR);
  711. (* Records the variant CASE selector field of rec (by name); called
  712. just after the tag's type is fixed, before the variant branches. *)
  713. VAR r: TypeIndex;
  714. BEGIN
  715. r := Resolve(rec);
  716. IF (r >= 0) AND (r < VAL(INTEGER, nTypes)) THEN
  717. ttag[r] := FindField(r, name)
  718. END
  719. END SetVariantTag;
  720. PROCEDURE MarkVariant (rec: TypeIndex);
  721. (* Records that this record has a variant part (its fields overlap
  722. from the tag slot on, so whole-record comparison is 236). *)
  723. VAR r: TypeIndex;
  724. BEGIN
  725. r := Resolve(rec);
  726. IF (r >= 0) AND (r < VAL(INTEGER, nTypes)) THEN
  727. tvtag[r] := TRUE
  728. END
  729. END MarkVariant;
  730. PROCEDURE IsVariant (rec: TypeIndex): BOOLEAN;
  731. VAR r: TypeIndex;
  732. BEGIN
  733. r := Resolve(rec);
  734. IF (r >= 0) AND (r < VAL(INTEGER, nTypes)) THEN
  735. RETURN tvtag[r]
  736. END;
  737. RETURN FALSE
  738. END IsVariant;
  739. PROCEDURE PushClassScope (t: TypeIndex);
  740. VAR r: TypeIndex;
  741. BEGIN
  742. r := Resolve(t);
  743. IF (r = InvalidType) OR (tform[r] # FClass) THEN RETURN END;
  744. PushScope;
  745. tscope[r] := curScope
  746. END PushClassScope;
  747. PROCEDURE SetTarget (t, base: TypeIndex);
  748. BEGIN
  749. IF (t >= 0) AND (t < VAL(INTEGER, nTypes)) AND (tform[t] = FAlias) THEN
  750. tref[t] := base
  751. END
  752. END SetTarget;
  753. PROCEDURE IntType (): TypeIndex;
  754. BEGIN RETURN dInt END IntType;
  755. PROCEDURE UCharType (): TypeIndex;
  756. BEGIN RETURN dUChar END UCharType;
  757. PROCEDURE AddrType (): TypeIndex;
  758. BEGIN RETURN dAddr END AddrType;
  759. PROCEDURE LongType (): TypeIndex;
  760. BEGIN RETURN dLong END LongType;
  761. PROCEDURE RealType (): TypeIndex;
  762. BEGIN RETURN dReal END RealType;
  763. PROCEDURE CharType (): TypeIndex;
  764. BEGIN RETURN dChar END CharType;
  765. PROCEDURE BoolType (): TypeIndex;
  766. BEGIN RETURN dBool END BoolType;
  767. PROCEDURE ClassOf (t: TypeIndex): INTEGER;
  768. VAR r: TypeIndex;
  769. BEGIN
  770. r := Resolve(t);
  771. IF r = InvalidType THEN
  772. (* an opaque/undeclared alias (e.g. gm2's String) is pointer-like *)
  773. IF (t >= 0) AND (t < VAL(INTEGER, nTypes))
  774. AND (tform[t] = FAlias) THEN
  775. RETURN ClPtr
  776. END;
  777. RETURN ClInvalid
  778. END;
  779. CASE tform[r] OF
  780. FInt : RETURN ClInt
  781. | FLong : RETURN ClLong
  782. | FReal : RETURN ClReal
  783. | FChar : RETURN ClChar
  784. | FBool : RETURN ClBool
  785. | FEnum : RETURN ClEnum
  786. | FArray : RETURN ClArray
  787. | FOpenArr : RETURN ClArray
  788. | FRecord : RETURN ClRecord
  789. | FSet : RETURN ClSet
  790. | FPtr : RETURN ClPtr
  791. | FStr : RETURN ClStr
  792. | FClass : RETURN ClClass
  793. | FProc : RETURN ClProc
  794. | FUChar : RETURN ClUChar
  795. | FUStr : RETURN ClUStr
  796. | FNil : RETURN ClNil
  797. | FSub : IF tref[r] = InvalidType THEN RETURN ClInt
  798. ELSE RETURN ClassOf(tref[r]) END
  799. ELSE RETURN ClInvalid
  800. END
  801. END ClassOf;
  802. PROCEDURE IsIntFamily (t: TypeIndex): BOOLEAN;
  803. BEGIN
  804. RETURN ClassOf(t) = ClInt
  805. END IsIntFamily;
  806. PROCEDURE IsLongFamily (t: TypeIndex): BOOLEAN;
  807. BEGIN
  808. RETURN ClassOf(t) = ClLong
  809. END IsLongFamily;
  810. PROCEDURE SameType (a, b: TypeIndex): BOOLEAN;
  811. BEGIN
  812. IF (a = InvalidType) OR (b = InvalidType) THEN RETURN TRUE END;
  813. RETURN Resolve(a) = Resolve(b)
  814. END SameType;
  815. PROCEDURE FieldExists (rec: TypeIndex; name: ARRAY OF CHAR): BOOLEAN;
  816. BEGIN
  817. RETURN FindField(Resolve(rec), name) # NIL
  818. END FieldExists;
  819. PROCEDURE FieldType (rec: TypeIndex; name: ARRAY OF CHAR): TypeIndex;
  820. VAR f: FieldPtr;
  821. BEGIN
  822. f := FindField(Resolve(rec), name);
  823. IF f = NIL THEN RETURN InvalidType END;
  824. RETURN f^.typ
  825. END FieldType;
  826. PROCEDURE ArrayElem (t: TypeIndex): TypeIndex;
  827. VAR r: TypeIndex;
  828. BEGIN
  829. r := Resolve(t);
  830. IF (r = InvalidType) OR ((tform[r] # FArray)
  831. AND (tform[r] # FOpenArr)) THEN
  832. RETURN InvalidType
  833. END;
  834. RETURN tref[r]
  835. END ArrayElem;
  836. PROCEDURE IsOpenArray (t: TypeIndex): BOOLEAN;
  837. VAR r: TypeIndex;
  838. BEGIN
  839. r := Resolve(t);
  840. IF r = InvalidType THEN RETURN FALSE END;
  841. RETURN tform[r] = FOpenArr
  842. END IsOpenArray;
  843. PROCEDURE ArrayLo (t: TypeIndex): INTEGER;
  844. VAR r: TypeIndex;
  845. BEGIN
  846. r := Resolve(t);
  847. IF (r = InvalidType) OR (tform[r] # FArray) THEN RETURN 0 END;
  848. RETURN alo[r]
  849. END ArrayLo;
  850. PROCEDURE ArrayHi (t: TypeIndex): INTEGER;
  851. VAR r: TypeIndex;
  852. BEGIN
  853. r := Resolve(t);
  854. IF (r = InvalidType) OR (tform[r] # FArray) THEN RETURN 0 END;
  855. RETURN ahi[r]
  856. END ArrayHi;
  857. PROCEDURE ArrayLen (t: TypeIndex): CARDINAL;
  858. VAR r: TypeIndex;
  859. lo, hi: INTEGER;
  860. BEGIN
  861. r := Resolve(t);
  862. IF (r = InvalidType) OR (tform[r] # FArray) THEN RETURN 0 END;
  863. lo := alo[r]; hi := ahi[r];
  864. IF hi < lo THEN RETURN 0 END;
  865. RETURN VAL(CARDINAL, hi - lo + 1)
  866. END ArrayLen;
  867. PROCEDURE ArrayDepth (t: TypeIndex): CARDINAL;
  868. VAR r: TypeIndex;
  869. d: CARDINAL;
  870. BEGIN
  871. d := 0; r := Resolve(t);
  872. WHILE (r # InvalidType) AND ((tform[r] = FArray)
  873. OR (tform[r] = FOpenArr)) DO
  874. INC(d); r := Resolve(tref[r])
  875. END;
  876. RETURN d
  877. END ArrayDepth;
  878. PROCEDURE SubBounds (t: TypeIndex; VAR lo, hi: INTEGER): BOOLEAN;
  879. VAR r: TypeIndex;
  880. BEGIN
  881. lo := 0; hi := -1;
  882. r := Resolve(t);
  883. IF (r = InvalidType) OR (tform[r] # FSub)
  884. OR (tref[r] # InvalidType) THEN
  885. RETURN FALSE
  886. END;
  887. lo := tlo[r]; hi := thi[r];
  888. RETURN TRUE
  889. END SubBounds;
  890. PROCEDURE SetBase (t: TypeIndex): TypeIndex;
  891. VAR r: TypeIndex;
  892. BEGIN
  893. r := Resolve(t);
  894. IF (r = InvalidType) OR (tform[r] # FSet) THEN
  895. RETURN InvalidType
  896. END;
  897. RETURN tref[r]
  898. END SetBase;
  899. PROCEDURE SetSpan (t: TypeIndex; VAR lo, n: INTEGER): BOOLEAN;
  900. (* Base span for mask sizing; FALSE when unsuitable. Internal. *)
  901. VAR b, r: TypeIndex;
  902. blo, bhi: INTEGER;
  903. BEGIN
  904. lo := 0; n := 0;
  905. b := SetBase(t);
  906. IF b = InvalidType THEN RETURN FALSE END;
  907. r := Resolve(b);
  908. IF r = InvalidType THEN RETURN FALSE END;
  909. IF tform[r] = FBool THEN lo := 0; n := 2; RETURN TRUE END;
  910. IF tform[r] = FChar THEN lo := 0; n := 256; RETURN TRUE END;
  911. IF tform[r] = FEnum THEN
  912. IF tenum[r] = 0 THEN RETURN FALSE END;
  913. lo := 0; n := VAL(INTEGER, tenum[r]); RETURN TRUE
  914. END;
  915. IF (tform[r] = FSub) AND (tref[r] = InvalidType)
  916. AND SubBounds(b, blo, bhi) AND (bhi >= blo)
  917. AND (bhi - blo < 65536) THEN
  918. lo := blo; n := bhi - blo + 1; RETURN TRUE
  919. END;
  920. RETURN FALSE
  921. END SetSpan;
  922. PROCEDURE SetWords (t: TypeIndex): CARDINAL;
  923. VAR lo, n: INTEGER;
  924. BEGIN
  925. IF NOT SetSpan(t, lo, n) THEN RETURN 0 END;
  926. RETURN VAL(CARDINAL, (n + 31) DIV 32)
  927. END SetWords;
  928. PROCEDURE SetBaseLo (t: TypeIndex): INTEGER;
  929. VAR lo, n: INTEGER;
  930. BEGIN
  931. IF NOT SetSpan(t, lo, n) THEN RETURN 0 END;
  932. RETURN lo
  933. END SetBaseLo;
  934. PROCEDURE SetCount (t: TypeIndex): CARDINAL;
  935. VAR lo, n: INTEGER;
  936. BEGIN
  937. IF NOT SetSpan(t, lo, n) THEN RETURN 0 END;
  938. RETURN VAL(CARDINAL, n)
  939. END SetCount;
  940. PROCEDURE TypeBounds (t: TypeIndex; VAR lo, hi: INTEGER): BOOLEAN;
  941. (* The ordinal bounds of a type, for MIN/MAX: subrange/array bounds,
  942. CHAR/UCHAR, BOOLEAN, enumeration, or a set's base span. *)
  943. VAR r: TypeIndex;
  944. c: INTEGER;
  945. BEGIN
  946. lo := 0; hi := -1;
  947. r := Resolve(t);
  948. IF r = InvalidType THEN RETURN FALSE END;
  949. IF tform[r] = FSub THEN RETURN SubBounds(r, lo, hi) END;
  950. IF tform[r] = FArray THEN lo := alo[r]; hi := ahi[r]; RETURN TRUE END;
  951. c := ClassOf(r);
  952. IF c = ClChar THEN lo := 0; hi := 255; RETURN TRUE END;
  953. IF c = ClUChar THEN lo := 0; hi := 1114111; RETURN TRUE END;
  954. IF c = ClBool THEN lo := 0; hi := 1; RETURN TRUE END;
  955. IF c = ClEnum THEN
  956. lo := 0;
  957. IF tenum[r] = 0 THEN hi := -1
  958. ELSE hi := VAL(INTEGER, tenum[r]) - 1
  959. END;
  960. RETURN TRUE
  961. END;
  962. IF c = ClSet THEN
  963. lo := SetBaseLo(r);
  964. IF SetCount(r) = 0 THEN hi := lo - 1
  965. ELSE hi := lo + VAL(INTEGER, SetCount(r)) - 1
  966. END;
  967. RETURN TRUE
  968. END;
  969. IF c = ClInt THEN
  970. lo := -2147483648; hi := 2147483647; RETURN TRUE
  971. END;
  972. RETURN FALSE
  973. END TypeBounds;
  974. PROCEDURE PtrBase (t: TypeIndex): TypeIndex;
  975. VAR r: TypeIndex;
  976. BEGIN
  977. r := Resolve(t);
  978. IF (r = InvalidType) OR (tform[r] # FPtr) THEN
  979. RETURN InvalidType
  980. END;
  981. RETURN tref[r]
  982. END PtrBase;
  983. (* ---------------- procedure types (step 8.5) ---------------- *)
  984. PROCEDURE NewProcType (res: TypeIndex): TypeIndex;
  985. VAR t: TypeIndex;
  986. BEGIN
  987. t := NewDesc(FProc, res);
  988. IF t = InvalidType THEN RETURN t END;
  989. procstart[t] := nProcP;
  990. procn[t] := 0;
  991. RETURN t
  992. END NewProcType;
  993. PROCEDURE ProcTypeAdd (t: TypeIndex; isVar: BOOLEAN; pt: TypeIndex);
  994. VAR r: TypeIndex;
  995. BEGIN
  996. r := Resolve(t);
  997. IF (r = InvalidType) OR (tform[r] # FProc) THEN RETURN END;
  998. IF nProcP < MaxPP THEN
  999. procp[nProcP] := pt;
  1000. procvis[nProcP] := isVar;
  1001. INC(nProcP); INC(procn[r])
  1002. END
  1003. END ProcTypeAdd;
  1004. PROCEDURE SetProcTypeRes (t: TypeIndex; res: TypeIndex);
  1005. VAR r: TypeIndex;
  1006. BEGIN
  1007. r := Resolve(t);
  1008. IF (r # InvalidType) AND (tform[r] = FProc) THEN tref[r] := res END
  1009. END SetProcTypeRes;
  1010. PROCEDURE ProcTypeNPar (t: TypeIndex): CARDINAL;
  1011. VAR r: TypeIndex;
  1012. BEGIN
  1013. r := Resolve(t);
  1014. IF (r = InvalidType) OR (tform[r] # FProc) THEN RETURN 0 END;
  1015. RETURN procn[r]
  1016. END ProcTypeNPar;
  1017. PROCEDURE ProcTypeParamType (t: TypeIndex; i: CARDINAL): TypeIndex;
  1018. VAR r: TypeIndex;
  1019. BEGIN
  1020. r := Resolve(t);
  1021. IF (r = InvalidType) OR (tform[r] # FProc) OR (i >= procn[r]) THEN
  1022. RETURN InvalidType
  1023. END;
  1024. RETURN procp[procstart[r] + i]
  1025. END ProcTypeParamType;
  1026. PROCEDURE ProcTypeParamIsVar (t: TypeIndex; i: CARDINAL): BOOLEAN;
  1027. VAR r: TypeIndex;
  1028. BEGIN
  1029. r := Resolve(t);
  1030. IF (r = InvalidType) OR (tform[r] # FProc) OR (i >= procn[r]) THEN
  1031. RETURN FALSE
  1032. END;
  1033. RETURN procvis[procstart[r] + i]
  1034. END ProcTypeParamIsVar;
  1035. PROCEDURE ProcTypeRes (t: TypeIndex): TypeIndex;
  1036. VAR r: TypeIndex;
  1037. BEGIN
  1038. r := Resolve(t);
  1039. IF (r = InvalidType) OR (tform[r] # FProc) THEN
  1040. RETURN InvalidType
  1041. END;
  1042. RETURN tref[r]
  1043. END ProcTypeRes;
  1044. PROCEDURE ProcTypeOf (name: ARRAY OF CHAR): TypeIndex;
  1045. VAR node, p: SymPtr;
  1046. t: TypeIndex;
  1047. k: CARDINAL;
  1048. BEGIN
  1049. node := Find(name);
  1050. IF node = NIL THEN RETURN InvalidType END;
  1051. IF node^.kind # KindProc THEN RETURN InvalidType END;
  1052. t := NewDesc(FProc, node^.rslt);
  1053. IF t = InvalidType THEN RETURN t END;
  1054. procstart[t] := nProcP;
  1055. k := 0;
  1056. p := node^.plink;
  1057. WHILE (p # NIL) AND (nProcP < MaxPP) DO
  1058. procp[nProcP] := p^.typ;
  1059. procvis[nProcP] := p^.isVar;
  1060. INC(nProcP); INC(k);
  1061. p := p^.plink
  1062. END;
  1063. procn[t] := k;
  1064. RETURN t
  1065. END ProcTypeOf;
  1066. PROCEDURE ElemBytes (t: TypeIndex): CARDINAL;
  1067. (* element size of array descriptor t (bytes) *)
  1068. VAR cls: INTEGER;
  1069. BEGIN
  1070. cls := ClassOf(ArrayElem(t));
  1071. IF cls = ClChar THEN RETURN 1 END;
  1072. IF cls = ClReal THEN RETURN 8 END;
  1073. IF (cls = ClArray) OR (cls = ClPtr) OR (cls = ClRecord)
  1074. OR (cls = ClClass) OR (cls = ClProc) THEN
  1075. RETURN 8
  1076. END;
  1077. RETURN 4
  1078. END ElemBytes;
  1079. PROCEDURE IsCharArray (t: TypeIndex): BOOLEAN;
  1080. BEGIN RETURN ClassOf(ArrayElem(t)) = ClChar END IsCharArray;
  1081. PROCEDURE ArrObjSize (t: TypeIndex): CARDINAL;
  1082. (* full inline size of a fixed array: header (count) + packed elements
  1083. (+1 terminator byte for CHAR arrays) *)
  1084. VAR n: CARDINAL;
  1085. BEGIN
  1086. n := ArrayLen(t) * ElemBytes(t);
  1087. IF IsCharArray(t) THEN n := n + 1 END;
  1088. RETURN 8 + n
  1089. END ArrObjSize;
  1090. PROCEDURE TypeSizeD (t: TypeIndex; depth: CARDINAL): CARDINAL;
  1091. (* Inline footprint in bytes: scalars 4/8, sets words*4, pointers,
  1092. open and fixed arrays 8 (descriptor address — array objects live
  1093. separately); records sum members. Depth guards cycles (not 223). *)
  1094. VAR r: TypeIndex;
  1095. f: FieldPtr;
  1096. tagF: FieldPtr;
  1097. n, plain, high: CARDINAL;
  1098. BEGIN
  1099. IF depth > ResDepth THEN RETURN 0 END;
  1100. r := Resolve(t);
  1101. IF r = InvalidType THEN RETURN 0 END;
  1102. CASE tform[r] OF
  1103. FInt, FBool, FChar, FUChar : RETURN 4
  1104. | FLong : RETURN 8
  1105. | FReal : RETURN 8
  1106. | FEnum, FSub : RETURN 4
  1107. | FSet : RETURN SetWords(t) * 4
  1108. | FPtr, FOpenArr, FArray, FProc, FUStr : RETURN 8
  1109. | FRecord, FClass :
  1110. n := 0;
  1111. IF (tform[r] = FClass) AND (tparent[r] # InvalidType) THEN
  1112. (* single inheritance: parent fields (and its vptr) come first *)
  1113. n := TypeSizeD(tparent[r], depth + 1)
  1114. END;
  1115. IF (tform[r] = FClass) AND (tvptr[r] >= 0)
  1116. AND (tvptr[r] = VAL(INTEGER, n)) THEN
  1117. (* this class introduces its vptr here *)
  1118. n := n + 8
  1119. END;
  1120. IF tvtag[r] AND (ttag[r] # NIL) THEN
  1121. (* variant record: plain fields (declared before the tag) pack
  1122. normally; the tag and every variant field overlay in one
  1123. slot, so the record is plainSize + max(tag, variants). *)
  1124. plain := 0; high := 0;
  1125. f := fields;
  1126. WHILE f # NIL DO
  1127. IF f^.owner = r THEN
  1128. IF f^.ord < ttag[r]^.ord THEN
  1129. (* a plain field, packed before the tag *)
  1130. IF ClassOf(f^.typ) = ClArray THEN
  1131. plain := plain + ArrObjSize(f^.typ)
  1132. ELSE
  1133. plain := plain + TypeSizeD(f^.typ, depth + 1)
  1134. END
  1135. ELSIF f = ttag[r] THEN
  1136. (* the tag itself: its own slot *)
  1137. IF ClassOf(f^.typ) = ClArray THEN
  1138. plain := plain + ArrObjSize(f^.typ)
  1139. ELSE
  1140. plain := plain + TypeSizeD(f^.typ, depth + 1)
  1141. END
  1142. ELSE
  1143. (* a variant field: overlay in the region after the tag *)
  1144. IF ClassOf(f^.typ) = ClArray THEN
  1145. IF ArrObjSize(f^.typ) > high THEN
  1146. high := ArrObjSize(f^.typ)
  1147. END
  1148. ELSE
  1149. IF TypeSizeD(f^.typ, depth + 1) > high THEN
  1150. high := TypeSizeD(f^.typ, depth + 1)
  1151. END
  1152. END
  1153. END
  1154. END;
  1155. f := f^.next
  1156. END;
  1157. RETURN n + plain + high (* n = parent size, if any *)
  1158. END;
  1159. f := fields;
  1160. WHILE f # NIL DO
  1161. IF f^.owner = r THEN
  1162. IF ClassOf(f^.typ) = ClArray THEN
  1163. n := n + ArrObjSize(f^.typ) (* inline array field *)
  1164. ELSE
  1165. n := n + TypeSizeD(f^.typ, depth + 1)
  1166. END
  1167. END;
  1168. f := f^.next
  1169. END;
  1170. RETURN n
  1171. | FAlias :
  1172. RETURN TypeSizeD(tref[r], depth + 1)
  1173. ELSE RETURN 0
  1174. END
  1175. END TypeSizeD;
  1176. PROCEDURE TypeSize (t: TypeIndex): CARDINAL;
  1177. BEGIN
  1178. RETURN TypeSizeD(t, 0)
  1179. END TypeSize;
  1180. PROCEDURE FieldSize (t: TypeIndex): CARDINAL;
  1181. (* inline footprint of a record field: fixed arrays are inline objects *)
  1182. BEGIN
  1183. IF ClassOf(t) = ClArray THEN RETURN ArrObjSize(t) END;
  1184. RETURN TypeSizeD(t, 0)
  1185. END FieldSize;
  1186. PROCEDURE ObjectSize (t: TypeIndex): CARDINAL;
  1187. (* full allocation footprint: arrays 8 + count*elem, else TypeSize.
  1188. Used by SYSTEM.SIZE/TSIZE. *)
  1189. VAR r: TypeIndex;
  1190. BEGIN
  1191. r := Resolve(t);
  1192. IF (r # InvalidType) AND ((tform[r] = FArray)
  1193. OR (tform[r] = FOpenArr)) THEN
  1194. RETURN 8 + ArrayLen(t) * ElemBytes(t)
  1195. END;
  1196. RETURN TypeSize(t)
  1197. END ObjectSize;
  1198. PROCEDURE BuildVTable (ct: TypeIndex);
  1199. (* Assigns ct its virtual-method slots: the parent's are inherited
  1200. first (a same-named virtual method overrides in place), then ct's
  1201. own new virtual methods append. Each method node records its slot
  1202. in vslot. Idempotent. *)
  1203. VAR r, p: TypeIndex;
  1204. s: ScopePtr;
  1205. k: CARDINAL;
  1206. PROCEDURE AddMeth (node: SymPtr);
  1207. (* override an inherited slot or append a new one *)
  1208. VAR found: BOOLEAN; j: CARDINAL;
  1209. BEGIN
  1210. IF (node^.kind # KindProc) OR NOT node^.virt THEN RETURN END;
  1211. found := FALSE; j := 0;
  1212. WHILE (j < nVirt[r]) AND NOT found DO
  1213. IF Equal(vtName[vtBase[r] + j], node^.name) THEN
  1214. vtUid[vtBase[r] + j] := node^.uid;
  1215. node^.vslot := VAL(INTEGER, j);
  1216. found := TRUE
  1217. END;
  1218. INC(j)
  1219. END;
  1220. IF NOT found AND (vtTop < MaxVt) THEN
  1221. Assign(vtName[vtTop], node^.name);
  1222. vtUid[vtTop] := node^.uid;
  1223. node^.vslot := VAL(INTEGER, nVirt[r]);
  1224. INC(vtTop); INC(nVirt[r])
  1225. END
  1226. END AddMeth;
  1227. PROCEDURE Walk (node: SymPtr);
  1228. BEGIN
  1229. IF node = NIL THEN RETURN END;
  1230. Walk(node^.left);
  1231. AddMeth(node);
  1232. Walk(node^.right)
  1233. END Walk;
  1234. BEGIN
  1235. r := Resolve(ct);
  1236. IF (r = InvalidType) OR (tform[r] # FClass) THEN RETURN END;
  1237. IF vtBuilt[r] THEN RETURN END; (* already built *)
  1238. s := tscope[r];
  1239. IF s = NIL THEN RETURN END;
  1240. vtBase[r] := vtTop;
  1241. nVirt[r] := 0;
  1242. (* inherit the parent's slots *)
  1243. p := ParentOf(r);
  1244. IF p # InvalidType THEN
  1245. IF NOT vtBuilt[p] THEN BuildVTable(p) END;
  1246. k := 0;
  1247. WHILE (k < nVirt[p]) AND (vtTop < MaxVt) DO
  1248. Assign(vtName[vtTop], vtName[vtBase[p] + k]);
  1249. vtUid[vtTop] := vtUid[vtBase[p] + k];
  1250. INC(vtTop); INC(nVirt[r]);
  1251. INC(k)
  1252. END
  1253. END;
  1254. (* ct's own virtual methods: override or append *)
  1255. Walk(s^.root);
  1256. (* vptr field offset: inherited from a parent that already has one,
  1257. else introduced after the parent's fields (or at 0) *)
  1258. IF (p # InvalidType) AND (nVirt[p] > 0) THEN
  1259. tvptr[r] := tvptr[p]
  1260. ELSIF nVirt[r] > 0 THEN
  1261. IF p # InvalidType THEN tvptr[r] := VAL(INTEGER, TypeSizeD(p, 0))
  1262. ELSE tvptr[r] := 0
  1263. END
  1264. ELSE tvptr[r] := -1
  1265. END;
  1266. IF (nVirt[r] > 0) AND (nVtl < MaxTypes) THEN
  1267. vtl[nVtl] := r; INC(nVtl)
  1268. END;
  1269. vtBuilt[r] := TRUE
  1270. END BuildVTable;
  1271. PROCEDURE ComputeOffsets (r: TypeIndex);
  1272. (* Declaration-order offsets over the (prepend-built, hence reverse)
  1273. field chain, plus declaration ranks. Array fields count 8
  1274. (pointer-sized in records, matching the locked layout).
  1275. A record with a variant part lays every field from the first tag
  1276. slot on at that slot's offset (all variant fields overlap), and
  1277. the record's size is the largest such field. *)
  1278. VAR f: FieldPtr;
  1279. tagF: FieldPtr; (* the variant CASE selector field *)
  1280. total, high, tagSize, varOff, baseOff: INTEGER;
  1281. cnt, ord: CARDINAL;
  1282. off, p: INTEGER;
  1283. BEGIN
  1284. (* a class with a parent lays its own fields after the parent's *)
  1285. baseOff := 0;
  1286. IF (tform[r] = FClass) AND (tparent[r] # InvalidType) THEN
  1287. p := Resolve(tparent[r]);
  1288. IF p # InvalidType THEN
  1289. IF NOT vtBuilt[p] THEN BuildVTable(p) END;
  1290. IF NOT tdone[p] THEN ComputeOffsets(p) END;
  1291. baseOff := VAL(INTEGER, TypeSizeD(p, 0))
  1292. END
  1293. END;
  1294. (* a class that introduces (rather than inherits) a vptr reserves
  1295. 8 bytes for it after the parent's fields *)
  1296. IF (tform[r] = FClass) AND (tvptr[r] >= 0)
  1297. AND (tvptr[r] = baseOff) THEN
  1298. baseOff := baseOff + 8
  1299. END;
  1300. IF NOT tvtag[r] THEN
  1301. (* plain record/class: declaration-ordered, tightly packed *)
  1302. total := baseOff; cnt := 0;
  1303. f := fields;
  1304. WHILE f # NIL DO
  1305. IF f^.owner = r THEN
  1306. total := total + VAL(INTEGER, FieldSize(f^.typ));
  1307. INC(cnt)
  1308. END;
  1309. f := f^.next
  1310. END;
  1311. off := total; ord := cnt;
  1312. f := fields;
  1313. WHILE f # NIL DO
  1314. IF f^.owner = r THEN
  1315. off := off - VAL(INTEGER, FieldSize(f^.typ));
  1316. DEC(ord);
  1317. f^.off := off;
  1318. f^.ord := ord
  1319. END;
  1320. f := f^.next
  1321. END;
  1322. tdone[r] := TRUE;
  1323. RETURN
  1324. END;
  1325. (* variant record. Fields declared before the CASE tag pack
  1326. normally; the tag starts the overlay region and every variant
  1327. field (declared after the tag) overlays at the tag's slot.
  1328. Ranks are reverse-declaration (0 = last declared), so the tag
  1329. has rank = number-of-fields-after-it, and plain fields have
  1330. larger ranks. *)
  1331. tagF := ttag[r];
  1332. IF tagF = NIL THEN
  1333. (* no tag recorded (malformed); fall back to plain layout *)
  1334. tvtag[r] := FALSE;
  1335. ComputeOffsets(r);
  1336. RETURN
  1337. END;
  1338. cnt := 0;
  1339. f := fields;
  1340. WHILE f # NIL DO
  1341. IF f^.owner = r THEN INC(cnt) END;
  1342. f := f^.next
  1343. END;
  1344. ord := cnt;
  1345. f := fields;
  1346. WHILE f # NIL DO
  1347. IF f^.owner = r THEN DEC(ord); f^.ord := ord END;
  1348. f := f^.next
  1349. END;
  1350. (* plain fields: pack in declaration order up to the tag *)
  1351. total := 0;
  1352. f := fields;
  1353. WHILE f # NIL DO
  1354. IF (f^.owner = r) AND (f^.ord < tagF^.ord) THEN
  1355. total := total + VAL(INTEGER, FieldSize(f^.typ))
  1356. END;
  1357. f := f^.next
  1358. END;
  1359. off := total;
  1360. f := fields;
  1361. WHILE f # NIL DO
  1362. IF (f^.owner = r) AND (f^.ord < tagF^.ord) THEN
  1363. off := off - VAL(INTEGER, FieldSize(f^.typ));
  1364. f^.off := off
  1365. END;
  1366. f := f^.next
  1367. END;
  1368. (* the tag occupies its own slot after the plain fields; every
  1369. variant field overlays in the region after the tag *)
  1370. tagF^.off := total;
  1371. varOff := total + VAL(INTEGER, FieldSize(tagF^.typ));
  1372. f := fields;
  1373. WHILE f # NIL DO
  1374. IF (f^.owner = r) AND (f^.ord > tagF^.ord) THEN
  1375. f^.off := varOff
  1376. END;
  1377. f := f^.next
  1378. END;
  1379. tdone[r] := TRUE
  1380. END ComputeOffsets;
  1381. PROCEDURE LayoutClass (t: TypeIndex);
  1382. (* Computes a class's vtable and field offsets (and thus its size). *)
  1383. VAR r: TypeIndex;
  1384. BEGIN
  1385. r := Resolve(t);
  1386. IF (r # InvalidType) AND (tform[r] = FClass) THEN
  1387. IF NOT vtBuilt[r] THEN BuildVTable(r) END;
  1388. IF NOT tdone[r] THEN ComputeOffsets(r) END
  1389. END
  1390. END LayoutClass;
  1391. PROCEDURE LayoutRecord (t: TypeIndex);
  1392. (* Computes a record's field offsets / size now (idempotent). *)
  1393. VAR r: TypeIndex;
  1394. BEGIN
  1395. r := Resolve(t);
  1396. IF (r # InvalidType) AND (tform[r] = FRecord)
  1397. AND NOT tdone[r] THEN
  1398. ComputeOffsets(r)
  1399. END
  1400. END LayoutRecord;
  1401. PROCEDURE FieldOffset (rec: TypeIndex; name: ARRAY OF CHAR): INTEGER;
  1402. VAR r: TypeIndex;
  1403. f: FieldPtr;
  1404. BEGIN
  1405. r := Resolve(rec);
  1406. IF (r = InvalidType) OR ((tform[r] # FRecord)
  1407. AND (tform[r] # FClass)) THEN
  1408. RETURN -1
  1409. END;
  1410. IF NOT tdone[r] THEN ComputeOffsets(r) END;
  1411. f := FindField(r, name);
  1412. IF f = NIL THEN RETURN -1 END;
  1413. RETURN f^.off
  1414. END FieldOffset;
  1415. PROCEDURE FieldOwner (name: ARRAY OF CHAR): TypeIndex;
  1416. VAR node: SymPtr;
  1417. BEGIN
  1418. node := Find(name);
  1419. IF node = NIL THEN RETURN InvalidType END;
  1420. IF node^.kind # KindField THEN RETURN InvalidType END;
  1421. IF node^.scope = NIL THEN RETURN InvalidType END;
  1422. RETURN node^.scope^.ofRec
  1423. END FieldOwner;
  1424. PROCEDURE FieldCount (rec: TypeIndex): CARDINAL;
  1425. VAR r: TypeIndex;
  1426. f: FieldPtr;
  1427. n: CARDINAL;
  1428. BEGIN
  1429. n := 0;
  1430. r := Resolve(rec);
  1431. IF (r = InvalidType) OR ((tform[r] # FRecord)
  1432. AND (tform[r] # FClass)) THEN
  1433. RETURN 0
  1434. END;
  1435. f := fields;
  1436. WHILE f # NIL DO
  1437. IF f^.owner = r THEN INC(n) END;
  1438. f := f^.next
  1439. END;
  1440. RETURN n
  1441. END FieldCount;
  1442. PROCEDURE FieldName (rec: TypeIndex; i: CARDINAL; VAR name: Name);
  1443. (* i-th field in DECLARATION order (chain is reverse; ord ranks it). *)
  1444. VAR r: TypeIndex;
  1445. f: FieldPtr;
  1446. BEGIN
  1447. name[0] := CHR(0);
  1448. r := Resolve(rec);
  1449. IF (r = InvalidType) OR ((tform[r] # FRecord)
  1450. AND (tform[r] # FClass)) THEN
  1451. RETURN
  1452. END;
  1453. IF NOT tdone[r] THEN ComputeOffsets(r) END;
  1454. f := fields;
  1455. WHILE f # NIL DO
  1456. IF (f^.owner = r) AND (f^.ord = i) THEN
  1457. Assign(name, f^.name); RETURN
  1458. END;
  1459. f := f^.next
  1460. END
  1461. END FieldName;
  1462. PROCEDURE EnterFieldsOf (rec: TypeIndex);
  1463. (* Enters rec's own fields as KindField into the current scope. *)
  1464. VAR f: FieldPtr;
  1465. BEGIN
  1466. f := fields;
  1467. WHILE f # NIL DO
  1468. IF f^.owner = rec THEN
  1469. IF Enter(f^.name, KindField) THEN
  1470. SetSymType(f^.name, f^.typ)
  1471. END
  1472. END;
  1473. f := f^.next
  1474. END
  1475. END EnterFieldsOf;
  1476. PROCEDURE PushRecord (t: TypeIndex): BOOLEAN;
  1477. (* Pushes a scope with t's fields (and, for a class, its ancestors'
  1478. fields); caller must PopScope afterwards. Classes share the field
  1479. machinery (methods stay in the class scope itself). *)
  1480. VAR r, p: TypeIndex;
  1481. guard: CARDINAL;
  1482. BEGIN
  1483. r := Resolve(t);
  1484. IF (r < 0) OR ((tform[r] # FRecord) AND (tform[r] # FClass)) THEN
  1485. RETURN FALSE
  1486. END;
  1487. PushScope;
  1488. curScope^.ofRec := r;
  1489. EnterFieldsOf(r);
  1490. IF tform[r] = FClass THEN
  1491. guard := 0;
  1492. p := ParentOf(r);
  1493. WHILE (p # InvalidType) AND (guard < ResDepth) DO
  1494. EnterFieldsOf(p);
  1495. p := ParentOf(p);
  1496. INC(guard)
  1497. END
  1498. END;
  1499. RETURN TRUE
  1500. END PushRecord;
  1501. (* ---------------- classes ---------------- *)
  1502. PROCEDURE ClassMethodNode (t: TypeIndex; name: ARRAY OF CHAR): SymPtr;
  1503. (* The method symbol named name in class t or an ancestor, or NIL. *)
  1504. VAR r: TypeIndex;
  1505. s: ScopePtr;
  1506. node: SymPtr;
  1507. guard: CARDINAL;
  1508. BEGIN
  1509. r := Resolve(t);
  1510. guard := 0;
  1511. WHILE (r # InvalidType) AND (tform[r] = FClass) AND (guard < ResDepth) DO
  1512. s := tscope[r];
  1513. IF s # NIL THEN
  1514. node := TreeFind(s^.root, name);
  1515. IF (node # NIL) AND (node^.kind = KindProc) THEN RETURN node END
  1516. END;
  1517. r := ParentOf(r);
  1518. INC(guard)
  1519. END;
  1520. RETURN NIL
  1521. END ClassMethodNode;
  1522. PROCEDURE MethodExists (t: TypeIndex; name: ARRAY OF CHAR): BOOLEAN;
  1523. (* TRUE when the class (or an ancestor) declares name as a method. *)
  1524. BEGIN
  1525. RETURN ClassMethodNode(t, name) # NIL
  1526. END MethodExists;
  1527. PROCEDURE ResumeMethod (ct: TypeIndex; name: ARRAY OF CHAR): BOOLEAN;
  1528. (* Resumes a class's declared method for its CLASS IMPLEMENTATION
  1529. body: pushes the existing symbol (reusing its uid so calls bind),
  1530. clearing the formal chain for the body's own heading to rebuild. *)
  1531. VAR node: SymPtr;
  1532. BEGIN
  1533. node := ClassMethodNode(ct, name);
  1534. IF node = NIL THEN RETURN FALSE END;
  1535. node^.plink := NIL;
  1536. node^.hasBody := TRUE;
  1537. curProc := node;
  1538. curPTail := NIL;
  1539. PushProc(node);
  1540. PushScope;
  1541. RETURN TRUE
  1542. END ResumeMethod;
  1543. PROCEDURE MethUid (): CARDINAL;
  1544. (* uid of the procedure currently being headed (0 when none): set by
  1545. ResumeMethod, whose node lives in a detached class scope that
  1546. ProcUid/Find cannot reach. *)
  1547. BEGIN
  1548. IF curProc = NIL THEN RETURN 0 END;
  1549. RETURN curProc^.uid
  1550. END MethUid;
  1551. PROCEDURE ClassMethodUid (t: TypeIndex; name: ARRAY OF CHAR): CARDINAL;
  1552. VAR n: SymPtr;
  1553. BEGIN
  1554. n := ClassMethodNode(t, name);
  1555. IF n = NIL THEN RETURN 0 END;
  1556. RETURN n^.uid
  1557. END ClassMethodUid;
  1558. PROCEDURE ClassMethodNPar (t: TypeIndex; name: ARRAY OF CHAR): CARDINAL;
  1559. (* Number of user formals (excludes the hidden THIS). *)
  1560. VAR n: SymPtr;
  1561. p: SymPtr;
  1562. k: CARDINAL;
  1563. BEGIN
  1564. n := ClassMethodNode(t, name);
  1565. IF n = NIL THEN RETURN 0 END;
  1566. k := 0;
  1567. p := n^.plink;
  1568. WHILE p # NIL DO INC(k); p := p^.plink END;
  1569. IF k > 0 THEN DEC(k) END; (* drop THIS *)
  1570. RETURN k
  1571. END ClassMethodNPar;
  1572. PROCEDURE ClassMethodParamType (t: TypeIndex; name: ARRAY OF CHAR;
  1573. i: CARDINAL): TypeIndex;
  1574. (* Type of the i-th USER formal (index 0 skips the hidden THIS). *)
  1575. VAR n, p: SymPtr;
  1576. k: CARDINAL;
  1577. BEGIN
  1578. n := ClassMethodNode(t, name);
  1579. IF n = NIL THEN RETURN InvalidType END;
  1580. p := n^.plink;
  1581. IF p # NIL THEN p := p^.plink END; (* skip THIS *)
  1582. k := 0;
  1583. WHILE (p # NIL) AND (k < i) DO p := p^.plink; INC(k) END;
  1584. IF p = NIL THEN RETURN InvalidType END;
  1585. RETURN p^.typ
  1586. END ClassMethodParamType;
  1587. PROCEDURE ClassMethodParamIsVar (t: TypeIndex; name: ARRAY OF CHAR;
  1588. i: CARDINAL): BOOLEAN;
  1589. VAR n, p: SymPtr;
  1590. k: CARDINAL;
  1591. BEGIN
  1592. n := ClassMethodNode(t, name);
  1593. IF n = NIL THEN RETURN FALSE END;
  1594. p := n^.plink;
  1595. IF p # NIL THEN p := p^.plink END; (* skip THIS *)
  1596. k := 0;
  1597. WHILE (p # NIL) AND (k < i) DO p := p^.plink; INC(k) END;
  1598. IF p = NIL THEN RETURN FALSE END;
  1599. RETURN p^.isVar
  1600. END ClassMethodParamIsVar;
  1601. PROCEDURE ClassMethodRes (t: TypeIndex; name: ARRAY OF CHAR): TypeIndex;
  1602. VAR n: SymPtr;
  1603. BEGIN
  1604. n := ClassMethodNode(t, name);
  1605. IF n = NIL THEN RETURN InvalidType END;
  1606. RETURN n^.rslt
  1607. END ClassMethodRes;
  1608. PROCEDURE PushImplClass (ct: TypeIndex);
  1609. BEGIN
  1610. IF nImpl <= HIGH(implStk) THEN
  1611. implStk[nImpl] := ct; INC(nImpl)
  1612. END
  1613. END PushImplClass;
  1614. PROCEDURE PopImplClass;
  1615. BEGIN IF nImpl > 0 THEN DEC(nImpl) END
  1616. END PopImplClass;
  1617. PROCEDURE CurImplClass (): TypeIndex;
  1618. (* The class whose CLASS IMPLEMENTATION body is innermost open, or
  1619. InvalidType. Bare method names inside a body resolve against it. *)
  1620. BEGIN
  1621. IF nImpl = 0 THEN RETURN InvalidType END;
  1622. RETURN implStk[nImpl - 1]
  1623. END CurImplClass;
  1624. PROCEDURE VtClassCount (): CARDINAL;
  1625. BEGIN RETURN nVtl END VtClassCount;
  1626. PROCEDURE VtClassAt (k: CARDINAL): TypeIndex;
  1627. BEGIN
  1628. IF k >= nVtl THEN RETURN InvalidType END;
  1629. RETURN vtl[k]
  1630. END VtClassAt;
  1631. PROCEDURE IsSubclass (sub, sup: TypeIndex): BOOLEAN;
  1632. (* TRUE when sub is sup or inherits (transitively) from sup. *)
  1633. VAR r: TypeIndex;
  1634. guard: CARDINAL;
  1635. BEGIN
  1636. r := Resolve(sub);
  1637. sup := Resolve(sup);
  1638. guard := 0;
  1639. WHILE (r # InvalidType) AND (guard < ResDepth) DO
  1640. IF r = sup THEN RETURN TRUE END;
  1641. r := ParentOf(r);
  1642. INC(guard)
  1643. END;
  1644. RETURN FALSE
  1645. END IsSubclass;
  1646. PROCEDURE VptrOffset (ct: TypeIndex): INTEGER;
  1647. VAR r: TypeIndex;
  1648. BEGIN
  1649. r := Resolve(ct);
  1650. IF (r = InvalidType) OR (tform[r] # FClass) THEN RETURN -1 END;
  1651. IF NOT vtBuilt[r] THEN BuildVTable(r) END;
  1652. RETURN tvptr[r]
  1653. END VptrOffset;
  1654. PROCEDURE HasVTable (ct: TypeIndex): BOOLEAN;
  1655. (* TRUE when ct has (or inherits) any virtual method. *)
  1656. VAR r: TypeIndex;
  1657. BEGIN
  1658. r := Resolve(ct);
  1659. IF (r = InvalidType) OR (tform[r] # FClass) THEN RETURN FALSE END;
  1660. IF NOT vtBuilt[r] THEN BuildVTable(r) END;
  1661. RETURN nVirt[r] > 0
  1662. END HasVTable;
  1663. PROCEDURE VirtSlot (ct: TypeIndex; name: ARRAY OF CHAR): INTEGER;
  1664. (* Vtable slot of ct's method name, or -1 when it is not virtual. *)
  1665. VAR r: TypeIndex;
  1666. node: SymPtr;
  1667. BEGIN
  1668. node := ClassMethodNode(ct, name);
  1669. IF (node = NIL) OR NOT node^.virt THEN RETURN -1 END;
  1670. r := Resolve(ct);
  1671. IF NOT vtBuilt[r] THEN BuildVTable(r) END;
  1672. RETURN node^.vslot
  1673. END VirtSlot;
  1674. PROCEDURE VtCount (ct: TypeIndex): CARDINAL;
  1675. VAR r: TypeIndex;
  1676. BEGIN
  1677. r := Resolve(ct);
  1678. IF (r = InvalidType) OR (tform[r] # FClass) THEN RETURN 0 END;
  1679. IF NOT vtBuilt[r] THEN BuildVTable(r) END;
  1680. RETURN nVirt[r]
  1681. END VtCount;
  1682. PROCEDURE VtName (ct: TypeIndex; k: CARDINAL; VAR name: Name): BOOLEAN;
  1683. VAR r: TypeIndex;
  1684. BEGIN
  1685. name[0] := CHR(0);
  1686. r := Resolve(ct);
  1687. IF (r = InvalidType) OR (k >= nVirt[r]) THEN RETURN FALSE END;
  1688. Assign(name, vtName[vtBase[r] + k]);
  1689. RETURN TRUE
  1690. END VtName;
  1691. PROCEDURE VtHasBody (ct: TypeIndex; k: CARDINAL): BOOLEAN;
  1692. (* TRUE when slot k's method has an emitted body (else the vtable
  1693. entry is a null pointer). *)
  1694. VAR r: TypeIndex;
  1695. node: SymPtr;
  1696. BEGIN
  1697. r := Resolve(ct);
  1698. IF (r = InvalidType) OR (k >= nVirt[r]) THEN RETURN FALSE END;
  1699. node := ClassMethodNode(r, vtName[vtBase[r] + k]);
  1700. IF node = NIL THEN RETURN FALSE END;
  1701. RETURN node^.hasBody
  1702. END VtHasBody;
  1703. PROCEDURE VtUid (ct: TypeIndex; k: CARDINAL): CARDINAL;
  1704. VAR r: TypeIndex;
  1705. BEGIN
  1706. r := Resolve(ct);
  1707. IF (r = InvalidType) OR (k >= nVirt[r]) THEN RETURN 0 END;
  1708. RETURN vtUid[vtBase[r] + k]
  1709. END VtUid;
  1710. PROCEDURE PushClassMembers (t: TypeIndex): BOOLEAN;
  1711. (* Pushes a scope with t's fields and its ancestors' fields
  1712. (inheritance) as KindField, for method bodies in CLASS
  1713. IMPLEMENTATION. Method NAMES are deliberately not copied; bodies
  1714. re-enter them fresh via ResumeMethod (copying would collide). *)
  1715. VAR r, p: TypeIndex;
  1716. s: ScopePtr;
  1717. guard: CARDINAL;
  1718. BEGIN
  1719. r := Resolve(t);
  1720. IF (r = InvalidType) OR (tform[r] # FClass) THEN RETURN FALSE END;
  1721. s := tscope[r];
  1722. IF s = NIL THEN RETURN FALSE END;
  1723. PushScope;
  1724. curScope^.ofRec := r;
  1725. EnterFieldsOf(r);
  1726. (* ancestors' fields, nearest first *)
  1727. guard := 0;
  1728. p := ParentOf(r);
  1729. WHILE (p # InvalidType) AND (guard < ResDepth) DO
  1730. EnterFieldsOf(p);
  1731. p := ParentOf(p);
  1732. INC(guard)
  1733. END;
  1734. RETURN TRUE
  1735. END PushClassMembers;
  1736. PROCEDURE MarkVirtual;
  1737. BEGIN
  1738. IF curProc # NIL THEN curProc^.virt := TRUE END
  1739. END MarkVirtual;
  1740. (* ---------------- procedures ---------------- *)
  1741. PROCEDURE EnterProc (name: ARRAY OF CHAR): BOOLEAN;
  1742. VAR node: SymPtr;
  1743. BEGIN
  1744. node := RawEnter(name, KindProc);
  1745. IF node = NIL THEN curProc := NIL; RETURN FALSE END;
  1746. node^.rslt := InvalidType;
  1747. node^.plink := NIL;
  1748. node^.isVar := FALSE;
  1749. node^.fwd := FALSE;
  1750. node^.virt := FALSE;
  1751. node^.ext := FALSE;
  1752. node^.fsnap := FALSE;
  1753. node^.link[0] := CHR(0);
  1754. node^.uid := nextUid; INC(nextUid);
  1755. node^.fdep := nProc;
  1756. node^.vslot := -1;
  1757. node^.hasBody := FALSE;
  1758. curProc := node;
  1759. curPTail := NIL;
  1760. PushProc(node);
  1761. PushScope;
  1762. RETURN TRUE
  1763. END EnterProc;
  1764. PROCEDURE DeclareCProc (name: ARRAY OF CHAR): BOOLEAN;
  1765. (* Enter name in the current scope as an external C procedure with a
  1766. permissive (varargs, no-result) signature. Used for intrinsic
  1767. `FROM libc IMPORT ...`; not pushed as the current proc. *)
  1768. VAR node: SymPtr;
  1769. BEGIN
  1770. node := RawEnter(name, KindProc);
  1771. IF node = NIL THEN RETURN FALSE END;
  1772. node^.rslt := InvalidType;
  1773. node^.plink := NIL;
  1774. node^.isVar := FALSE;
  1775. node^.fwd := FALSE;
  1776. node^.virt := FALSE;
  1777. node^.ext := TRUE;
  1778. node^.varargs := TRUE;
  1779. node^.fsnap := FALSE;
  1780. Assign(node^.link, name);
  1781. node^.uid := nextUid; INC(nextUid);
  1782. node^.fdep := nProc;
  1783. node^.vslot := -1;
  1784. node^.hasBody := TRUE;
  1785. RETURN TRUE
  1786. END DeclareCProc;
  1787. PROCEDURE Varargs (name: ARRAY OF CHAR): BOOLEAN;
  1788. (* TRUE for a C-varargs procedure (its calls skip arity/type checks). *)
  1789. VAR node: SymPtr;
  1790. BEGIN
  1791. node := Find(name);
  1792. IF node = NIL THEN RETURN FALSE END;
  1793. RETURN node^.varargs
  1794. END Varargs;
  1795. PROCEDURE ResumeProc (name: ARRAY OF CHAR): BOOLEAN;
  1796. (* Resumes a DEFINITION procedure heading for its IMPLEMENTATION
  1797. body. The definition's signature (result type, formals in order,
  1798. VAR-ness) is snapshotted before the implementation re-enters its
  1799. own formals; SetProcRes/FixPending then compare (strict 231). *)
  1800. VAR node, f: SymPtr;
  1801. i, n: CARDINAL;
  1802. BEGIN
  1803. IF curUnit # UnitImpl THEN RETURN FALSE END;
  1804. node := TreeFind(curScope^.root, name);
  1805. IF node = NIL THEN RETURN FALSE END;
  1806. IF node^.kind # KindProc THEN RETURN FALSE END;
  1807. (* snapshot the definition signature *)
  1808. node^.snapRes := node^.rslt;
  1809. node^.nSnap := 0;
  1810. n := 0;
  1811. f := node^.plink;
  1812. WHILE (f # NIL) AND (n <= HighSnap) DO
  1813. snapT[n] := f^.typ;
  1814. snapV[n] := f^.isVar;
  1815. INC(n);
  1816. f := f^.plink
  1817. END;
  1818. FOR i := 0 TO HighSnap DO
  1819. IF i < n THEN
  1820. node^.snapT[i] := snapT[i];
  1821. node^.snapV[i] := snapV[i]
  1822. END
  1823. END;
  1824. node^.nSnap := n;
  1825. node^.fsnap := TRUE;
  1826. node^.plink := NIL; (* implementation re-enters formals *)
  1827. curProc := node;
  1828. curPTail := NIL;
  1829. PushProc(node);
  1830. PushScope;
  1831. RETURN TRUE
  1832. END ResumeProc;
  1833. PROCEDURE ReenterProc (name: ARRAY OF CHAR): BOOLEAN;
  1834. VAR node: SymPtr;
  1835. BEGIN
  1836. node := TreeFind(curScope^.root, name);
  1837. IF node = NIL THEN RETURN FALSE END;
  1838. IF (node^.kind # KindProc) OR NOT node^.fwd THEN
  1839. RETURN FALSE
  1840. END;
  1841. node^.fwd := FALSE;
  1842. node^.plink := NIL; (* fresh signature; step 4 compares old vs new *)
  1843. curProc := node;
  1844. curPTail := NIL;
  1845. PushProc(node);
  1846. PushScope;
  1847. RETURN TRUE
  1848. END ReenterProc;
  1849. PROCEDURE EnterParam (name: ARRAY OF CHAR; isVar: BOOLEAN): BOOLEAN;
  1850. VAR node: SymPtr;
  1851. BEGIN
  1852. node := RawEnter(name, KindParam);
  1853. IF node = NIL THEN RETURN FALSE END;
  1854. node^.isVar := isVar;
  1855. node^.plink := NIL;
  1856. IF (nPend < MaxPend) THEN
  1857. pend[nPend] := node; INC(nPend)
  1858. END;
  1859. IF curProc # NIL THEN
  1860. IF curProc^.plink = NIL THEN curProc^.plink := node
  1861. ELSE curPTail^.plink := node
  1862. END;
  1863. curPTail := node
  1864. END;
  1865. RETURN TRUE
  1866. END EnterParam;
  1867. PROCEDURE EnterThisParam (cls: TypeIndex): BOOLEAN;
  1868. (* Enters the hidden first parameter THIS (a VAR param of the class
  1869. type) for a method heading. Field access inside the body binds
  1870. THIS as the WITH base. THIS is not left pending (it is emitted
  1871. explicitly by the heading, before any user formals). *)
  1872. VAR ok: BOOLEAN;
  1873. BEGIN
  1874. ok := EnterParam("THIS", TRUE);
  1875. nPend := 0;
  1876. RETURN ok
  1877. END EnterThisParam;
  1878. PROCEDURE SetProcRes (t: TypeIndex) : BOOLEAN;
  1879. (* Sets the current procedure's result type. If the heading resumed
  1880. a DEFINITION (ResumeProc), this is the strict-231 checkpoint: the
  1881. implementation's result type, formal count, formal types and
  1882. VAR-ness are compared against the snapshot; the outcome is
  1883. returned (TRUE = match). *)
  1884. VAR f, node: SymPtr;
  1885. i, n: CARDINAL;
  1886. isV: BOOLEAN;
  1887. BEGIN
  1888. IF curProc # NIL THEN curProc^.rslt := t END;
  1889. node := curProc;
  1890. IF (node = NIL) OR NOT node^.fsnap THEN RETURN TRUE END;
  1891. IF NOT FormalOk(t, node^.snapRes) THEN RETURN FALSE END;
  1892. (* count the implementation heading's formals *)
  1893. n := 0;
  1894. f := node^.plink;
  1895. WHILE (f # NIL) AND (n <= HighSnap) DO INC(n); f := f^.plink END;
  1896. IF n # node^.nSnap THEN RETURN FALSE END;
  1897. f := node^.plink;
  1898. i := 0;
  1899. WHILE f # NIL DO
  1900. IF i > HighSnap THEN RETURN FALSE END;
  1901. isV := f^.isVar;
  1902. IF isV # node^.snapV[i] THEN RETURN FALSE END;
  1903. IF isV THEN
  1904. IF NOT VarParamOk(f^.typ, node^.snapT[i]) THEN RETURN FALSE END
  1905. ELSE
  1906. IF NOT FormalOk(f^.typ, node^.snapT[i]) THEN RETURN FALSE END
  1907. END;
  1908. f := f^.plink;
  1909. INC(i)
  1910. END;
  1911. RETURN TRUE
  1912. END SetProcRes;
  1913. PROCEDURE ProcRes (name: ARRAY OF CHAR): TypeIndex;
  1914. VAR node: SymPtr;
  1915. BEGIN
  1916. node := Find(name);
  1917. IF node = NIL THEN RETURN InvalidType END;
  1918. IF node^.kind # KindProc THEN RETURN InvalidType END;
  1919. RETURN node^.rslt
  1920. END ProcRes;
  1921. PROCEDURE MarkFwd;
  1922. BEGIN
  1923. IF curProc # NIL THEN curProc^.fwd := TRUE END
  1924. END MarkFwd;
  1925. PROCEDURE MarkExternal (link: ARRAY OF CHAR);
  1926. (* Marks the current procedure EXTERNAL; link '' means "use the
  1927. procedure's own name" (must be a valid C symbol). *)
  1928. BEGIN
  1929. IF curProc = NIL THEN RETURN END;
  1930. curProc^.ext := TRUE;
  1931. IF link[0] = CHR(0) THEN Assign(curProc^.link, curProc^.name)
  1932. ELSE Assign(curProc^.link, link)
  1933. END
  1934. END MarkExternal;
  1935. PROCEDURE IsExternal (name: ARRAY OF CHAR): BOOLEAN;
  1936. VAR node: SymPtr;
  1937. BEGIN
  1938. node := Find(name);
  1939. IF node = NIL THEN RETURN FALSE END;
  1940. RETURN node^.ext
  1941. END IsExternal;
  1942. PROCEDURE ProcLink (name: ARRAY OF CHAR; VAR link: Name): BOOLEAN;
  1943. VAR node: SymPtr;
  1944. BEGIN
  1945. node := Find(name);
  1946. IF node = NIL THEN RETURN FALSE END;
  1947. IF NOT node^.ext THEN RETURN FALSE END;
  1948. Assign(link, node^.link);
  1949. RETURN TRUE
  1950. END ProcLink;
  1951. PROCEDURE CloseProc;
  1952. BEGIN
  1953. IF nProc > 0 THEN DEC(nProc) END;
  1954. PopScope
  1955. END CloseProc;
  1956. PROCEDURE InProc (): BOOLEAN;
  1957. BEGIN
  1958. RETURN nProc > 0
  1959. END InProc;
  1960. PROCEDURE CurRes (): TypeIndex;
  1961. BEGIN
  1962. IF nProc = 0 THEN RETURN InvalidType END;
  1963. RETURN procStk[nProc - 1]^.rslt
  1964. END CurRes;
  1965. PROCEDURE ProcDepthOf (name: ARRAY OF CHAR): CARDINAL;
  1966. VAR node: SymPtr;
  1967. BEGIN
  1968. node := Find(name);
  1969. IF node = NIL THEN RETURN 0 END;
  1970. IF node^.kind # KindProc THEN RETURN 0 END;
  1971. RETURN node^.fdep
  1972. END ProcDepthOf;
  1973. PROCEDURE ProcUid (name: ARRAY OF CHAR): CARDINAL;
  1974. VAR node: SymPtr;
  1975. BEGIN
  1976. node := Find(name);
  1977. IF node = NIL THEN RETURN 0 END;
  1978. IF node^.kind # KindProc THEN RETURN 0 END;
  1979. RETURN node^.uid
  1980. END ProcUid;
  1981. PROCEDURE NthParam (node: SymPtr; i: CARDINAL): SymPtr;
  1982. BEGIN
  1983. node := node^.plink;
  1984. WHILE (i > 0) AND (node # NIL) DO
  1985. node := node^.plink; DEC(i)
  1986. END;
  1987. RETURN node
  1988. END NthParam;
  1989. PROCEDURE ProcNPar (name: ARRAY OF CHAR): CARDINAL;
  1990. VAR node, p: SymPtr;
  1991. n: CARDINAL;
  1992. BEGIN
  1993. node := Find(name);
  1994. IF node = NIL THEN RETURN 0 END;
  1995. IF node^.kind # KindProc THEN RETURN 0 END;
  1996. n := 0; p := node^.plink;
  1997. WHILE p # NIL DO INC(n); p := p^.plink END;
  1998. RETURN n
  1999. END ProcNPar;
  2000. PROCEDURE ParamType (name: ARRAY OF CHAR; i: CARDINAL): TypeIndex;
  2001. VAR node, p: SymPtr;
  2002. BEGIN
  2003. node := Find(name);
  2004. IF node = NIL THEN RETURN InvalidType END;
  2005. IF node^.kind # KindProc THEN RETURN InvalidType END;
  2006. p := NthParam(node, i);
  2007. IF p = NIL THEN RETURN InvalidType END;
  2008. RETURN p^.typ
  2009. END ParamType;
  2010. PROCEDURE ParamIsVar (name: ARRAY OF CHAR; i: CARDINAL): BOOLEAN;
  2011. VAR node, p: SymPtr;
  2012. BEGIN
  2013. node := Find(name);
  2014. IF node = NIL THEN RETURN FALSE END;
  2015. IF node^.kind # KindProc THEN RETURN FALSE END;
  2016. p := NthParam(node, i);
  2017. IF p = NIL THEN RETURN FALSE END;
  2018. RETURN p^.isVar
  2019. END ParamIsVar;
  2020. (* ---------------- modules / separate compilation (step 4.3) ---------------- *)
  2021. PROCEDURE EnterIn (s: ScopePtr; name: ARRAY OF CHAR;
  2022. kind: INTEGER): BOOLEAN;
  2023. VAR node: SymPtr;
  2024. BEGIN
  2025. NEW(node);
  2026. Assign(node^.name, name);
  2027. Assign(node^.sym, name);
  2028. node^.mod[0] := CHR(0);
  2029. node^.kind := kind;
  2030. node^.typ := InvalidType;
  2031. node^.scope := s;
  2032. node^.left := NIL;
  2033. node^.right := NIL;
  2034. node^.rslt := InvalidType;
  2035. node^.plink := NIL;
  2036. node^.isVar := FALSE;
  2037. node^.fwd := FALSE;
  2038. node^.virt := FALSE;
  2039. node^.ext := FALSE;
  2040. node^.link[0] := CHR(0);
  2041. node^.fdep := 0;
  2042. node^.uid := 0;
  2043. node^.val[0] := CHR(0);
  2044. IF NOT TreeInsert(s, node) THEN RETURN FALSE END;
  2045. RETURN TRUE
  2046. END EnterIn;
  2047. PROCEDURE FindMod (name: ARRAY OF CHAR): INTEGER;
  2048. VAR i : CARDINAL;
  2049. BEGIN
  2050. i := 0;
  2051. WHILE i < nMods DO
  2052. IF Equal(modNames[i], name) THEN RETURN VAL(INTEGER, i) END;
  2053. INC(i)
  2054. END;
  2055. RETURN -1
  2056. END FindMod;
  2057. PROCEDURE NewMod (name: ARRAY OF CHAR; kind: INTEGER): BOOLEAN;
  2058. VAR idx : CARDINAL;
  2059. s : ScopePtr;
  2060. BEGIN
  2061. IF nMods >= MaxMods THEN RETURN FALSE END;
  2062. IF FindMod(name) # -1 THEN RETURN FALSE END;
  2063. idx := nMods;
  2064. Assign(modNames[idx], name);
  2065. s := NewScope(globScope, 1);
  2066. modScopes[idx] := s;
  2067. modKind[idx] := kind;
  2068. modImpl[idx] := FALSE;
  2069. INC(nMods);
  2070. (* the module name lives in the global scope *)
  2071. IF NOT EnterIn(globScope, name, KindModule) THEN
  2072. DEC(nMods); RETURN FALSE
  2073. END;
  2074. curMod := VAL(INTEGER, idx);
  2075. curUnit := kind;
  2076. curScope := s;
  2077. RETURN TRUE
  2078. END NewMod;
  2079. PROCEDURE BeginDef (name: ARRAY OF CHAR): BOOLEAN;
  2080. BEGIN
  2081. RETURN NewMod(name, UnitDef)
  2082. END BeginDef;
  2083. PROCEDURE BeginImpl (name: ARRAY OF CHAR): BOOLEAN;
  2084. VAR idx : INTEGER;
  2085. BEGIN
  2086. idx := FindMod(name);
  2087. IF idx = -1 THEN RETURN FALSE END;
  2088. IF (modKind[idx] # UnitDef) OR modImpl[idx] THEN RETURN FALSE END;
  2089. modImpl[idx] := TRUE;
  2090. curMod := idx;
  2091. curUnit := UnitImpl;
  2092. curScope := modScopes[idx];
  2093. RETURN TRUE
  2094. END BeginImpl;
  2095. PROCEDURE BeginProg (name: ARRAY OF CHAR): BOOLEAN;
  2096. VAR ok : BOOLEAN;
  2097. BEGIN
  2098. ok := NewMod(name, UnitProg);
  2099. IF ok THEN haveProg := TRUE END;
  2100. RETURN ok
  2101. END BeginProg;
  2102. PROCEDURE HaveProgram (): BOOLEAN;
  2103. BEGIN
  2104. RETURN haveProg
  2105. END HaveProgram;
  2106. PROCEDURE EndUnit;
  2107. BEGIN
  2108. curScope := globScope;
  2109. curMod := -1;
  2110. curUnit := -1
  2111. END EndUnit;
  2112. PROCEDURE ModKnown (name: ARRAY OF CHAR): BOOLEAN;
  2113. BEGIN
  2114. RETURN FindMod(name) # -1
  2115. END ModKnown;
  2116. PROCEDURE OpaqueBase (name: ARRAY OF CHAR): TypeIndex;
  2117. VAR node: SymPtr;
  2118. r : TypeIndex;
  2119. BEGIN
  2120. node := Find(name);
  2121. IF node = NIL THEN RETURN InvalidType END;
  2122. IF node^.kind # KindType THEN RETURN InvalidType END;
  2123. r := node^.typ;
  2124. IF (r < 0) OR (r >= VAL(INTEGER, nTypes)) THEN
  2125. RETURN InvalidType
  2126. END;
  2127. IF (tform[r] = FAlias) AND (tref[r] = InvalidType) THEN RETURN r END;
  2128. RETURN InvalidType
  2129. END OpaqueBase;
  2130. PROCEDURE BeginTypeBlock;
  2131. BEGIN
  2132. INC(typeBlockDepth)
  2133. END BeginTypeBlock;
  2134. PROCEDURE EndTypeBlock;
  2135. BEGIN
  2136. IF typeBlockDepth > 0 THEN DEC(typeBlockDepth) END
  2137. END EndTypeBlock;
  2138. PROCEDURE IsUnresolved (t: TypeIndex): BOOLEAN;
  2139. VAR r: TypeIndex;
  2140. BEGIN
  2141. IF (t < 0) OR (t >= VAL(INTEGER, nTypes)) THEN RETURN FALSE END;
  2142. r := t;
  2143. RETURN (tform[r] = FAlias) AND (tref[r] = InvalidType)
  2144. END IsUnresolved;
  2145. PROCEDURE ForwardType (name: ARRAY OF CHAR): TypeIndex;
  2146. (* Registers an undeclared type name as an opaque placeholder that a
  2147. later TYPE declaration completes. Active inside a TYPE block, and
  2148. at module declaration level (so a global may reference a type
  2149. declared further down). *)
  2150. VAR node: SymPtr;
  2151. t: TypeIndex;
  2152. BEGIN
  2153. IF (typeBlockDepth = 0) AND (nProc > 0) THEN
  2154. RETURN InvalidType
  2155. END;
  2156. node := Find(name);
  2157. IF node # NIL THEN
  2158. IF node^.kind = KindType THEN RETURN node^.typ END;
  2159. RETURN InvalidType
  2160. END;
  2161. IF NOT Enter(name, KindType) THEN RETURN InvalidType END;
  2162. t := NewAlias();
  2163. SetSymType(name, t);
  2164. IF (typeBlockDepth = 0) AND (pfwdN <= HIGH(pfwdName)) THEN
  2165. Assign(pfwdName[pfwdN], name);
  2166. pfwdT[pfwdN] := t;
  2167. INC(pfwdN)
  2168. END;
  2169. RETURN t
  2170. END ForwardType;
  2171. PROCEDURE FwdPending (): CARDINAL;
  2172. BEGIN RETURN pfwdN END FwdPending;
  2173. PROCEDURE FwdInfo (i: CARDINAL; VAR name: Name; VAR unresolved: BOOLEAN);
  2174. BEGIN
  2175. name[0] := CHR(0);
  2176. unresolved := FALSE;
  2177. IF i < pfwdN THEN
  2178. Assign(name, pfwdName[i]);
  2179. unresolved := Resolve(pfwdT[i]) = InvalidType
  2180. END
  2181. END FwdInfo;
  2182. PROCEDURE FwdClear;
  2183. BEGIN pfwdN := 0 END FwdClear;
  2184. PROCEDURE QualNode (mod, name: ARRAY OF CHAR): SymPtr;
  2185. VAR i : INTEGER;
  2186. BEGIN
  2187. i := FindMod(mod);
  2188. IF i = -1 THEN RETURN NIL END;
  2189. RETURN TreeFind(modScopes[i]^.root, name)
  2190. END QualNode;
  2191. PROCEDURE QualType (mod, name: ARRAY OF CHAR): TypeIndex;
  2192. VAR n : SymPtr;
  2193. BEGIN
  2194. n := QualNode(mod, name);
  2195. IF n = NIL THEN RETURN InvalidType END;
  2196. RETURN n^.typ
  2197. END QualType;
  2198. PROCEDURE QualNthParam (n: SymPtr; i: CARDINAL): SymPtr;
  2199. BEGIN
  2200. n := n^.plink;
  2201. WHILE (i > 0) AND (n # NIL) DO
  2202. n := n^.plink; DEC(i)
  2203. END;
  2204. RETURN n
  2205. END QualNthParam;
  2206. PROCEDURE ExportUp (name: ARRAY OF CHAR);
  2207. VAR src, node: SymPtr;
  2208. parent: ScopePtr;
  2209. BEGIN
  2210. IF curScope = NIL THEN RETURN END;
  2211. src := TreeFind(curScope^.root, name);
  2212. IF src = NIL THEN RETURN END;
  2213. parent := curScope^.parent;
  2214. IF parent = NIL THEN RETURN END;
  2215. IF TreeFind(parent^.root, name) # NIL THEN RETURN END;
  2216. NEW(node);
  2217. node^ := src^;
  2218. node^.left := NIL;
  2219. node^.right := NIL;
  2220. node^.scope := parent;
  2221. IF NOT TreeInsert(parent, node) THEN
  2222. (* duplicate at this level: ignore *)
  2223. END
  2224. END ExportUp;
  2225. PROCEDURE Materialize (mod, name: ARRAY OF CHAR): BOOLEAN;
  2226. (* FROM-import: clones mod's export into the current scope under
  2227. its plain name. *)
  2228. VAR src, node : SymPtr;
  2229. BEGIN
  2230. src := QualNode(mod, name);
  2231. IF src = NIL THEN RETURN FALSE END;
  2232. (* already visible (repeat import): nothing to do *)
  2233. IF TreeFind(curScope^.root, name) # NIL THEN RETURN TRUE END;
  2234. NEW(node);
  2235. node^ := src^;
  2236. node^.left := NIL;
  2237. node^.right := NIL;
  2238. node^.scope := curScope;
  2239. IF NOT TreeInsert(curScope, node) THEN RETURN FALSE END;
  2240. RETURN TRUE
  2241. END Materialize;
  2242. PROCEDURE MaterializeReplace (mod, name: ARRAY OF CHAR): BOOLEAN;
  2243. (* Like Materialize, but when `name` is already visible it is updated in
  2244. place to the given module's symbol. Lower re-emits one unit at a time
  2245. and every unit has its own `scopeTop`/`EOL`/..., so the current unit's
  2246. global must win GlobalRef; the plain Materialize keeps the first one. *)
  2247. VAR src, node, l, r : SymPtr; sc : ScopePtr;
  2248. BEGIN
  2249. src := QualNode(mod, name);
  2250. IF src = NIL THEN RETURN FALSE END;
  2251. node := TreeFind(curScope^.root, name);
  2252. IF node # NIL THEN
  2253. l := node^.left; r := node^.right; sc := node^.scope;
  2254. node^ := src^;
  2255. node^.left := l; node^.right := r; node^.scope := sc;
  2256. RETURN TRUE
  2257. END;
  2258. NEW(node);
  2259. node^ := src^;
  2260. node^.left := NIL;
  2261. node^.right := NIL;
  2262. node^.scope := curScope;
  2263. IF NOT TreeInsert(curScope, node) THEN RETURN FALSE END;
  2264. RETURN TRUE
  2265. END MaterializeReplace;
  2266. PROCEDURE BuildAlias (mod, name: ARRAY OF CHAR; VAR alias: Name);
  2267. (* alias := "<mod>$<name>" (a key no identifier can collide with). *)
  2268. VAR i, j : CARDINAL;
  2269. BEGIN
  2270. i := 0;
  2271. WHILE (i < HIGH(alias)) AND (mod[i] # CHR(0)) DO
  2272. alias[i] := mod[i]; INC(i)
  2273. END;
  2274. IF i < HIGH(alias) THEN alias[i] := "$"; INC(i) END;
  2275. j := 0;
  2276. WHILE (i < HIGH(alias)) AND (name[j] # CHR(0)) DO
  2277. alias[i] := name[j]; INC(i); INC(j)
  2278. END;
  2279. IF i <= HIGH(alias) THEN alias[i] := CHR(0) END
  2280. END BuildAlias;
  2281. PROCEDURE MaterializeAlias (mod, name: ARRAY OF CHAR;
  2282. VAR alias: Name): BOOLEAN;
  2283. (* Qualified access: clones mod's export under a per-module alias
  2284. key so same-named exports of different modules never collide.
  2285. The node keeps sym = name and mod = defining module, so QBE
  2286. symbols (data and calls) resolve correctly. *)
  2287. VAR src, node : SymPtr;
  2288. BEGIN
  2289. src := QualNode(mod, name);
  2290. IF src = NIL THEN RETURN FALSE END;
  2291. BuildAlias(mod, name, alias);
  2292. IF TreeFind(curScope^.root, alias) = NIL THEN
  2293. NEW(node);
  2294. node^ := src^;
  2295. Assign(node^.name, alias); (* BST key *)
  2296. Assign(node^.sym, name); (* real symbol name *)
  2297. node^.left := NIL;
  2298. node^.right := NIL;
  2299. node^.scope := curScope;
  2300. IF NOT TreeInsert(curScope, node) THEN RETURN FALSE END
  2301. END;
  2302. RETURN TRUE
  2303. END MaterializeAlias;
  2304. PROCEDURE SymBase (name: ARRAY OF CHAR; VAR base: Name): BOOLEAN;
  2305. (* Base symbol name of the visible entry (differs from `name` for
  2306. qualified aliases). *)
  2307. VAR node: SymPtr;
  2308. BEGIN
  2309. node := Find(name);
  2310. IF node = NIL THEN RETURN FALSE END;
  2311. Assign(base, node^.sym);
  2312. RETURN TRUE
  2313. END SymBase;
  2314. PROCEDURE GlobalRef (name: ARRAY OF CHAR; VAR g: Name): BOOLEAN;
  2315. (* QBE global-symbol name for a module-level entry: "<mod>_<sym>".
  2316. FALSE when name is not a module-level symbol. *)
  2317. VAR node: SymPtr;
  2318. i, j : CARDINAL;
  2319. BEGIN
  2320. node := Find(name);
  2321. IF node = NIL THEN RETURN FALSE END;
  2322. IF node^.mod[0] = CHR(0) THEN RETURN FALSE END;
  2323. i := 0;
  2324. WHILE (i < HIGH(g)) AND (node^.mod[i] # CHR(0)) DO
  2325. g[i] := node^.mod[i]; INC(i)
  2326. END;
  2327. IF i < HIGH(g) THEN g[i] := "_"; INC(i) END;
  2328. j := 0;
  2329. WHILE (i < HIGH(g)) AND (node^.sym[j] # CHR(0)) DO
  2330. g[i] := node^.sym[j]; INC(i); INC(j)
  2331. END;
  2332. IF i <= HIGH(g) THEN g[i] := CHR(0) END;
  2333. RETURN TRUE
  2334. END GlobalRef;
  2335. (* ---- forward module-level variables ----
  2336. Inside a procedure body a not-yet-declared identifier may be a
  2337. module-level variable declared further down (gm2 tolerates this).
  2338. SymTab records the reference and reports it (FwdVarFix) once the
  2339. module's declarations are complete; an identifier never declared
  2340. still yields a 201. *)
  2341. PROCEDURE IsFwdVar (t: TypeIndex): BOOLEAN;
  2342. (* TRUE when t is a forward-variable placeholder (its real type is not
  2343. yet known, so type checks must be lenient). *)
  2344. VAR k: CARDINAL;
  2345. BEGIN
  2346. k := 0;
  2347. WHILE k < nFwdVar DO
  2348. IF fwdVarT[k] = t THEN RETURN TRUE END;
  2349. INC(k)
  2350. END;
  2351. RETURN FALSE
  2352. END IsFwdVar;
  2353. PROCEDURE FwdVarName (id: INTEGER; VAR name: Name);
  2354. (* The identifier behind a forward reference id (1-based). *)
  2355. BEGIN
  2356. name[0] := CHR(0);
  2357. IF (id >= 1) AND (id <= VAL(INTEGER, nFwdVar)) THEN
  2358. Assign(name, fwdVarName[id - 1])
  2359. END
  2360. END FwdVarName;
  2361. PROCEDURE FwdVarRef (name: ARRAY OF CHAR; kind: INTEGER;
  2362. VAR id: INTEGER; VAR t: TypeIndex): BOOLEAN;
  2363. (* Records (or finds) a forward reference to a module-level name used
  2364. inside a procedure body before its declaration. Returns FALSE when
  2365. the buffer is full. *)
  2366. VAR k: CARDINAL;
  2367. BEGIN
  2368. k := 0;
  2369. WHILE k < nFwdVar DO
  2370. IF Equal(fwdVarName[k], name) THEN
  2371. id := VAL(INTEGER, k) + 1;
  2372. t := fwdVarT[k];
  2373. RETURN TRUE
  2374. END;
  2375. INC(k)
  2376. END;
  2377. IF nFwdVar > HIGH(fwdVarName) THEN id := 0; t := InvalidType;
  2378. RETURN FALSE
  2379. END;
  2380. Assign(fwdVarName[nFwdVar], name);
  2381. fwdVarKind[nFwdVar] := kind;
  2382. t := NewAlias();
  2383. fwdVarT[nFwdVar] := t;
  2384. id := VAL(INTEGER, nFwdVar) + 1;
  2385. INC(nFwdVar);
  2386. RETURN TRUE
  2387. END FwdVarRef;
  2388. PROCEDURE FwdVarType (id: INTEGER): TypeIndex;
  2389. BEGIN
  2390. IF (id >= 1) AND (id <= VAL(INTEGER, nFwdVar)) THEN
  2391. RETURN fwdVarT[id - 1]
  2392. END;
  2393. RETURN InvalidType
  2394. END FwdVarType;
  2395. PROCEDURE FwdVarResolve (id: INTEGER): BOOLEAN;
  2396. (* Resolves forward reference id against the module's declarations.
  2397. TRUE when the name now exists; sets the recorded placeholder's
  2398. target so ClassOf/Assignable see the real type. *)
  2399. VAR node: SymPtr;
  2400. BEGIN
  2401. IF (id < 1) OR (id > VAL(INTEGER, nFwdVar)) THEN RETURN TRUE END;
  2402. node := Find(fwdVarName[id - 1]);
  2403. IF node = NIL THEN RETURN FALSE END;
  2404. IF fwdVarKind[id - 1] = KindProc THEN
  2405. IF node^.kind # KindProc THEN RETURN FALSE END
  2406. ELSE
  2407. IF (node^.kind # KindVar) AND (node^.kind # KindParam) THEN
  2408. RETURN FALSE
  2409. END
  2410. END;
  2411. fwdVarT[id - 1] := node^.typ;
  2412. RETURN TRUE
  2413. END FwdVarResolve;
  2414. PROCEDURE FwdVarName1 (id: INTEGER; VAR name: Name);
  2415. BEGIN
  2416. FwdVarName(id, name)
  2417. END FwdVarName1;
  2418. PROCEDURE ImportFrom (mod, name: ARRAY OF CHAR): BOOLEAN;
  2419. BEGIN
  2420. RETURN Materialize(mod, name)
  2421. END ImportFrom;
  2422. (* ---------------- predicates (unchanged) ---------------- *)
  2423. PROCEDURE BaseSpanOk (b: TypeIndex): BOOLEAN;
  2424. (* TRUE for set-suitable bases: bool, char, subranges ≤ 256 wide. *)
  2425. VAR r: TypeIndex;
  2426. lo, hi: INTEGER;
  2427. BEGIN
  2428. r := Resolve(b);
  2429. IF r = InvalidType THEN RETURN TRUE END;
  2430. IF tform[r] = FBool THEN RETURN TRUE END;
  2431. IF tform[r] = FChar THEN RETURN TRUE END;
  2432. IF (tform[r] = FSub) AND (tref[r] = InvalidType)
  2433. AND SubBounds(b, lo, hi) AND (hi >= lo) AND (hi - lo < 256) THEN
  2434. RETURN TRUE
  2435. END;
  2436. RETURN FALSE
  2437. END BaseSpanOk;
  2438. PROCEDURE SetBasesOk (a, b: TypeIndex): BOOLEAN;
  2439. (* base compatibility for two SET types: same, or both suitable
  2440. (masks compare over min words + zero-check extras) *)
  2441. BEGIN
  2442. IF SameType(a, b) THEN RETURN TRUE END;
  2443. RETURN BaseSpanOk(a) AND BaseSpanOk(b)
  2444. END SetBasesOk;
  2445. PROCEDURE ParamTypesOk (x, y: TypeIndex): BOOLEAN;
  2446. (* Procedure-type formal compatibility: identical, or an open array
  2447. matching an open/fixed 1-D array of the same element type (open
  2448. arrays are distinct descriptors, so index equality is too strict). *)
  2449. BEGIN
  2450. IF SameType(x, y) THEN RETURN TRUE END;
  2451. IF (x = InvalidType) OR (y = InvalidType) THEN RETURN TRUE END;
  2452. IF IsOpenArray(x) AND (ClassOf(y) = ClArray) AND (ArrayDepth(y) = 1) THEN
  2453. RETURN SameType(ArrayElem(x), ArrayElem(y))
  2454. END;
  2455. IF IsOpenArray(y) AND (ClassOf(x) = ClArray) AND (ArrayDepth(x) = 1) THEN
  2456. RETURN SameType(ArrayElem(x), ArrayElem(y))
  2457. END;
  2458. RETURN FALSE
  2459. END ParamTypesOk;
  2460. PROCEDURE ProcTypesOk (a, b: TypeIndex): BOOLEAN;
  2461. (* Structural compatibility of two procedure types: same result and
  2462. same parameter types / VAR flags. *)
  2463. VAR i, n: CARDINAL;
  2464. BEGIN
  2465. IF (tform[a] # FProc) OR (tform[b] # FProc) THEN RETURN FALSE END;
  2466. IF NOT SameType(tref[a], tref[b]) THEN RETURN FALSE END;
  2467. n := procn[a];
  2468. IF n # procn[b] THEN RETURN FALSE END;
  2469. i := 0;
  2470. WHILE i < n DO
  2471. IF procvis[procstart[a] + i] # procvis[procstart[b] + i] THEN
  2472. RETURN FALSE
  2473. END;
  2474. IF NOT ParamTypesOk(procp[procstart[a] + i],
  2475. procp[procstart[b] + i]) THEN
  2476. RETURN FALSE
  2477. END;
  2478. INC(i)
  2479. END;
  2480. RETURN TRUE
  2481. END ProcTypesOk;
  2482. PROCEDURE Assignable (src, dst: TypeIndex): BOOLEAN;
  2483. VAR rs, rd: TypeIndex;
  2484. BEGIN
  2485. IF (src = InvalidType) OR (dst = InvalidType) THEN RETURN TRUE END;
  2486. IF IsFwdVar(src) OR IsFwdVar(dst) THEN RETURN TRUE END;
  2487. rs := Resolve(src); rd := Resolve(dst);
  2488. IF rs = rd THEN RETURN TRUE END;
  2489. IF (rs = InvalidType) OR (rd = InvalidType) THEN RETURN TRUE END;
  2490. IF (tform[rs] = FSet) AND (tform[rd] = FSet) THEN
  2491. RETURN SetBasesOk(tref[rs], tref[rd])
  2492. END;
  2493. IF (tform[rs] = FProc) AND (tform[rd] = FProc) THEN
  2494. RETURN ProcTypesOk(rs, rd)
  2495. END;
  2496. IF (ClassOf(src) = ClArray) AND (ClassOf(dst) = ClArray) THEN
  2497. (* a fixed 1-D array is compatible with an open formal of the
  2498. same element type (value or VAR) *)
  2499. IF IsOpenArray(dst) AND (ArrayDepth(src) = 1) THEN
  2500. RETURN SameType(ArrayElem(src), ArrayElem(dst))
  2501. END;
  2502. RETURN SameType(src, dst)
  2503. END;
  2504. IF (ClassOf(src) = ClStr) AND (ClassOf(dst) = ClArray) THEN
  2505. RETURN (ArrayDepth(dst) = 1)
  2506. AND (ClassOf(ArrayElem(dst)) = ClChar)
  2507. END;
  2508. IF (ClassOf(src) = ClUStr) AND (ClassOf(dst) = ClArray) THEN
  2509. (* a U"..." literal assigns/ passes to a 1-D ARRAY OF UCHAR by
  2510. content copy (count-clamped, UCHAR-0 terminated). *)
  2511. RETURN (ArrayDepth(dst) = 1)
  2512. AND (ClassOf(ArrayElem(dst)) = ClUChar)
  2513. END;
  2514. IF ClassOf(src) = ClNil THEN
  2515. RETURN ClassOf(dst) = ClPtr
  2516. END;
  2517. (* ADDRESS assigns to/from any pointer (check before the subclass
  2518. test, which returns early) *)
  2519. IF (Resolve(src) = dAddr) AND (ClassOf(dst) = ClPtr) THEN
  2520. RETURN TRUE
  2521. END;
  2522. IF (Resolve(dst) = dAddr) AND (ClassOf(src) = ClPtr) THEN
  2523. RETURN TRUE
  2524. END;
  2525. (* POINTER TO Derived assigns to POINTER TO Base (subtyping) *)
  2526. IF (ClassOf(src) = ClPtr) AND (ClassOf(dst) = ClPtr) THEN
  2527. RETURN IsSubclass(PtrBase(src), PtrBase(dst))
  2528. END;
  2529. IF (ClassOf(src) = ClInt) AND (ClassOf(dst) = ClInt) THEN
  2530. RETURN TRUE
  2531. END;
  2532. IF (ClassOf(src) = ClInt) AND (ClassOf(dst) = ClLong) THEN
  2533. RETURN TRUE
  2534. END;
  2535. IF (ClassOf(src) = ClInt) AND (ClassOf(dst) = ClReal) THEN
  2536. RETURN TRUE
  2537. END;
  2538. RETURN FALSE
  2539. END Assignable;
  2540. PROCEDURE ArithCheck (l, r: TypeIndex; divmod: BOOLEAN;
  2541. VAR res: TypeIndex): BOOLEAN;
  2542. BEGIN
  2543. res := InvalidType;
  2544. IF (l = InvalidType) OR (r = InvalidType) THEN RETURN TRUE END;
  2545. IF IsFwdVar(l) OR IsFwdVar(r) THEN res := dInt; RETURN TRUE END;
  2546. IF (IsLongFamily(l) AND IsLongFamily(r))
  2547. OR (IsLongFamily(l) AND IsIntFamily(r))
  2548. OR (IsIntFamily(l) AND IsLongFamily(r)) THEN
  2549. res := dLong; RETURN TRUE
  2550. END;
  2551. IF IsIntFamily(l) AND IsIntFamily(r) THEN
  2552. res := dInt; RETURN TRUE
  2553. END;
  2554. IF NOT divmod AND (ClassOf(l) = ClReal) AND (ClassOf(r) = ClReal) THEN
  2555. res := dReal; RETURN TRUE
  2556. END;
  2557. RETURN FALSE
  2558. END ArithCheck;
  2559. PROCEDURE BoolCheck (t: TypeIndex): BOOLEAN;
  2560. BEGIN
  2561. IF t = InvalidType THEN RETURN TRUE END;
  2562. RETURN ClassOf(t) = ClBool
  2563. END BoolCheck;
  2564. PROCEDURE IsStrType (t: TypeIndex): BOOLEAN;
  2565. (* A string literal, or a 1-D ARRAY OF CHAR. *)
  2566. VAR c: TypeIndex;
  2567. BEGIN
  2568. c := Resolve(t);
  2569. IF c = InvalidType THEN RETURN FALSE END;
  2570. IF ClassOf(c) = ClStr THEN RETURN TRUE END;
  2571. IF (ClassOf(c) = ClArray) AND (ArrayDepth(c) = 1) THEN
  2572. RETURN ClassOf(ArrayElem(c)) = ClChar
  2573. END;
  2574. RETURN FALSE
  2575. END IsStrType;
  2576. PROCEDURE UStrCompat (l, r: TypeIndex): BOOLEAN;
  2577. (* Both operands are UString literals (ClUStr): `+` concatenates. *)
  2578. BEGIN
  2579. RETURN (l # InvalidType) AND (r # InvalidType)
  2580. AND (ClassOf(l) = ClUStr) AND (ClassOf(r) = ClUStr)
  2581. END UStrCompat;
  2582. PROCEDURE IsUCharArray (t: TypeIndex): BOOLEAN;
  2583. (* A 1-D ARRAY OF UCHAR: a destination for U"..." content copy. *)
  2584. VAR c: TypeIndex;
  2585. BEGIN
  2586. c := Resolve(t);
  2587. IF c = InvalidType THEN RETURN FALSE END;
  2588. IF (ClassOf(c) = ClArray) AND (ArrayDepth(c) = 1) THEN
  2589. RETURN ClassOf(ArrayElem(c)) = ClUChar
  2590. END;
  2591. RETURN FALSE
  2592. END IsUCharArray;
  2593. PROCEDURE StrCompat (l, r: TypeIndex): BOOLEAN;
  2594. (* Both operands are string-compatible (content equality via the
  2595. shim); used for `=`/`#` only. *)
  2596. BEGIN
  2597. RETURN IsStrType(l) AND IsStrType(r)
  2598. END StrCompat;
  2599. PROCEDURE EqCheck (l, r: TypeIndex): BOOLEAN;
  2600. VAR rl, rr: TypeIndex;
  2601. BEGIN
  2602. IF IsFwdVar(l) OR IsFwdVar(r) THEN RETURN TRUE END;
  2603. IF (l = InvalidType) OR (r = InvalidType) THEN RETURN TRUE END;
  2604. IF ClassOf(l) = ClNil THEN
  2605. RETURN (ClassOf(r) = ClNil) OR (ClassOf(r) = ClPtr)
  2606. END;
  2607. IF ClassOf(r) = ClNil THEN
  2608. RETURN (ClassOf(l) = ClNil) OR (ClassOf(l) = ClPtr)
  2609. END;
  2610. IF SameType(l, r) THEN
  2611. (* Whole-array, string, record and class equality are not
  2612. built-in (213); compare member-wise instead. *)
  2613. IF (ClassOf(l) = ClArray) OR (ClassOf(l) = ClStr)
  2614. OR (ClassOf(l) = ClRecord) OR (ClassOf(l) = ClClass) THEN
  2615. IF StrCompat(l, r) THEN RETURN TRUE END; (* string content *)
  2616. RETURN FALSE
  2617. END;
  2618. RETURN TRUE
  2619. END;
  2620. IF StrCompat(l, r) THEN RETURN TRUE END;
  2621. IF IsIntFamily(l) AND IsIntFamily(r) THEN RETURN TRUE END;
  2622. IF (ClassOf(l) = ClLong) AND (ClassOf(r) = ClLong) THEN
  2623. RETURN TRUE
  2624. END;
  2625. IF (ClassOf(l) = ClLong) AND IsIntFamily(r) THEN RETURN TRUE END;
  2626. IF IsIntFamily(l) AND (ClassOf(r) = ClLong) THEN RETURN TRUE END;
  2627. IF (ClassOf(l) = ClReal) AND (ClassOf(r) = ClReal) THEN
  2628. RETURN TRUE
  2629. END;
  2630. IF (ClassOf(l) = ClChar) AND (ClassOf(r) = ClChar) THEN
  2631. RETURN TRUE
  2632. END;
  2633. IF (ClassOf(l) = ClUChar) AND (ClassOf(r) = ClUChar) THEN
  2634. RETURN TRUE
  2635. END;
  2636. IF (ClassOf(l) = ClBool) AND (ClassOf(r) = ClBool) THEN
  2637. RETURN TRUE
  2638. END;
  2639. rl := Resolve(l); rr := Resolve(r);
  2640. IF (rl = InvalidType) OR (rr = InvalidType) THEN RETURN TRUE END;
  2641. IF (tform[rl] = FSet) AND (tform[rr] = FSet) THEN
  2642. RETURN SetBasesOk(tref[rl], tref[rr])
  2643. END;
  2644. RETURN FALSE
  2645. END EqCheck;
  2646. PROCEDURE OrdCheck (l, r: TypeIndex): BOOLEAN;
  2647. BEGIN
  2648. IF IsFwdVar(l) OR IsFwdVar(r) THEN RETURN TRUE END;
  2649. IF (l = InvalidType) OR (r = InvalidType) THEN RETURN TRUE END;
  2650. IF IsIntFamily(l) AND IsIntFamily(r) THEN RETURN TRUE END;
  2651. IF (ClassOf(l) = ClLong) AND (ClassOf(r) = ClLong) THEN
  2652. RETURN TRUE
  2653. END;
  2654. IF (ClassOf(l) = ClLong) AND IsIntFamily(r) THEN RETURN TRUE END;
  2655. IF IsIntFamily(l) AND (ClassOf(r) = ClLong) THEN RETURN TRUE END;
  2656. IF (ClassOf(l) = ClReal) AND (ClassOf(r) = ClReal) THEN
  2657. RETURN TRUE
  2658. END;
  2659. IF (ClassOf(l) = ClChar) AND (ClassOf(r) = ClChar) THEN
  2660. RETURN TRUE
  2661. END;
  2662. IF (ClassOf(l) = ClUChar) AND (ClassOf(r) = ClUChar) THEN
  2663. RETURN TRUE
  2664. END;
  2665. IF (ClassOf(l) = ClEnum) AND SameType(l, r) THEN RETURN TRUE END;
  2666. RETURN FALSE
  2667. END OrdCheck;
  2668. PROCEDURE SetElemClassOk (c: INTEGER): BOOLEAN;
  2669. (* TRUE for an element class acceptable in a set constructor. *)
  2670. BEGIN
  2671. RETURN (c = ClInt) OR (c = ClChar) OR (c = ClBool)
  2672. OR (c = ClEnum) OR (c = ClUChar)
  2673. END SetElemClassOk;
  2674. PROCEDURE InCheck (l, set: TypeIndex): BOOLEAN;
  2675. VAR rs, b: TypeIndex;
  2676. BEGIN
  2677. IF (l = InvalidType) OR (set = InvalidType) THEN RETURN TRUE END;
  2678. rs := Resolve(set);
  2679. IF (rs = InvalidType) OR (tform[rs] # FSet) THEN RETURN FALSE END;
  2680. b := tref[rs];
  2681. IF SameType(l, b) THEN RETURN TRUE END;
  2682. IF IsIntFamily(l) AND IsIntFamily(b) THEN RETURN TRUE END;
  2683. IF (ClassOf(l) = ClChar) AND (ClassOf(b) = ClChar) THEN
  2684. RETURN TRUE
  2685. END;
  2686. (* lenient: small int/char/bool/enum tested against suitable sets;
  2687. the span trap decides out-of-range at runtime *)
  2688. IF ((ClassOf(l) = ClInt) OR (ClassOf(l) = ClChar)
  2689. OR (ClassOf(l) = ClBool) OR (ClassOf(l) = ClEnum))
  2690. AND (SetWords(set) > 0) THEN
  2691. RETURN TRUE
  2692. END;
  2693. RETURN FALSE
  2694. END InCheck;
  2695. PROCEDURE RelCheck (l, r: TypeIndex; op: INTEGER): BOOLEAN;
  2696. BEGIN
  2697. IF (l = InvalidType) OR (r = InvalidType) THEN RETURN TRUE END;
  2698. IF op = OpIn THEN RETURN InCheck(l, r) END;
  2699. IF (op = OpEq) OR (op = OpNeq1) OR (op = OpNeq2) THEN
  2700. RETURN EqCheck(l, r)
  2701. END;
  2702. RETURN OrdCheck(l, r)
  2703. END RelCheck;
  2704. (* ---------------- init ---------------- *)
  2705. PROCEDURE Predef (name: ARRAY OF CHAR; kind: INTEGER; t: TypeIndex);
  2706. BEGIN
  2707. IF Enter(name, kind) THEN SetSymType(name, t) END
  2708. END Predef;
  2709. PROCEDURE AddFormal (pr: SymPtr; t: TypeIndex; isVar: BOOLEAN);
  2710. (* Appends a formal-position node to procedure pr's plink chain.
  2711. These formals are not in any scope: they exist only to give the
  2712. external builtin a signature the caller checks against. *)
  2713. VAR p, q: SymPtr;
  2714. BEGIN
  2715. IF pr = NIL THEN RETURN END;
  2716. NEW(p);
  2717. p^.name[0] := CHR(0);
  2718. p^.sym[0] := CHR(0);
  2719. p^.mod[0] := CHR(0);
  2720. p^.kind := KindParam;
  2721. p^.typ := t;
  2722. p^.scope := NIL;
  2723. p^.left := NIL; p^.right := NIL;
  2724. p^.rslt := InvalidType;
  2725. p^.plink := NIL;
  2726. p^.isVar := isVar;
  2727. p^.fwd := FALSE; p^.virt := FALSE;
  2728. p^.fdep := 0;
  2729. p^.snapRes := InvalidType;
  2730. p^.nSnap := 0;
  2731. p^.fsnap := FALSE;
  2732. p^.vslot := -1;
  2733. p^.hasBody := FALSE;
  2734. p^.ext := FALSE; p^.varargs := FALSE;
  2735. p^.link[0] := CHR(0);
  2736. p^.uid := 0;
  2737. p^.val[0] := CHR(0);
  2738. IF pr^.plink = NIL THEN
  2739. pr^.plink := p
  2740. ELSE
  2741. q := pr^.plink;
  2742. WHILE q^.plink # NIL DO q := q^.plink END;
  2743. q^.plink := p
  2744. END
  2745. END AddFormal;
  2746. PROCEDURE PredefCProc (name, cname: ARRAY OF CHAR; res: TypeIndex): SymPtr;
  2747. (* Defines an external C procedure in the global scope with an
  2748. explicit (not varargs) signature; formals are added with AddFormal. *)
  2749. VAR node: SymPtr;
  2750. BEGIN
  2751. node := RawEnter(name, KindProc);
  2752. IF node = NIL THEN RETURN NIL END;
  2753. node^.rslt := res;
  2754. node^.plink := NIL;
  2755. node^.isVar := FALSE;
  2756. node^.fwd := FALSE;
  2757. node^.virt := FALSE;
  2758. node^.ext := TRUE;
  2759. node^.varargs := FALSE;
  2760. node^.fsnap := FALSE;
  2761. Assign(node^.link, cname);
  2762. node^.uid := nextUid; INC(nextUid);
  2763. node^.fdep := 0;
  2764. node^.vslot := -1;
  2765. node^.hasBody := TRUE;
  2766. RETURN node
  2767. END PredefCProc;
  2768. PROCEDURE Init;
  2769. VAR pr: SymPtr;
  2770. BEGIN
  2771. scopeList := NIL; scopeTail := NIL;
  2772. fields := NIL; nFields := 0;
  2773. nPend := 0; nPendF := 0;
  2774. nTypes := 0; nProc := 0; nBounds := 0; nextUid := 0;
  2775. vtTop := 0; nVtl := 0; nImpl := 0;
  2776. curProc := NIL; curPTail := NIL;
  2777. nMods := 0; curMod := -1; curUnit := -1; haveProg := FALSE;
  2778. curScope := NewScope(NIL, 0);
  2779. globScope := curScope;
  2780. dInt := NewDesc(FInt, InvalidType);
  2781. dCard := NewDesc(FInt, InvalidType);
  2782. dReal := NewDesc(FReal, InvalidType);
  2783. dChar := NewDesc(FChar, InvalidType);
  2784. dBool := NewDesc(FBool, InvalidType);
  2785. dNil := NewDesc(FNil, InvalidType);
  2786. dAddr := NewDesc(FPtr, InvalidType); (* ADDRESS: pointer-sized *)
  2787. dLong := NewDesc(FLong, InvalidType); (* LONGINT/LONGCARD: 64-bit *)
  2788. dUChar := NewDesc(FUChar, InvalidType);
  2789. dBitset := NewSet(NewSubR(0, 15)); (* BITSET *)
  2790. dProc := NewProcType(InvalidType); (* PROC: no params, no result *)
  2791. Predef("INTEGER", KindPredef, dInt);
  2792. Predef("CARDINAL", KindPredef, dCard);
  2793. Predef("SHORTINT", KindPredef, dInt);
  2794. Predef("LONGINT", KindPredef, dLong);
  2795. Predef("SHORTCARD", KindPredef, dCard);
  2796. Predef("REAL", KindPredef, dReal);
  2797. Predef("LONGREAL", KindPredef, dReal);
  2798. Predef("CHAR", KindPredef, dChar);
  2799. Predef("BOOLEAN", KindPredef, dBool);
  2800. Predef("TRUE", KindConst, dBool);
  2801. Predef("FALSE", KindConst, dBool);
  2802. Predef("ADDRESS", KindPredef, dAddr);
  2803. Predef("UCHAR", KindPredef, dUChar);
  2804. Predef("BITSET", KindPredef, dBitset);
  2805. (* SYSTEM storage types (PIM/gm2): mapped onto V3's integer family
  2806. (BYTE/WORD -> the 32-bit ordinal, LONGWORD -> LONGINT, the
  2807. address forms -> ADDRESS) so `FROM SYSTEM IMPORT BYTE;` and
  2808. `ARRAY OF BYTE` resolve. *)
  2809. Predef("BYTE", KindPredef, dCard);
  2810. Predef("SBYTE", KindPredef, dInt);
  2811. Predef("WORD", KindPredef, dCard);
  2812. Predef("SWORD", KindPredef, dInt);
  2813. Predef("LONGWORD", KindPredef, dLong);
  2814. Predef("SHORTADDR", KindPredef, dAddr);
  2815. Predef("LONGADDR", KindPredef, dAddr);
  2816. Predef("PROC", KindPredef, dAddr);
  2817. Predef("LOC", KindPredef, dAddr);
  2818. (* gm2 sized/scalar names (mapped onto V3's families) *)
  2819. Predef("LONGCARD", KindPredef, dLong);
  2820. Predef("SHORTREAL", KindPredef, dReal);
  2821. Predef("INTEGER8", KindPredef, dInt);
  2822. Predef("INTEGER16", KindPredef, dInt);
  2823. Predef("INTEGER32", KindPredef, dInt);
  2824. Predef("INTEGER64", KindPredef, dLong);
  2825. Predef("CARDINAL8", KindPredef, dCard);
  2826. Predef("CARDINAL16", KindPredef, dCard);
  2827. Predef("CARDINAL32", KindPredef, dCard);
  2828. Predef("CARDINAL64", KindPredef, dLong);
  2829. (* PIM/SYSTEM coroutines: PROCESS is pointer-sized; the three
  2830. builtins bind to C helpers in the runtime shim. Signatures:
  2831. NEWPROCESS(P: PROC; A: ADDRESS; n: CARDINAL; VAR c: PROCESS);
  2832. TRANSFER(VAR a, b: PROCESS);
  2833. IOTRANSFER(VAR a, b: PROCESS; interruptNo: CARDINAL). *)
  2834. Predef("PROCESS", KindPredef, dAddr);
  2835. pr := PredefCProc("NEWPROCESS", "m2_newprocess", InvalidType);
  2836. AddFormal(pr, dProc, FALSE);
  2837. AddFormal(pr, dAddr, FALSE);
  2838. AddFormal(pr, dCard, FALSE);
  2839. AddFormal(pr, dAddr, TRUE);
  2840. pr := PredefCProc("TRANSFER", "m2_transfer", InvalidType);
  2841. AddFormal(pr, dAddr, TRUE);
  2842. AddFormal(pr, dAddr, TRUE);
  2843. pr := PredefCProc("IOTRANSFER", "m2_iotransfer", InvalidType);
  2844. AddFormal(pr, dAddr, TRUE);
  2845. AddFormal(pr, dAddr, TRUE);
  2846. AddFormal(pr, dCard, FALSE);
  2847. Predef("NIL", KindConst, dNil)
  2848. END Init;
  2849. (* ---------------- listing ---------------- *)
  2850. PROCEDURE WriteKind (kind: INTEGER);
  2851. BEGIN
  2852. CASE kind OF
  2853. KindConst : FileIO.WriteString(FileIO.StdOut, "CONST")
  2854. | KindType : FileIO.WriteString(FileIO.StdOut, "TYPE")
  2855. | KindVar : FileIO.WriteString(FileIO.StdOut, "VAR")
  2856. | KindImport : FileIO.WriteString(FileIO.StdOut, "IMPORT")
  2857. | KindModule : FileIO.WriteString(FileIO.StdOut, "MODULE")
  2858. | KindPredef : FileIO.WriteString(FileIO.StdOut, "PREDEF")
  2859. | KindField : FileIO.WriteString(FileIO.StdOut, "FIELD")
  2860. | KindProc : FileIO.WriteString(FileIO.StdOut, "PROC")
  2861. | KindParam : FileIO.WriteString(FileIO.StdOut, "PARAM")
  2862. ELSE FileIO.WriteString(FileIO.StdOut, "???")
  2863. END
  2864. END WriteKind;
  2865. PROCEDURE WriteNode (node: SymPtr);
  2866. BEGIN
  2867. IF node = NIL THEN RETURN END;
  2868. WriteNode(node^.left);
  2869. FileIO.WriteString(FileIO.StdOut, " ");
  2870. FileIO.WriteString(FileIO.StdOut, node^.name);
  2871. FileIO.WriteString(FileIO.StdOut, " : ");
  2872. WriteKind(node^.kind);
  2873. FileIO.WriteString(FileIO.StdOut, " #");
  2874. FileIO.WriteInt(FileIO.StdOut, node^.typ, 1);
  2875. FileIO.WriteLn(FileIO.StdOut);
  2876. WriteNode(node^.right)
  2877. END WriteNode;
  2878. PROCEDURE PrintTable;
  2879. VAR s: ScopePtr;
  2880. BEGIN
  2881. FileIO.WriteLn(FileIO.StdOut);
  2882. FileIO.WriteString(FileIO.StdOut, "--- Symbol table ---");
  2883. FileIO.WriteLn(FileIO.StdOut);
  2884. s := scopeList;
  2885. WHILE s # NIL DO
  2886. WriteNode(s^.root);
  2887. s := s^.link
  2888. END
  2889. END PrintTable;
  2890. BEGIN
  2891. Init
  2892. END SymTab.