FoxBasic.Mod 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467
  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* = -1;
  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. Integer* = SIGNED64;
  38. Set* = SET64;
  39. ObjectArray = POINTER TO ARRAY OF ANY;
  40. IntegerArray = POINTER TO ARRAY OF LONGINT;
  41. ErrorMsgs = POINTER TO ARRAY OF StringPool.Index;
  42. ComparisonFunction = PROCEDURE {DELEGATE} (object1, object2: ANY): BOOLEAN;
  43. Position*= RECORD
  44. start*, end*, line*, linepos*: LONGINT;
  45. reader*: Streams.Reader;
  46. END;
  47. ErrorCode*=LONGINT;
  48. Fingerprint* = ObjectFile.Fingerprint;
  49. List* = OBJECT (* by Luc Bläser *)
  50. VAR
  51. list: ObjectArray;
  52. count-: LONGINT;
  53. multipleAllowed*: BOOLEAN;
  54. nilAllowed*: BOOLEAN;
  55. PROCEDURE & InitList*(initialSize: LONGINT) ;
  56. BEGIN
  57. IF initialSize <= 0 THEN initialSize := 8 END;
  58. INC( lists ); NEW( list, initialSize ); count := 0; multipleAllowed := FALSE; nilAllowed := FALSE
  59. END InitList;
  60. PROCEDURE Length*( ): LONGINT;
  61. BEGIN
  62. RETURN count
  63. END Length;
  64. PROCEDURE Grow;
  65. VAR old: ObjectArray; i: LONGINT;
  66. BEGIN
  67. INC( enlarged ); old := list; NEW( list, (LEN( list ) * 3+1) DIV 2 (* more optimal for first-fit memory allocators *) ) ;
  68. FOR i := 0 TO count - 1 DO list[i] := old[i] END
  69. END Grow;
  70. PROCEDURE Get*( i: LONGINT ): ANY;
  71. BEGIN
  72. IF (i < 0) OR (i >= count) THEN HALT( 101 ) END;
  73. RETURN list[i]
  74. END Get;
  75. PROCEDURE Set*(i: LONGINT; x: ANY);
  76. BEGIN
  77. IF (i < 0) OR (i >= count) THEN HALT( 101 ) END;
  78. list[i] := x;
  79. END Set;
  80. PROCEDURE Add*( x: ANY );
  81. BEGIN
  82. IF ~nilAllowed THEN ASSERT( x # NIL ) END;
  83. IF ~multipleAllowed THEN ASSERT( ~debug OR ~Contains( x ) ) END; (* already contained *)
  84. IF count = LEN( list ) THEN Grow END;
  85. list[count] := x; INC( count )
  86. END Add;
  87. PROCEDURE Prepend*(x: ANY);
  88. VAR i: LONGINT;
  89. BEGIN
  90. IF ~nilAllowed THEN ASSERT( x # NIL ) END;
  91. IF ~multipleAllowed THEN ASSERT( debug OR ~Contains( x ) ) END; (* already contained *)
  92. IF count = LEN( list ) THEN Grow END;
  93. FOR i := count-1 TO 0 BY - 1 DO
  94. list[i+1] := list[i];
  95. END;
  96. list[0] := x; INC(count);
  97. END Prepend;
  98. PROCEDURE Append*(x: List);
  99. VAR i: LONGINT;
  100. BEGIN
  101. FOR i := 0 TO x.Length() - 1 DO
  102. IF multipleAllowed OR (~debug OR ~Contains(x.Get(i))) THEN
  103. Add(x.Get(i));
  104. END;
  105. END;
  106. END Append;
  107. PROCEDURE Remove*( x: ANY );
  108. VAR i: LONGINT;
  109. BEGIN
  110. i := 0;
  111. WHILE (i < count) & (list[i] # x) DO INC( i ) END;
  112. IF i < count THEN
  113. WHILE (i < count - 1) DO list[i] := list[i + 1]; INC( i ) END;
  114. DEC( count ); list[count] := NIL
  115. END
  116. END Remove;
  117. PROCEDURE RemoveByIndex*( i: LONGINT );
  118. BEGIN
  119. IF i < count THEN
  120. WHILE (i < count - 1) DO list[i] := list[i + 1]; INC( i ) END;
  121. DEC( count ); list[count] := NIL
  122. END
  123. END RemoveByIndex;
  124. PROCEDURE Insert*( i: LONGINT; x: ANY );
  125. VAR j: LONGINT;
  126. BEGIN
  127. IF ~nilAllowed THEN ASSERT( x # NIL ) END;
  128. IF ~multipleAllowed THEN ASSERT( ~debug OR ~Contains( x ) ) END; (* already contained *)
  129. IF count = LEN( list ) THEN Grow END; INC( count );
  130. j := count - 2;
  131. WHILE (j >= i) DO list[j+1] := list[j]; DEC( j ) END;
  132. list[i] := x;
  133. END Insert;
  134. PROCEDURE Replace*( x, y: ANY );
  135. VAR i: LONGINT;
  136. BEGIN
  137. IF ~nilAllowed THEN ASSERT( x # NIL ); ASSERT( y # NIL ) END;
  138. i := IndexOf( x );
  139. IF i >= 0 THEN list[i] := y END
  140. END Replace;
  141. PROCEDURE ReplaceByIndex*( i: LONGINT; x: ANY );
  142. BEGIN
  143. IF ~nilAllowed THEN ASSERT( x # NIL ) END;
  144. IF (i >= 0) & (i < count) THEN list[i] := x
  145. ELSE HALT( 101 ) (* out of boundaries *)
  146. END
  147. END ReplaceByIndex;
  148. (** If the object is not present, -1 is returned *)
  149. PROCEDURE IndexOf*( x: ANY ): LONGINT;
  150. VAR i: LONGINT;
  151. BEGIN
  152. i := 0;
  153. WHILE i < count DO
  154. IF list[i] = x THEN RETURN i END;
  155. INC( i )
  156. END;
  157. RETURN -1
  158. END IndexOf;
  159. PROCEDURE Contains*( x: ANY ): BOOLEAN;
  160. BEGIN
  161. RETURN IndexOf( x ) # -1
  162. END Contains;
  163. PROCEDURE Clear*;
  164. VAR i: LONGINT;
  165. BEGIN
  166. FOR i := 0 TO count - 1 DO list[i] := NIL END;
  167. count := 0
  168. END Clear;
  169. PROCEDURE GrowAndSet*(i: LONGINT; x: ANY);
  170. BEGIN
  171. IF (i<0) THEN HALT(101) END;
  172. WHILE i>=LEN(list) DO Grow END;
  173. list[i] := x;
  174. INC(i); IF count < i THEN count := i END;
  175. END GrowAndSet;
  176. PROCEDURE Sort*(comparisonFunction: ComparisonFunction);
  177. BEGIN
  178. IF count > 0 THEN
  179. QuickSort(comparisonFunction, 0, count - 1)
  180. END
  181. END Sort;
  182. PROCEDURE QuickSort(comparisonFunction: ComparisonFunction; lo, hi: LONGINT);
  183. VAR
  184. i, j: LONGINT;
  185. x, t: ANY;
  186. BEGIN
  187. i := lo; j := hi;
  188. x := list[(lo + hi) DIV 2];
  189. WHILE i <= j DO
  190. WHILE comparisonFunction(list[i], x) DO INC(i) END;
  191. WHILE comparisonFunction(x, list[j]) DO DEC(j) END;
  192. IF i <= j THEN
  193. (*IF (i < j) & comparisonFunction(list[j], list[i]) THEN*)
  194. t := list[i]; list[i] := list[j]; list[j] := t; (* swap i and j *)
  195. (*END;*)
  196. INC(i); DEC(j)
  197. END
  198. END;
  199. IF lo < j THEN QuickSort(comparisonFunction, lo, j) END;
  200. IF i < hi THEN QuickSort(comparisonFunction, i, hi) END
  201. END QuickSort;
  202. END List;
  203. HashEntryAny = RECORD
  204. key, value: ANY;
  205. valueInt: LONGINT;
  206. END;
  207. HashEntryInt = RECORD
  208. key, valueInt: LONGINT;
  209. value: ANY;
  210. END;
  211. HashAnyArray = POINTER TO ARRAY OF HashEntryAny;
  212. HashIntArray = POINTER TO ARRAY OF HashEntryInt;
  213. HashTable* = OBJECT
  214. VAR
  215. table: HashAnyArray;
  216. size: LONGINT;
  217. used-: LONGINT;
  218. maxLoadFactor: REAL;
  219. (* Interface *)
  220. PROCEDURE & Init* (initialSize: LONGINT);
  221. BEGIN
  222. ASSERT(initialSize > 2);
  223. NEW(table, initialSize);
  224. size := initialSize;
  225. used := 0;
  226. maxLoadFactor := 0.75;
  227. END Init;
  228. PROCEDURE Put*(key, value: ANY);
  229. VAR hash: LONGINT;
  230. BEGIN
  231. ASSERT(used < size);
  232. ASSERT(key # NIL);
  233. hash := HashValue(key);
  234. IF table[hash].key = NIL THEN
  235. INC(used, 1);
  236. ELSE
  237. ASSERT(table[hash].key = key);
  238. END;
  239. table[hash].key := key;
  240. table[hash].value := value;
  241. IF (used / size) > maxLoadFactor THEN Grow END;
  242. END Put;
  243. PROCEDURE Get*(key: ANY):ANY;
  244. BEGIN
  245. RETURN table[HashValue(key)].value;
  246. END Get;
  247. PROCEDURE Has*(key: ANY):BOOLEAN;
  248. BEGIN
  249. RETURN table[HashValue(key)].key = key;
  250. END Has;
  251. PROCEDURE Length*():LONGINT;
  252. BEGIN RETURN used; END Length;
  253. PROCEDURE Clear*;
  254. VAR i: LONGINT;
  255. BEGIN FOR i := 0 TO size - 1 DO table[i].key := NIL; table[i].value := NIL; table[i].valueInt := 0 END; END Clear;
  256. (* Interface for integer values *)
  257. PROCEDURE PutInt*(key: ANY; value: LONGINT);
  258. VAR hash: LONGINT;
  259. BEGIN
  260. ASSERT(used < size);
  261. hash := HashValue(key);
  262. IF table[hash].key = NIL THEN
  263. INC(used, 1);
  264. END;
  265. table[hash].key := key;
  266. table[hash].valueInt := value;
  267. IF (used / size) > maxLoadFactor THEN Grow END;
  268. END PutInt;
  269. PROCEDURE GetInt*(key: ANY):LONGINT;
  270. BEGIN RETURN table[HashValue(key)].valueInt; END GetInt;
  271. (* Internals *)
  272. (* only correctly working, if NIL key cannot be entered *)
  273. PROCEDURE HashValue(key: ANY):LONGINT;
  274. VAR value, h1, h2, i: LONGINT;
  275. BEGIN
  276. value := SYSTEM.VAL(LONGINT, key) DIV SIZEOF(ADDRESS);
  277. i := 0;
  278. h1 := value MOD size;
  279. h2 := 1; (* Linear probing *)
  280. REPEAT
  281. value := (h1 + i*h2) MOD size;
  282. INC(i);
  283. UNTIL((table[value].key = NIL) OR (table[value].key = key) OR (i > size));
  284. ASSERT((table[value].key = NIL) & (table[value].value = NIL) OR (table[value].key = key));
  285. RETURN value;
  286. END HashValue;
  287. PROCEDURE Grow;
  288. VAR oldTable: HashAnyArray; oldSize, i: LONGINT; key: ANY;
  289. BEGIN
  290. oldSize := size;
  291. oldTable := table;
  292. Init(size*2);
  293. FOR i := 0 TO oldSize-1 DO
  294. key := oldTable[i].key;
  295. IF key # NIL THEN
  296. IF oldTable[i].value # NIL THEN
  297. Put(key, oldTable[i].value);
  298. ELSE
  299. PutInt(key, oldTable[i].valueInt);
  300. END;
  301. END;
  302. END;
  303. END Grow;
  304. END HashTable;
  305. IntIterator*= OBJECT
  306. VAR
  307. table: HashIntArray;
  308. count : LONGINT;
  309. PROCEDURE & Init(t: HashIntArray);
  310. BEGIN
  311. table := t;
  312. count := -1;
  313. END Init;
  314. PROCEDURE GetNext*(VAR key: LONGINT; VAR value: ANY): BOOLEAN;
  315. BEGIN
  316. REPEAT
  317. INC(count);
  318. UNTIL (count = LEN(table)) OR (table[count].value # NIL);
  319. IF count = LEN(table) THEN
  320. RETURN FALSE
  321. END;
  322. key := table[count].key;
  323. value := table[count].value;
  324. RETURN TRUE;
  325. END GetNext;
  326. END IntIterator;
  327. HashTableInt* = OBJECT
  328. VAR
  329. table: HashIntArray;
  330. size: LONGINT;
  331. used-: LONGINT;
  332. maxLoadFactor: REAL;
  333. (* Interface *)
  334. PROCEDURE & Init* (initialSize: LONGINT);
  335. BEGIN
  336. ASSERT(initialSize > 2);
  337. NEW(table, initialSize);
  338. size := initialSize;
  339. used := 0;
  340. maxLoadFactor := 0.75;
  341. END Init;
  342. PROCEDURE Put*(key: LONGINT; value: ANY);
  343. VAR hash: LONGINT;
  344. BEGIN
  345. ASSERT(key # 0);
  346. ASSERT(used < size);
  347. hash := HashValue(key);
  348. IF table[hash].key = 0 THEN
  349. INC(used, 1);
  350. END;
  351. table[hash].key := key;
  352. table[hash].value := value;
  353. IF (used / size) > maxLoadFactor THEN Grow END;
  354. END Put;
  355. PROCEDURE Get*(key: LONGINT):ANY;
  356. BEGIN
  357. RETURN table[HashValue(key)].value;
  358. END Get;
  359. PROCEDURE Has*(key: LONGINT):BOOLEAN;
  360. BEGIN
  361. RETURN table[HashValue(key)].key = key;
  362. END Has;
  363. PROCEDURE Length*():LONGINT;
  364. BEGIN RETURN used; END Length;
  365. PROCEDURE Clear*;
  366. VAR i: LONGINT;
  367. BEGIN FOR i := 0 TO size - 1 DO table[i].key := 0; END; END Clear;
  368. (* Interface for integer values *)
  369. PROCEDURE PutInt*(key, value: LONGINT);
  370. VAR hash: LONGINT;
  371. BEGIN
  372. (*ASSERT(key # 0);*)
  373. ASSERT(used < size);
  374. hash := HashValue(key);
  375. IF table[hash].key = 0 THEN
  376. INC(used, 1);
  377. END;
  378. table[hash].key := key;
  379. table[hash].valueInt := value;
  380. IF (used / size) > maxLoadFactor THEN Grow END;
  381. END PutInt;
  382. PROCEDURE GetInt*(key: LONGINT):LONGINT;
  383. BEGIN RETURN table[HashValue(key)].valueInt; END GetInt;
  384. (* Internals *)
  385. PROCEDURE HashValue(key: LONGINT):LONGINT;
  386. VAR value, h1, h2, i: LONGINT;
  387. BEGIN
  388. i := 0;
  389. value := key;
  390. h1 := key MOD size;
  391. h2 := 1; (* Linear probing *)
  392. REPEAT
  393. value := (h1 + i*h2) MOD size;
  394. INC(i);
  395. UNTIL((table[value].key = 0) OR (table[value].key = key) OR (i > size));
  396. ASSERT((table[value].key = 0) OR (table[value].key = key));
  397. RETURN value;
  398. END HashValue;
  399. PROCEDURE Grow;
  400. VAR oldTable: HashIntArray; oldSize, i, key: LONGINT;
  401. BEGIN
  402. oldSize := size;
  403. oldTable := table;
  404. Init(size*2);
  405. FOR i := 0 TO oldSize-1 DO
  406. key := oldTable[i].key;
  407. IF key # 0 THEN
  408. IF oldTable[i].value # NIL THEN
  409. Put(key, oldTable[i].value);
  410. ELSE
  411. PutInt(key, oldTable[i].valueInt);
  412. END;
  413. END;
  414. END;
  415. END Grow;
  416. PROCEDURE GetIterator*(): IntIterator;
  417. VAR iterator: IntIterator;
  418. BEGIN
  419. NEW(iterator, table);
  420. RETURN iterator;
  421. END GetIterator;
  422. END HashTableInt;
  423. HashEntrySegmentedName = RECORD
  424. key: ObjectFile.SegmentedName; (* key[0]= MIN(LONGINT) <=> empty *)
  425. value: ANY;
  426. END;
  427. HashSegmentedNameArray = POINTER TO ARRAY OF HashEntrySegmentedName;
  428. HashTableSegmentedName* = OBJECT
  429. VAR
  430. table: HashSegmentedNameArray;
  431. size: LONGINT;
  432. used-: LONGINT;
  433. maxLoadFactor: REAL;
  434. (* Interface *)
  435. PROCEDURE & Init* (initialSize: LONGINT);
  436. BEGIN
  437. ASSERT(initialSize > 2);
  438. NEW(table, initialSize);
  439. size := initialSize;
  440. used := 0;
  441. maxLoadFactor := 0.75;
  442. Clear;
  443. END Init;
  444. PROCEDURE Put*(CONST key: SegmentedName; value: ANY);
  445. VAR hash: LONGINT;
  446. BEGIN
  447. ASSERT(used < size);
  448. hash := HashValue(key);
  449. IF table[hash].key[0] < 0 THEN
  450. INC(used, 1);
  451. END;
  452. table[hash].key := key;
  453. table[hash].value := value;
  454. IF (used / size) > maxLoadFactor THEN Grow END;
  455. END Put;
  456. PROCEDURE Get*(CONST key: SegmentedName):ANY;
  457. BEGIN
  458. RETURN table[HashValue(key)].value;
  459. END Get;
  460. PROCEDURE Has*(CONST key: SegmentedName):BOOLEAN;
  461. BEGIN
  462. RETURN table[HashValue(key)].key = key;
  463. END Has;
  464. PROCEDURE Length*():LONGINT;
  465. BEGIN RETURN used; END Length;
  466. PROCEDURE Clear*;
  467. VAR i: LONGINT;
  468. BEGIN FOR i := 0 TO size - 1 DO table[i].key[0] := -1; END; END Clear;
  469. (* Internals *)
  470. PROCEDURE Hash*(CONST name: SegmentedName): LONGINT;
  471. VAR fp,i: LONGINT;
  472. BEGIN
  473. fp := name[0]; i := 1;
  474. WHILE (i<LEN(name)) & (name[i] >= 0) DO
  475. fp:=SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, ROT(fp, 7)) / SYSTEM.VAL(SET, name[i]));
  476. INC(i);
  477. END;
  478. RETURN fp
  479. END Hash;
  480. PROCEDURE HashValue(CONST key: SegmentedName):LONGINT;
  481. VAR value, h,i: LONGINT;
  482. BEGIN
  483. ASSERT(key[0] >= 0);
  484. h := Hash(key);
  485. i := 0;
  486. REPEAT
  487. value := (h + i) MOD size;
  488. INC(i);
  489. UNTIL((table[value].key[0] < 0) OR (table[value].key = key) OR (i > size));
  490. ASSERT((table[value].key[0] <0 ) OR (table[value].key = key));
  491. RETURN value;
  492. END HashValue;
  493. PROCEDURE Grow;
  494. VAR oldTable: HashSegmentedNameArray; oldSize, i: LONGINT; key: SegmentedName;
  495. BEGIN
  496. oldSize := size;
  497. oldTable := table;
  498. Init(size*2);
  499. FOR i := 0 TO oldSize-1 DO
  500. key := oldTable[i].key;
  501. IF key[0] # MIN(LONGINT) THEN
  502. IF oldTable[i].value # NIL THEN
  503. Put(key, oldTable[i].value);
  504. END;
  505. END;
  506. END;
  507. END Grow;
  508. END HashTableSegmentedName;
  509. IntegerObject = OBJECT
  510. END IntegerObject;
  511. Writer* = OBJECT (Streams.Writer)
  512. VAR
  513. indent-: LONGINT;
  514. doindent: BOOLEAN;
  515. w-: Streams.Writer;
  516. PROCEDURE InitBasicWriter*( w: Streams.Writer );
  517. BEGIN
  518. SELF.w := w; indent := 0; doindent := TRUE;
  519. END InitBasicWriter;
  520. PROCEDURE & InitW(w: Streams.Writer); (* protect against use of NEW *)
  521. BEGIN InitBasicWriter(w);
  522. END InitW;
  523. PROCEDURE Reset*;
  524. BEGIN w.Reset;
  525. END Reset;
  526. PROCEDURE CanSetPos*( ): BOOLEAN;
  527. BEGIN RETURN w.CanSetPos();
  528. END CanSetPos;
  529. PROCEDURE SetPos*( pos: Streams.Position );
  530. BEGIN w.SetPos(pos);
  531. END SetPos;
  532. PROCEDURE Update*;
  533. BEGIN w.Update;
  534. END Update;
  535. PROCEDURE Pos*( ): Streams.Position;
  536. BEGIN RETURN w.Pos()
  537. END Pos;
  538. PROCEDURE Indent;
  539. VAR i: LONGINT;
  540. BEGIN
  541. IF doindent THEN
  542. FOR i := 0 TO indent-1 DO
  543. w.Char(9X);
  544. END;
  545. doindent := FALSE
  546. END;
  547. END Indent;
  548. PROCEDURE Char*( x: CHAR );
  549. BEGIN Indent; w.Char(x);
  550. END Char;
  551. PROCEDURE Bytes*(CONST x: ARRAY OF CHAR; ofs, len: LONGINT );
  552. BEGIN w.Bytes(x,ofs,len);
  553. END Bytes;
  554. PROCEDURE RawSInt*( x: SHORTINT );
  555. BEGIN w.RawSInt(x)
  556. END RawSInt;
  557. PROCEDURE RawInt*( x: INTEGER );
  558. BEGIN w.RawInt(x)
  559. END RawInt;
  560. PROCEDURE RawLInt*( x: LONGINT );
  561. BEGIN w.RawLInt(x)
  562. END RawLInt;
  563. PROCEDURE RawHInt*( x: HUGEINT );
  564. BEGIN w.RawHInt(x)
  565. END RawHInt;
  566. PROCEDURE Net32*( x: LONGINT );
  567. BEGIN w.Net32(x)
  568. END Net32;
  569. PROCEDURE Net16*( x: LONGINT );
  570. BEGIN w.Net16(x)
  571. END Net16;
  572. PROCEDURE Net8*( x: LONGINT );
  573. BEGIN w.Net8(x)
  574. END Net8;
  575. PROCEDURE RawSet*( x: SET );
  576. BEGIN w.RawSet(x)
  577. END RawSet;
  578. PROCEDURE RawBool*( x: BOOLEAN );
  579. BEGIN w.RawBool(x)
  580. END RawBool;
  581. PROCEDURE RawReal*( x: REAL );
  582. BEGIN w.RawReal(x)
  583. END RawReal;
  584. PROCEDURE RawLReal*( x: LONGREAL );
  585. BEGIN w.RawLReal(x)
  586. END RawLReal;
  587. PROCEDURE RawString*(CONST x: ARRAY OF CHAR );
  588. BEGIN w.RawString(x)
  589. END RawString;
  590. PROCEDURE RawNum*( x: HUGEINT );
  591. BEGIN w.RawNum(x)
  592. END RawNum;
  593. PROCEDURE Ln*;
  594. BEGIN w.Ln; doindent := TRUE;
  595. END Ln;
  596. PROCEDURE String*(CONST x: ARRAY OF CHAR );
  597. BEGIN Indent; w.String(x)
  598. END String;
  599. PROCEDURE Int*( x: HUGEINT; wd: SIZE );
  600. BEGIN Indent; w.Int(x,wd)
  601. END Int;
  602. PROCEDURE Set*( s: SET ); (* from P. Saladin *)
  603. BEGIN Indent; w.Set(s)
  604. END Set;
  605. PROCEDURE Hex*(x: HUGEINT; wd: SIZE );
  606. BEGIN Indent; w.Hex(x,wd)
  607. END Hex;
  608. PROCEDURE Address* (x: ADDRESS);
  609. BEGIN Indent; w.Address(x)
  610. END Address;
  611. PROCEDURE Date*( t, d: LONGINT );
  612. BEGIN Indent; w.Date(t,d)
  613. END Date;
  614. PROCEDURE Date822*( t, d, tz: LONGINT );
  615. BEGIN Indent; w.Date822(t,d,tz)
  616. END Date822;
  617. PROCEDURE Float*( x: LONGREAL; n: LONGINT );
  618. BEGIN Indent; w.Float(x,n)
  619. END Float;
  620. PROCEDURE FloatFix*( x: LONGREAL; n, f, D: LONGINT );
  621. BEGIN Indent; w.FloatFix(x,n,f,D)
  622. END FloatFix;
  623. PROCEDURE SetIndent*(i: LONGINT);
  624. BEGIN
  625. indent := i
  626. END SetIndent;
  627. PROCEDURE IncIndent*;
  628. BEGIN INC(indent)
  629. END IncIndent;
  630. PROCEDURE DecIndent*;
  631. BEGIN DEC(indent)
  632. END DecIndent;
  633. PROCEDURE BeginAlert*;
  634. END BeginAlert;
  635. PROCEDURE EndAlert*;
  636. END EndAlert;
  637. PROCEDURE BeginKeyword*;
  638. BEGIN
  639. END BeginKeyword;
  640. PROCEDURE EndKeyword*;
  641. BEGIN
  642. END EndKeyword;
  643. PROCEDURE BeginComment*;
  644. END BeginComment;
  645. PROCEDURE EndComment*;
  646. END EndComment;
  647. PROCEDURE AlertString*(CONST s: ARRAY OF CHAR);
  648. BEGIN
  649. BeginAlert; w.String(s); EndAlert;
  650. END AlertString;
  651. END Writer;
  652. TracingDiagnostics = OBJECT (Diagnostics.Diagnostics)
  653. VAR diagnostics: Diagnostics.Diagnostics;
  654. PROCEDURE &InitDiagnostics(diagnostics: Diagnostics.Diagnostics);
  655. BEGIN
  656. SELF.diagnostics := diagnostics
  657. END InitDiagnostics;
  658. PROCEDURE Error*(CONST source: ARRAY OF CHAR; position: Streams.Position; CONST message : ARRAY OF CHAR);
  659. BEGIN
  660. IF diagnostics # NIL THEN
  661. diagnostics.Error(source,position,message);
  662. END;
  663. D.Ln;
  664. D.String(" ---------------------- TRACE for COMPILER ERROR < ");
  665. D.String(source);
  666. IF position # Streams.Invalid THEN D.String("@"); D.Int(position,1) END;
  667. D.String(" "); D.String(message);
  668. D.String(" > ---------------------- ");
  669. D.TraceBack
  670. END Error;
  671. PROCEDURE Warning*(CONST source : ARRAY OF CHAR; position: Streams.Position; CONST message : ARRAY OF CHAR);
  672. BEGIN
  673. IF diagnostics # NIL THEN
  674. diagnostics.Warning(source,position,message);
  675. END;
  676. END Warning;
  677. PROCEDURE Information*(CONST source : ARRAY OF CHAR; position: Streams.Position; CONST message : ARRAY OF CHAR);
  678. BEGIN
  679. IF diagnostics # NIL THEN
  680. diagnostics.Information(source,position,message);
  681. END;
  682. END Information;
  683. END TracingDiagnostics;
  684. DebugWriterFactory*= PROCEDURE{DELEGATE} (CONST title: ARRAY OF CHAR): Streams.Writer;
  685. WriterFactory*=PROCEDURE{DELEGATE} (w: Streams.Writer): Writer;
  686. DiagnosticsFactory*=PROCEDURE{DELEGATE} (w: Streams.Writer): Diagnostics.Diagnostics;
  687. VAR
  688. lists-: LONGINT; enlarged-: LONGINT; strings-: LONGINT; integerObjects: HashTableInt;
  689. errMsg: ErrorMsgs; (*error messages*)
  690. emptyString-: String;
  691. debug: BOOLEAN;
  692. getDebugWriter: DebugWriterFactory;
  693. getWriter: WriterFactory;
  694. getDiagnostics: DiagnosticsFactory;
  695. invalidPosition-: Position;
  696. (* Make a string out of a series of characters. *)
  697. PROCEDURE MakeString*( CONST s: ARRAY OF CHAR ): String;
  698. (* VAR str: String; *)
  699. BEGIN
  700. INC( strings );
  701. (*
  702. (* allocation based *)
  703. NEW( str, Strings.Length( s ) +1); COPY( s, str^ ); RETURN str;
  704. *)
  705. RETURN StringPool.GetIndex1( s )
  706. END MakeString;
  707. PROCEDURE GetString*(s: String; VAR str: ARRAY OF CHAR);
  708. BEGIN
  709. StringPool.GetString(s,str);
  710. END GetString;
  711. PROCEDURE StringEqual*( s, t: String ): BOOLEAN;
  712. BEGIN
  713. RETURN s = t;
  714. (*
  715. (* allocation based *)
  716. RETURN s^ = t^
  717. *)
  718. END StringEqual;
  719. PROCEDURE GetErrorMessage*(err: LONGINT; CONST msg: ARRAY OF CHAR; VAR res: ARRAY OF CHAR);
  720. VAR str: ARRAY 128 OF CHAR;
  721. BEGIN
  722. res := "";
  723. IF (errMsg # NIL) & (0 <= err) & (err < LEN(errMsg)) THEN
  724. StringPool.GetString(errMsg[err], str);
  725. Strings.Append(res,str);
  726. Strings.Append(res, " ");
  727. END;
  728. Strings.Append(res, msg);
  729. Strings.Append(res, ". ");
  730. END GetErrorMessage;
  731. PROCEDURE AppendDetailedErrorMessage*(VAR message: ARRAY OF CHAR; pos: Position; reader: Streams.Reader);
  732. VAR err: ARRAY 512 OF CHAR; ch: CHAR; oldpos: LONGINT;
  733. BEGIN
  734. IF (reader # NIL) & (reader.CanSetPos()) THEN
  735. oldpos := reader.Pos();
  736. reader.SetPos(pos.linepos);
  737. reader.Char(ch);
  738. (* read until end of source line *)
  739. WHILE (ch # 0X) & (ch # 0AX) & (ch # 0DX) DO
  740. Strings.AppendChar(err, ch);
  741. IF reader.Pos() = pos.start THEN
  742. Strings.Append(err,"(*!*)");
  743. END;
  744. reader.Char(ch);
  745. END;
  746. reader.SetPos(oldpos);
  747. END;
  748. Strings.TrimWS(err);
  749. Strings.Append(message, err);
  750. END AppendDetailedErrorMessage;
  751. PROCEDURE AppendPosition*(VAR msg: ARRAY OF CHAR; pos: Position);
  752. BEGIN
  753. IF pos.line >= 0 THEN
  754. Strings.Append(msg, " in line ");
  755. Strings.AppendInt(msg, pos.line);
  756. Strings.Append(msg, ", col ");
  757. Strings.AppendInt(msg, pos.start- pos.linepos);
  758. END;
  759. END AppendPosition;
  760. PROCEDURE MakeMessage(pos: Position; code: ErrorCode; CONST msg: ARRAY OF CHAR; VAR message: ARRAY OF CHAR);
  761. BEGIN
  762. MakeDetailedMessage(pos, code, msg, NIL, message);
  763. Strings.AppendChar(message, 0X); (* terminate message *)
  764. END MakeMessage;
  765. PROCEDURE MakeDetailedMessage(pos: Position; code: ErrorCode; CONST msg: ARRAY OF CHAR; reader: Streams.Reader; VAR message: ARRAY OF CHAR);
  766. BEGIN
  767. GetErrorMessage(code, msg, message);
  768. AppendDetailedErrorMessage(message, pos, reader);
  769. AppendPosition(message, pos);
  770. END MakeDetailedMessage;
  771. (* error message with code *)
  772. PROCEDURE ErrorC*(diagnostics: Diagnostics.Diagnostics; CONST source: ARRAY OF CHAR; pos: Position; code: ErrorCode; CONST msg: ARRAY OF CHAR);
  773. VAR message: ARRAY 1024 OF CHAR; file: Files.File;
  774. PROCEDURE GetReader(): Streams.Reader;
  775. VAR reader := NIL: Streams.Reader; fileReader : Files.Reader;
  776. BEGIN
  777. IF (pos.linepos >= 0) & ((source # "") OR (pos.reader # NIL)) THEN
  778. reader := pos.reader;
  779. IF reader = NIL THEN
  780. file := Files.Old(source);
  781. IF file # NIL THEN
  782. NEW (fileReader, file, pos.linepos);
  783. reader := fileReader;
  784. END;
  785. END;
  786. END;
  787. RETURN reader;
  788. END GetReader;
  789. BEGIN
  790. IF diagnostics # NIL THEN
  791. MakeDetailedMessage(pos, code, msg, GetReader(), message);
  792. diagnostics.Error(source, pos.start, message);
  793. END;
  794. END ErrorC;
  795. (* error message without code *)
  796. PROCEDURE Error*(diagnostics: Diagnostics.Diagnostics; CONST source: ARRAY OF CHAR; pos: Position; CONST msg: ARRAY OF CHAR);
  797. BEGIN
  798. ErrorC(diagnostics, source, pos, InvalidCode, msg);
  799. END Error;
  800. PROCEDURE Warning*(diagnostics: Diagnostics.Diagnostics; CONST source: ARRAY OF CHAR; pos: Position; CONST msg: ARRAY OF CHAR);
  801. VAR message: ARRAY 256 OF CHAR;
  802. BEGIN
  803. IF diagnostics # NIL THEN
  804. MakeMessage(pos, InvalidCode, msg,message);
  805. diagnostics.Warning(source, pos.start, message);
  806. END;
  807. END Warning;
  808. PROCEDURE Information*(diagnostics: Diagnostics.Diagnostics; CONST source: ARRAY OF CHAR; pos: Position;CONST msg: ARRAY OF CHAR);
  809. VAR message: ARRAY 256 OF CHAR;
  810. BEGIN
  811. IF diagnostics # NIL THEN
  812. MakeMessage(pos, InvalidCode, msg,message);
  813. diagnostics.Information(source, pos.start, message);
  814. END;
  815. END Information;
  816. (** SetErrorMsg - Set message for error n *)
  817. PROCEDURE SetErrorMessage*(n: LONGINT; CONST msg: ARRAY OF CHAR);
  818. BEGIN
  819. IF errMsg = NIL THEN NEW(errMsg, InitErrMsgSize) END;
  820. WHILE LEN(errMsg^) < n DO Expand(errMsg) END;
  821. StringPool.GetIndex(msg, errMsg[n])
  822. END SetErrorMessage;
  823. PROCEDURE SetErrorExpected*(n: LONGINT; CONST msg: ARRAY OF CHAR);
  824. VAR err: ARRAY 256 OF CHAR;
  825. BEGIN
  826. err := "missing '";
  827. Strings.Append(err,msg);
  828. Strings.Append(err, "'");
  829. SetErrorMessage(n,err);
  830. END SetErrorExpected;
  831. PROCEDURE AppendNumber*(VAR s: ARRAY OF CHAR; num: LONGINT);
  832. VAR nums: ARRAY 32 OF CHAR;
  833. BEGIN
  834. Strings.IntToStr(num,nums);
  835. Strings.Append(s,nums);
  836. END AppendNumber;
  837. PROCEDURE InitSegmentedName*(VAR name: SegmentedName);
  838. VAR i: LONGINT;
  839. BEGIN FOR i := 0 TO LEN(name)-1 DO name[i] := -1 END;
  840. END InitSegmentedName;
  841. PROCEDURE ToSegmentedName*(CONST name: ARRAY OF CHAR; VAR pooledName: SegmentedName);
  842. BEGIN
  843. ObjectFile.StringToSegmentedName(name,pooledName);
  844. END ToSegmentedName;
  845. PROCEDURE SegmentedNameToString*(CONST pooledName: SegmentedName; VAR name: ARRAY OF CHAR);
  846. BEGIN
  847. ObjectFile.SegmentedNameToString(pooledName, name);
  848. END SegmentedNameToString;
  849. PROCEDURE WriteSegmentedName*(w: Streams.Writer; name: SegmentedName);
  850. VAR sectionName: ObjectFile.SectionName;
  851. BEGIN
  852. SegmentedNameToString(name, sectionName);
  853. w.String(sectionName);
  854. END WriteSegmentedName;
  855. PROCEDURE AppendToSegmentedName*(VAR name: SegmentedName; CONST this: ARRAY OF CHAR);
  856. VAR i,j: LONGINT; string: ObjectFile.SectionName;
  857. BEGIN
  858. i := 0;
  859. WHILE (i<LEN(name)) & (name[i] >= 0) DO
  860. INC(i)
  861. END;
  862. IF (this[0] = ".") & (i < LEN(name)) THEN (* suffix *)
  863. j := 0;
  864. WHILE this[j+1] # 0X DO
  865. string[j] := this[j+1];
  866. INC(j);
  867. END;
  868. string[j] := 0X;
  869. name[i] := StringPool.GetIndex1(string);
  870. IF i<LEN(name)-1 THEN name[i+1] := -1 END;
  871. ELSE
  872. StringPool.GetString(name[i-1], string);
  873. Strings.Append(string, this);
  874. name[i-1] := StringPool.GetIndex1(string);
  875. END;
  876. END AppendToSegmentedName;
  877. (* suffix using separation character "." *)
  878. PROCEDURE SuffixSegmentedName*(VAR name: SegmentedName; this: StringPool.Index);
  879. VAR string, suffix: ObjectFile.SectionName; i: LONGINT;
  880. BEGIN
  881. i := 0;
  882. WHILE (i < LEN(name)) & (name[i] >= 0) DO
  883. INC(i);
  884. END;
  885. IF i < LEN(name) THEN (* suffix *)
  886. name[i] := this;
  887. IF i<LEN(name)-1 THEN name[i+1] := -1 END;
  888. ELSE
  889. StringPool.GetString(name[i-1], string);
  890. StringPool.GetString(this, suffix);
  891. Strings.Append(string,".");
  892. Strings.Append(string, suffix);
  893. name[i-1] := StringPool.GetIndex1(string);
  894. END;
  895. END SuffixSegmentedName;
  896. PROCEDURE SegmentedNameEndsWith*(CONST name: SegmentedName; CONST this: ARRAY OF CHAR): BOOLEAN;
  897. VAR string: ObjectFile.SectionName; i: LONGINT;
  898. BEGIN
  899. i := 0;
  900. WHILE (i< LEN(name)) & (name[i] >= 0) DO
  901. INC(i);
  902. END;
  903. DEC(i);
  904. IF i < 0 THEN
  905. RETURN FALSE
  906. ELSE
  907. StringPool.GetString(name[i],string);
  908. RETURN Strings.EndsWith(this, string);
  909. END
  910. END SegmentedNameEndsWith;
  911. PROCEDURE RemoveSuffix*(VAR name: SegmentedName);
  912. VAR i,pos,pos0: LONGINT;string: ObjectFile.SectionName;
  913. BEGIN
  914. i := 0;
  915. WHILE (i< LEN(name)) & (name[i] >= 0) DO
  916. INC(i);
  917. END;
  918. ASSERT(i>0);
  919. IF i < LEN(name) THEN (* name[i] = empty *) name[i-1] := -1
  920. ELSE (* i = LEN(name), name[i] = nonempty *)
  921. DEC(i);
  922. StringPool.GetString(name[i],string);
  923. pos0 := 0; pos := 0;
  924. WHILE (pos0 < LEN(string)) & (string[pos0] # 0X) DO
  925. IF string[pos0] = "." THEN pos := pos0 END;
  926. INC(pos0);
  927. END;
  928. IF pos = 0 THEN (* no dot in name or name starts with dot *)
  929. name[i] := -1
  930. ELSE (* remove last part in name *)
  931. string[pos] := 0X;
  932. name[i] := StringPool.GetIndex1(string);
  933. END;
  934. END;
  935. END RemoveSuffix;
  936. PROCEDURE GetSuffix*(CONST name: SegmentedName; VAR string: ARRAY OF CHAR);
  937. VAR i,pos,pos0: LONGINT;
  938. BEGIN
  939. i := 0;
  940. WHILE (i< LEN(name)) & (name[i] >= 0) DO
  941. INC(i);
  942. END;
  943. ASSERT(i>0);
  944. StringPool.GetString(name[i-1],string);
  945. IF i = LEN(name) THEN
  946. pos0 := 0; pos := 0;
  947. WHILE (pos0 < LEN(string)) & (string[pos0] # 0X) DO
  948. IF string[pos0] = "." THEN pos := pos0 END;
  949. INC(pos0);
  950. END;
  951. IF pos # 0 THEN (* no dot in name or name starts with dot *)
  952. pos0 := 0;
  953. REPEAT
  954. INC(pos); (* start with character after "." *)
  955. string[pos0] := string[pos];
  956. INC(pos0);
  957. UNTIL string[pos] = 0X;
  958. END;
  959. END;
  960. END GetSuffix;
  961. PROCEDURE IsPrefix*(CONST prefix, of: SegmentedName): BOOLEAN;
  962. VAR prefixS, ofS: SectionName; i: LONGINT;
  963. BEGIN
  964. i := 0;
  965. WHILE (i< LEN(prefix)) & (prefix[i] = of[i]) DO INC(i) END;
  966. IF i = LEN(prefix) THEN RETURN TRUE (* identical *)
  967. ELSE (* prefix[i] # of[i] *)
  968. IF prefix[i] < 0 THEN RETURN TRUE
  969. ELSIF of[i] < 0 THEN RETURN FALSE
  970. ELSIF (i<LEN(prefix)-1) THEN RETURN FALSE
  971. ELSE
  972. StringPool.GetString(prefix[i], prefixS);
  973. StringPool.GetString(of[i], ofS);
  974. RETURN Strings.StartsWith(prefixS, 0, ofS)
  975. END
  976. END;
  977. END IsPrefix;
  978. PROCEDURE Expand(VAR oldAry: ErrorMsgs);
  979. VAR
  980. len, i: LONGINT;
  981. newAry: ErrorMsgs;
  982. BEGIN
  983. IF oldAry = NIL THEN RETURN END;
  984. len := LEN(oldAry^);
  985. NEW(newAry, len * 2);
  986. FOR i := 0 TO len-1 DO
  987. newAry[i] := oldAry[i];
  988. END;
  989. oldAry := newAry;
  990. END Expand;
  991. PROCEDURE Concat*(VAR result: ARRAY OF CHAR; CONST prefix, name, suffix: ARRAY OF CHAR);
  992. VAR i, j: LONGINT;
  993. BEGIN
  994. i := 0; WHILE prefix[i] # 0X DO result[i] := prefix[i]; INC(i) END;
  995. j := 0; WHILE name[j] # 0X DO result[i+j] := name[j]; INC(j) END;
  996. INC(i, j);
  997. j := 0; WHILE suffix[j] # 0X DO result[i+j] := suffix[j]; INC(j) END;
  998. result[i+j] := 0X;
  999. END Concat;
  1000. PROCEDURE Lowercase*(CONST name: ARRAY OF CHAR; VAR result: ARRAY OF CHAR);
  1001. VAR ch: CHAR; i: LONGINT;
  1002. BEGIN
  1003. i := 0;
  1004. REPEAT
  1005. ch := name[i];
  1006. IF (ch >= 'A') & (ch <= 'Z') THEN
  1007. ch := CHR(ORD(ch)-ORD('A')+ORD('a'));
  1008. END;
  1009. result[i] := ch; INC(i);
  1010. UNTIL ch = 0X;
  1011. END Lowercase;
  1012. PROCEDURE Uppercase*(CONST name: ARRAY OF CHAR; VAR result: ARRAY OF CHAR);
  1013. VAR ch: CHAR; i: LONGINT;
  1014. BEGIN
  1015. i := 0;
  1016. REPEAT
  1017. ch := name[i];
  1018. IF (ch >= 'a') & (ch <= 'z') THEN
  1019. ch := CHR(ORD(ch)-ORD('a')+ORD('A'));
  1020. END;
  1021. result[i] := ch; INC(i);
  1022. UNTIL ch = 0X;
  1023. END Uppercase;
  1024. PROCEDURE GetIntegerObj*(value: LONGINT):ANY;
  1025. VAR obj: IntegerObject;
  1026. BEGIN
  1027. IF integerObjects.Has(value) THEN
  1028. RETURN integerObjects.Get(value);
  1029. END;
  1030. NEW(obj);
  1031. integerObjects.Put(value, obj);
  1032. RETURN obj;
  1033. END GetIntegerObj;
  1034. PROCEDURE Align*(VAR offset: LONGINT; alignment: LONGINT);
  1035. BEGIN
  1036. IF alignment >0 THEN
  1037. INC(offset,(-offset) MOD alignment);
  1038. ELSIF alignment < 0 THEN
  1039. DEC(offset,offset MOD (-alignment));
  1040. END;
  1041. END Align;
  1042. PROCEDURE InitErrorMessages;
  1043. BEGIN
  1044. SetErrorMessage(UndeclaredIdentifier, "undeclared identifier");
  1045. SetErrorMessage(MultiplyDefinedIdentifier, "multiply defined identifier");
  1046. SetErrorMessage(NumberIllegalCharacter, "illegal character in number");
  1047. SetErrorMessage(StringIllegalCharacter, "illegal character in string");
  1048. SetErrorMessage(NoMatchProcedureName, "procedure name does not match");
  1049. SetErrorMessage(CommentNotClosed, "comment not closed");
  1050. SetErrorMessage(IllegalCharacterValue, "illegal character value");
  1051. SetErrorMessage(ValueStartIncorrectSymbol, "value starts with incorrect symbol");
  1052. SetErrorMessage(IllegalyMarkedIdentifier, "illegaly marked identifier");
  1053. SetErrorMessage(IdentifierNoType, "identifier is not a type");
  1054. SetErrorMessage(IdentifierNoRecordType, "identifier is not a record type");
  1055. SetErrorMessage(IdentifierNoObjectType, "identifier is not an object type");
  1056. SetErrorMessage(ImportNotAvailable, "import is not available");
  1057. SetErrorMessage(RecursiveTypeDeclaration, "recursive type declaration");
  1058. SetErrorMessage(NumberTooLarge, "number too large");
  1059. SetErrorMessage(IdentifierTooLong, "identifier too long");
  1060. SetErrorMessage(StringTooLong, "string too long");
  1061. END InitErrorMessages;
  1062. PROCEDURE ActivateDebug*;
  1063. BEGIN
  1064. debug := TRUE;
  1065. END ActivateDebug;
  1066. PROCEDURE Test*;
  1067. VAR table: HashTableInt; dump: LONGINT;
  1068. BEGIN
  1069. NEW(table, 32);
  1070. table.PutInt(32, -4);
  1071. dump := table.GetInt(32);
  1072. HALT(100);
  1073. END Test;
  1074. PROCEDURE GetFileReader*(CONST filename: ARRAY OF CHAR): Streams.Reader;
  1075. VAR
  1076. file: Files.File; fileReader: Files.Reader; offset: LONGINT;
  1077. BEGIN
  1078. (* Optimisation: skip header of oberon files and return a file reader instead of default text reader*)
  1079. file := Files.Old (filename);
  1080. IF file = NIL THEN RETURN NIL END;
  1081. NEW (fileReader, file, 0);
  1082. IF (fileReader.Get () = 0F0X) & (fileReader.Get () = 001X) THEN
  1083. offset := ORD (fileReader.Get ());
  1084. INC (offset, LONG (ORD (fileReader.Get ())) * 0100H);
  1085. fileReader.SetPos(offset);
  1086. ELSE fileReader.SetPos(0)
  1087. END;
  1088. RETURN fileReader
  1089. END GetFileReader;
  1090. PROCEDURE GetWriter*(w: Streams.Writer): Writer;
  1091. VAR writer: Writer;
  1092. BEGIN
  1093. ASSERT(w # NIL);
  1094. IF w IS Writer THEN RETURN w(Writer)
  1095. ELSIF getWriter = NIL THEN
  1096. NEW(writer,w); RETURN writer
  1097. ELSE RETURN getWriter(w)
  1098. END;
  1099. END GetWriter;
  1100. PROCEDURE GetDebugWriter*(CONST title: ARRAY OF CHAR): Streams.Writer;
  1101. VAR w: Streams.Writer;
  1102. BEGIN
  1103. IF getDebugWriter # NIL THEN w:= getDebugWriter(title)
  1104. ELSE NEW(w, KernelLog.Send,1024)
  1105. END;
  1106. RETURN w;
  1107. END GetDebugWriter;
  1108. PROCEDURE GetDiagnostics*(w: Streams.Writer): Diagnostics.Diagnostics;
  1109. VAR diagnostics: Diagnostics.StreamDiagnostics;
  1110. BEGIN
  1111. IF getDiagnostics # NIL THEN RETURN getDiagnostics(w)
  1112. ELSE NEW(diagnostics,w); RETURN diagnostics
  1113. END;
  1114. END GetDiagnostics;
  1115. PROCEDURE GetDefaultDiagnostics*(): Diagnostics.Diagnostics;
  1116. VAR w: Streams.Writer;
  1117. BEGIN
  1118. NEW(w, KernelLog.Send,128);
  1119. RETURN GetDiagnostics(w);
  1120. END GetDefaultDiagnostics;
  1121. PROCEDURE InitWindowWriter;
  1122. VAR install: PROCEDURE;
  1123. BEGIN
  1124. getDebugWriter := NIL; getWriter := NIL;
  1125. IF Modules.ModuleByName("WindowManager") # NIL THEN
  1126. GETPROCEDURE("FoxA2Interface","Install",install);
  1127. END;
  1128. IF install # NIL THEN install END;
  1129. END InitWindowWriter;
  1130. PROCEDURE InstallWriterFactory*(writer: WriterFactory; debug: DebugWriterFactory; diagnostics: DiagnosticsFactory);
  1131. BEGIN
  1132. getWriter := writer;
  1133. getDebugWriter := debug;
  1134. getDiagnostics := diagnostics;
  1135. END InstallWriterFactory;
  1136. PROCEDURE Replace(VAR in: ARRAY OF CHAR; CONST this, by: ARRAY OF CHAR);
  1137. VAR pos: SIZE;
  1138. BEGIN
  1139. pos := Strings.Pos(this,in);
  1140. IF pos >= 0 THEN
  1141. Strings.Delete(in,pos,Strings.Length(this));
  1142. Strings.Insert(by, in, pos);
  1143. END;
  1144. END Replace;
  1145. OPERATOR "="*(CONST left: ARRAY OF CHAR; right: String): BOOLEAN;
  1146. BEGIN
  1147. RETURN right = StringPool.GetIndex1(left);
  1148. END "=";
  1149. OPERATOR "="*(left: String; CONST right: ARRAY OF CHAR): BOOLEAN;
  1150. BEGIN
  1151. RETURN right = left;
  1152. END "=";
  1153. PROCEDURE MessageS*(CONST format, s0: ARRAY OF CHAR): MessageString;
  1154. VAR message: MessageString;
  1155. BEGIN
  1156. COPY(format, message);
  1157. Replace(message,"%0",s0);
  1158. RETURN message
  1159. END MessageS;
  1160. PROCEDURE MessageSS*(CONST format, s0, s1: ARRAY OF CHAR): MessageString;
  1161. VAR message: MessageString;
  1162. BEGIN
  1163. COPY(format, message);
  1164. Replace(message,"%0",s0);
  1165. Replace(message,"%1",s1);
  1166. RETURN message
  1167. END MessageSS;
  1168. PROCEDURE MessageI*(CONST format: ARRAY OF CHAR; i0: LONGINT): MessageString;
  1169. VAR message: MessageString; number: ARRAY 32 OF CHAR;
  1170. BEGIN
  1171. COPY(format, message);
  1172. Strings.IntToStr(i0,number);
  1173. Replace(message,"%0",number);
  1174. END MessageI;
  1175. PROCEDURE MessageSI*(CONST format: ARRAY OF CHAR; CONST s0: ARRAY OF CHAR; i1: LONGINT): MessageString;
  1176. VAR message: MessageString; number: ARRAY 32 OF CHAR;
  1177. BEGIN
  1178. COPY(format, message);
  1179. Replace(message,"%0",s0);
  1180. Strings.IntToStr(i1,number);
  1181. Replace(message,"%1",number);
  1182. END MessageSI;
  1183. (*
  1184. Get next available name from stream ignoring comments and end of comment brackets
  1185. Returns TRUE on success, returns FALSE on end of stream, on error or if "~" or ";" encountered.
  1186. Scanner based on Peek() feature of stream. Necessary to make it restartable.
  1187. *)
  1188. PROCEDURE GetStringParameter*(r: Streams.Reader; VAR string: ARRAY OF CHAR): BOOLEAN;
  1189. VAR ch: CHAR; i: LONGINT; done,error: BOOLEAN;
  1190. PROCEDURE Next;
  1191. BEGIN r.Char(ch); ch := r.Peek();
  1192. END Next;
  1193. PROCEDURE Append(ch: CHAR);
  1194. BEGIN string[i] := ch; INC(i)
  1195. END Append;
  1196. PROCEDURE SkipWhitespace;
  1197. BEGIN WHILE (ch <= " ") & (ch # 0X) DO Next END;
  1198. END SkipWhitespace;
  1199. PROCEDURE Comment;
  1200. VAR done: BOOLEAN;
  1201. BEGIN
  1202. done := FALSE;
  1203. Next;
  1204. REPEAT
  1205. CASE ch OF
  1206. |"(": Next; IF ch = "*" THEN Comment; SkipWhitespace END;
  1207. |"*": Next; IF ch =")" THEN Next; done:= TRUE END;
  1208. | 0X: done := TRUE;
  1209. ELSE Next;
  1210. END;
  1211. UNTIL done;
  1212. END Comment;
  1213. PROCEDURE String(delimiter: CHAR);
  1214. VAR done: BOOLEAN;
  1215. BEGIN
  1216. done := FALSE; Next;
  1217. REPEAT
  1218. IF ch = delimiter THEN done := TRUE; Next;
  1219. ELSIF ch = 0X THEN done := TRUE; error := TRUE;
  1220. ELSE Append(ch); Next;
  1221. END;
  1222. UNTIL done OR (i=LEN(string)-1);
  1223. END String;
  1224. BEGIN
  1225. i := 0; done := FALSE;
  1226. ch := r.Peek(); (* restart scanning *)
  1227. SkipWhitespace;
  1228. REPEAT
  1229. CASE ch OF
  1230. "(": Next; IF ch = "*" THEN Comment ; SkipWhitespace ELSE Append(ch) END;
  1231. | "*": Next; IF ch = ")" THEN Next; SkipWhitespace ELSE Append(ch) END;
  1232. | '"', "'": done := TRUE; IF i = 0 THEN String(ch) END;
  1233. | 0X .. ' ', '~', ';': done := TRUE;
  1234. ELSE
  1235. Append(ch);
  1236. Next;
  1237. END;
  1238. UNTIL done OR (i = LEN(string)-1);
  1239. string[i] := 0X;
  1240. RETURN (i > 0) & done & ~error;
  1241. END GetStringParameter;
  1242. PROCEDURE GetTracingDiagnostics*(diagnostics: Diagnostics.Diagnostics): Diagnostics.Diagnostics;
  1243. VAR tracing: TracingDiagnostics;
  1244. BEGIN
  1245. NEW(tracing, diagnostics); RETURN tracing
  1246. END GetTracingDiagnostics;
  1247. BEGIN
  1248. InitErrorMessages;
  1249. InitWindowWriter;
  1250. lists := 0; enlarged := 0; strings := 0;
  1251. emptyString := MakeString("");
  1252. debug := FALSE;
  1253. invalidPosition.start := -1;
  1254. invalidPosition.end := -1;
  1255. invalidPosition.line := -1;
  1256. invalidPosition.linepos := -1;
  1257. NEW(integerObjects, 128);
  1258. END FoxBasic.
  1259. FoxBasic.ActivateDebug ~
  1260. FoxBasic.Test ~