pmodules.pas 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195
  1. {
  2. $Id$
  3. Copyright (c) 1998 by Florian Klaempfl
  4. Handles the parsing and loading of the modules (ppufiles)
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit pmodules;
  19. interface
  20. uses
  21. dos,strings,
  22. cobjects,globals,scanner,symtable,aasm,tree,pass_1,
  23. types,hcodegen,files,verbose,systems,link,assemble
  24. {$ifdef GDB}
  25. ,gdb
  26. {$endif GDB}
  27. {$ifdef NEWPPU}
  28. ,ppu
  29. {$endif}
  30. { parser specific stuff }
  31. ,pbase,pdecl,pstatmnt,psub
  32. { processor specific stuff }
  33. {$ifdef i386}
  34. ,i386
  35. ,cgai386
  36. ,tgeni386
  37. ,cgi386
  38. ,aopt386
  39. {$endif}
  40. {$ifdef m68k}
  41. ,m68k
  42. ,cga68k
  43. ,tgen68k
  44. ,cg68k
  45. {$endif}
  46. ;
  47. procedure addlinkerfiles(hp:pmodule);
  48. function loadunit(const s : string;compile_system, in_uses : boolean) : pmodule;
  49. procedure proc_unit;
  50. procedure proc_program(islibrary : boolean);
  51. implementation
  52. uses
  53. parser;
  54. {$I innr.inc}
  55. procedure addlinkerfiles(hp:pmodule);
  56. begin
  57. with hp^ do
  58. begin
  59. while not linkofiles.empty do
  60. Linker.AddObject(linkofiles.Get);
  61. while not linksharedlibs.empty do
  62. Linker.AddSharedLibrary(linksharedlibs.Get);
  63. while not linkstaticlibs.empty do
  64. Linker.AddStaticLibrary(linkstaticlibs.Get);
  65. end;
  66. end;
  67. procedure insertsegment;
  68. begin
  69. {Insert Ident of the compiler}
  70. if (not (cs_smartlink in aktswitches))
  71. {$ifndef EXTDEBUG}
  72. and (not current_module^.is_unit)
  73. {$endif}
  74. then
  75. begin
  76. datasegment^.insert(new(pai_align,init(4)));
  77. datasegment^.insert(new(pai_string,init('FPC '+version_string+' for '+target_string+' - '+target_info.short_name)));
  78. end;
  79. { Insert start and end of sections }
  80. codesegment^.insert(new(pai_section,init(sec_code)));
  81. codesegment^.concat(new(pai_section,init(sec_none)));
  82. datasegment^.insert(new(pai_section,init(sec_data)));
  83. datasegment^.concat(new(pai_section,init(sec_none)));
  84. bsssegment^.insert(new(pai_section,init(sec_bss)));
  85. bsssegment^.concat(new(pai_section,init(sec_none)));
  86. consts^.insert(new(pai_asm_comment,init('Constants')));
  87. consts^.insert(new(pai_section,init(sec_data)));
  88. consts^.concat(new(pai_section,init(sec_none)));
  89. end;
  90. procedure insertheap;
  91. begin
  92. if (cs_smartlink in aktswitches) then
  93. begin
  94. bsssegment^.concat(new(pai_cut,init));
  95. datasegment^.concat(new(pai_cut,init));
  96. end;
  97. { On the Macintosh Classic M68k Architecture
  98. The Heap variable is simply a POINTER to the
  99. real HEAP. The HEAP must be set up by the RTL
  100. and must store the pointer in this value.
  101. On OS/2 the heap is also intialized by the RTL. We do
  102. not output a pointer }
  103. case target_info.target of
  104. target_OS2 : ;
  105. target_Mac68K : bsssegment^.concat(new(pai_datablock,init_global('HEAP',4)));
  106. else
  107. bsssegment^.concat(new(pai_datablock,init_global('HEAP',heapsize)));
  108. end;
  109. datasegment^.concat(new(pai_symbol,init_global('HEAPSIZE')));
  110. datasegment^.concat(new(pai_const,init_32bit(heapsize)));
  111. end;
  112. procedure inserttargetspecific;
  113. var
  114. i : longint;
  115. begin
  116. case target_info.target of
  117. target_GO32V2 : begin
  118. { stacksize can be specified }
  119. datasegment^.concat(new(pai_symbol,init_global('__stklen')));
  120. datasegment^.concat(new(pai_const,init_32bit(stacksize)));
  121. end;
  122. target_WIN32 : begin
  123. { generate the last entry for the imports directory }
  124. if not(assigned(importssection)) then
  125. importssection:=new(paasmoutput,init);
  126. { $3 ensure that it is the last entry, all other entries }
  127. { are written to $2 }
  128. importssection^.concat(new(pai_section,init_idata(3)));
  129. for i:=1 to 5 do
  130. importssection^.concat(new(pai_const,init_32bit(0)));
  131. end;
  132. end;
  133. end;
  134. { all intern procedures for system unit }
  135. procedure insertinternsyms(p : psymtable);
  136. begin
  137. p^.insert(new(psyssym,init('CONCAT',in_concat_x)));
  138. p^.insert(new(psyssym,init('WRITE',in_write_x)));
  139. p^.insert(new(psyssym,init('WRITELN',in_writeln_x)));
  140. p^.insert(new(psyssym,init('ASSIGNED',in_assigned_x)));
  141. p^.insert(new(psyssym,init('READ',in_read_x)));
  142. p^.insert(new(psyssym,init('READLN',in_readln_x)));
  143. p^.insert(new(psyssym,init('OFS',in_ofs_x)));
  144. p^.insert(new(psyssym,init('SIZEOF',in_sizeof_x)));
  145. p^.insert(new(psyssym,init('TYPEOF',in_typeof_x)));
  146. p^.insert(new(psyssym,init('LOW',in_low_x)));
  147. p^.insert(new(psyssym,init('HIGH',in_high_x)));
  148. p^.insert(new(psyssym,init('SEG',in_seg_x)));
  149. p^.insert(new(psyssym,init('ORD',in_ord_x)));
  150. p^.insert(new(psyssym,init('PRED',in_pred_x)));
  151. p^.insert(new(psyssym,init('SUCC',in_succ_x)));
  152. p^.insert(new(psyssym,init('EXCLUDE',in_exclude_x_y)));
  153. p^.insert(new(psyssym,init('INCLUDE',in_include_x_y)));
  154. p^.insert(new(psyssym,init('BREAK',in_break)));
  155. p^.insert(new(psyssym,init('CONTINUE',in_continue)));
  156. { for testing purpose }
  157. p^.insert(new(psyssym,init('DECI',in_dec_x)));
  158. p^.insert(new(psyssym,init('INCI',in_inc_x)));
  159. p^.insert(new(psyssym,init('STR',in_str_x_string)));
  160. end;
  161. { all the types inserted into the system unit }
  162. procedure insert_intern_types(p : psymtable);
  163. {$ifdef GDB}
  164. var
  165. { several defs to simulate more or less C++ objects for GDB }
  166. vmtdef : precdef;
  167. pvmtdef : ppointerdef;
  168. vmtarraydef : parraydef;
  169. vmtsymtable : psymtable;
  170. {$endif GDB}
  171. begin
  172. p^.insert(new(ptypesym,init('longint',s32bitdef)));
  173. p^.insert(new(ptypesym,init('ulong',u32bitdef)));
  174. p^.insert(new(ptypesym,init('void',voiddef)));
  175. p^.insert(new(ptypesym,init('char',cchardef)));
  176. {$ifdef i386}
  177. p^.insert(new(ptypesym,init('s64real',c64floatdef)));
  178. {$endif i386}
  179. p^.insert(new(ptypesym,init('s80real',s80floatdef)));
  180. p^.insert(new(ptypesym,init('cs32fixed',s32fixeddef)));
  181. p^.insert(new(ptypesym,init('byte',u8bitdef)));
  182. p^.insert(new(ptypesym,init('string',cstringdef)));
  183. p^.insert(new(ptypesym,init('longstring',clongstringdef)));
  184. p^.insert(new(ptypesym,init('ansistring',cansistringdef)));
  185. p^.insert(new(ptypesym,init('widestring',cwidestringdef)));
  186. p^.insert(new(ptypesym,init('word',u16bitdef)));
  187. p^.insert(new(ptypesym,init('boolean',booldef)));
  188. p^.insert(new(ptypesym,init('void_pointer',voidpointerdef)));
  189. p^.insert(new(ptypesym,init('file',cfiledef)));
  190. {$ifdef i386}
  191. p^.insert(new(ptypesym,init('REAL',new(pfloatdef,init(s64real)))));
  192. p^.insert(new(ptypesym,init('COMP',new(pfloatdef,init(s64bit)))));
  193. p^.insert(new(ptypesym,init('EXTENDED',new(pfloatdef,init(s80real)))));
  194. {$endif}
  195. {$ifdef m68k}
  196. { internal definitions }
  197. p^.insert(new(ptypesym,init('s32real',c64floatdef)));
  198. { mappings... }
  199. p^.insert(new(ptypesym,init('REAL',new(pfloatdef,init(s32real)))));
  200. if (cs_fp_emulation) in aktswitches then
  201. p^.insert(new(ptypesym,init('DOUBLE',new(pfloatdef,init(s32real)))))
  202. else
  203. p^.insert(new(ptypesym,init('DOUBLE',new(pfloatdef,init(s64real)))));
  204. { p^.insert(new(ptypesym,init('COMP',new(pfloatdef,init(s32real)))));}
  205. if (cs_fp_emulation) in aktswitches then
  206. p^.insert(new(ptypesym,init('EXTENDED',new(pfloatdef,init(s32real)))))
  207. else
  208. p^.insert(new(ptypesym,init('EXTENDED',new(pfloatdef,init(s80real)))));
  209. {$endif}
  210. p^.insert(new(ptypesym,init('SINGLE',new(pfloatdef,init(s32real)))));
  211. p^.insert(new(ptypesym,init('POINTER',new(ppointerdef,init(voiddef)))));
  212. p^.insert(new(ptypesym,init('STRING',cstringdef)));
  213. p^.insert(new(ptypesym,init('LONGSTRING',clongstringdef)));
  214. p^.insert(new(ptypesym,init('ANSISTRING',cansistringdef)));
  215. p^.insert(new(ptypesym,init('WIDESTRING',cwidestringdef)));
  216. p^.insert(new(ptypesym,init('BOOLEAN',new(porddef,init(bool8bit,0,1)))));
  217. p^.insert(new(ptypesym,init('CHAR',new(porddef,init(uchar,0,255)))));
  218. p^.insert(new(ptypesym,init('TEXT',new(pfiledef,init(ft_text,nil)))));
  219. p^.insert(new(ptypesym,init('CARDINAL',new(porddef,init(u32bit,0,$ffffffff)))));
  220. p^.insert(new(ptypesym,init('FIXED',new(pfloatdef,init(f32bit)))));
  221. p^.insert(new(ptypesym,init('FIXED16',new(pfloatdef,init(f16bit)))));
  222. p^.insert(new(ptypesym,init('TYPEDFILE',new(pfiledef,init(ft_typed,voiddef)))));
  223. { !!!!!
  224. p^.insert(new(ptypesym,init('COMP',new(porddef,init(s64bit,0,0)))));
  225. p^.insert(new(ptypesym,init('SINGLE',new(porddef,init(s32real,0,0)))));
  226. p^.insert(new(ptypesym,init('EXTENDED',new(porddef,init(s80real,0,0)))));
  227. p^.insert(new(ptypesym,init('FILE',new(pfiledef,init(ft_untyped,nil)))));
  228. }
  229. { Add a type for virtual method tables in lowercase }
  230. { so it isn't reachable! }
  231. {$ifdef GDB}
  232. vmtsymtable:=new(psymtable,init(recordsymtable));
  233. vmtdef:=new(precdef,init(vmtsymtable));
  234. pvmtdef:=new(ppointerdef,init(vmtdef));
  235. vmtsymtable^.insert(new(pvarsym,init('parent',pvmtdef)));
  236. vmtsymtable^.insert(new(pvarsym,init('length',globaldef('longint'))));
  237. vmtsymtable^.insert(new(pvarsym,init('mlength',globaldef('longint'))));
  238. vmtarraydef:=new(parraydef,init(0,1,s32bitdef));
  239. vmtarraydef^.definition := voidpointerdef;
  240. vmtsymtable^.insert(new(pvarsym,init('__pfn',vmtarraydef)));
  241. p^.insert(new(ptypesym,init('__vtbl_ptr_type',vmtdef)));
  242. p^.insert(new(ptypesym,init('pvmt',pvmtdef)));
  243. vmtarraydef:=new(parraydef,init(0,1,s32bitdef));
  244. vmtarraydef^.definition := pvmtdef;
  245. p^.insert(new(ptypesym,init('vtblarray',vmtarraydef)));
  246. {$endif GDB}
  247. insertinternsyms(p);
  248. end;
  249. procedure load_ppu(oldhp,hp : pmodule;compile_system : boolean);
  250. var
  251. loaded_unit : pmodule;
  252. b : byte;
  253. checksum,
  254. {$ifndef NEWPPU}
  255. count,
  256. {$endif NEWPPU}
  257. nextmapentry : longint;
  258. hs : string;
  259. begin
  260. { init the map }
  261. new(hp^.map);
  262. nextmapentry:=1;
  263. {$ifdef NEWPPU}
  264. { load the used units from interface }
  265. b:=hp^.ppufile^.readentry;
  266. if b=ibloadunit_int then
  267. begin
  268. while not hp^.ppufile^.endofentry do
  269. begin
  270. hs:=hp^.ppufile^.getstring;
  271. checksum:=hp^.ppufile^.getlongint;
  272. loaded_unit:=loadunit(hs,false,false);
  273. if hp^.compiled then
  274. exit;
  275. { if the crc of a used unit is the same as written to the
  276. PPU file, we needn't to recompile the current unit }
  277. if (loaded_unit^.crc<>checksum) then
  278. begin
  279. { we have to compile the current unit remove stuff which isn't
  280. needed }
  281. { forget the map }
  282. dispose(hp^.map);
  283. hp^.map:=nil;
  284. { remove the ppufile }
  285. dispose(hp^.ppufile,done);
  286. hp^.ppufile:=nil;
  287. { recompile or give an fatal error }
  288. if not(hp^.sources_avail) then
  289. Message1(unit_f_cant_compile_unit,hp^.modulename^)
  290. else
  291. begin
  292. {$ifdef TEST_TEMPCLOSE}
  293. if assigned(oldhp^.current_inputfile) then
  294. oldhp^.current_inputfile^.tempclose;
  295. {$endif TEST_TEMPCLOSE}
  296. compile(hp^.mainsource^,compile_system);
  297. {$ifdef TEST_TEMPCLOSE}
  298. if not oldhp^.compiled then
  299. oldhp^.current_inputfile^.tempreopen;
  300. {$endif TEST_TEMPCLOSE}
  301. end;
  302. exit;
  303. end;
  304. { setup the map entry for deref }
  305. hp^.map^[nextmapentry]:=loaded_unit^.symtable;
  306. inc(nextmapentry);
  307. if nextmapentry>maxunits then
  308. Message(unit_f_too_much_units);
  309. end;
  310. { ok, now load the unit }
  311. hp^.symtable:=new(punitsymtable,load(hp^.modulename^));
  312. { if this is the system unit insert the intern symbols }
  313. make_ref:=false;
  314. if compile_system then
  315. insertinternsyms(psymtable(hp^.symtable));
  316. make_ref:=true;
  317. end;
  318. { now only read the implementation part }
  319. hp^.in_implementation:=true;
  320. { load the used units from implementation }
  321. b:=hp^.ppufile^.readentry;
  322. if b=ibloadunit_imp then
  323. begin
  324. while not hp^.ppufile^.endofentry do
  325. begin
  326. hs:=hp^.ppufile^.getstring;
  327. checksum:=hp^.ppufile^.getlongint;
  328. loaded_unit:=loadunit(hs,false,false);
  329. if hp^.compiled then
  330. exit;
  331. end;
  332. end;
  333. hp^.ppufile^.close;
  334. {! dispose(hp^.ppufile,done);}
  335. {$else}
  336. { load the used units from interface }
  337. hp^.ppufile^.read_data(b,1,count);
  338. while (b=ibloadunit) do
  339. begin
  340. { read unit name }
  341. hp^.ppufile^.read_data(hs[0],1,count);
  342. hp^.ppufile^.read_data(hs[1],byte(hs[0]),count);
  343. hp^.ppufile^.read_data(checksum,4,count);
  344. loaded_unit:=loadunit(hs,false,false);
  345. if hp^.compiled then
  346. exit;
  347. { if the crc of a used unit is the same as }
  348. { written to the PPU file, we needn't to }
  349. { recompile the current unit }
  350. if (loaded_unit^.crc<>checksum) then
  351. begin
  352. { we have to compile the current unit }
  353. { remove stuff which isn't needed }
  354. { forget the map }
  355. dispose(hp^.map);
  356. hp^.map:=nil;
  357. hp^.ppufile^.close;
  358. dispose(hp^.ppufile,done);
  359. hp^.ppufile:=nil;
  360. if not(hp^.sources_avail) then
  361. Message1(unit_f_cant_compile_unit,hp^.modulename^)
  362. else
  363. begin
  364. {$ifdef TEST_TEMPCLOSE}
  365. if assigned(oldhp^.current_inputfile) then
  366. oldhp^.current_inputfile^.tempclose;
  367. {$endif TEST_TEMPCLOSE}
  368. compile(hp^.mainsource^,compile_system);
  369. {$ifdef TEST_TEMPCLOSE}
  370. if not oldhp^.compiled then
  371. oldhp^.current_inputfile^.tempreopen;
  372. {$endif TEST_TEMPCLOSE}
  373. end;
  374. exit;
  375. end;
  376. { setup the map entry for deref }
  377. hp^.map^[nextmapentry]:=loaded_unit^.symtable;
  378. inc(nextmapentry);
  379. if nextmapentry>maxunits then
  380. Message(unit_f_too_much_units);
  381. { read until ibend }
  382. hp^.ppufile^.read_data(b,1,count);
  383. end;
  384. { ok, now load the unit }
  385. hp^.symtable:=new(punitsymtable,load(hp^.modulename^));
  386. { if this is the system unit insert the intern }
  387. { symbols }
  388. make_ref:=false;
  389. if compile_system then
  390. insertinternsyms(psymtable(hp^.symtable));
  391. make_ref:=true;
  392. { now only read the implementation part }
  393. hp^.in_implementation:=true;
  394. { load the used units from implementation }
  395. hp^.ppufile^.read_data(b,1,count);
  396. while (b<>ibend) and (b=ibloadunit) do
  397. begin
  398. { read unit name }
  399. hp^.ppufile^.read_data(hs[0],1,count);
  400. hp^.ppufile^.read_data(hs[1],byte(hs[0]),count);
  401. hp^.ppufile^.read_data(checksum,4,count);
  402. loaded_unit:=loadunit(hs,false,false);
  403. if hp^.compiled then exit;
  404. { if the crc of a used unit is the same as }
  405. { written to the PPU file, we needn't to }
  406. { recompile the current unit }
  407. { but for the implementation part }
  408. { the written crc is false, because }
  409. { not defined when writing the ppufile !! }
  410. (* if {(loaded_unit^.crc<>checksum) or}
  411. (do_build and loaded_unit^.sources_avail) then
  412. begin
  413. { we have to compile the current unit }
  414. { remove stuff which isn't needed }
  415. { forget the map }
  416. dispose(hp^.map);
  417. hp^.map:=nil;
  418. hp^.ppufile^.close;
  419. dispose(hp^.ppufile,done);
  420. hp^.ppufile:=nil;
  421. if not(hp^.sources_avail) then
  422. Message1(unit_f_cant_compile_unit,hp^.unitname^)
  423. else
  424. begin
  425. {ifdef TEST_TEMPCLOSE}
  426. oldhp^.current_inputfile^.tempclose;
  427. {endif TEST_TEMPCLOSE}
  428. compile(hp^.mainsource^,compile_system);
  429. {ifdef TEST_TEMPCLOSE}
  430. oldhp^.current_inputfile^.tempclose;
  431. {endif TEST_TEMPCLOSE}
  432. end;
  433. exit;
  434. end; *)
  435. { read until ibend }
  436. hp^.ppufile^.read_data(b,1,count);
  437. end;
  438. hp^.ppufile^.close;
  439. {$endif}
  440. dispose(hp^.map);
  441. hp^.map:=nil;
  442. end;
  443. function loadunit(const s : string;compile_system, in_uses : boolean) : pmodule;
  444. var
  445. st : punitsymtable;
  446. old_current_module,hp,nextmodule : pmodule;
  447. pu : pused_unit;
  448. hs : pstring;
  449. begin
  450. old_current_module:=current_module;
  451. { be sure not to mix lines from different files }
  452. { update_line; }
  453. { unit not found }
  454. st:=nil;
  455. { search all loaded units }
  456. hp:=pmodule(loaded_units.first);
  457. while assigned(hp) do
  458. begin
  459. if hp^.modulename^=s then
  460. begin
  461. { the unit is already registered }
  462. { and this means that the unit }
  463. { is already compiled }
  464. { else there is a cyclic unit use }
  465. if assigned(hp^.symtable) then
  466. st:=punitsymtable(hp^.symtable)
  467. else
  468. begin
  469. { recompile the unit ? }
  470. if (not current_module^.in_implementation) and (hp^.in_implementation) then
  471. Message(unit_f_circular_unit_reference);
  472. end;
  473. break;
  474. end;
  475. { the next unit }
  476. hp:=pmodule(hp^.next);
  477. end;
  478. { no error and the unit isn't loaded }
  479. if not(assigned(hp)) and (st=nil) then
  480. begin
  481. { generates a new unit info record }
  482. hp:=new(pmodule,init(s,true));
  483. { now we can register the unit }
  484. loaded_units.insert(hp);
  485. current_module:=hp;
  486. { force build ? }
  487. if (hp^.do_compile) or (hp^.sources_avail and do_build) then
  488. begin
  489. { we needn't the ppufile }
  490. if assigned(hp^.ppufile) then
  491. begin
  492. dispose(hp^.ppufile,done);
  493. hp^.ppufile:=nil;
  494. end;
  495. if not(hp^.sources_avail) then
  496. Message1(unit_f_cant_compile_unit,hp^.modulename^)
  497. else
  498. begin
  499. {$ifdef TEST_TEMPCLOSE}
  500. if assigned(old_current_module^.current_inputfile) then
  501. old_current_module^.current_inputfile^.tempclose;
  502. {$endif TEST_TEMPCLOSE}
  503. compile(hp^.mainsource^,compile_system);
  504. {$ifdef TEST_TEMPCLOSE}
  505. if not old_current_module^.compiled then
  506. old_current_module^.current_inputfile^.tempreopen;
  507. {$endif TEST_TEMPCLOSE}
  508. end;
  509. end
  510. else
  511. begin
  512. { only reassemble ? }
  513. if (hp^.do_assemble) then
  514. OnlyAsm(hp^.asmfilename^);
  515. { we should know there the PPU file else it's an error and
  516. we can't load the unit }
  517. {$ifdef NEWPPU}
  518. { if hp^.ppufile^.name^<>'' then}
  519. {$else}
  520. if hp^.ppufile^.name^<>'' then
  521. {$endif}
  522. load_ppu(old_current_module,hp,compile_system);
  523. { add the files for the linker }
  524. addlinkerfiles(hp);
  525. end;
  526. { register the unit _once_ }
  527. usedunits.concat(new(pused_unit,init(hp,0)));
  528. { the unit is written, so we can set the symtable type }
  529. { to unitsymtable, else we get some dupid errors }
  530. { this is not the right place because of the }
  531. { ready label }
  532. { psymtable(hp^.symtable)^.symtabletype:=unitsymtable; }
  533. { placed at this end of proc_unit }
  534. psymtable(hp^.symtable)^.unitid:=0;
  535. { reset the unitnumbers for the other units }
  536. pu:=pused_unit(old_current_module^.used_units.first);
  537. while assigned(pu) do
  538. begin
  539. psymtable(pu^.u^.symtable)^.unitid:=pu^.unitid;
  540. pu:=pused_unit(pu^.next);
  541. end;
  542. end
  543. else
  544. if assigned(hp) and (st=nil) then
  545. begin
  546. { we have to compile the unit again, but it is already inserted !!}
  547. { we may have problem with the lost symtable !! }
  548. current_module:=hp;
  549. { we must preserve the unit chain }
  550. nextmodule:=pmodule(hp^.next);
  551. { we have to cleanup a little }
  552. hp^.special_done;
  553. new(hs);
  554. hs^:=hp^.mainsource^;
  555. hp^.init(hs^,true);
  556. dispose(hs);
  557. { we must preserve the unit chain }
  558. hp^.next:=nextmodule;
  559. if assigned(hp^.ppufile) then
  560. load_ppu(old_current_module,hp,compile_system)
  561. else
  562. begin
  563. {$ifdef UseBrowser}
  564. { here we need to remove the names ! }
  565. hp^.sourcefiles.done;
  566. hp^.sourcefiles.init;
  567. {$endif not UseBrowser}
  568. {$ifdef TEST_TEMPCLOSE}
  569. if assigned(old_current_module^.current_inputfile) then
  570. old_current_module^.current_inputfile^.tempclose;
  571. {$endif TEST_TEMPCLOSE}
  572. Message1(parser_d_compiling_second_time,hp^.mainsource^);
  573. compile(hp^.mainsource^,compile_system);
  574. {$ifdef TEST_TEMPCLOSE}
  575. if not old_current_module^.compiled then
  576. old_current_module^.current_inputfile^.tempreopen;
  577. {$endif TEST_TEMPCLOSE}
  578. end;
  579. current_module^.compiled:=true;
  580. end;
  581. { set the old module }
  582. current_module:=old_current_module;
  583. { the current module uses the unit hp }
  584. current_module^.used_units.concat(new(pused_unit,init(hp,0)));
  585. pused_unit(current_module^.used_units.last)^.in_uses:=in_uses;
  586. if in_uses and not current_module^.in_implementation then
  587. pused_unit(current_module^.used_units.last)^.in_interface:=true;
  588. loadunit:=hp;
  589. end;
  590. procedure loadunits;
  591. var
  592. s : stringid;
  593. hp : pused_unit;
  594. hp2 : pmodule;
  595. hp3 : psymtable;
  596. oldprocsym:Pprocsym;
  597. begin
  598. oldprocsym:=aktprocsym;
  599. consume(_USES);
  600. {$ifdef DEBUG}
  601. test_symtablestack;
  602. {$endif DEBUG}
  603. repeat
  604. s:=pattern;
  605. consume(ID);
  606. hp2:=loadunit(s,false,true);
  607. if current_module^.compiled then
  608. exit;
  609. refsymtable^.insert(new(punitsym,init(s,hp2^.symtable)));
  610. if token=COMMA then
  611. begin
  612. pattern:='';
  613. consume(COMMA);
  614. end
  615. else
  616. break;
  617. until false;
  618. consume(SEMICOLON);
  619. { now insert the units in the symtablestack }
  620. hp:=pused_unit(current_module^.used_units.first);
  621. { set the symtable to systemunit so it gets reorderd correctly }
  622. symtablestack:=systemunit;
  623. while assigned(hp) do
  624. begin
  625. {$IfDef GDB}
  626. if (cs_debuginfo in aktswitches) and
  627. not hp^.is_stab_written then
  628. begin
  629. punitsymtable(hp^.u^.symtable)^.concattypestabto(debuglist);
  630. hp^.is_stab_written:=true;
  631. hp^.unitid:=psymtable(hp^.u^.symtable)^.unitid;
  632. end;
  633. {$EndIf GDB}
  634. if hp^.in_uses then
  635. begin
  636. hp3:=symtablestack;
  637. while assigned(hp3) do
  638. begin
  639. { insert units only once ! }
  640. if hp^.u^.symtable=hp3 then
  641. break;
  642. hp3:=hp3^.next;
  643. { unit isn't inserted }
  644. if hp3=nil then
  645. begin
  646. psymtable(hp^.u^.symtable)^.next:=symtablestack;
  647. symtablestack:=psymtable(hp^.u^.symtable);
  648. {$ifdef CHAINPROCSYMS}
  649. symtablestack^.chainprocsyms;
  650. {$endif CHAINPROCSYMS}
  651. {$ifdef DEBUG}
  652. test_symtablestack;
  653. {$endif DEBUG}
  654. end;
  655. end;
  656. end;
  657. hp:=pused_unit(hp^.next);
  658. end;
  659. aktprocsym:=oldprocsym;
  660. end;
  661. procedure parse_implementation_uses(symt:Psymtable);
  662. var
  663. old_module_in_implementation : boolean;
  664. begin
  665. if token=_USES then
  666. begin
  667. old_module_in_implementation:=module_in_implementation;
  668. module_in_implementation:=true;
  669. current_module^.in_implementation:=true;
  670. symt^.symtabletype:=unitsymtable;
  671. loadunits;
  672. symt^.symtabletype:=globalsymtable;
  673. {$ifdef DEBUG}
  674. test_symtablestack;
  675. {$endif DEBUG}
  676. module_in_implementation:=old_module_in_implementation;
  677. end;
  678. end;
  679. procedure proc_unit;
  680. var
  681. { unitname : stringid; }
  682. names:Tstringcontainer;
  683. p : psymtable;
  684. unitst : punitsymtable;
  685. pu : pused_unit;
  686. s1,s2 : ^string; {Saves stack space}
  687. begin
  688. consume(_UNIT);
  689. if token=ID then
  690. begin
  691. { create filenames and unit name }
  692. current_module^.SetFileName(current_module^.current_inputfile^.path^,current_module^.current_inputfile^.name^);
  693. stringdispose(current_module^.modulename);
  694. current_module^.modulename:=stringdup(upper(pattern));
  695. { check for system unit }
  696. new(s1);
  697. new(s2);
  698. s1^:=upper(target_info.system_unit);
  699. s2^:=upper(current_module^.current_inputfile^.name^);
  700. if (cs_compilesystem in aktswitches) then
  701. begin
  702. if (cs_check_unit_name in aktswitches) and
  703. ((length(current_module^.modulename^)>8) or
  704. (current_module^.modulename^<>s1^) or
  705. (current_module^.modulename^<>s2^)) then
  706. Message1(unit_e_illegal_unit_name,s1^);
  707. end
  708. else
  709. if (current_module^.modulename^=s1^) then
  710. Message(unit_w_switch_us_missed);
  711. dispose(s2);
  712. dispose(s1);
  713. { Add Object File }
  714. if (cs_smartlink in aktswitches) then
  715. current_module^.linkstaticlibs.insert(current_module^.libfilename^)
  716. else
  717. current_module^.linkofiles.insert(current_module^.objfilename^);
  718. end;
  719. consume(ID);
  720. consume(SEMICOLON);
  721. consume(_INTERFACE);
  722. { this should be placed after uses !!}
  723. {$ifndef UseNiceNames}
  724. procprefix:='_'+current_module^.modulename^+'$$';
  725. {$else UseNiceNames}
  726. procprefix:='_'+tostr(length(current_module^.unitname^))+lowercase(current_module^.unitname^)+'_';
  727. {$endif UseNiceNames}
  728. parse_only:=true;
  729. { generate now the global symboltable }
  730. p:=new(punitsymtable,init(globalsymtable,current_module^.modulename^));
  731. refsymtable:=p;
  732. unitst:=punitsymtable(p);
  733. { the unit name must be usable as a unit specifier }
  734. { inside the unit itself (PM) }
  735. { this also forbids to have another symbol }
  736. { with the same name as the unit }
  737. refsymtable^.insert(new(punitsym,init(current_module^.modulename^,unitst)));
  738. { set the symbol table for the current unit }
  739. { this must be set later for interdependency }
  740. { current_module^.symtable:=psymtable(p); }
  741. { a unit compiled at command line must be inside the loaded_unit list }
  742. if (compile_level=1) then
  743. begin
  744. loaded_units.insert(current_module);
  745. if cs_unit_to_lib in initswitches then
  746. begin
  747. current_module^.flags:=current_module^.flags or uf_in_library;
  748. if cs_shared_lib in initswitches then
  749. current_module^.flags:=current_module^.flags or uf_shared_library;
  750. end;
  751. end;
  752. { insert qualifier for the system unit (allows system.writeln) }
  753. if not(cs_compilesystem in aktswitches) then
  754. begin
  755. { insert the system unit }
  756. { it is allways the first }
  757. systemunit^.next:=nil;
  758. symtablestack:=systemunit;
  759. refsymtable^.insert(new(punitsym,init('SYSTEM',systemunit)));
  760. if token=_USES then
  761. begin
  762. unitst^.symtabletype:=unitsymtable;
  763. loadunits;
  764. { has it been compiled at a higher level ?}
  765. if current_module^.compiled then
  766. exit;
  767. unitst^.symtabletype:=globalsymtable;
  768. end;
  769. { ... but insert the symbol table later }
  770. p^.next:=symtablestack;
  771. symtablestack:=p;
  772. end
  773. else
  774. { while compiling a system unit, some types are directly inserted }
  775. begin
  776. p^.next:=symtablestack;
  777. symtablestack:=p;
  778. insert_intern_types(p);
  779. end;
  780. { displaced for inter-dependency considerations }
  781. current_module^.symtable:=psymtable(p);
  782. constsymtable:=symtablestack;
  783. { ... parse the declarations }
  784. read_interface_declarations;
  785. consume(_IMPLEMENTATION);
  786. parse_only:=false;
  787. refsymtable^.number_defs;
  788. {$ifdef GDB}
  789. { add all used definitions even for implementation}
  790. if (cs_debuginfo in aktswitches) then
  791. begin
  792. { all types }
  793. punitsymtable(refsymtable)^.concattypestabto(debuglist);
  794. { and all local symbols}
  795. refsymtable^.concatstabto(debuglist);
  796. end;
  797. {$endif GDB}
  798. { for interdependent units
  799. the crc is included in the ppufile
  800. but it is not known when writing the first ppufile
  801. so I tried to add a fake writing of the ppu
  802. just to get the CRC
  803. but the result is different for the real CRC
  804. it calculates after, I don't know why
  805. Answer:
  806. -------
  807. When reading the interface part, the compiler assumes
  808. that all registers are modified by a procedure
  809. usedinproc:=$ff !
  810. If the definition is read, the compiler determines
  811. the used registers and write the correct value
  812. to usedinproc
  813. only_calculate_crc:=true;
  814. writeunitas(current_module^.current_inputfile^.path^+current_module^.current_inputfile^.name^+
  815. +'.PPS',punitsymtable(symtablestack));
  816. only_calculate_crc:=false;
  817. }
  818. { generates static symbol table }
  819. p:=new(punitsymtable,init(staticsymtable,current_module^.modulename^));
  820. { must be done only after _USES !! (PM)
  821. refsymtable:=p;}
  822. {Generate a procsym.}
  823. aktprocsym:=new(Pprocsym,init(current_module^.modulename^+'_init'));
  824. aktprocsym^.definition:=new(Pprocdef,init);
  825. aktprocsym^.definition^.options:=aktprocsym^.definition^.options or pounitinit;
  826. aktprocsym^.definition^.setmangledname(current_module^.modulename^+'_init');
  827. {The generated procsym has a local symtable. Discard it and turn
  828. it into the static one.}
  829. dispose(aktprocsym^.definition^.localst,done);
  830. aktprocsym^.definition^.localst:=p;
  831. { testing !!!!!!!!! }
  832. { we set the interface part as a unitsymtable }
  833. { for the case we need to compile another unit }
  834. { remove the globalsymtable from the symtable stack }
  835. { to reinsert it after loading the implementation units }
  836. symtablestack:=unitst^.next;
  837. parse_implementation_uses(unitst);
  838. { now we can change refsymtable }
  839. refsymtable:=p;
  840. { but reinsert the global symtable as lasts }
  841. unitst^.next:=symtablestack;
  842. symtablestack:=unitst;
  843. {$ifdef DEBUG}
  844. test_symtablestack;
  845. {$endif DEBUG}
  846. constsymtable:=symtablestack;
  847. {$ifdef Splitheap}
  848. if testsplit then
  849. begin
  850. Split_Heap;
  851. allow_special:=true;
  852. Switch_to_temp_heap;
  853. end;
  854. { it will report all crossings }
  855. allow_special:=false;
  856. {$endif Splitheap}
  857. { set some informations }
  858. procinfo.retdef:=voiddef;
  859. procinfo._class:=nil;
  860. procinfo.call_offset:=8;
  861. { for temporary values }
  862. procinfo.framepointer:=frame_pointer;
  863. { clear flags }
  864. procinfo.flags:=0;
  865. {Reset the codegenerator.}
  866. codegen_newprocedure;
  867. names.init;
  868. names.insert(current_module^.modulename^+'_init');
  869. names.insert('INIT$$'+current_module^.modulename^);
  870. compile_proc_body(names,true,false);
  871. names.done;
  872. codegen_doneprocedure;
  873. consume(POINT);
  874. { size of the static data }
  875. datasize:=symtablestack^.datasize;
  876. { unsed static symbols ? }
  877. symtablestack^.allsymbolsused;
  878. {$ifdef GDB}
  879. { add all used definitions even for implementation}
  880. if (cs_debuginfo in aktswitches) then
  881. begin
  882. { all types }
  883. punitsymtable(symtablestack)^.concattypestabto(debuglist);
  884. { and all local symbols}
  885. symtablestack^.concatstabto(debuglist);
  886. end;
  887. {$endif GDB}
  888. current_module^.in_implementation:=false;
  889. { deletes all symtables generated in the implementation part }
  890. while symtablestack^.symtabletype<>globalsymtable do
  891. dellexlevel;
  892. { tests, if all forwards are resolved }
  893. symtablestack^.check_forwards;
  894. symtablestack^.symtabletype:=unitsymtable;
  895. punitsymtable(symtablestack)^.is_stab_written:=false;
  896. {Write out the unit if the compile was succesfull.}
  897. if status.errorcount=0 then
  898. writeunitas(current_module^.ppufilename^,punitsymtable(symtablestack));
  899. pu:=pused_unit(usedunits.first);
  900. while assigned(pu) do
  901. begin
  902. punitsymtable(pu^.u^.symtable)^.is_stab_written:=false;
  903. pu:=pused_unit(pu^.next);
  904. end;
  905. inc(datasize,symtablestack^.datasize);
  906. { finish asmlist by adding segment starts }
  907. insertsegment;
  908. end;
  909. procedure proc_program(islibrary : boolean);
  910. var
  911. st : psymtable;
  912. names : Tstringcontainer;
  913. begin
  914. { Trying to compile the system unit... }
  915. { if no unit defined... then issue a }
  916. { fatal error (avoids pointer problems)}
  917. { when referencing the non-existant }
  918. { system unit. }
  919. { System Unit should be compiled using proc_unit !! (PFV) }
  920. { if (cs_compilesystem in aktswitches) then
  921. Begin
  922. if token<>_UNIT then
  923. Message1(scan_f_syn_expected,'UNIT');
  924. consume(_UNIT);
  925. end;}
  926. parse_only:=false;
  927. if islibrary then
  928. begin
  929. consume(_LIBRARY);
  930. stringdispose(current_module^.modulename);
  931. current_module^.modulename:=stringdup(pattern);
  932. consume(ID);
  933. consume(SEMICOLON);
  934. end
  935. else
  936. { is there an program head ? }
  937. if token=_PROGRAM then
  938. begin
  939. consume(_PROGRAM);
  940. stringdispose(current_module^.modulename);
  941. current_module^.modulename:=stringdup(pattern);
  942. consume(ID);
  943. if token=LKLAMMER then
  944. begin
  945. consume(LKLAMMER);
  946. idlist;
  947. consume(RKLAMMER);
  948. end;
  949. consume(SEMICOLON);
  950. end;
  951. { insert after the unit symbol tables the static symbol table }
  952. { of the program }
  953. st:=new(punitsymtable,init(staticsymtable,current_module^.modulename^));
  954. {Generate a procsym.}
  955. aktprocsym:=new(Pprocsym,init('main'));
  956. aktprocsym^.definition:=new(Pprocdef,init);
  957. aktprocsym^.definition^.options:=aktprocsym^.definition^.options or poproginit;
  958. aktprocsym^.definition^.setmangledname(target_os.Cprefix+'main');
  959. {The localst is a local symtable. Change it into the static
  960. symtable.}
  961. dispose(aktprocsym^.definition^.localst,done);
  962. aktprocsym^.definition^.localst:=st;
  963. refsymtable:=st;
  964. { necessary for browser }
  965. loaded_units.insert(current_module);
  966. {Insert the symbols of the system unit into the stack of symbol
  967. tables.}
  968. symtablestack:=systemunit;
  969. systemunit^.next:=nil;
  970. refsymtable^.insert(new(punitsym,init('SYSTEM',systemunit)));
  971. {Load the units used by the program we compile.}
  972. if token=_USES then
  973. loadunits;
  974. {Insert the name of the main program into the symbol table.}
  975. if current_module^.modulename^<>'' then
  976. st^.insert(new(pprogramsym,init(current_module^.modulename^)));
  977. { ...is also constsymtable, this is the symtable where }
  978. { the elements of enumeration types are inserted }
  979. constsymtable:=st;
  980. { set some informations about the main program }
  981. with procinfo do
  982. begin
  983. retdef:=voiddef;
  984. _class:=nil;
  985. call_offset:=8;
  986. framepointer:=frame_pointer;
  987. flags:=0;
  988. end;
  989. procprefix:='';
  990. in_except_block:=false;
  991. codegen_newprocedure;
  992. {The program intialization needs an alias, so it can be called
  993. from the bootstrap code.}
  994. names.init;
  995. names.insert('program_init');
  996. names.insert('PASCALMAIN');
  997. names.insert(target_os.cprefix+'main');
  998. compile_proc_body(names,true,false);
  999. names.done;
  1000. codegen_doneprocedure;
  1001. consume(POINT);
  1002. if (cs_smartlink in aktswitches) then
  1003. current_module^.linkstaticlibs.insert(current_module^.libfilename^)
  1004. else
  1005. current_module^.linkofiles.insert(current_module^.objfilename^);
  1006. insertheap;
  1007. inserttargetspecific;
  1008. datasize:=symtablestack^.datasize;
  1009. { finish asmlist by adding segment starts }
  1010. insertsegment;
  1011. end;
  1012. end.
  1013. {
  1014. $Log$
  1015. Revision 1.16 1998-05-27 19:45:06 peter
  1016. * symtable.pas splitted into includefiles
  1017. * symtable adapted for $ifdef NEWPPU
  1018. Revision 1.15 1998/05/23 01:21:22 peter
  1019. + aktasmmode, aktoptprocessor, aktoutputformat
  1020. + smartlink per module $SMARTLINK-/+ (like MMX) and moved to aktswitches
  1021. + $LIBNAME to set the library name where the unit will be put in
  1022. * splitted cgi386 a bit (codeseg to large for bp7)
  1023. * nasm, tasm works again. nasm moved to ag386nsm.pas
  1024. Revision 1.14 1998/05/20 09:42:35 pierre
  1025. + UseTokenInfo now default
  1026. * unit in interface uses and implementation uses gives error now
  1027. * only one error for unknown symbol (uses lastsymknown boolean)
  1028. the problem came from the label code !
  1029. + first inlined procedures and function work
  1030. (warning there might be allowed cases were the result is still wrong !!)
  1031. * UseBrower updated gives a global list of all position of all used symbols
  1032. with switch -gb
  1033. Revision 1.13 1998/05/12 10:47:00 peter
  1034. * moved printstatus to verb_def
  1035. + V_Normal which is between V_Error and V_Warning and doesn't have a
  1036. prefix like error: warning: and is included in V_Default
  1037. * fixed some messages
  1038. * first time parameter scan is only for -v and -T
  1039. - removed old style messages
  1040. Revision 1.12 1998/05/11 13:07:56 peter
  1041. + $ifdef NEWPPU for the new ppuformat
  1042. + $define GDB not longer required
  1043. * removed all warnings and stripped some log comments
  1044. * no findfirst/findnext anymore to remove smartlink *.o files
  1045. Revision 1.11 1998/05/06 18:36:53 peter
  1046. * tai_section extended with code,data,bss sections and enumerated type
  1047. * ident 'compiled by FPC' moved to pmodules
  1048. * small fix for smartlink
  1049. Revision 1.10 1998/05/04 17:54:28 peter
  1050. + smartlinking works (only case jumptable left todo)
  1051. * redesign of systems.pas to support assemblers and linkers
  1052. + Unitname is now also in the PPU-file, increased version to 14
  1053. Revision 1.9 1998/05/01 16:38:45 florian
  1054. * handling of private and protected fixed
  1055. + change_keywords_to_tp implemented to remove
  1056. keywords which aren't supported by tp
  1057. * break and continue are now symbols of the system unit
  1058. + widestring, longstring and ansistring type released
  1059. Revision 1.8 1998/04/30 15:59:41 pierre
  1060. * GDB works again better :
  1061. correct type info in one pass
  1062. + UseTokenInfo for better source position
  1063. * fixed one remaining bug in scanner for line counts
  1064. * several little fixes
  1065. Revision 1.7 1998/04/29 10:33:59 pierre
  1066. + added some code for ansistring (not complete nor working yet)
  1067. * corrected operator overloading
  1068. * corrected nasm output
  1069. + started inline procedures
  1070. + added starstarn : use ** for exponentiation (^ gave problems)
  1071. + started UseTokenInfo cond to get accurate positions
  1072. Revision 1.6 1998/04/27 23:10:28 peter
  1073. + new scanner
  1074. * $makelib -> if smartlink
  1075. * small filename fixes pmodule.setfilename
  1076. * moved import from files.pas -> import.pas
  1077. Revision 1.5 1998/04/14 23:27:03 florian
  1078. + exclude/include with constant second parameter added
  1079. Revision 1.4 1998/04/10 14:41:43 peter
  1080. * removed some Hints
  1081. * small speed optimization for AsmLn
  1082. Revision 1.3 1998/04/03 09:51:00 daniel
  1083. * Fixed heap allocation for OS/2.
  1084. }