FoxBasic.Mod 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345
  1. MODULE FoxBasic; (** AUTHOR "fof"; PURPOSE "Oberon Compiler: basic helpers: strings, lists, hash tables, graphs, indented writer"; **)
  2. (* (c) fof ETH Zürich, 2009 *)
  3. IMPORT KernelLog, StringPool, Strings, Streams, Diagnostics, Files, SYSTEM, ObjectFile, Modules, D:= Debugging;
  4. CONST
  5. (* error numbers *)
  6. (* first 255 tokens reserved for expected symbol error message *)
  7. UndeclaredIdentifier* = 256;
  8. MultiplyDefinedIdentifier* = 257;
  9. NumberIllegalCharacter* = 258;
  10. StringIllegalCharacter* = 259;
  11. NoMatchProcedureName* = 260;
  12. CommentNotClosed* = 261;
  13. IllegalCharacterValue* = 262;
  14. ValueStartIncorrectSymbol* = 263;
  15. IllegalyMarkedIdentifier* = 264;
  16. IdentifierNoType* = 265;
  17. IdentifierNoRecordType* = 266;
  18. IdentifierNoObjectType* = 267;
  19. ImportNotAvailable* = 268;
  20. RecursiveTypeDeclaration* = 269;
  21. NumberTooLarge* = 270;
  22. IdentifierTooLong* = 271;
  23. StringTooLong* = 272;
  24. InitListSize = 4;
  25. InitErrMsgSize = 300; (* initial size of array of error messages *)
  26. (* value of constant NIL *)
  27. nilval* = 0;
  28. ExportedUnicodeSupport* = FALSE;
  29. (* target machine minimum values of basic types expressed in host machine format: *)
  30. MinSInt* = -80H;
  31. MinInt* = -8000H;
  32. MinLInt* = -80000000H; (* i386: -2147483648*)
  33. (* target machine maximum values of basic types expressed in host machine format: *)
  34. MaxSInt* = 7FH;
  35. MaxInt* = 7FFFH;
  36. MaxLInt* = 7FFFFFFFH; (* i386: 2147483647*)
  37. MaxSet* = 31; (* must be >= 15, else the bootstraped compiler cannot run (IN-tests) *)
  38. invalidString*=-1;
  39. InvalidCode*=Diagnostics.Invalid;
  40. TYPE
  41. (*
  42. String* = POINTER TO ARRAY OF CHAR;
  43. *)
  44. String* = StringPool.Index;
  45. SegmentedName*= ObjectFile.SegmentedName;
  46. FileName*= Files.FileName;
  47. SectionName*= ARRAY 256 OF CHAR;
  48. MessageString*= ARRAY 256 OF CHAR;
  49. ObjectArray = POINTER TO ARRAY OF ANY;
  50. IntegerArray = POINTER TO ARRAY OF LONGINT;
  51. ErrorMsgs = POINTER TO ARRAY OF StringPool.Index;
  52. ComparisonFunction = PROCEDURE {DELEGATE} (object1, object2: ANY): BOOLEAN;
  53. Position*= RECORD
  54. start*, end*, line*, linepos*: LONGINT;
  55. reader*: Streams.Reader;
  56. END;
  57. ErrorCode*=LONGINT;
  58. List* = OBJECT (* by Luc Bläser *)
  59. VAR
  60. list: ObjectArray;
  61. count-: LONGINT;
  62. multipleAllowed*: BOOLEAN;
  63. nilAllowed*: BOOLEAN;
  64. PROCEDURE & InitList*(initialSize: LONGINT) ;
  65. BEGIN
  66. IF initialSize <= 0 THEN initialSize := 8 END;
  67. INC( lists ); NEW( list, initialSize ); count := 0; multipleAllowed := FALSE; nilAllowed := FALSE
  68. END InitList;
  69. PROCEDURE Length*( ): LONGINT;
  70. BEGIN
  71. RETURN count
  72. END Length;
  73. PROCEDURE Grow;
  74. VAR old: ObjectArray; i: LONGINT;
  75. BEGIN
  76. INC( enlarged ); old := list; NEW( list, (LEN( list ) * 3+1) DIV 2 (* more optimal for first-fit memory allocators *) ) ;
  77. FOR i := 0 TO count - 1 DO list[i] := old[i] END
  78. END Grow;
  79. PROCEDURE Get*( i: LONGINT ): ANY;
  80. BEGIN
  81. IF (i < 0) OR (i >= count) THEN HALT( 101 ) END;
  82. RETURN list[i]
  83. END Get;
  84. PROCEDURE Set*(i: LONGINT; x: ANY);
  85. BEGIN
  86. IF (i < 0) OR (i >= count) THEN HALT( 101 ) END;
  87. list[i] := x;
  88. END Set;
  89. PROCEDURE Add*( x: ANY );
  90. BEGIN
  91. IF ~nilAllowed THEN ASSERT( x # NIL ) END;
  92. IF ~multipleAllowed THEN ASSERT( ~debug OR ~Contains( x ) ) END; (* already contained *)
  93. IF count = LEN( list ) THEN Grow END;
  94. list[count] := x; INC( count )
  95. END Add;
  96. PROCEDURE Prepend*(x: ANY);
  97. VAR i: LONGINT;
  98. BEGIN
  99. IF ~nilAllowed THEN ASSERT( x # NIL ) END;
  100. IF ~multipleAllowed THEN ASSERT( debug OR ~Contains( x ) ) END; (* already contained *)
  101. IF count = LEN( list ) THEN Grow END;
  102. FOR i := count-1 TO 0 BY - 1 DO
  103. list[i+1] := list[i];
  104. END;
  105. list[0] := x; INC(count);
  106. END Prepend;
  107. PROCEDURE Append*(x: List);
  108. VAR i: LONGINT;
  109. BEGIN
  110. FOR i := 0 TO x.Length() - 1 DO
  111. IF multipleAllowed OR (~debug OR ~Contains(x.Get(i))) THEN
  112. Add(x.Get(i));
  113. END;
  114. END;
  115. END Append;
  116. PROCEDURE Remove*( x: ANY );
  117. VAR i: LONGINT;
  118. BEGIN
  119. i := 0;
  120. WHILE (i < count) & (list[i] # x) DO INC( i ) END;
  121. IF i < count THEN
  122. WHILE (i < count - 1) DO list[i] := list[i + 1]; INC( i ) END;
  123. DEC( count ); list[count] := NIL
  124. END
  125. END Remove;
  126. PROCEDURE RemoveByIndex*( i: LONGINT );
  127. BEGIN
  128. IF i < count THEN
  129. WHILE (i < count - 1) DO list[i] := list[i + 1]; INC( i ) END;
  130. DEC( count ); list[count] := NIL
  131. END
  132. END RemoveByIndex;
  133. PROCEDURE Insert*( i: LONGINT; x: ANY );
  134. VAR j: LONGINT;
  135. BEGIN
  136. IF ~nilAllowed THEN ASSERT( x # NIL ) END;
  137. IF ~multipleAllowed THEN ASSERT( ~debug OR ~Contains( x ) ) END; (* already contained *)
  138. IF count = LEN( list ) THEN Grow END; INC( count );
  139. j := count - 2;
  140. WHILE (j >= i) DO list[j+1] := list[j]; DEC( j ) END;
  141. list[i] := x;
  142. END Insert;
  143. PROCEDURE Replace*( x, y: ANY );
  144. VAR i: LONGINT;
  145. BEGIN
  146. IF ~nilAllowed THEN ASSERT( x # NIL ); ASSERT( y # NIL ) END;
  147. i := IndexOf( x );
  148. IF i >= 0 THEN list[i] := y END
  149. END Replace;
  150. PROCEDURE ReplaceByIndex*( i: LONGINT; x: ANY );
  151. BEGIN
  152. IF ~nilAllowed THEN ASSERT( x # NIL ) END;
  153. IF (i >= 0) & (i < count) THEN list[i] := x
  154. ELSE HALT( 101 ) (* out of boundaries *)
  155. END
  156. END ReplaceByIndex;
  157. (** If the object is not present, -1 is returned *)
  158. PROCEDURE IndexOf*( x: ANY ): LONGINT;
  159. VAR i: LONGINT;
  160. BEGIN
  161. i := 0;
  162. WHILE i < count DO
  163. IF list[i] = x THEN RETURN i END;
  164. INC( i )
  165. END;
  166. RETURN -1
  167. END IndexOf;
  168. PROCEDURE Contains*( x: ANY ): BOOLEAN;
  169. BEGIN
  170. RETURN IndexOf( x ) # -1
  171. END Contains;
  172. PROCEDURE Clear*;
  173. VAR i: LONGINT;
  174. BEGIN
  175. FOR i := 0 TO count - 1 DO list[i] := NIL END;
  176. count := 0
  177. END Clear;
  178. PROCEDURE GrowAndSet*(i: LONGINT; x: ANY);
  179. BEGIN
  180. IF (i<0) THEN HALT(101) END;
  181. WHILE i>=LEN(list) DO Grow END;
  182. list[i] := x;
  183. INC(i); IF count < i THEN count := i END;
  184. END GrowAndSet;
  185. PROCEDURE Sort*(comparisonFunction: ComparisonFunction);
  186. BEGIN
  187. IF count > 0 THEN
  188. QuickSort(comparisonFunction, 0, count - 1)
  189. END
  190. END Sort;
  191. PROCEDURE QuickSort(comparisonFunction: ComparisonFunction; lo, hi: LONGINT);
  192. VAR
  193. i, j: LONGINT;
  194. x, t: ANY;
  195. BEGIN
  196. i := lo; j := hi;
  197. x := list[(lo + hi) DIV 2];
  198. WHILE i <= j DO
  199. WHILE comparisonFunction(list[i], x) DO INC(i) END;
  200. WHILE comparisonFunction(x, list[j]) DO DEC(j) END;
  201. IF i <= j THEN
  202. (*IF (i < j) & comparisonFunction(list[j], list[i]) THEN*)
  203. t := list[i]; list[i] := list[j]; list[j] := t; (* swap i and j *)
  204. (*END;*)
  205. INC(i); DEC(j)
  206. END
  207. END;
  208. IF lo < j THEN QuickSort(comparisonFunction, lo, j) END;
  209. IF i < hi THEN QuickSort(comparisonFunction, i, hi) END
  210. END QuickSort;
  211. END List;
  212. IntegerList* = OBJECT
  213. VAR list: IntegerArray;
  214. count-: LONGINT;
  215. PROCEDURE & InitList*(initialSize: LONGINT) ;
  216. BEGIN
  217. INC( lists ); NEW( list, initialSize ); count := 0;
  218. END InitList;
  219. PROCEDURE Length*( ): LONGINT;
  220. BEGIN RETURN count END Length;
  221. PROCEDURE Grow;
  222. VAR old: IntegerArray; i: LONGINT;
  223. BEGIN
  224. INC( enlarged ); old := list; NEW( list, LEN( list ) * 4 );
  225. FOR i := 0 TO count - 1 DO list[i] := old[i] END
  226. END Grow;
  227. PROCEDURE Get*( i: LONGINT ): LONGINT;
  228. BEGIN
  229. IF (i < 0) OR (i >= count) THEN HALT( 101 ) END;
  230. RETURN list[i]
  231. END Get;
  232. PROCEDURE Set*(i: LONGINT; x: LONGINT);
  233. BEGIN
  234. IF (i < 0) OR (i >= count) THEN HALT( 101 ) END;
  235. list[i] := x;
  236. END Set;
  237. PROCEDURE Add*( x: LONGINT );
  238. BEGIN
  239. IF count = LEN( list ) THEN Grow END;
  240. list[count] := x; INC( count )
  241. END Add;
  242. PROCEDURE Prepend*(x: LONGINT);
  243. VAR i: LONGINT;
  244. BEGIN
  245. IF count = LEN( list ) THEN Grow END;
  246. FOR i := count-1 TO 0 BY - 1 DO
  247. list[i+1] := list[i];
  248. END;
  249. list[0] := x; INC(count);
  250. END Prepend;
  251. PROCEDURE Append*(x: IntegerList);
  252. VAR i: LONGINT;
  253. BEGIN
  254. FOR i := 0 TO x.Length() - 1 DO
  255. Add(x.Get(i));
  256. END;
  257. END Append;
  258. PROCEDURE Remove*( x: LONGINT );
  259. VAR i: LONGINT;
  260. BEGIN
  261. i := 0;
  262. WHILE (i < count) & (list[i] # x) DO INC( i ) END;
  263. IF i < count THEN
  264. WHILE (i < count - 1) DO list[i] := list[i + 1]; INC( i ) END;
  265. DEC( count );
  266. END
  267. END Remove;
  268. PROCEDURE RemoveByIndex*( i: LONGINT );
  269. BEGIN
  270. IF i < count THEN
  271. WHILE (i < count - 1) DO list[i] := list[i + 1]; INC( i ) END;
  272. DEC( count );
  273. END
  274. END RemoveByIndex;
  275. PROCEDURE Insert*( i,x: LONGINT);
  276. VAR j: LONGINT;
  277. BEGIN
  278. ASSERT((i >= 0) & (i < count));
  279. IF count = LEN( list ) THEN Grow END; INC( count );
  280. j := count - 2;
  281. WHILE (j >= i) DO list[j+1] := list[j]; DEC( j ) END;
  282. list[i] := x;
  283. END Insert;
  284. PROCEDURE Replace*( x, y: LONGINT );
  285. VAR i: LONGINT;
  286. BEGIN
  287. i := IndexOf( x );
  288. IF i >= 0 THEN list[i] := y END
  289. END Replace;
  290. PROCEDURE IndexOf*( x: LONGINT ): LONGINT;
  291. VAR i: LONGINT;
  292. BEGIN
  293. i := 0;
  294. WHILE i < count DO
  295. IF list[i] = x THEN RETURN i END;
  296. INC( i )
  297. END;
  298. RETURN -1
  299. END IndexOf;
  300. PROCEDURE Contains*( x: LONGINT ): BOOLEAN;
  301. BEGIN RETURN IndexOf( x ) # -1; END Contains;
  302. PROCEDURE Clear*;
  303. BEGIN count := 0 END Clear;
  304. END IntegerList;
  305. (* Supports get, add, contain, append in O(1) *)
  306. Bag* = OBJECT
  307. VAR
  308. count-: LONGINT;
  309. list: List;
  310. PROCEDURE & InitBag* ;
  311. BEGIN
  312. Clear();
  313. END InitBag;
  314. PROCEDURE Length*( ): LONGINT;
  315. BEGIN
  316. RETURN list.Length();
  317. END Length;
  318. PROCEDURE Get*( i: LONGINT ): ANY;
  319. BEGIN RETURN list.Get(i); END Get;
  320. PROCEDURE Add*( x: ANY );
  321. BEGIN
  322. ASSERT( x # NIL );
  323. IF ~Contains(x) THEN
  324. list.Add(x);
  325. END;
  326. END Add;
  327. PROCEDURE Append*(x: Bag);
  328. VAR i: LONGINT;
  329. BEGIN
  330. FOR i := 0 TO x.Length() - 1 DO
  331. IF ~Contains(x.Get(i)) THEN
  332. Add(x.Get(i));
  333. END;
  334. END;
  335. END Append;
  336. PROCEDURE Remove*( x: ANY );
  337. BEGIN
  338. list.Remove(x);
  339. END Remove;
  340. PROCEDURE Contains*( x: ANY ): BOOLEAN;
  341. BEGIN RETURN list.Contains(x); END Contains;
  342. PROCEDURE Clear*;
  343. BEGIN
  344. count := 0;
  345. NEW(list,InitListSize);
  346. list.multipleAllowed := TRUE; list.nilAllowed := TRUE;
  347. END Clear;
  348. END Bag;
  349. (* Supports get, add, contain, append in O(1) *)
  350. IntegerBag* = OBJECT
  351. VAR
  352. count-: LONGINT;
  353. list: IntegerList;
  354. PROCEDURE & InitBag* ;
  355. BEGIN
  356. Clear();
  357. END InitBag;
  358. PROCEDURE Length*( ): LONGINT;
  359. BEGIN
  360. RETURN list.Length();
  361. END Length;
  362. PROCEDURE Get*( i: LONGINT ):LONGINT;
  363. BEGIN RETURN list.Get(i); END Get;
  364. PROCEDURE Add*( x: LONGINT );
  365. BEGIN
  366. IF ~Contains(x) THEN
  367. list.Add(x);
  368. END;
  369. END Add;
  370. PROCEDURE Append*(x: IntegerBag);
  371. VAR i: LONGINT;
  372. BEGIN
  373. FOR i := 0 TO x.Length() - 1 DO
  374. IF ~Contains(x.Get(i)) THEN
  375. Add(x.Get(i));
  376. END;
  377. END;
  378. END Append;
  379. PROCEDURE Remove*(x: LONGINT );
  380. BEGIN
  381. list.Remove(x);
  382. END Remove;
  383. PROCEDURE Contains*( x: LONGINT ): BOOLEAN;
  384. BEGIN RETURN list.Contains(x); END Contains;
  385. PROCEDURE Clear*;
  386. BEGIN
  387. count := 0;
  388. NEW(list,InitListSize);
  389. END Clear;
  390. END IntegerBag;
  391. HashEntryAny = RECORD
  392. key, value: ANY;
  393. valueInt: LONGINT;
  394. END;
  395. HashEntryInt = RECORD
  396. key, valueInt: LONGINT;
  397. value: ANY;
  398. END;
  399. HashAnyArray = POINTER TO ARRAY OF HashEntryAny;
  400. HashIntArray = POINTER TO ARRAY OF HashEntryInt;
  401. HashTable* = OBJECT
  402. VAR
  403. table: HashAnyArray;
  404. size: LONGINT;
  405. used-: LONGINT;
  406. maxLoadFactor: REAL;
  407. (* Interface *)
  408. PROCEDURE & Init* (initialSize: LONGINT);
  409. BEGIN
  410. ASSERT(initialSize > 2);
  411. NEW(table, initialSize);
  412. size := initialSize;
  413. used := 0;
  414. maxLoadFactor := 0.75;
  415. END Init;
  416. PROCEDURE Put*(key, value: ANY);
  417. VAR hash: LONGINT;
  418. BEGIN
  419. ASSERT(used < size);
  420. ASSERT(key # NIL);
  421. hash := HashValue(key);
  422. IF table[hash].key = NIL THEN
  423. INC(used, 1);
  424. ELSE
  425. ASSERT(table[hash].key = key);
  426. END;
  427. table[hash].key := key;
  428. table[hash].value := value;
  429. IF (used / size) > maxLoadFactor THEN Grow END;
  430. END Put;
  431. PROCEDURE Get*(key: ANY):ANY;
  432. BEGIN
  433. RETURN table[HashValue(key)].value;
  434. END Get;
  435. PROCEDURE Has*(key: ANY):BOOLEAN;
  436. BEGIN
  437. RETURN table[HashValue(key)].key = key;
  438. END Has;
  439. PROCEDURE Length*():LONGINT;
  440. BEGIN RETURN used; END Length;
  441. PROCEDURE Clear*;
  442. VAR i: LONGINT;
  443. BEGIN FOR i := 0 TO size - 1 DO table[i].key := NIL; table[i].value := NIL; table[i].valueInt := 0 END; END Clear;
  444. (* Interface for integer values *)
  445. PROCEDURE PutInt*(key: ANY; value: LONGINT);
  446. VAR hash: LONGINT;
  447. BEGIN
  448. ASSERT(used < size);
  449. hash := HashValue(key);
  450. IF table[hash].key = NIL THEN
  451. INC(used, 1);
  452. END;
  453. table[hash].key := key;
  454. table[hash].valueInt := value;
  455. IF (used / size) > maxLoadFactor THEN Grow END;
  456. END PutInt;
  457. PROCEDURE GetInt*(key: ANY):LONGINT;
  458. BEGIN RETURN table[HashValue(key)].valueInt; END GetInt;
  459. (* Internals *)
  460. (* only correctly working, if NIL key cannot be entered *)
  461. PROCEDURE HashValue(key: ANY):LONGINT;
  462. VAR value, h1, h2, i: LONGINT;
  463. BEGIN
  464. value := SYSTEM.VAL(LONGINT, key) DIV SIZEOF(ADDRESS);
  465. i := 0;
  466. h1 := value MOD size;
  467. h2 := 1; (* Linear probing *)
  468. REPEAT
  469. value := (h1 + i*h2) MOD size;
  470. INC(i);
  471. UNTIL((table[value].key = NIL) OR (table[value].key = key) OR (i > size));
  472. ASSERT((table[value].key = NIL) & (table[value].value = NIL) OR (table[value].key = key));
  473. RETURN value;
  474. END HashValue;
  475. PROCEDURE Grow;
  476. VAR oldTable: HashAnyArray; oldSize, i: LONGINT; key: ANY;
  477. BEGIN
  478. oldSize := size;
  479. oldTable := table;
  480. Init(size*2);
  481. FOR i := 0 TO oldSize-1 DO
  482. key := oldTable[i].key;
  483. IF key # NIL THEN
  484. IF oldTable[i].value # NIL THEN
  485. Put(key, oldTable[i].value);
  486. ELSE
  487. PutInt(key, oldTable[i].valueInt);
  488. END;
  489. END;
  490. END;
  491. END Grow;
  492. END HashTable;
  493. IntIterator*= OBJECT
  494. VAR
  495. table: HashIntArray;
  496. count : LONGINT;
  497. PROCEDURE & Init(t: HashIntArray);
  498. BEGIN
  499. table := t;
  500. count := -1;
  501. END Init;
  502. PROCEDURE GetNext*(VAR key: LONGINT; VAR value: ANY): BOOLEAN;
  503. BEGIN
  504. REPEAT
  505. INC(count);
  506. UNTIL (count = LEN(table)) OR (table[count].value # NIL);
  507. IF count = LEN(table) THEN
  508. RETURN FALSE
  509. END;
  510. key := table[count].key;
  511. value := table[count].value;
  512. RETURN TRUE;
  513. END GetNext;
  514. END IntIterator;
  515. HashTableInt* = OBJECT
  516. VAR
  517. table: HashIntArray;
  518. size: LONGINT;
  519. used-: LONGINT;
  520. maxLoadFactor: REAL;
  521. (* Interface *)
  522. PROCEDURE & Init* (initialSize: LONGINT);
  523. BEGIN
  524. ASSERT(initialSize > 2);
  525. NEW(table, initialSize);
  526. size := initialSize;
  527. used := 0;
  528. maxLoadFactor := 0.75;
  529. END Init;
  530. PROCEDURE Put*(key: LONGINT; value: ANY);
  531. VAR hash: LONGINT;
  532. BEGIN
  533. ASSERT(key # 0);
  534. ASSERT(used < size);
  535. hash := HashValue(key);
  536. IF table[hash].key = 0 THEN
  537. INC(used, 1);
  538. END;
  539. table[hash].key := key;
  540. table[hash].value := value;
  541. IF (used / size) > maxLoadFactor THEN Grow END;
  542. END Put;
  543. PROCEDURE Get*(key: LONGINT):ANY;
  544. BEGIN
  545. RETURN table[HashValue(key)].value;
  546. END Get;
  547. PROCEDURE Has*(key: LONGINT):BOOLEAN;
  548. BEGIN
  549. RETURN table[HashValue(key)].key = key;
  550. END Has;
  551. PROCEDURE Length*():LONGINT;
  552. BEGIN RETURN used; END Length;
  553. PROCEDURE Clear*;
  554. VAR i: LONGINT;
  555. BEGIN FOR i := 0 TO size - 1 DO table[i].key := 0; END; END Clear;
  556. (* Interface for integer values *)
  557. PROCEDURE PutInt*(key, value: LONGINT);
  558. VAR hash: LONGINT;
  559. BEGIN
  560. (*ASSERT(key # 0);*)
  561. ASSERT(used < size);
  562. hash := HashValue(key);
  563. IF table[hash].key = 0 THEN
  564. INC(used, 1);
  565. END;
  566. table[hash].key := key;
  567. table[hash].valueInt := value;
  568. IF (used / size) > maxLoadFactor THEN Grow END;
  569. END PutInt;
  570. PROCEDURE GetInt*(key: LONGINT):LONGINT;
  571. BEGIN RETURN table[HashValue(key)].valueInt; END GetInt;
  572. (* Internals *)
  573. PROCEDURE HashValue(key: LONGINT):LONGINT;
  574. VAR value, h1, h2, i: LONGINT;
  575. BEGIN
  576. i := 0;
  577. value := key;
  578. h1 := key MOD size;
  579. h2 := 1; (* Linear probing *)
  580. REPEAT
  581. value := (h1 + i*h2) MOD size;
  582. INC(i);
  583. UNTIL((table[value].key = 0) OR (table[value].key = key) OR (i > size));
  584. ASSERT((table[value].key = 0) OR (table[value].key = key));
  585. RETURN value;
  586. END HashValue;
  587. PROCEDURE Grow;
  588. VAR oldTable: HashIntArray; oldSize, i, key: LONGINT;
  589. BEGIN
  590. oldSize := size;
  591. oldTable := table;
  592. Init(size*2);
  593. FOR i := 0 TO oldSize-1 DO
  594. key := oldTable[i].key;
  595. IF key # 0 THEN
  596. IF oldTable[i].value # NIL THEN
  597. Put(key, oldTable[i].value);
  598. ELSE
  599. PutInt(key, oldTable[i].valueInt);
  600. END;
  601. END;
  602. END;
  603. END Grow;
  604. PROCEDURE GetIterator*(): IntIterator;
  605. VAR iterator: IntIterator;
  606. BEGIN
  607. NEW(iterator, table);
  608. RETURN iterator;
  609. END GetIterator;
  610. END HashTableInt;
  611. HashEntrySegmentedName = RECORD
  612. key: ObjectFile.SegmentedName; (* key[0]= MIN(LONGINT) <=> empty *)
  613. value: ANY;
  614. END;
  615. HashSegmentedNameArray = POINTER TO ARRAY OF HashEntrySegmentedName;
  616. HashTableSegmentedName* = OBJECT
  617. VAR
  618. table: HashSegmentedNameArray;
  619. size: LONGINT;
  620. used-: LONGINT;
  621. maxLoadFactor: REAL;
  622. (* Interface *)
  623. PROCEDURE & Init* (initialSize: LONGINT);
  624. BEGIN
  625. ASSERT(initialSize > 2);
  626. NEW(table, initialSize);
  627. size := initialSize;
  628. used := 0;
  629. maxLoadFactor := 0.75;
  630. Clear;
  631. END Init;
  632. PROCEDURE Put*(CONST key: SegmentedName; value: ANY);
  633. VAR hash: LONGINT;
  634. BEGIN
  635. ASSERT(used < size);
  636. hash := HashValue(key);
  637. IF table[hash].key[0] < 0 THEN
  638. INC(used, 1);
  639. END;
  640. table[hash].key := key;
  641. table[hash].value := value;
  642. IF (used / size) > maxLoadFactor THEN Grow END;
  643. END Put;
  644. PROCEDURE Get*(CONST key: SegmentedName):ANY;
  645. BEGIN
  646. RETURN table[HashValue(key)].value;
  647. END Get;
  648. PROCEDURE Has*(CONST key: SegmentedName):BOOLEAN;
  649. BEGIN
  650. RETURN table[HashValue(key)].key = key;
  651. END Has;
  652. PROCEDURE Length*():LONGINT;
  653. BEGIN RETURN used; END Length;
  654. PROCEDURE Clear*;
  655. VAR i: LONGINT;
  656. BEGIN FOR i := 0 TO size - 1 DO table[i].key[0] := -1; END; END Clear;
  657. (* Internals *)
  658. PROCEDURE Hash*(CONST name: SegmentedName): LONGINT;
  659. VAR fp,i: LONGINT;
  660. BEGIN
  661. fp := name[0]; i := 1;
  662. WHILE (i<LEN(name)) & (name[i] >= 0) DO
  663. fp:=SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, ROT(fp, 7)) / SYSTEM.VAL(SET, name[i]));
  664. INC(i);
  665. END;
  666. RETURN fp
  667. END Hash;
  668. PROCEDURE HashValue(CONST key: SegmentedName):LONGINT;
  669. VAR value, h,i: LONGINT;
  670. BEGIN
  671. ASSERT(key[0] >= 0);
  672. h := Hash(key);
  673. i := 0;
  674. REPEAT
  675. value := (h + i) MOD size;
  676. INC(i);
  677. UNTIL((table[value].key[0] < 0) OR (table[value].key = key) OR (i > size));
  678. ASSERT((table[value].key[0] <0 ) OR (table[value].key = key));
  679. RETURN value;
  680. END HashValue;
  681. PROCEDURE Grow;
  682. VAR oldTable: HashSegmentedNameArray; oldSize, i: LONGINT; key: SegmentedName;
  683. BEGIN
  684. oldSize := size;
  685. oldTable := table;
  686. Init(size*2);
  687. FOR i := 0 TO oldSize-1 DO
  688. key := oldTable[i].key;
  689. IF key[0] # MIN(LONGINT) THEN
  690. IF oldTable[i].value # NIL THEN
  691. Put(key, oldTable[i].value);
  692. END;
  693. END;
  694. END;
  695. END Grow;
  696. END HashTableSegmentedName;
  697. (* Hash table supporting 2 keys *)
  698. HashTable2D* = OBJECT(HashTable);
  699. VAR
  700. initialSize: LONGINT;
  701. (* Interface *)
  702. PROCEDURE & Init* (initialSize: LONGINT);
  703. BEGIN
  704. Init^(initialSize);
  705. SELF.initialSize := initialSize;
  706. END Init;
  707. PROCEDURE Get2D*(key1, key2: ANY):ANY;
  708. VAR
  709. any: ANY;
  710. second: HashTable;
  711. BEGIN
  712. any := Get(key1);
  713. second := any(HashTable);
  714. RETURN second.Get(key2);
  715. END Get2D;
  716. PROCEDURE Put2D*(key1, key2, value: ANY);
  717. VAR
  718. any: ANY;
  719. second: HashTable;
  720. BEGIN
  721. IF ~Has(key1) THEN
  722. NEW(second, initialSize);
  723. Put(key1, second);
  724. ELSE
  725. any := Get(key1);
  726. second := any(HashTable);
  727. END;
  728. second.Put(key2, value);
  729. END Put2D;
  730. PROCEDURE Has2D*(key1, key2: ANY):BOOLEAN;
  731. VAR
  732. any: ANY;
  733. second: HashTable;
  734. BEGIN
  735. IF ~Has(key1) THEN RETURN FALSE; END;
  736. any := Get(key1);
  737. second := any(HashTable);
  738. RETURN second.Has(key2);
  739. END Has2D;
  740. END HashTable2D;
  741. (* Data structure implementing a stack using lists *)
  742. Stack* = OBJECT
  743. VAR
  744. list: List;
  745. PROCEDURE & Init*;
  746. BEGIN NEW(list,InitListSize); END Init;
  747. (* Push on top of stack *)
  748. PROCEDURE Push*(x: ANY);
  749. BEGIN list.Add(x); END Push;
  750. (* Get top element *)
  751. PROCEDURE Peek*():ANY;
  752. BEGIN RETURN list.Get(list.Length() - 1); END Peek;
  753. (* Get and remove top element *)
  754. PROCEDURE Pop*():ANY;
  755. VAR old: ANY;
  756. BEGIN
  757. old := Peek();
  758. RemoveTop();
  759. RETURN old;
  760. END Pop;
  761. (* Remove top element without reading it *)
  762. PROCEDURE RemoveTop*;
  763. BEGIN list.RemoveByIndex(list.Length() - 1); END RemoveTop;
  764. (* Check if empty *)
  765. PROCEDURE Empty*():BOOLEAN;
  766. BEGIN RETURN list.Length() = 0; END Empty;
  767. PROCEDURE Length*():LONGINT;
  768. BEGIN RETURN list.count; END Length;
  769. END Stack;
  770. (* Data structure implementing a stack using lists *)
  771. IntegerStack* = OBJECT
  772. VAR
  773. list: IntegerList;
  774. PROCEDURE & Init*;
  775. BEGIN NEW(list,InitListSize); END Init;
  776. (* Push on top of stack *)
  777. PROCEDURE Push*(x: LONGINT);
  778. BEGIN list.Add(x); END Push;
  779. (* Get top element *)
  780. PROCEDURE Peek*():LONGINT;
  781. BEGIN RETURN list.Get(list.Length() - 1); END Peek;
  782. (* Get and remove top element *)
  783. PROCEDURE Pop*():LONGINT;
  784. VAR old: LONGINT;
  785. BEGIN
  786. old := Peek();
  787. RemoveTop();
  788. RETURN old;
  789. END Pop;
  790. (* Remove top element without reading it *)
  791. PROCEDURE RemoveTop*;
  792. BEGIN list.RemoveByIndex(list.Length() - 1); END RemoveTop;
  793. (* Check if empty *)
  794. PROCEDURE Empty*():BOOLEAN;
  795. BEGIN RETURN list.Length() = 0; END Empty;
  796. PROCEDURE Length*():LONGINT;
  797. BEGIN RETURN list.count; END Length;
  798. END IntegerStack;
  799. QueueEntry = POINTER TO RECORD
  800. value: ANY;
  801. next: QueueEntry;
  802. END;
  803. Queue* = OBJECT
  804. VAR
  805. top, last: QueueEntry;
  806. PROCEDURE & Init *;
  807. BEGIN
  808. top := NIL; last := NIL;
  809. END Init;
  810. (* Add to end of queue *)
  811. PROCEDURE Append*(x: ANY);
  812. VAR entry: QueueEntry;
  813. BEGIN
  814. NEW(entry);
  815. entry.value := x;
  816. IF top = NIL THEN
  817. top := entry;
  818. ELSE
  819. last.next := entry;
  820. END;
  821. last := entry;
  822. END Append;
  823. (* Get top element *)
  824. PROCEDURE Peek*():ANY;
  825. BEGIN
  826. RETURN top.value;
  827. END Peek;
  828. (* Get and remove top element *)
  829. PROCEDURE Pop*():ANY;
  830. VAR old: QueueEntry;
  831. BEGIN
  832. ASSERT(~Empty());
  833. old := top;
  834. top := top.next;
  835. RETURN old.value;
  836. END Pop;
  837. (* Check if empty *)
  838. PROCEDURE Empty*():BOOLEAN;
  839. BEGIN
  840. RETURN top = NIL;
  841. END Empty;
  842. END Queue;
  843. PQItem = RECORD
  844. key: LONGINT;
  845. value: ANY;
  846. END;
  847. PQItemList = POINTER TO ARRAY OF PQItem;
  848. (* Priority queue using binary heap *)
  849. PriorityQueue* = OBJECT
  850. VAR
  851. heap: PQItemList;
  852. count-: LONGINT;
  853. (** Interface **)
  854. PROCEDURE & Init(size: LONGINT);
  855. BEGIN
  856. NEW(heap, size + 1);
  857. count := 0;
  858. END Init;
  859. PROCEDURE Min*():ANY; (* O(n) *)
  860. BEGIN
  861. ASSERT(count > 0);
  862. RETURN heap[1].value;
  863. END Min;
  864. PROCEDURE RemoveMin*():ANY; (* O(log n) *)
  865. VAR min: ANY;
  866. BEGIN
  867. min := Min();
  868. heap[1] := heap[count];
  869. DEC(count);
  870. IF count > 0 THEN BubbleDown(1); END;
  871. RETURN min;
  872. END RemoveMin;
  873. PROCEDURE Insert*(key: LONGINT; value: ANY); (* O(log n) *)
  874. VAR index: LONGINT;
  875. BEGIN
  876. INC(count);
  877. index := count;
  878. heap[index].key := key;
  879. heap[index].value := value;
  880. BubbleUp(index);
  881. END Insert;
  882. PROCEDURE Empty*():BOOLEAN;
  883. BEGIN
  884. RETURN count = 0;
  885. END Empty;
  886. (** Implementation **)
  887. PROCEDURE BubbleUp(VAR index: LONGINT);
  888. VAR swap: PQItem;
  889. BEGIN
  890. WHILE (index > 1) & (heap[index].key < heap[index DIV 2].key) DO
  891. swap := heap[index DIV 2];
  892. heap[index DIV 2] := heap[index];
  893. heap[index] := swap;
  894. index := index DIV 2;
  895. END;
  896. END BubbleUp;
  897. PROCEDURE BubbleDown(index: LONGINT);
  898. VAR min, minkey: LONGINT; swap: PQItem;
  899. PROCEDURE Child(child: LONGINT);
  900. BEGIN
  901. IF (child <= count) & (heap[child].key < minkey) THEN
  902. min := child;
  903. minkey := heap[child].key;
  904. END;
  905. END Child;
  906. BEGIN
  907. REPEAT
  908. min := 0;
  909. minkey := heap[index].key;
  910. Child(index * 2);
  911. Child((index * 2) + 1);
  912. IF min # 0 THEN
  913. swap := heap[min];
  914. heap[min] := heap[index];
  915. heap[index] := swap;
  916. index := min;
  917. END;
  918. UNTIL
  919. min = 0;
  920. END BubbleDown;
  921. END PriorityQueue;
  922. IndexList = POINTER TO ARRAY OF LONGINT;
  923. Edge* = OBJECT
  924. VAR
  925. from-, to-: Block;
  926. PROCEDURE Accept(v: GraphVisitor);
  927. BEGIN v.VisitEdge(SELF); END Accept;
  928. END Edge;
  929. Graph* = OBJECT
  930. VAR
  931. firstBlock*, lastBlock-: Block;
  932. blocks*: BlockList;
  933. edges-: EdgeList;
  934. edgesLookup: HashTable2D;
  935. PROCEDURE & Init *;
  936. BEGIN
  937. NEW(blocks,InitListSize);
  938. NEW(edges,InitListSize);
  939. NEW(edgesLookup, 1024);
  940. END Init;
  941. PROCEDURE AddBlock*(block: Block);
  942. BEGIN
  943. IF blocks.Length() = 0 THEN firstBlock := block; END;
  944. block.index := blocks.Length();
  945. blocks.Add(block);
  946. lastBlock := block;
  947. END AddBlock;
  948. PROCEDURE Connect*(from, to: Block);
  949. VAR edge: Edge;
  950. BEGIN
  951. IF edgesLookup.Has2D(from, to) THEN RETURN; END;
  952. from.successors.Add(to);
  953. to.predecessors.Add(from);
  954. NEW(edge);
  955. edge.from := from;
  956. edge.to := to;
  957. edges.Add(edge);
  958. edgesLookup.Put2D(from, to, edge);
  959. END Connect;
  960. PROCEDURE Split*(from, to: Block);
  961. BEGIN
  962. from.successors.Remove(to);
  963. to.predecessors.Remove(from);
  964. edges.Remove(edgesLookup.Get2D(from, to));
  965. END Split;
  966. (* Reorder blocks so that they form a reverse post order *)
  967. PROCEDURE ReIndex*;
  968. VAR b: Block; i: LONGINT; done: POINTER TO ARRAY OF BOOLEAN; new: BlockList;
  969. PROCEDURE Work(b: Block);
  970. VAR i: LONGINT; p: Block;
  971. BEGIN
  972. done[b.index] := TRUE;
  973. FOR i := 0 TO b.successors.Length() - 1 DO
  974. p := b.successors.GetBlock(i);
  975. IF ~done[p.index] THEN
  976. Work(p);
  977. END;
  978. END;
  979. new.Add(b);
  980. END Work;
  981. BEGIN
  982. NEW(new,InitListSize);
  983. NEW(done, blocks.Length());
  984. i := 0;
  985. Work(blocks.GetBlock(0));
  986. NEW(blocks,InitListSize);
  987. FOR i := new.Length() - 1 TO 0 BY -1 DO
  988. b := new.GetBlock(i);
  989. b.index := blocks.Length();
  990. blocks.Add(b);
  991. END;
  992. END ReIndex;
  993. (* Calculate dominance tree. Algorithm taken from:
  994. "A simple, fast dominance algorithm" (Cooper, Harvey, Kennedy) *)
  995. PROCEDURE CalculateDominance*;
  996. VAR
  997. doms: IndexList;
  998. i, j, len, runner, newIdom: LONGINT;
  999. changed: BOOLEAN;
  1000. block, pred: Block;
  1001. PROCEDURE Intersect(b1, b2: LONGINT):LONGINT;
  1002. BEGIN
  1003. WHILE(b1 # b2) DO
  1004. WHILE(b1 > b2) DO
  1005. IF b1 = doms[b1] THEN HALT(100); END;
  1006. b1 := doms[b1];
  1007. END;
  1008. WHILE(b2 > b1) DO
  1009. IF b2 = doms[b2] THEN HALT(100); END;
  1010. b2 := doms[b2];
  1011. END;
  1012. END;
  1013. RETURN b1;
  1014. END Intersect;
  1015. BEGIN
  1016. (* Initialize the arrays *)
  1017. len := blocks.Length();
  1018. NEW(doms, len);
  1019. FOR i := 0 TO len - 1 DO
  1020. doms[i] := -1;
  1021. END;
  1022. doms[0] := 0;
  1023. (* Iteration loop *)
  1024. changed := TRUE;
  1025. WHILE(changed) DO
  1026. changed := FALSE;
  1027. FOR i := 1 TO len - 1 DO
  1028. block := blocks.GetBlock(i);
  1029. pred := block.predecessors.GetBlock(0);
  1030. newIdom := pred.index;
  1031. FOR j := 1 TO block.predecessors.Length() - 1 DO
  1032. pred := block.predecessors.GetBlock(j);
  1033. IF doms[pred.index] # -1 THEN
  1034. newIdom := Intersect(pred.index, newIdom);
  1035. END;
  1036. END;
  1037. IF doms[i] # newIdom THEN
  1038. doms[i] := newIdom;
  1039. changed := TRUE;
  1040. END;
  1041. END;
  1042. END;
  1043. FOR i := 0 TO len - 1 DO
  1044. block := blocks.GetBlock(i);
  1045. (* Set immediate dominators *)
  1046. block.immediateDominator := doms[i];
  1047. (* Calculate frontier *)
  1048. IF block.predecessors.Length() >= 2 THEN
  1049. FOR j := 0 TO block.predecessors.Length() - 1 DO
  1050. pred := block.predecessors.GetBlock(j);
  1051. runner := pred.index;
  1052. WHILE runner # doms[block.index] DO
  1053. pred := blocks.GetBlock(runner);
  1054. IF ~pred.dominanceFrontier.Contains(block) THEN
  1055. pred.dominanceFrontier.Add(block);
  1056. END;
  1057. runner := doms[runner];
  1058. END;
  1059. END;
  1060. END;
  1061. END;
  1062. END CalculateDominance;
  1063. END Graph;
  1064. BlockList* = OBJECT(List)
  1065. VAR
  1066. PROCEDURE GetBlock*(i: LONGINT):Block;
  1067. VAR block: ANY;
  1068. BEGIN
  1069. block := Get(i);
  1070. RETURN block(Block);
  1071. END GetBlock;
  1072. PROCEDURE GetIndex*(i: LONGINT):LONGINT;
  1073. VAR block: Block;
  1074. BEGIN
  1075. block := GetBlock(i);
  1076. RETURN block.index;
  1077. END GetIndex;
  1078. END BlockList;
  1079. EdgeList* = OBJECT(List)
  1080. VAR
  1081. PROCEDURE GetEdge*(i: LONGINT):Edge;
  1082. VAR
  1083. edge: ANY;
  1084. BEGIN
  1085. edge := Get(i);
  1086. RETURN edge(Edge);
  1087. END GetEdge;
  1088. END EdgeList;
  1089. Block* = OBJECT
  1090. VAR
  1091. predecessors-, successors-, dominanceFrontier-: BlockList;
  1092. index*, immediateDominator*: LONGINT;
  1093. PROCEDURE & Init*;
  1094. BEGIN
  1095. NEW(predecessors,InitListSize);
  1096. NEW(successors,InitListSize);
  1097. NEW(dominanceFrontier,InitListSize);
  1098. END Init;
  1099. PROCEDURE Accept(v: GraphVisitor);
  1100. BEGIN v.VisitBlock(SELF); END Accept;
  1101. PROCEDURE PredecessorIndex*(block: Block):LONGINT;
  1102. VAR i: LONGINT;
  1103. BEGIN
  1104. FOR i := 0 TO predecessors.Length() - 1 DO
  1105. IF predecessors.Get(i) = block THEN
  1106. RETURN i;
  1107. END;
  1108. END;
  1109. HALT(100);
  1110. END PredecessorIndex;
  1111. END Block;
  1112. ContentFunction = PROCEDURE {DELEGATE} (block: Block);
  1113. GraphVisitor* = OBJECT
  1114. VAR
  1115. block-: Block;
  1116. edge-: Edge;
  1117. graph-: Graph;
  1118. PROCEDURE VisitEdge*(edge: Edge);
  1119. BEGIN END VisitEdge;
  1120. PROCEDURE VisitBlock*(block: Block);
  1121. BEGIN END VisitBlock;
  1122. PROCEDURE VisitGraph*(graph: Graph);
  1123. VAR i: LONGINT;
  1124. BEGIN
  1125. SELF.graph := graph;
  1126. FOR i := 0 TO graph.blocks.Length() - 1 DO
  1127. block := graph.blocks.GetBlock(i);
  1128. block.Accept(SELF);
  1129. END;
  1130. FOR i := 0 TO graph.edges.Length() - 1 DO
  1131. edge := graph.edges.GetEdge(i);
  1132. edge.Accept(SELF);
  1133. END;
  1134. END VisitGraph;
  1135. END GraphVisitor;
  1136. (** Outputs a .dot file which can be parsed into a graph by GraphViz *)
  1137. GraphPrinter* = OBJECT(GraphVisitor)
  1138. VAR
  1139. active-: Block;
  1140. writer-: Streams.Writer;
  1141. content: ContentFunction;
  1142. PROCEDURE VisitEdge*(edge: Edge);
  1143. BEGIN
  1144. writer.String("block"); writer.Int(edge.from.index, 0);
  1145. writer.String("->");
  1146. writer.String("block"); writer.Int(edge.to.index, 0);
  1147. writer.String(";"); writer.Ln;
  1148. END VisitEdge;
  1149. PROCEDURE VisitBlock*(block: Block);
  1150. VAR
  1151. i: LONGINT;
  1152. dom: Block;
  1153. BEGIN
  1154. writer.String("block");
  1155. writer.Int(block.index, 0);
  1156. writer.String(' [ label=<<table border="0" cellpadding="1" cellspacing="1"><tr><td>#');
  1157. writer.Int(block.index, 0);
  1158. writer.String("</td><td>idom=");
  1159. writer.Int(block.immediateDominator, 0);
  1160. writer.String("</td><td>df=");
  1161. FOR i := 0 TO block.dominanceFrontier.Length() - 1 DO
  1162. dom := block.dominanceFrontier.GetBlock(i);
  1163. writer.Int(dom.index, 0);
  1164. writer.String(" ");
  1165. END;
  1166. writer.String("</td></tr>");
  1167. content(block);
  1168. writer.String('</table>>]; ');
  1169. writer.Ln;
  1170. END VisitBlock;
  1171. PROCEDURE VisitGraph*(graph: Graph);
  1172. BEGIN
  1173. SELF.graph := graph;
  1174. (* Print header of dot file *)
  1175. writer.String("digraph G {"); writer.Ln;
  1176. (* Print all blocks *)
  1177. writer.String("node [shape=box]; ");
  1178. VisitGraph^(graph);
  1179. (* Footer *)
  1180. writer.Ln;
  1181. writer.String("overlap=false;"); writer.Ln;
  1182. writer.String('label=" Created with OC";'); writer.Ln;
  1183. writer.String("fontsize=12;"); writer.Ln;
  1184. writer.String("}");
  1185. END VisitGraph;
  1186. PROCEDURE SetWriter*(w: Streams.Writer);
  1187. BEGIN
  1188. writer := w;
  1189. END SetWriter;
  1190. PROCEDURE & Init*(c: ContentFunction);
  1191. BEGIN
  1192. content := c;
  1193. END Init;
  1194. END GraphPrinter;
  1195. IntegerObject = OBJECT
  1196. END IntegerObject;
  1197. Writer* = OBJECT (Streams.Writer)
  1198. VAR
  1199. indent-: LONGINT;
  1200. doindent: BOOLEAN;
  1201. w-: Streams.Writer;
  1202. PROCEDURE InitBasicWriter*( w: Streams.Writer );
  1203. BEGIN
  1204. SELF.w := w; indent := 0; doindent := TRUE;
  1205. END InitBasicWriter;
  1206. PROCEDURE & InitW(w: Streams.Writer); (* protect against use of NEW *)
  1207. BEGIN InitBasicWriter(w);
  1208. END InitW;
  1209. PROCEDURE Reset*;
  1210. BEGIN w.Reset;
  1211. END Reset;
  1212. PROCEDURE CanSetPos*( ): BOOLEAN;
  1213. BEGIN RETURN w.CanSetPos();
  1214. END CanSetPos;
  1215. PROCEDURE SetPos*( pos: LONGINT );
  1216. BEGIN w.SetPos(pos);
  1217. END SetPos;
  1218. PROCEDURE Update*;
  1219. BEGIN w.Update;
  1220. END Update;
  1221. PROCEDURE Pos*( ): LONGINT;
  1222. BEGIN RETURN w.Pos()
  1223. END Pos;
  1224. PROCEDURE Indent;
  1225. VAR i: LONGINT;
  1226. BEGIN
  1227. IF doindent THEN
  1228. FOR i := 0 TO indent-1 DO
  1229. w.Char(9X);
  1230. END;
  1231. doindent := FALSE
  1232. END;
  1233. END Indent;
  1234. PROCEDURE Char*( x: CHAR );
  1235. BEGIN Indent; w.Char(x);
  1236. END Char;
  1237. PROCEDURE Bytes*(CONST x: ARRAY OF CHAR; ofs, len: LONGINT );
  1238. BEGIN w.Bytes(x,ofs,len);
  1239. END Bytes;
  1240. PROCEDURE RawSInt*( x: SHORTINT );
  1241. BEGIN w.RawSInt(x)
  1242. END RawSInt;
  1243. PROCEDURE RawInt*( x: INTEGER );
  1244. BEGIN w.RawInt(x)
  1245. END RawInt;
  1246. PROCEDURE RawLInt*( x: LONGINT );
  1247. BEGIN w.RawLInt(x)
  1248. END RawLInt;
  1249. PROCEDURE RawHInt*( x: HUGEINT );
  1250. BEGIN w.RawHInt(x)
  1251. END RawHInt;
  1252. PROCEDURE Net32*( x: LONGINT );
  1253. BEGIN w.Net32(x)
  1254. END Net32;
  1255. PROCEDURE Net16*( x: LONGINT );
  1256. BEGIN w.Net16(x)
  1257. END Net16;
  1258. PROCEDURE Net8*( x: LONGINT );
  1259. BEGIN w.Net8(x)
  1260. END Net8;
  1261. PROCEDURE RawSet*( x: SET );
  1262. BEGIN w.RawSet(x)
  1263. END RawSet;
  1264. PROCEDURE RawBool*( x: BOOLEAN );
  1265. BEGIN w.RawBool(x)
  1266. END RawBool;
  1267. PROCEDURE RawReal*( x: REAL );
  1268. BEGIN w.RawReal(x)
  1269. END RawReal;
  1270. PROCEDURE RawLReal*( x: LONGREAL );
  1271. BEGIN w.RawLReal(x)
  1272. END RawLReal;
  1273. PROCEDURE RawString*(CONST x: ARRAY OF CHAR );
  1274. BEGIN w.RawString(x)
  1275. END RawString;
  1276. PROCEDURE RawNum*( x: LONGINT );
  1277. BEGIN w.RawNum(x)
  1278. END RawNum;
  1279. PROCEDURE Ln*;
  1280. BEGIN w.Ln; doindent := TRUE;
  1281. END Ln;
  1282. PROCEDURE String*(CONST x: ARRAY OF CHAR );
  1283. BEGIN Indent; w.String(x)
  1284. END String;
  1285. PROCEDURE Int*( x: HUGEINT; wd: SIZE );
  1286. BEGIN Indent; w.Int(x,wd)
  1287. END Int;
  1288. PROCEDURE Set*( s: SET ); (* from P. Saladin *)
  1289. BEGIN Indent; w.Set(s)
  1290. END Set;
  1291. PROCEDURE Hex*(x: HUGEINT; wd: SIZE );
  1292. BEGIN Indent; w.Hex(x,wd)
  1293. END Hex;
  1294. PROCEDURE Address* (x: ADDRESS);
  1295. BEGIN Indent; w.Address(x)
  1296. END Address;
  1297. PROCEDURE Date*( t, d: LONGINT );
  1298. BEGIN Indent; w.Date(t,d)
  1299. END Date;
  1300. PROCEDURE Date822*( t, d, tz: LONGINT );
  1301. BEGIN Indent; w.Date822(t,d,tz)
  1302. END Date822;
  1303. PROCEDURE Float*( x: LONGREAL; n: LONGINT );
  1304. BEGIN Indent; w.Float(x,n)
  1305. END Float;
  1306. PROCEDURE FloatFix*( x: LONGREAL; n, f, D: LONGINT );
  1307. BEGIN Indent; w.FloatFix(x,n,f,D)
  1308. END FloatFix;
  1309. PROCEDURE SetIndent*(i: LONGINT);
  1310. BEGIN
  1311. indent := i
  1312. END SetIndent;
  1313. PROCEDURE IncIndent*;
  1314. BEGIN INC(indent)
  1315. END IncIndent;
  1316. PROCEDURE DecIndent*;
  1317. BEGIN DEC(indent)
  1318. END DecIndent;
  1319. PROCEDURE BeginAlert*;
  1320. END BeginAlert;
  1321. PROCEDURE EndAlert*;
  1322. END EndAlert;
  1323. PROCEDURE BeginKeyword*;
  1324. BEGIN
  1325. END BeginKeyword;
  1326. PROCEDURE EndKeyword*;
  1327. BEGIN
  1328. END EndKeyword;
  1329. PROCEDURE BeginComment*;
  1330. END BeginComment;
  1331. PROCEDURE EndComment*;
  1332. END EndComment;
  1333. PROCEDURE AlertString*(CONST s: ARRAY OF CHAR);
  1334. BEGIN
  1335. BeginAlert; w.String(s); EndAlert;
  1336. END AlertString;
  1337. END Writer;
  1338. CRC32Stream* = OBJECT(Streams.Writer) (* from CRC.Mod *)
  1339. VAR
  1340. crc : LONGINT;
  1341. PROCEDURE &InitStream*;
  1342. BEGIN
  1343. crc := LONGINT(0FFFFFFFFH);
  1344. InitWriter(Send, 256)
  1345. END InitStream;
  1346. PROCEDURE Send*(CONST buf: ARRAY OF CHAR; ofs, len: LONGINT; propagate: BOOLEAN; VAR res: LONGINT);
  1347. VAR idx: LONGINT;
  1348. BEGIN
  1349. WHILE len > 0 DO
  1350. idx := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, crc) / SYSTEM.VAL(SET, LONG(ORD(buf[ofs])))) MOD 100H;
  1351. crc := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, CRC32Table[idx])/SYSTEM.VAL(SET, LSH(crc, -8)));
  1352. DEC(len); INC(ofs)
  1353. END;
  1354. res := Streams.Ok
  1355. END Send;
  1356. PROCEDURE GetCRC*():LONGINT;
  1357. BEGIN
  1358. Update();
  1359. RETURN SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, crc)/{0..31})
  1360. END GetCRC;
  1361. END CRC32Stream;
  1362. TracingDiagnostics=OBJECT (Diagnostics.Diagnostics)
  1363. VAR diagnostics: Diagnostics.Diagnostics;
  1364. PROCEDURE &InitDiagnostics(diagnostics: Diagnostics.Diagnostics);
  1365. BEGIN
  1366. SELF.diagnostics := diagnostics
  1367. END InitDiagnostics;
  1368. PROCEDURE Error*(CONST source: ARRAY OF CHAR; position, errorCode : LONGINT; CONST message : ARRAY OF CHAR);
  1369. BEGIN
  1370. IF diagnostics # NIL THEN
  1371. diagnostics.Error(source,position,errorCode,message);
  1372. END;
  1373. D.Ln;
  1374. D.String(" ---------------------- TRACE for COMPILER ERROR < ");
  1375. D.String(source);
  1376. IF position # Diagnostics.Invalid THEN D.String("@"); D.Int(position,1) END;
  1377. IF errorCode # Diagnostics.Invalid THEN D.String(" "); D.Int(errorCode,1); END;
  1378. D.String(" "); D.String(message);
  1379. D.String(" > ---------------------- ");
  1380. D.TraceBack
  1381. END Error;
  1382. PROCEDURE Warning*(CONST source : ARRAY OF CHAR; position, errorCode : LONGINT; CONST message : ARRAY OF CHAR);
  1383. BEGIN
  1384. IF diagnostics # NIL THEN
  1385. diagnostics.Warning(source,position,errorCode,message);
  1386. END;
  1387. END Warning;
  1388. PROCEDURE Information*(CONST source : ARRAY OF CHAR; position, errorCode : LONGINT; CONST message : ARRAY OF CHAR);
  1389. BEGIN
  1390. IF diagnostics # NIL THEN
  1391. diagnostics.Information(source,position,errorCode,message);
  1392. END;
  1393. END Information;
  1394. END TracingDiagnostics;
  1395. DebugWriterFactory*= PROCEDURE{DELEGATE} (CONST title: ARRAY OF CHAR): Streams.Writer;
  1396. WriterFactory*=PROCEDURE{DELEGATE} (w: Streams.Writer): Writer;
  1397. DiagnosticsFactory*=PROCEDURE{DELEGATE} (w: Streams.Writer): Diagnostics.Diagnostics;
  1398. VAR
  1399. lists-: LONGINT; enlarged-: LONGINT; strings-: LONGINT; integerObjects: HashTableInt;
  1400. errMsg: ErrorMsgs; (*error messages*)
  1401. emptyString-: String;
  1402. debug: BOOLEAN;
  1403. getDebugWriter: DebugWriterFactory;
  1404. getWriter: WriterFactory;
  1405. getDiagnostics: DiagnosticsFactory;
  1406. CRC32Table: ARRAY 256 OF SET;
  1407. invalidPosition-: Position;
  1408. (* Make a string out of a series of characters. *)
  1409. PROCEDURE MakeString*( CONST s: ARRAY OF CHAR ): String;
  1410. (* VAR str: String; *)
  1411. BEGIN
  1412. INC( strings );
  1413. (*
  1414. (* allocation based *)
  1415. NEW( str, Strings.Length( s ) +1); COPY( s, str^ ); RETURN str;
  1416. *)
  1417. RETURN StringPool.GetIndex1( s )
  1418. END MakeString;
  1419. PROCEDURE GetString*(s: String; VAR str: ARRAY OF CHAR);
  1420. BEGIN
  1421. StringPool.GetString(s,str);
  1422. END GetString;
  1423. PROCEDURE StringEqual*( s, t: String ): BOOLEAN;
  1424. BEGIN
  1425. RETURN s = t;
  1426. (*
  1427. (* allocation based *)
  1428. RETURN s^ = t^
  1429. *)
  1430. END StringEqual;
  1431. PROCEDURE GetErrorMessage*(err: LONGINT; CONST msg: ARRAY OF CHAR; VAR res: ARRAY OF CHAR);
  1432. VAR str: ARRAY 128 OF CHAR;
  1433. BEGIN
  1434. res := "";
  1435. IF (errMsg # NIL) & (0 <= err) & (err < LEN(errMsg)) THEN
  1436. StringPool.GetString(errMsg[err], str);
  1437. Strings.Append(res,str);
  1438. Strings.Append(res, " ");
  1439. END;
  1440. Strings.Append(res, msg);
  1441. Strings.Append(res, ". ");
  1442. END GetErrorMessage;
  1443. PROCEDURE AppendDetailedErrorMessage*(VAR message: ARRAY OF CHAR; pos: Position; reader: Streams.Reader);
  1444. VAR err: ARRAY 512 OF CHAR; ch: CHAR; oldpos: LONGINT;
  1445. BEGIN
  1446. IF (reader # NIL) & (reader.CanSetPos()) THEN
  1447. oldpos := reader.Pos();
  1448. reader.SetPos(pos.linepos);
  1449. reader.Char(ch);
  1450. (* read until end of source line *)
  1451. WHILE (ch # 0X) & (ch # 0AX) & (ch # 0DX) DO
  1452. Strings.AppendChar(err, ch);
  1453. IF reader.Pos() = pos.start THEN
  1454. Strings.Append(err,"(*!*)");
  1455. END;
  1456. reader.Char(ch);
  1457. END;
  1458. reader.SetPos(oldpos);
  1459. END;
  1460. Strings.TrimWS(err);
  1461. Strings.Append(message, err);
  1462. END AppendDetailedErrorMessage;
  1463. PROCEDURE AppendPosition*(VAR msg: ARRAY OF CHAR; pos: Position);
  1464. BEGIN
  1465. IF pos.line >= 0 THEN
  1466. Strings.Append(msg, " in line ");
  1467. Strings.AppendInt(msg, pos.line);
  1468. Strings.Append(msg, ", col ");
  1469. Strings.AppendInt(msg, pos.start- pos.linepos);
  1470. END;
  1471. END AppendPosition;
  1472. PROCEDURE MakeMessage(pos: Position; code: ErrorCode; CONST msg: ARRAY OF CHAR; VAR message: ARRAY OF CHAR);
  1473. BEGIN
  1474. MakeDetailedMessage(pos, code, msg, NIL, message);
  1475. Strings.AppendChar(message, 0X); (* terminate message *)
  1476. END MakeMessage;
  1477. PROCEDURE MakeDetailedMessage(pos: Position; code: ErrorCode; CONST msg: ARRAY OF CHAR; reader: Streams.Reader; VAR message: ARRAY OF CHAR);
  1478. BEGIN
  1479. GetErrorMessage(code, msg, message);
  1480. AppendDetailedErrorMessage(message, pos, reader);
  1481. AppendPosition(message, pos);
  1482. END MakeDetailedMessage;
  1483. (* error message with code *)
  1484. PROCEDURE ErrorC*(diagnostics: Diagnostics.Diagnostics; CONST source: ARRAY OF CHAR; pos: Position; code: ErrorCode; CONST msg: ARRAY OF CHAR);
  1485. VAR message: ARRAY 1024 OF CHAR; file: Files.File;
  1486. PROCEDURE GetReader(): Streams.Reader;
  1487. VAR reader := NIL: Streams.Reader;
  1488. BEGIN
  1489. IF (pos.linepos >= 0) & ((source # "") OR (pos.reader # NIL)) THEN
  1490. reader := pos.reader;
  1491. IF reader = NIL THEN
  1492. file := Files.Old(source);
  1493. IF file # NIL THEN
  1494. reader := NEW Files.Reader(file, pos.linepos);
  1495. END;
  1496. END;
  1497. END;
  1498. RETURN reader;
  1499. END GetReader;
  1500. BEGIN
  1501. IF diagnostics # NIL THEN
  1502. MakeDetailedMessage(pos, code, msg, GetReader(), message);
  1503. diagnostics.Error(source, pos.start, code, message);
  1504. END;
  1505. END ErrorC;
  1506. (* error message without code *)
  1507. PROCEDURE Error*(diagnostics: Diagnostics.Diagnostics; CONST source: ARRAY OF CHAR; pos: Position; CONST msg: ARRAY OF CHAR);
  1508. BEGIN
  1509. ErrorC(diagnostics, source, pos, InvalidCode, msg);
  1510. END Error;
  1511. PROCEDURE Warning*(diagnostics: Diagnostics.Diagnostics; CONST source: ARRAY OF CHAR; pos: Position; CONST msg: ARRAY OF CHAR);
  1512. VAR message: ARRAY 256 OF CHAR;
  1513. BEGIN
  1514. IF diagnostics # NIL THEN
  1515. MakeMessage(pos, InvalidCode, msg,message);
  1516. diagnostics.Warning(source, pos.start, InvalidCode, message);
  1517. END;
  1518. END Warning;
  1519. PROCEDURE Information*(diagnostics: Diagnostics.Diagnostics; CONST source: ARRAY OF CHAR; pos: Position;CONST msg: ARRAY OF CHAR);
  1520. VAR message: ARRAY 256 OF CHAR;
  1521. BEGIN
  1522. IF diagnostics # NIL THEN
  1523. MakeMessage(pos, InvalidCode, msg,message);
  1524. diagnostics.Information(source, pos.start, InvalidCode, message);
  1525. END;
  1526. END Information;
  1527. (** SetErrorMsg - Set message for error n *)
  1528. PROCEDURE SetErrorMessage*(n: LONGINT; CONST msg: ARRAY OF CHAR);
  1529. BEGIN
  1530. IF errMsg = NIL THEN NEW(errMsg, InitErrMsgSize) END;
  1531. WHILE LEN(errMsg^) < n DO Expand(errMsg) END;
  1532. StringPool.GetIndex(msg, errMsg[n])
  1533. END SetErrorMessage;
  1534. PROCEDURE SetErrorExpected*(n: LONGINT; CONST msg: ARRAY OF CHAR);
  1535. VAR err: ARRAY 256 OF CHAR;
  1536. BEGIN
  1537. err := "missing '";
  1538. Strings.Append(err,msg);
  1539. Strings.Append(err, "'");
  1540. SetErrorMessage(n,err);
  1541. END SetErrorExpected;
  1542. PROCEDURE AppendNumber*(VAR s: ARRAY OF CHAR; num: LONGINT);
  1543. VAR nums: ARRAY 32 OF CHAR;
  1544. BEGIN
  1545. Strings.IntToStr(num,nums);
  1546. Strings.Append(s,nums);
  1547. END AppendNumber;
  1548. PROCEDURE InitSegmentedName*(VAR name: SegmentedName);
  1549. VAR i: LONGINT;
  1550. BEGIN FOR i := 0 TO LEN(name)-1 DO name[i] := -1 END;
  1551. END InitSegmentedName;
  1552. PROCEDURE ToSegmentedName*(CONST name: ARRAY OF CHAR; VAR pooledName: SegmentedName);
  1553. BEGIN
  1554. ObjectFile.StringToSegmentedName(name,pooledName);
  1555. END ToSegmentedName;
  1556. PROCEDURE SegmentedNameToString*(CONST pooledName: SegmentedName; VAR name: ARRAY OF CHAR);
  1557. BEGIN
  1558. ObjectFile.SegmentedNameToString(pooledName, name);
  1559. END SegmentedNameToString;
  1560. PROCEDURE WriteSegmentedName*(w: Streams.Writer; name: SegmentedName);
  1561. VAR sectionName: ObjectFile.SectionName;
  1562. BEGIN
  1563. SegmentedNameToString(name, sectionName);
  1564. w.String(sectionName);
  1565. END WriteSegmentedName;
  1566. PROCEDURE AppendToSegmentedName*(VAR name: SegmentedName; CONST this: ARRAY OF CHAR);
  1567. VAR i,j: LONGINT; string: ObjectFile.SectionName;
  1568. BEGIN
  1569. i := 0;
  1570. WHILE (i<LEN(name)) & (name[i] >= 0) DO
  1571. INC(i)
  1572. END;
  1573. IF (this[0] = ".") & (i < LEN(name)) THEN (* suffix *)
  1574. j := 0;
  1575. WHILE this[j+1] # 0X DO
  1576. string[j] := this[j+1];
  1577. INC(j);
  1578. END;
  1579. string[j] := 0X;
  1580. name[i] := StringPool.GetIndex1(string);
  1581. IF i<LEN(name)-1 THEN name[i+1] := -1 END;
  1582. ELSE
  1583. StringPool.GetString(name[i-1], string);
  1584. Strings.Append(string, this);
  1585. name[i-1] := StringPool.GetIndex1(string);
  1586. END;
  1587. END AppendToSegmentedName;
  1588. (* suffix using separation character "." *)
  1589. PROCEDURE SuffixSegmentedName*(VAR name: SegmentedName; this: StringPool.Index);
  1590. VAR string, suffix: ObjectFile.SectionName; i: LONGINT;
  1591. BEGIN
  1592. i := 0;
  1593. WHILE (i < LEN(name)) & (name[i] >= 0) DO
  1594. INC(i);
  1595. END;
  1596. IF i < LEN(name) THEN (* suffix *)
  1597. name[i] := this;
  1598. IF i<LEN(name)-1 THEN name[i+1] := -1 END;
  1599. ELSE
  1600. StringPool.GetString(name[i-1], string);
  1601. StringPool.GetString(this, suffix);
  1602. Strings.Append(string,".");
  1603. Strings.Append(string, suffix);
  1604. name[i-1] := StringPool.GetIndex1(string);
  1605. END;
  1606. END SuffixSegmentedName;
  1607. PROCEDURE SegmentedNameEndsWith*(CONST name: SegmentedName; CONST this: ARRAY OF CHAR): BOOLEAN;
  1608. VAR string: ObjectFile.SectionName; i: LONGINT;
  1609. BEGIN
  1610. i := 0;
  1611. WHILE (i< LEN(name)) & (name[i] >= 0) DO
  1612. INC(i);
  1613. END;
  1614. DEC(i);
  1615. IF i < 0 THEN
  1616. RETURN FALSE
  1617. ELSE
  1618. StringPool.GetString(name[i],string);
  1619. RETURN Strings.EndsWith(this, string);
  1620. END
  1621. END SegmentedNameEndsWith;
  1622. PROCEDURE RemoveSuffix*(VAR name: SegmentedName);
  1623. VAR i,pos,pos0: LONGINT;string: ObjectFile.SectionName;
  1624. BEGIN
  1625. i := 0;
  1626. WHILE (i< LEN(name)) & (name[i] >= 0) DO
  1627. INC(i);
  1628. END;
  1629. ASSERT(i>0);
  1630. IF i < LEN(name) THEN (* name[i] = empty *) name[i-1] := -1
  1631. ELSE (* i = LEN(name), name[i] = nonempty *)
  1632. DEC(i);
  1633. StringPool.GetString(name[i],string);
  1634. pos0 := 0; pos := 0;
  1635. WHILE (pos0 < LEN(string)) & (string[pos0] # 0X) DO
  1636. IF string[pos0] = "." THEN pos := pos0 END;
  1637. INC(pos0);
  1638. END;
  1639. IF pos = 0 THEN (* no dot in name or name starts with dot *)
  1640. name[i] := -1
  1641. ELSE (* remove last part in name *)
  1642. string[pos] := 0X;
  1643. name[i] := StringPool.GetIndex1(string);
  1644. END;
  1645. END;
  1646. END RemoveSuffix;
  1647. PROCEDURE GetSuffix*(CONST name: SegmentedName; VAR string: ARRAY OF CHAR);
  1648. VAR i,pos,pos0: LONGINT;
  1649. BEGIN
  1650. i := 0;
  1651. WHILE (i< LEN(name)) & (name[i] >= 0) DO
  1652. INC(i);
  1653. END;
  1654. ASSERT(i>0);
  1655. StringPool.GetString(name[i-1],string);
  1656. IF i = LEN(name) THEN
  1657. pos0 := 0; pos := 0;
  1658. WHILE (pos0 < LEN(string)) & (string[pos0] # 0X) DO
  1659. IF string[pos0] = "." THEN pos := pos0 END;
  1660. INC(pos0);
  1661. END;
  1662. IF pos # 0 THEN (* no dot in name or name starts with dot *)
  1663. pos0 := 0;
  1664. REPEAT
  1665. INC(pos); (* start with character after "." *)
  1666. string[pos0] := string[pos];
  1667. INC(pos0);
  1668. UNTIL string[pos] = 0X;
  1669. END;
  1670. END;
  1671. END GetSuffix;
  1672. PROCEDURE IsPrefix*(CONST prefix, of: SegmentedName): BOOLEAN;
  1673. VAR prefixS, ofS: SectionName; i: LONGINT;
  1674. BEGIN
  1675. i := 0;
  1676. WHILE (i< LEN(prefix)) & (prefix[i] = of[i]) DO INC(i) END;
  1677. IF i = LEN(prefix) THEN RETURN TRUE (* identical *)
  1678. ELSE (* prefix[i] # of[i] *)
  1679. IF prefix[i] < 0 THEN RETURN TRUE
  1680. ELSIF of[i] < 0 THEN RETURN FALSE
  1681. ELSIF (i<LEN(prefix)-1) THEN RETURN FALSE
  1682. ELSE
  1683. StringPool.GetString(prefix[i], prefixS);
  1684. StringPool.GetString(of[i], ofS);
  1685. RETURN Strings.StartsWith(prefixS, 0, ofS)
  1686. END
  1687. END;
  1688. END IsPrefix;
  1689. PROCEDURE Expand(VAR oldAry: ErrorMsgs);
  1690. VAR
  1691. len, i: LONGINT;
  1692. newAry: ErrorMsgs;
  1693. BEGIN
  1694. IF oldAry = NIL THEN RETURN END;
  1695. len := LEN(oldAry^);
  1696. NEW(newAry, len * 2);
  1697. FOR i := 0 TO len-1 DO
  1698. newAry[i] := oldAry[i];
  1699. END;
  1700. oldAry := newAry;
  1701. END Expand;
  1702. PROCEDURE Concat*(VAR result: ARRAY OF CHAR; CONST prefix, name, suffix: ARRAY OF CHAR);
  1703. VAR i, j: LONGINT;
  1704. BEGIN
  1705. i := 0; WHILE prefix[i] # 0X DO result[i] := prefix[i]; INC(i) END;
  1706. j := 0; WHILE name[j] # 0X DO result[i+j] := name[j]; INC(j) END;
  1707. INC(i, j);
  1708. j := 0; WHILE suffix[j] # 0X DO result[i+j] := suffix[j]; INC(j) END;
  1709. result[i+j] := 0X;
  1710. END Concat;
  1711. PROCEDURE Lowercase*(CONST name: ARRAY OF CHAR; VAR result: ARRAY OF CHAR);
  1712. VAR ch: CHAR; i: LONGINT;
  1713. BEGIN
  1714. i := 0;
  1715. REPEAT
  1716. ch := name[i];
  1717. IF (ch >= 'A') & (ch <= 'Z') THEN
  1718. ch := CHR(ORD(ch)-ORD('A')+ORD('a'));
  1719. END;
  1720. result[i] := ch; INC(i);
  1721. UNTIL ch = 0X;
  1722. END Lowercase;
  1723. PROCEDURE Uppercase*(CONST name: ARRAY OF CHAR; VAR result: ARRAY OF CHAR);
  1724. VAR ch: CHAR; i: LONGINT;
  1725. BEGIN
  1726. i := 0;
  1727. REPEAT
  1728. ch := name[i];
  1729. IF (ch >= 'a') & (ch <= 'z') THEN
  1730. ch := CHR(ORD(ch)-ORD('a')+ORD('A'));
  1731. END;
  1732. result[i] := ch; INC(i);
  1733. UNTIL ch = 0X;
  1734. END Uppercase;
  1735. PROCEDURE GetIntegerObj*(value: LONGINT):ANY;
  1736. VAR obj: IntegerObject;
  1737. BEGIN
  1738. IF integerObjects.Has(value) THEN
  1739. RETURN integerObjects.Get(value);
  1740. END;
  1741. NEW(obj);
  1742. integerObjects.Put(value, obj);
  1743. RETURN obj;
  1744. END GetIntegerObj;
  1745. PROCEDURE Align*(VAR offset: LONGINT; alignment: LONGINT);
  1746. BEGIN
  1747. IF alignment >0 THEN
  1748. INC(offset,(-offset) MOD alignment);
  1749. ELSIF alignment < 0 THEN
  1750. DEC(offset,offset MOD (-alignment));
  1751. END;
  1752. END Align;
  1753. PROCEDURE InitErrorMessages;
  1754. BEGIN
  1755. SetErrorMessage(UndeclaredIdentifier, "undeclared identifier");
  1756. SetErrorMessage(MultiplyDefinedIdentifier, "multiply defined identifier");
  1757. SetErrorMessage(NumberIllegalCharacter, "illegal character in number");
  1758. SetErrorMessage(StringIllegalCharacter, "illegal character in string");
  1759. SetErrorMessage(NoMatchProcedureName, "procedure name does not match");
  1760. SetErrorMessage(CommentNotClosed, "comment not closed");
  1761. SetErrorMessage(IllegalCharacterValue, "illegal character value");
  1762. SetErrorMessage(ValueStartIncorrectSymbol, "value starts with incorrect symbol");
  1763. SetErrorMessage(IllegalyMarkedIdentifier, "illegaly marked identifier");
  1764. SetErrorMessage(IdentifierNoType, "identifier is not a type");
  1765. SetErrorMessage(IdentifierNoRecordType, "identifier is not a record type");
  1766. SetErrorMessage(IdentifierNoObjectType, "identifier is not an object type");
  1767. SetErrorMessage(ImportNotAvailable, "import is not available");
  1768. SetErrorMessage(RecursiveTypeDeclaration, "recursive type declaration");
  1769. SetErrorMessage(NumberTooLarge, "number too large");
  1770. SetErrorMessage(IdentifierTooLong, "identifier too long");
  1771. SetErrorMessage(StringTooLong, "string too long");
  1772. END InitErrorMessages;
  1773. PROCEDURE ActivateDebug*;
  1774. BEGIN
  1775. debug := TRUE;
  1776. END ActivateDebug;
  1777. PROCEDURE Test*;
  1778. VAR table: HashTableInt; dump: LONGINT;
  1779. BEGIN
  1780. NEW(table, 32);
  1781. table.PutInt(32, -4);
  1782. dump := table.GetInt(32);
  1783. HALT(100);
  1784. END Test;
  1785. PROCEDURE GetFileReader*(CONST filename: ARRAY OF CHAR): Streams.Reader;
  1786. VAR
  1787. file: Files.File; fileReader: Files.Reader; offset: LONGINT;
  1788. BEGIN
  1789. (* Optimisation: skip header of oberon files and return a file reader instead of default text reader*)
  1790. file := Files.Old (filename);
  1791. IF file = NIL THEN RETURN NIL END;
  1792. NEW (fileReader, file, 0);
  1793. IF (fileReader.Get () = 0F0X) & (fileReader.Get () = 001X) THEN
  1794. offset := ORD (fileReader.Get ());
  1795. INC (offset, LONG (ORD (fileReader.Get ())) * 0100H);
  1796. fileReader.SetPos(offset);
  1797. ELSE fileReader.SetPos(0)
  1798. END;
  1799. RETURN fileReader
  1800. END GetFileReader;
  1801. PROCEDURE GetWriter*(w: Streams.Writer): Writer;
  1802. VAR writer: Writer;
  1803. BEGIN
  1804. ASSERT(w # NIL);
  1805. IF w IS Writer THEN RETURN w(Writer)
  1806. ELSIF getWriter = NIL THEN
  1807. NEW(writer,w); RETURN writer
  1808. ELSE RETURN getWriter(w)
  1809. END;
  1810. END GetWriter;
  1811. PROCEDURE GetDebugWriter*(CONST title: ARRAY OF CHAR): Streams.Writer;
  1812. VAR w: Streams.Writer;
  1813. BEGIN
  1814. IF getDebugWriter # NIL THEN w:= getDebugWriter(title)
  1815. ELSE NEW(w, KernelLog.Send,1024)
  1816. END;
  1817. RETURN w;
  1818. END GetDebugWriter;
  1819. PROCEDURE GetDiagnostics*(w: Streams.Writer): Diagnostics.Diagnostics;
  1820. VAR diagnostics: Diagnostics.StreamDiagnostics;
  1821. BEGIN
  1822. IF getDiagnostics # NIL THEN RETURN getDiagnostics(w)
  1823. ELSE NEW(diagnostics,w); RETURN diagnostics
  1824. END;
  1825. END GetDiagnostics;
  1826. PROCEDURE GetDefaultDiagnostics*(): Diagnostics.Diagnostics;
  1827. VAR w: Streams.Writer;
  1828. BEGIN
  1829. NEW(w, KernelLog.Send,128);
  1830. RETURN GetDiagnostics(w);
  1831. END GetDefaultDiagnostics;
  1832. PROCEDURE InitWindowWriter;
  1833. VAR install: PROCEDURE;
  1834. BEGIN
  1835. getDebugWriter := NIL; getWriter := NIL;
  1836. IF Modules.ModuleByName("WindowManager") # NIL THEN
  1837. GETPROCEDURE("FoxA2Interface","Install",install);
  1838. END;
  1839. IF install # NIL THEN install END;
  1840. END InitWindowWriter;
  1841. PROCEDURE InstallWriterFactory*(writer: WriterFactory; debug: DebugWriterFactory; diagnostics: DiagnosticsFactory);
  1842. BEGIN
  1843. getWriter := writer;
  1844. getDebugWriter := debug;
  1845. getDiagnostics := diagnostics;
  1846. END InstallWriterFactory;
  1847. PROCEDURE Replace(VAR in: ARRAY OF CHAR; CONST this, by: ARRAY OF CHAR);
  1848. VAR pos: LONGINT;
  1849. BEGIN
  1850. pos := Strings.Pos(this,in);
  1851. IF pos >= 0 THEN
  1852. Strings.Delete(in,pos,Strings.Length(this));
  1853. Strings.Insert(by, in, pos);
  1854. END;
  1855. END Replace;
  1856. PROCEDURE MessageS*(CONST format, s0: ARRAY OF CHAR): MessageString;
  1857. VAR message: MessageString;
  1858. BEGIN
  1859. COPY(format, message);
  1860. Replace(message,"%0",s0);
  1861. RETURN message
  1862. END MessageS;
  1863. PROCEDURE MessageSS*(CONST format, s0, s1: ARRAY OF CHAR): MessageString;
  1864. VAR message: MessageString;
  1865. BEGIN
  1866. COPY(format, message);
  1867. Replace(message,"%0",s0);
  1868. Replace(message,"%1",s1);
  1869. RETURN message
  1870. END MessageSS;
  1871. PROCEDURE MessageI*(CONST format: ARRAY OF CHAR; i0: LONGINT): MessageString;
  1872. VAR message: MessageString; number: ARRAY 32 OF CHAR;
  1873. BEGIN
  1874. COPY(format, message);
  1875. Strings.IntToStr(i0,number);
  1876. Replace(message,"%0",number);
  1877. END MessageI;
  1878. PROCEDURE MessageSI*(CONST format: ARRAY OF CHAR; CONST s0: ARRAY OF CHAR; i1: LONGINT): MessageString;
  1879. VAR message: MessageString; number: ARRAY 32 OF CHAR;
  1880. BEGIN
  1881. COPY(format, message);
  1882. Replace(message,"%0",s0);
  1883. Strings.IntToStr(i1,number);
  1884. Replace(message,"%1",number);
  1885. END MessageSI;
  1886. (*
  1887. Get next available name from stream ignoring comments and end of comment brackets
  1888. Returns TRUE on success, returns FALSE on end of stream, on error or if "~" or ";" encountered.
  1889. Scanner based on Peek() feature of stream. Necessary to make it restartable.
  1890. *)
  1891. PROCEDURE GetStringParameter*(r: Streams.Reader; VAR string: ARRAY OF CHAR): BOOLEAN;
  1892. VAR ch: CHAR; i: LONGINT; done,error: BOOLEAN;
  1893. PROCEDURE Next;
  1894. BEGIN r.Char(ch); ch := r.Peek();
  1895. END Next;
  1896. PROCEDURE Append(ch: CHAR);
  1897. BEGIN string[i] := ch; INC(i)
  1898. END Append;
  1899. PROCEDURE SkipWhitespace;
  1900. BEGIN WHILE (ch <= " ") & (ch # 0X) DO Next END;
  1901. END SkipWhitespace;
  1902. PROCEDURE Comment;
  1903. VAR done: BOOLEAN;
  1904. BEGIN
  1905. done := FALSE;
  1906. Next;
  1907. REPEAT
  1908. CASE ch OF
  1909. |"(": Next; IF ch = "*" THEN Comment; SkipWhitespace END;
  1910. |"*": Next; IF ch =")" THEN Next; done:= TRUE END;
  1911. | 0X: done := TRUE;
  1912. ELSE Next;
  1913. END;
  1914. UNTIL done;
  1915. END Comment;
  1916. PROCEDURE String(delimiter: CHAR);
  1917. VAR done: BOOLEAN;
  1918. BEGIN
  1919. done := FALSE; Next;
  1920. REPEAT
  1921. IF ch = delimiter THEN done := TRUE; Next;
  1922. ELSIF ch = 0X THEN done := TRUE; error := TRUE;
  1923. ELSE Append(ch); Next;
  1924. END;
  1925. UNTIL done OR (i=LEN(string)-1);
  1926. END String;
  1927. BEGIN
  1928. i := 0; done := FALSE;
  1929. ch := r.Peek(); (* restart scanning *)
  1930. SkipWhitespace;
  1931. REPEAT
  1932. CASE ch OF
  1933. "(": Next; IF ch = "*" THEN Comment ; SkipWhitespace ELSE Append(ch) END;
  1934. | "*": Next; IF ch = ")" THEN Next; SkipWhitespace ELSE Append(ch) END;
  1935. | '"', "'": done := TRUE; IF i = 0 THEN String(ch) END;
  1936. | 0X .. ' ', '~', ';': done := TRUE;
  1937. ELSE
  1938. Append(ch);
  1939. Next;
  1940. END;
  1941. UNTIL done OR (i = LEN(string)-1);
  1942. string[i] := 0X;
  1943. RETURN (i > 0) & done & ~error;
  1944. END GetStringParameter;
  1945. PROCEDURE GetTracingDiagnostics*(diagnostics: Diagnostics.Diagnostics): Diagnostics.Diagnostics;
  1946. VAR tracing: TracingDiagnostics;
  1947. BEGIN
  1948. NEW(tracing, diagnostics); RETURN tracing
  1949. END GetTracingDiagnostics;
  1950. PROCEDURE InitTable32;
  1951. CONST poly = LONGINT(0EDB88320H);
  1952. VAR n, c, k: LONGINT;
  1953. BEGIN
  1954. FOR n := 0 TO 255 DO
  1955. c := n;
  1956. FOR k := 0 TO 7 DO
  1957. IF ODD(c) THEN c := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, poly) / SYSTEM.VAL(SET, LSH(c, -1)))
  1958. ELSE c := LSH(c, -1)
  1959. END
  1960. END;
  1961. CRC32Table[n] := SYSTEM.VAL(SET, c)
  1962. END
  1963. END InitTable32;
  1964. BEGIN
  1965. InitErrorMessages;
  1966. InitWindowWriter;
  1967. InitTable32;
  1968. lists := 0; enlarged := 0; strings := 0;
  1969. emptyString := MakeString("");
  1970. debug := FALSE;
  1971. invalidPosition.start := -1;
  1972. invalidPosition.end := -1;
  1973. invalidPosition.line := -1;
  1974. invalidPosition.linepos := -1;
  1975. NEW(integerObjects, 128);
  1976. END FoxBasic.
  1977. FoxBasic.ActivateDebug ~
  1978. FoxBasic.Test ~