FoxBasic.Mod 54 KB

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