FoxBasic.Mod 37 KB

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