FoxBasic.Mod 54 KB

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