pdecl.pas 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl
  4. Does declaration (but not type) parsing for Free Pascal
  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 pdecl;
  19. interface
  20. uses
  21. globtype,tokens,globals,symtable;
  22. procedure parameter_dec(aktprocdef:pabstractprocdef);
  23. procedure read_var_decs(is_record,is_object,is_threadvar:boolean);
  24. { reads the declaration blocks }
  25. procedure read_declarations(islibrary : boolean);
  26. { reads declarations in the interface part of a unit }
  27. procedure read_interface_declarations;
  28. implementation
  29. uses
  30. cobjects,scanner,
  31. symconst,aasm,tree,pass_1,strings,
  32. files,types,verbose,systems,import,
  33. cpubase
  34. {$ifndef newcg}
  35. ,tccnv
  36. {$endif newcg}
  37. {$ifdef GDB}
  38. ,gdb
  39. {$endif GDB}
  40. { parser specific stuff }
  41. ,pbase,ptconst,pexpr,ptype,psub,pexports
  42. { processor specific stuff }
  43. { codegen }
  44. {$ifdef newcg}
  45. ,cgbase
  46. {$else}
  47. ,hcodegen
  48. {$endif}
  49. ,hcgdata
  50. ;
  51. procedure parameter_dec(aktprocdef:pabstractprocdef);
  52. {
  53. handle_procvar needs the same changes
  54. }
  55. var
  56. is_procvar : boolean;
  57. sc : Pstringcontainer;
  58. s : string;
  59. storetokenpos : tfileposinfo;
  60. tt : ttype;
  61. hsym : psym;
  62. hvs,
  63. vs : Pvarsym;
  64. hs1,hs2 : string;
  65. varspez : Tvarspez;
  66. inserthigh : boolean;
  67. begin
  68. { parsing a proc or procvar ? }
  69. is_procvar:=(aktprocdef^.deftype=procvardef);
  70. consume(_LKLAMMER);
  71. inc(testcurobject);
  72. repeat
  73. if try_to_consume(_VAR) then
  74. varspez:=vs_var
  75. else
  76. if try_to_consume(_CONST) then
  77. varspez:=vs_const
  78. else
  79. varspez:=vs_value;
  80. inserthigh:=false;
  81. tt.reset;
  82. if idtoken=_SELF then
  83. begin
  84. { only allowed in procvars and class methods }
  85. if is_procvar or
  86. (assigned(procinfo^._class) and procinfo^._class^.is_class) then
  87. begin
  88. if not is_procvar then
  89. begin
  90. {$ifndef UseNiceNames}
  91. hs2:=hs2+'$'+'self';
  92. {$else UseNiceNames}
  93. hs2:=hs2+tostr(length('self'))+'self';
  94. {$endif UseNiceNames}
  95. vs:=new(Pvarsym,initdef('@',procinfo^._class));
  96. vs^.varspez:=vs_var;
  97. { insert the sym in the parasymtable }
  98. pprocdef(aktprocdef)^.parast^.insert(vs);
  99. {$ifdef INCLUDEOK}
  100. include(aktprocdef^.procoptions,po_containsself);
  101. {$else}
  102. aktprocdef^.procoptions:=aktprocdef^.procoptions+[po_containsself];
  103. {$endif}
  104. inc(procinfo^.selfpointer_offset,vs^.address);
  105. end;
  106. consume(idtoken);
  107. consume(_COLON);
  108. single_type(tt,hs1,false);
  109. aktprocdef^.concatpara(tt,vs_value);
  110. { check the types for procedures only }
  111. if not is_procvar then
  112. CheckTypes(tt.def,procinfo^._class);
  113. end
  114. else
  115. consume(_ID);
  116. end
  117. else
  118. begin
  119. { read identifiers }
  120. sc:=idlist;
  121. {$ifdef fixLeaksOnError}
  122. strContStack.push(sc);
  123. {$endif fixLeaksOnError}
  124. { read type declaration, force reading for value and const paras }
  125. if (token=_COLON) or (varspez=vs_value) then
  126. begin
  127. consume(_COLON);
  128. { check for an open array }
  129. if token=_ARRAY then
  130. begin
  131. consume(_ARRAY);
  132. consume(_OF);
  133. { define range and type of range }
  134. tt.setdef(new(Parraydef,init(0,-1,s32bitdef)));
  135. { array of const ? }
  136. if (token=_CONST) and (m_objpas in aktmodeswitches) then
  137. begin
  138. consume(_CONST);
  139. srsym:=nil;
  140. getsymonlyin(systemunit,'TVARREC');
  141. if not assigned(srsym) then
  142. InternalError(1234124);
  143. Parraydef(tt.def)^.elementtype:=ptypesym(srsym)^.restype;
  144. Parraydef(tt.def)^.IsArrayOfConst:=true;
  145. hs1:='array_of_const';
  146. end
  147. else
  148. begin
  149. { define field type }
  150. single_type(parraydef(tt.def)^.elementtype,hs1,false);
  151. hs1:='array_of_'+hs1;
  152. end;
  153. inserthigh:=true;
  154. end
  155. { open string ? }
  156. else if (varspez=vs_var) and
  157. (
  158. (
  159. ((token=_STRING) or (idtoken=_SHORTSTRING)) and
  160. (cs_openstring in aktmoduleswitches) and
  161. not(cs_ansistrings in aktlocalswitches)
  162. ) or
  163. (idtoken=_OPENSTRING)) then
  164. begin
  165. consume(token);
  166. tt.setdef(openshortstringdef);
  167. hs1:='openstring';
  168. inserthigh:=true;
  169. end
  170. { everything else }
  171. else
  172. single_type(tt,hs1,false);
  173. end
  174. else
  175. begin
  176. {$ifndef UseNiceNames}
  177. hs1:='$$$';
  178. {$else UseNiceNames}
  179. hs1:='var';
  180. {$endif UseNiceNames}
  181. tt.setdef(cformaldef);
  182. end;
  183. if not is_procvar then
  184. hs2:=pprocdef(aktprocdef)^.mangledname;
  185. storetokenpos:=tokenpos;
  186. while not sc^.empty do
  187. begin
  188. s:=sc^.get_with_tokeninfo(tokenpos);
  189. aktprocdef^.concatpara(tt,varspez);
  190. { For proc vars we only need the definitions }
  191. if not is_procvar then
  192. begin
  193. {$ifndef UseNiceNames}
  194. hs2:=hs2+'$'+hs1;
  195. {$else UseNiceNames}
  196. hs2:=hs2+tostr(length(hs1))+hs1;
  197. {$endif UseNiceNames}
  198. vs:=new(pvarsym,init(s,tt));
  199. vs^.varspez:=varspez;
  200. { we have to add this to avoid var param to be in registers !!!}
  201. if (varspez in [vs_var,vs_const]) and push_addr_param(tt.def) then
  202. {$ifdef INCLUDEOK}
  203. include(vs^.varoptions,vo_regable);
  204. {$else}
  205. vs^.varoptions:=vs^.varoptions+[vo_regable];
  206. {$endif}
  207. { search for duplicate ids in object members/methods }
  208. { but only the current class, I don't know why ... }
  209. { at least TP and Delphi do it in that way (FK) }
  210. if assigned(procinfo^._class) and
  211. (lexlevel=normal_function_level) then
  212. begin
  213. hsym:=procinfo^._class^.symtable^.search(vs^.name);
  214. if assigned(hsym) then
  215. DuplicateSym(hsym);
  216. end;
  217. { do we need a local copy? }
  218. if (varspez=vs_value) and
  219. push_addr_param(tt.def) and
  220. not(is_open_array(tt.def) or is_array_of_const(tt.def)) then
  221. vs^.setname('val'+vs^.name);
  222. { insert the sym in the parasymtable }
  223. pprocdef(aktprocdef)^.parast^.insert(vs);
  224. { also need to push a high value? }
  225. if inserthigh then
  226. begin
  227. hvs:=new(Pvarsym,initdef('high'+s,s32bitdef));
  228. hvs^.varspez:=vs_const;
  229. pprocdef(aktprocdef)^.parast^.insert(hvs);
  230. end;
  231. end;
  232. end;
  233. {$ifdef fixLeaksOnError}
  234. if PStringContainer(strContStack.pop) <> sc then
  235. writeln('problem with strContStack in pdecl (1)');
  236. {$endif fixLeaksOnError}
  237. dispose(sc,done);
  238. tokenpos:=storetokenpos;
  239. end;
  240. { set the new mangled name }
  241. if not is_procvar then
  242. pprocdef(aktprocdef)^.setmangledname(hs2);
  243. until not try_to_consume(_SEMICOLON);
  244. dec(testcurobject);
  245. consume(_RKLAMMER);
  246. end;
  247. const
  248. variantrecordlevel : longint = 0;
  249. procedure read_var_decs(is_record,is_object,is_threadvar:boolean);
  250. { reads the filed of a record into a }
  251. { symtablestack, if record=false }
  252. { variants are forbidden, so this procedure }
  253. { can be used to read object fields }
  254. { if absolute is true, ABSOLUTE and file }
  255. { types are allowed }
  256. { => the procedure is also used to read }
  257. { a sequence of variable declaration }
  258. procedure insert_syms(st : psymtable;sc : pstringcontainer;tt : ttype;is_threadvar : boolean);
  259. { inserts the symbols of sc in st with def as definition or sym as ptypesym, sc is disposed }
  260. var
  261. s : string;
  262. filepos : tfileposinfo;
  263. ss : pvarsym;
  264. begin
  265. filepos:=tokenpos;
  266. while not sc^.empty do
  267. begin
  268. s:=sc^.get_with_tokeninfo(tokenpos);
  269. ss:=new(pvarsym,init(s,tt));
  270. if is_threadvar then
  271. {$ifdef INCLUDEOK}
  272. include(ss^.varoptions,vo_is_thread_var);
  273. {$else}
  274. ss^.varoptions:=ss^.varoptions+[vo_is_thread_var];
  275. {$endif}
  276. st^.insert(ss);
  277. { static data fields are inserted in the globalsymtable }
  278. if (st^.symtabletype=objectsymtable) and
  279. (sp_static in current_object_option) then
  280. begin
  281. s:=lower(st^.name^)+'_'+s;
  282. st^.defowner^.owner^.insert(new(pvarsym,init(s,tt)));
  283. end;
  284. end;
  285. {$ifdef fixLeaksOnError}
  286. if strContStack.pop <> sc then
  287. writeln('problem with strContStack in pdecl (2)');
  288. {$endif fixLeaksOnError}
  289. dispose(sc,done);
  290. tokenpos:=filepos;
  291. end;
  292. var
  293. sc : pstringcontainer;
  294. s : stringid;
  295. old_block_type : tblock_type;
  296. declarepos,storetokenpos : tfileposinfo;
  297. symdone : boolean;
  298. { to handle absolute }
  299. abssym : pabsolutesym;
  300. l : longint;
  301. code : integer;
  302. { c var }
  303. newtype : ptypesym;
  304. is_dll,
  305. is_gpc_name,is_cdecl,extern_aktvarsym,export_aktvarsym : boolean;
  306. old_current_object_option : tsymoptions;
  307. dll_name,
  308. C_name : string;
  309. tt,casetype : ttype;
  310. { Delphi initialized vars }
  311. pconstsym : ptypedconstsym;
  312. { maxsize contains the max. size of a variant }
  313. { startvarrec contains the start of the variant part of a record }
  314. maxsize,startvarrec : longint;
  315. pt : ptree;
  316. begin
  317. old_block_type:=block_type;
  318. block_type:=bt_type;
  319. is_gpc_name:=false;
  320. { Force an expected ID error message }
  321. if not (token in [_ID,_CASE,_END]) then
  322. consume(_ID);
  323. { read vars }
  324. while (token=_ID) and
  325. not(is_object and (idtoken in [_PUBLIC,_PRIVATE,_PUBLISHED,_PROTECTED])) do
  326. begin
  327. C_name:=orgpattern;
  328. sc:=idlist;
  329. {$ifdef fixLeaksOnError}
  330. strContStack.push(sc);
  331. {$endif fixLeaksOnError}
  332. consume(_COLON);
  333. if (m_gpc in aktmodeswitches) and
  334. not(is_record or is_object or is_threadvar) and
  335. (token=_ID) and (orgpattern='__asmname__') then
  336. begin
  337. consume(_ID);
  338. C_name:=pattern;
  339. if token=_CCHAR then
  340. consume(_CCHAR)
  341. else
  342. consume(_CSTRING);
  343. Is_gpc_name:=true;
  344. end;
  345. { this is needed for Delphi mode at least
  346. but should be OK for all modes !! (PM) }
  347. ignore_equal:=true;
  348. read_type(tt,'');
  349. if (variantrecordlevel>0) and tt.def^.needs_inittable then
  350. Message(parser_e_cant_use_inittable_here);
  351. ignore_equal:=false;
  352. symdone:=false;
  353. if is_gpc_name then
  354. begin
  355. storetokenpos:=tokenpos;
  356. s:=sc^.get_with_tokeninfo(tokenpos);
  357. if not sc^.empty then
  358. Message(parser_e_absolute_only_one_var);
  359. {$ifdef fixLeaksOnError}
  360. if strContStack.pop <> sc then
  361. writeln('problem with strContStack in pdecl (3)');
  362. {$endif fixLeaksOnError}
  363. dispose(sc,done);
  364. aktvarsym:=new(pvarsym,init_C(s,target_os.Cprefix+C_name,tt));
  365. {$ifdef INCLUDEOK}
  366. include(aktvarsym^.varoptions,vo_is_external);
  367. {$else}
  368. aktvarsym^.varoptions:=aktvarsym^.varoptions+[vo_is_external];
  369. {$endif}
  370. symtablestack^.insert(aktvarsym);
  371. tokenpos:=storetokenpos;
  372. symdone:=true;
  373. end;
  374. { check for absolute }
  375. if not symdone and
  376. (idtoken=_ABSOLUTE) and not(is_record or is_object or is_threadvar) then
  377. begin
  378. consume(_ABSOLUTE);
  379. { only allowed for one var }
  380. s:=sc^.get_with_tokeninfo(declarepos);
  381. if not sc^.empty then
  382. Message(parser_e_absolute_only_one_var);
  383. {$ifdef fixLeaksOnError}
  384. if strContStack.pop <> sc then
  385. writeln('problem with strContStack in pdecl (4)');
  386. {$endif fixLeaksOnError}
  387. dispose(sc,done);
  388. { parse the rest }
  389. if token=_ID then
  390. begin
  391. getsym(pattern,true);
  392. consume(_ID);
  393. { support unit.variable }
  394. if srsym^.typ=unitsym then
  395. begin
  396. consume(_POINT);
  397. getsymonlyin(punitsym(srsym)^.unitsymtable,pattern);
  398. consume(_ID);
  399. end;
  400. { we should check the result type of srsym }
  401. if not (srsym^.typ in [varsym,typedconstsym]) then
  402. Message(parser_e_absolute_only_to_var_or_const);
  403. storetokenpos:=tokenpos;
  404. tokenpos:=declarepos;
  405. abssym:=new(pabsolutesym,init(s,tt));
  406. abssym^.abstyp:=tovar;
  407. abssym^.ref:=srsym;
  408. symtablestack^.insert(abssym);
  409. tokenpos:=storetokenpos;
  410. end
  411. else
  412. if (token=_CSTRING) or (token=_CCHAR) then
  413. begin
  414. storetokenpos:=tokenpos;
  415. tokenpos:=declarepos;
  416. abssym:=new(pabsolutesym,init(s,tt));
  417. s:=pattern;
  418. consume(token);
  419. abssym^.abstyp:=toasm;
  420. abssym^.asmname:=stringdup(s);
  421. symtablestack^.insert(abssym);
  422. tokenpos:=storetokenpos;
  423. end
  424. else
  425. { absolute address ?!? }
  426. if token=_INTCONST then
  427. begin
  428. if (target_info.target=target_i386_go32v2) then
  429. begin
  430. storetokenpos:=tokenpos;
  431. tokenpos:=declarepos;
  432. abssym:=new(pabsolutesym,init(s,tt));
  433. abssym^.abstyp:=toaddr;
  434. abssym^.absseg:=false;
  435. s:=pattern;
  436. consume(_INTCONST);
  437. val(s,abssym^.address,code);
  438. if token=_COLON then
  439. begin
  440. consume(token);
  441. s:=pattern;
  442. consume(_INTCONST);
  443. val(s,l,code);
  444. abssym^.address:=abssym^.address shl 4+l;
  445. abssym^.absseg:=true;
  446. end;
  447. symtablestack^.insert(abssym);
  448. tokenpos:=storetokenpos;
  449. end
  450. else
  451. Message(parser_e_absolute_only_to_var_or_const);
  452. end
  453. else
  454. Message(parser_e_absolute_only_to_var_or_const);
  455. symdone:=true;
  456. end;
  457. { Handling of Delphi typed const = initialized vars ! }
  458. { When should this be rejected ?
  459. - in parasymtable
  460. - in record or object
  461. - ... (PM) }
  462. if (m_delphi in aktmodeswitches) and (token=_EQUAL) and
  463. not (symtablestack^.symtabletype in [parasymtable]) and
  464. not is_record and not is_object then
  465. begin
  466. storetokenpos:=tokenpos;
  467. s:=sc^.get_with_tokeninfo(tokenpos);
  468. if not sc^.empty then
  469. Message(parser_e_initialized_only_one_var);
  470. pconstsym:=new(ptypedconstsym,inittype(s,tt,false));
  471. symtablestack^.insert(pconstsym);
  472. tokenpos:=storetokenpos;
  473. consume(_EQUAL);
  474. readtypedconst(tt.def,pconstsym,false);
  475. symdone:=true;
  476. end;
  477. { for a record there doesn't need to be a ; before the END or ) }
  478. if not((is_record or is_object) and (token in [_END,_RKLAMMER])) then
  479. consume(_SEMICOLON);
  480. { procvar handling }
  481. if (tt.def^.deftype=procvardef) and (tt.def^.typesym=nil) then
  482. begin
  483. newtype:=new(ptypesym,init('unnamed',tt));
  484. parse_var_proc_directives(psym(newtype));
  485. newtype^.restype.def:=nil;
  486. tt.def^.typesym:=nil;
  487. dispose(newtype,done);
  488. end;
  489. { Check for variable directives }
  490. if not symdone and (token=_ID) then
  491. begin
  492. { Check for C Variable declarations }
  493. if (m_cvar_support in aktmodeswitches) and
  494. not(is_record or is_object or is_threadvar) and
  495. (idtoken in [_EXPORT,_EXTERNAL,_PUBLIC,_CVAR]) then
  496. begin
  497. { only allowed for one var }
  498. s:=sc^.get_with_tokeninfo(declarepos);
  499. if not sc^.empty then
  500. Message(parser_e_absolute_only_one_var);
  501. {$ifdef fixLeaksOnError}
  502. if strContStack.pop <> sc then
  503. writeln('problem with strContStack in pdecl (5)');
  504. {$endif fixLeaksOnError}
  505. dispose(sc,done);
  506. { defaults }
  507. is_dll:=false;
  508. is_cdecl:=false;
  509. extern_aktvarsym:=false;
  510. export_aktvarsym:=false;
  511. { cdecl }
  512. if idtoken=_CVAR then
  513. begin
  514. consume(_CVAR);
  515. consume(_SEMICOLON);
  516. is_cdecl:=true;
  517. C_name:=target_os.Cprefix+C_name;
  518. end;
  519. { external }
  520. if idtoken=_EXTERNAL then
  521. begin
  522. consume(_EXTERNAL);
  523. extern_aktvarsym:=true;
  524. end;
  525. { export }
  526. if idtoken in [_EXPORT,_PUBLIC] then
  527. begin
  528. consume(_ID);
  529. if extern_aktvarsym then
  530. Message(parser_e_not_external_and_export)
  531. else
  532. export_aktvarsym:=true;
  533. end;
  534. { external and export need a name after when no cdecl is used }
  535. if not is_cdecl then
  536. begin
  537. { dll name ? }
  538. if (extern_aktvarsym) and (idtoken<>_NAME) then
  539. begin
  540. is_dll:=true;
  541. dll_name:=get_stringconst;
  542. end;
  543. consume(_NAME);
  544. C_name:=get_stringconst;
  545. end;
  546. { consume the ; when export or external is used }
  547. if extern_aktvarsym or export_aktvarsym then
  548. consume(_SEMICOLON);
  549. { insert in the symtable }
  550. storetokenpos:=tokenpos;
  551. tokenpos:=declarepos;
  552. if is_dll then
  553. aktvarsym:=new(pvarsym,init_dll(s,tt))
  554. else
  555. aktvarsym:=new(pvarsym,init_C(s,C_name,tt));
  556. { set some vars options }
  557. if export_aktvarsym then
  558. inc(aktvarsym^.refs);
  559. if extern_aktvarsym then
  560. {$ifdef INCLUDEOK}
  561. include(aktvarsym^.varoptions,vo_is_external);
  562. {$else}
  563. aktvarsym^.varoptions:=aktvarsym^.varoptions+[vo_is_external];
  564. {$endif}
  565. { insert in the stack/datasegment }
  566. symtablestack^.insert(aktvarsym);
  567. tokenpos:=storetokenpos;
  568. { now we can insert it in the import lib if its a dll, or
  569. add it to the externals }
  570. if extern_aktvarsym then
  571. begin
  572. if is_dll then
  573. begin
  574. if not(current_module^.uses_imports) then
  575. begin
  576. current_module^.uses_imports:=true;
  577. importlib^.preparelib(current_module^.modulename^);
  578. end;
  579. importlib^.importvariable(aktvarsym^.mangledname,dll_name,C_name)
  580. end
  581. end;
  582. symdone:=true;
  583. end
  584. else
  585. if (is_object) and (cs_static_keyword in aktmoduleswitches) and (idtoken=_STATIC) then
  586. begin
  587. {$ifdef INCLUDEOK}
  588. include(current_object_option,sp_static);
  589. {$else}
  590. current_object_option:=current_object_option+[sp_static];
  591. {$endif}
  592. insert_syms(symtablestack,sc,tt,false);
  593. {$ifdef INCLUDEOK}
  594. exclude(current_object_option,sp_static);
  595. {$else}
  596. current_object_option:=current_object_option-[sp_static];
  597. {$endif}
  598. consume(_STATIC);
  599. consume(_SEMICOLON);
  600. symdone:=true;
  601. end;
  602. end;
  603. { insert it in the symtable, if not done yet }
  604. if not symdone then
  605. begin
  606. { save object option, because we can turn of the sp_published }
  607. old_current_object_option:=current_object_option;
  608. if (sp_published in current_object_option) and
  609. (not((tt.def^.deftype=objectdef) and (pobjectdef(tt.def)^.is_class))) then
  610. begin
  611. Message(parser_e_cant_publish_that);
  612. exclude(current_object_option,sp_published);
  613. end
  614. else
  615. if (sp_published in current_object_option) and
  616. not(oo_can_have_published in pobjectdef(tt.def)^.objectoptions) then
  617. begin
  618. Message(parser_e_only_publishable_classes_can__be_published);
  619. exclude(current_object_option,sp_published);
  620. end;
  621. insert_syms(symtablestack,sc,tt,is_threadvar);
  622. current_object_option:=old_current_object_option;
  623. end;
  624. end;
  625. { Check for Case }
  626. if is_record and (token=_CASE) then
  627. begin
  628. maxsize:=0;
  629. consume(_CASE);
  630. s:=pattern;
  631. getsym(s,false);
  632. { may be only a type: }
  633. if assigned(srsym) and (srsym^.typ in [typesym,unitsym]) then
  634. read_type(casetype,'')
  635. else
  636. begin
  637. consume(_ID);
  638. consume(_COLON);
  639. read_type(casetype,'');
  640. symtablestack^.insert(new(pvarsym,init(s,casetype)));
  641. end;
  642. if not(is_ordinal(casetype.def)) or is_64bitint(casetype.def) then
  643. Message(type_e_ordinal_expr_expected);
  644. consume(_OF);
  645. startvarrec:=symtablestack^.datasize;
  646. repeat
  647. repeat
  648. pt:=comp_expr(true);
  649. do_firstpass(pt);
  650. if not(pt^.treetype=ordconstn) then
  651. Message(cg_e_illegal_expression);
  652. disposetree(pt);
  653. if token=_COMMA then
  654. consume(_COMMA)
  655. else
  656. break;
  657. until false;
  658. consume(_COLON);
  659. { read the vars }
  660. consume(_LKLAMMER);
  661. inc(variantrecordlevel);
  662. if token<>_RKLAMMER then
  663. read_var_decs(true,false,false);
  664. dec(variantrecordlevel);
  665. consume(_RKLAMMER);
  666. { calculates maximal variant size }
  667. maxsize:=max(maxsize,symtablestack^.datasize);
  668. { the items of the next variant are overlayed }
  669. symtablestack^.datasize:=startvarrec;
  670. if (token<>_END) and (token<>_RKLAMMER) then
  671. consume(_SEMICOLON)
  672. else
  673. break;
  674. until (token=_END) or (token=_RKLAMMER);
  675. { at last set the record size to that of the biggest variant }
  676. symtablestack^.datasize:=maxsize;
  677. end;
  678. block_type:=old_block_type;
  679. end;
  680. procedure const_dec;
  681. var
  682. name : stringid;
  683. p : ptree;
  684. tt : ttype;
  685. sym : psym;
  686. storetokenpos,filepos : tfileposinfo;
  687. old_block_type : tblock_type;
  688. ps : pconstset;
  689. pd : pbestreal;
  690. sp : pchar;
  691. skipequal : boolean;
  692. begin
  693. consume(_CONST);
  694. old_block_type:=block_type;
  695. block_type:=bt_const;
  696. repeat
  697. name:=pattern;
  698. filepos:=tokenpos;
  699. consume(_ID);
  700. case token of
  701. _EQUAL:
  702. begin
  703. consume(_EQUAL);
  704. p:=comp_expr(true);
  705. do_firstpass(p);
  706. storetokenpos:=tokenpos;
  707. tokenpos:=filepos;
  708. case p^.treetype of
  709. ordconstn:
  710. begin
  711. if is_constintnode(p) then
  712. symtablestack^.insert(new(pconstsym,init_def(name,constint,p^.value,nil)))
  713. else if is_constcharnode(p) then
  714. symtablestack^.insert(new(pconstsym,init_def(name,constchar,p^.value,nil)))
  715. else if is_constboolnode(p) then
  716. symtablestack^.insert(new(pconstsym,init_def(name,constbool,p^.value,nil)))
  717. else if p^.resulttype^.deftype=enumdef then
  718. symtablestack^.insert(new(pconstsym,init_def(name,constord,p^.value,p^.resulttype)))
  719. else if p^.resulttype^.deftype=pointerdef then
  720. symtablestack^.insert(new(pconstsym,init_def(name,constord,p^.value,p^.resulttype)))
  721. else internalerror(111);
  722. end;
  723. stringconstn:
  724. begin
  725. getmem(sp,p^.length+1);
  726. move(p^.value_str^,sp^,p^.length+1);
  727. symtablestack^.insert(new(pconstsym,init_string(name,conststring,sp,p^.length)));
  728. end;
  729. realconstn :
  730. begin
  731. new(pd);
  732. pd^:=p^.value_real;
  733. symtablestack^.insert(new(pconstsym,init(name,constreal,longint(pd))));
  734. end;
  735. setconstn :
  736. begin
  737. new(ps);
  738. ps^:=p^.value_set^;
  739. symtablestack^.insert(new(pconstsym,init_def(name,constset,longint(ps),p^.resulttype)));
  740. end;
  741. pointerconstn :
  742. begin
  743. symtablestack^.insert(new(pconstsym,init_def(name,constpointer,p^.value,p^.resulttype)))
  744. end;
  745. niln :
  746. begin
  747. symtablestack^.insert(new(pconstsym,init_def(name,constnil,0,p^.resulttype)));
  748. end;
  749. else
  750. Message(cg_e_illegal_expression);
  751. end;
  752. tokenpos:=storetokenpos;
  753. consume(_SEMICOLON);
  754. disposetree(p);
  755. end;
  756. _COLON:
  757. begin
  758. { set the blocktype first so a consume also supports a
  759. caret, to support const s : ^string = nil }
  760. block_type:=bt_type;
  761. consume(_COLON);
  762. ignore_equal:=true;
  763. read_type(tt,'');
  764. ignore_equal:=false;
  765. block_type:=bt_const;
  766. skipequal:=false;
  767. { create symbol }
  768. storetokenpos:=tokenpos;
  769. tokenpos:=filepos;
  770. {$ifdef DELPHI_CONST_IN_RODATA}
  771. if m_delphi in aktmodeswitches then
  772. begin
  773. if assigned(readtypesym) then
  774. sym:=new(ptypedconstsym,initsym(name,readtypesym,true))
  775. else
  776. sym:=new(ptypedconstsym,init(name,def,true))
  777. end
  778. else
  779. {$endif DELPHI_CONST_IN_RODATA}
  780. begin
  781. sym:=new(ptypedconstsym,inittype(name,tt,false))
  782. end;
  783. tokenpos:=storetokenpos;
  784. symtablestack^.insert(sym);
  785. { procvar can have proc directives }
  786. if (tt.def^.deftype=procvardef) then
  787. begin
  788. { support p : procedure;stdcall=nil; }
  789. if (token=_SEMICOLON) then
  790. begin
  791. consume(_SEMICOLON);
  792. if is_proc_directive(token) then
  793. parse_var_proc_directives(sym)
  794. else
  795. begin
  796. Message(parser_e_proc_directive_expected);
  797. skipequal:=true;
  798. end;
  799. end
  800. else
  801. { support p : procedure stdcall=nil; }
  802. begin
  803. if is_proc_directive(token) then
  804. parse_var_proc_directives(sym);
  805. end;
  806. end;
  807. if not skipequal then
  808. begin
  809. { get init value }
  810. consume(_EQUAL);
  811. {$ifdef DELPHI_CONST_IN_RODATA}
  812. if m_delphi in aktmodeswitches then
  813. readtypedconst(tt.def,ptypedconstsym(sym),true)
  814. else
  815. {$endif DELPHI_CONST_IN_RODATA}
  816. readtypedconst(tt.def,ptypedconstsym(sym),false);
  817. consume(_SEMICOLON);
  818. end;
  819. end;
  820. else
  821. { generate an error }
  822. consume(_EQUAL);
  823. end;
  824. until token<>_ID;
  825. block_type:=old_block_type;
  826. end;
  827. procedure label_dec;
  828. var
  829. hl : pasmlabel;
  830. begin
  831. consume(_LABEL);
  832. if not(cs_support_goto in aktmoduleswitches) then
  833. Message(sym_e_goto_and_label_not_supported);
  834. repeat
  835. if not(token in [_ID,_INTCONST]) then
  836. consume(_ID)
  837. else
  838. begin
  839. getlabel(hl);
  840. symtablestack^.insert(new(plabelsym,init(pattern,hl)));
  841. consume(token);
  842. end;
  843. if token<>_SEMICOLON then consume(_COMMA);
  844. until not(token in [_ID,_INTCONST]);
  845. consume(_SEMICOLON);
  846. end;
  847. { search in symtablestack used, but not defined type }
  848. procedure resolve_type_forward(p : pnamedindexobject);{$ifndef FPC}far;{$endif}
  849. var
  850. hpd,pd : pdef;
  851. stpos : tfileposinfo;
  852. again : boolean;
  853. begin
  854. { Check only typesyms or record/object fields }
  855. case psym(p)^.typ of
  856. typesym :
  857. pd:=ptypesym(p)^.restype.def;
  858. varsym :
  859. if (psym(p)^.owner^.symtabletype in [objectsymtable,recordsymtable]) then
  860. pd:=pvarsym(p)^.vartype.def
  861. else
  862. exit;
  863. else
  864. exit;
  865. end;
  866. repeat
  867. again:=false;
  868. case pd^.deftype of
  869. arraydef :
  870. begin
  871. { elementtype could also be defined using a forwarddef }
  872. pd:=parraydef(pd)^.elementtype.def;
  873. again:=true;
  874. end;
  875. pointerdef,
  876. classrefdef :
  877. begin
  878. { classrefdef inherits from pointerdef }
  879. hpd:=ppointerdef(pd)^.pointertype.def;
  880. { still a forward def ? }
  881. if hpd^.deftype=forwarddef then
  882. begin
  883. { try to resolve the forward }
  884. { get the correct position for it }
  885. stpos:=tokenpos;
  886. tokenpos:=pforwarddef(hpd)^.forwardpos;
  887. resolving_forward:=true;
  888. make_ref:=false;
  889. getsym(pforwarddef(hpd)^.tosymname,false);
  890. make_ref:=true;
  891. resolving_forward:=false;
  892. tokenpos:=stpos;
  893. { we don't need the forwarddef anymore, dispose it }
  894. dispose(hpd,done);
  895. { was a type sym found ? }
  896. if assigned(srsym) and
  897. (srsym^.typ=typesym) then
  898. begin
  899. ppointerdef(pd)^.pointertype:=ptypesym(srsym)^.restype;
  900. { avoid wrong unused warnings web bug 801 PM }
  901. inc(srsym^.refs);
  902. {$ifdef GDB}
  903. if (cs_debuginfo in aktmoduleswitches) and assigned(debuglist) and
  904. (psym(p)^.owner^.symtabletype in [globalsymtable,staticsymtable]) then
  905. begin
  906. ptypesym(p)^.isusedinstab := true;
  907. psym(p)^.concatstabto(debuglist);
  908. end;
  909. {$endif GDB}
  910. { we need a class type for classrefdef }
  911. if (pd^.deftype=classrefdef) and
  912. not((ptypesym(srsym)^.restype.def^.deftype=objectdef) and
  913. pobjectdef(ptypesym(srsym)^.restype.def)^.is_class) then
  914. Message1(type_e_class_type_expected,ptypesym(srsym)^.restype.def^.typename);
  915. end
  916. else
  917. begin
  918. MessagePos1(psym(p)^.fileinfo,sym_e_forward_type_not_resolved,p^.name);
  919. { try to recover }
  920. ppointerdef(pd)^.pointertype.def:=generrordef;
  921. end;
  922. end;
  923. end;
  924. recorddef :
  925. precorddef(pd)^.symtable^.foreach({$ifndef TP}@{$endif}resolve_type_forward);
  926. objectdef :
  927. { Don't check objectdefs in objects/records, because these can't
  928. exist (anonymous objects aren't allowed) }
  929. if not(psym(p)^.owner^.symtabletype in [objectsymtable,recordsymtable]) then
  930. pobjectdef(pd)^.symtable^.foreach({$ifndef TP}@{$endif}resolve_type_forward);
  931. end;
  932. until not again;
  933. end;
  934. { reads a type declaration to the symbol table }
  935. procedure type_dec;
  936. var
  937. typename : stringid;
  938. newtype : ptypesym;
  939. sym : psym;
  940. tt : ttype;
  941. defpos,storetokenpos : tfileposinfo;
  942. old_block_type : tblock_type;
  943. begin
  944. old_block_type:=block_type;
  945. block_type:=bt_type;
  946. consume(_TYPE);
  947. typecanbeforward:=true;
  948. repeat
  949. typename:=pattern;
  950. defpos:=tokenpos;
  951. consume(_ID);
  952. consume(_EQUAL);
  953. { support 'ttype=type word' syntax }
  954. if token=_TYPE then
  955. Consume(_TYPE);
  956. { is the type already defined? }
  957. getsym(typename,false);
  958. sym:=srsym;
  959. newtype:=nil;
  960. { found a symbol with this name? }
  961. if assigned(sym) then
  962. begin
  963. if (sym^.typ=typesym) then
  964. begin
  965. if (token=_CLASS) and
  966. (assigned(ptypesym(sym)^.restype.def)) and
  967. (ptypesym(sym)^.restype.def^.deftype=objectdef) and
  968. pobjectdef(ptypesym(sym)^.restype.def)^.is_class and
  969. (oo_is_forward in pobjectdef(ptypesym(sym)^.restype.def)^.objectoptions) then
  970. begin
  971. { we can ignore the result }
  972. { the definition is modified }
  973. object_dec(typename,pobjectdef(ptypesym(sym)^.restype.def));
  974. newtype:=ptypesym(sym);
  975. end;
  976. end;
  977. end;
  978. { no old type reused ? Then insert this new type }
  979. if not assigned(newtype) then
  980. begin
  981. read_type(tt,typename);
  982. storetokenpos:=tokenpos;
  983. tokenpos:=defpos;
  984. newtype:=new(ptypesym,init(typename,tt));
  985. newtype:=ptypesym(symtablestack^.insert(newtype));
  986. tokenpos:=storetokenpos;
  987. end;
  988. consume(_SEMICOLON);
  989. if assigned(newtype^.restype.def) and
  990. (newtype^.restype.def^.deftype=procvardef) then
  991. parse_var_proc_directives(psym(newtype));
  992. until token<>_ID;
  993. typecanbeforward:=false;
  994. symtablestack^.foreach({$ifndef TP}@{$endif}resolve_type_forward);
  995. block_type:=old_block_type;
  996. end;
  997. procedure var_dec;
  998. { parses variable declarations and inserts them in }
  999. { the top symbol table of symtablestack }
  1000. begin
  1001. consume(_VAR);
  1002. read_var_decs(false,false,false);
  1003. end;
  1004. procedure threadvar_dec;
  1005. { parses thread variable declarations and inserts them in }
  1006. { the top symbol table of symtablestack }
  1007. begin
  1008. consume(_THREADVAR);
  1009. if not(symtablestack^.symtabletype in [staticsymtable,globalsymtable]) then
  1010. message(parser_e_threadvars_only_sg);
  1011. read_var_decs(false,false,true);
  1012. end;
  1013. procedure resourcestring_dec;
  1014. var
  1015. name : stringid;
  1016. p : ptree;
  1017. storetokenpos,filepos : tfileposinfo;
  1018. old_block_type : tblock_type;
  1019. sp : pchar;
  1020. begin
  1021. consume(_RESOURCESTRING);
  1022. if not(symtablestack^.symtabletype in [staticsymtable,globalsymtable]) then
  1023. message(parser_e_resourcestring_only_sg);
  1024. old_block_type:=block_type;
  1025. block_type:=bt_const;
  1026. repeat
  1027. name:=pattern;
  1028. filepos:=tokenpos;
  1029. consume(_ID);
  1030. case token of
  1031. _EQUAL:
  1032. begin
  1033. consume(_EQUAL);
  1034. p:=comp_expr(true);
  1035. do_firstpass(p);
  1036. storetokenpos:=tokenpos;
  1037. tokenpos:=filepos;
  1038. case p^.treetype of
  1039. ordconstn:
  1040. begin
  1041. if is_constcharnode(p) then
  1042. begin
  1043. getmem(sp,2);
  1044. sp[0]:=chr(p^.value);
  1045. sp[1]:=#0;
  1046. symtablestack^.insert(new(pconstsym,init_string(name,constresourcestring,sp,1)));
  1047. end
  1048. else
  1049. Message(cg_e_illegal_expression);
  1050. end;
  1051. stringconstn:
  1052. begin
  1053. getmem(sp,p^.length+1);
  1054. move(p^.value_str^,sp^,p^.length+1);
  1055. symtablestack^.insert(new(pconstsym,init_string(name,constresourcestring,sp,p^.length)));
  1056. end;
  1057. else
  1058. Message(cg_e_illegal_expression);
  1059. end;
  1060. tokenpos:=storetokenpos;
  1061. consume(_SEMICOLON);
  1062. disposetree(p);
  1063. end;
  1064. else consume(_EQUAL);
  1065. end;
  1066. until token<>_ID;
  1067. block_type:=old_block_type;
  1068. end;
  1069. procedure Not_supported_for_inline(t : ttoken);
  1070. begin
  1071. if assigned(aktprocsym) and
  1072. (pocall_inline in aktprocsym^.definition^.proccalloptions) then
  1073. Begin
  1074. Message1(parser_w_not_supported_for_inline,tokenstring(t));
  1075. Message(parser_w_inlining_disabled);
  1076. {$ifdef INCLUDEOK}
  1077. exclude(aktprocsym^.definition^.proccalloptions,pocall_inline);
  1078. {$else}
  1079. aktprocsym^.definition^.proccalloptions:=aktprocsym^.definition^.proccalloptions-[pocall_inline];
  1080. {$endif}
  1081. End;
  1082. end;
  1083. procedure read_declarations(islibrary : boolean);
  1084. begin
  1085. repeat
  1086. case token of
  1087. _LABEL:
  1088. begin
  1089. Not_supported_for_inline(token);
  1090. label_dec;
  1091. end;
  1092. _CONST:
  1093. begin
  1094. Not_supported_for_inline(token);
  1095. const_dec;
  1096. end;
  1097. _TYPE:
  1098. begin
  1099. Not_supported_for_inline(token);
  1100. type_dec;
  1101. end;
  1102. _VAR:
  1103. var_dec;
  1104. _THREADVAR:
  1105. threadvar_dec;
  1106. _CONSTRUCTOR,_DESTRUCTOR,
  1107. _FUNCTION,_PROCEDURE,_OPERATOR,_CLASS:
  1108. begin
  1109. Not_supported_for_inline(token);
  1110. read_proc;
  1111. end;
  1112. _RESOURCESTRING:
  1113. resourcestring_dec;
  1114. _EXPORTS:
  1115. begin
  1116. Not_supported_for_inline(token);
  1117. { here we should be at lexlevel 1, no ? PM }
  1118. if (lexlevel<>main_program_level) or
  1119. (current_module^.is_unit) then
  1120. begin
  1121. Message(parser_e_syntax_error);
  1122. consume_all_until(_SEMICOLON);
  1123. end
  1124. else if islibrary or (target_info.target=target_i386_WIN32) then
  1125. read_exports;
  1126. end
  1127. else break;
  1128. end;
  1129. until false;
  1130. end;
  1131. procedure read_interface_declarations;
  1132. begin
  1133. {Since the body is now parsed at lexlevel 1, and the declarations
  1134. must be parsed at the same lexlevel we increase the lexlevel.}
  1135. inc(lexlevel);
  1136. repeat
  1137. case token of
  1138. _CONST : const_dec;
  1139. _TYPE : type_dec;
  1140. _VAR : var_dec;
  1141. _THREADVAR : threadvar_dec;
  1142. _RESOURCESTRING:
  1143. resourcestring_dec;
  1144. _FUNCTION,
  1145. _PROCEDURE,
  1146. _OPERATOR : read_proc;
  1147. else
  1148. break;
  1149. end;
  1150. until false;
  1151. dec(lexlevel);
  1152. end;
  1153. end.
  1154. {
  1155. $Log$
  1156. Revision 1.180 2000-02-09 13:22:56 peter
  1157. * log truncated
  1158. Revision 1.179 2000/01/20 12:29:02 pierre
  1159. * bug 801 fixed
  1160. Revision 1.178 2000/01/11 17:16:05 jonas
  1161. * removed a lot of memory leaks when an error is encountered (caused by
  1162. procinfo and pstringcontainers). There are still plenty left though :)
  1163. Revision 1.177 2000/01/10 11:14:19 peter
  1164. * fixed memory leak with options, you must use StopOptions instead of
  1165. Stop
  1166. * fixed memory leak with forward resolving, make_ref is now false
  1167. Revision 1.176 2000/01/07 01:14:28 peter
  1168. * updated copyright to 2000
  1169. Revision 1.175 1999/12/10 10:04:21 peter
  1170. * also check elementtype of arraydef for forwarddef
  1171. Revision 1.174 1999/12/01 12:42:32 peter
  1172. * fixed bug 698
  1173. * removed some notes about unused vars
  1174. Revision 1.173 1999/11/30 10:40:44 peter
  1175. + ttype, tsymlist
  1176. Revision 1.172 1999/11/29 15:18:27 pierre
  1177. + allow exports in win32 executables
  1178. Revision 1.171 1999/11/09 23:43:08 pierre
  1179. * better browser info
  1180. Revision 1.170 1999/11/09 23:06:45 peter
  1181. * esi_offset -> selfpointer_offset to be newcg compatible
  1182. * hcogegen -> cgbase fixes for newcg
  1183. Revision 1.169 1999/11/09 12:58:29 peter
  1184. * support absolute unit.variable
  1185. Revision 1.168 1999/11/06 14:34:21 peter
  1186. * truncated log to 20 revs
  1187. Revision 1.167 1999/10/26 12:30:44 peter
  1188. * const parameter is now checked
  1189. * better and generic check if a node can be used for assigning
  1190. * export fixes
  1191. * procvar equal works now (it never had worked at least from 0.99.8)
  1192. * defcoll changed to linkedlist with pparaitem so it can easily be
  1193. walked both directions
  1194. Revision 1.166 1999/10/22 10:39:34 peter
  1195. * split type reading from pdecl to ptype unit
  1196. * parameter_dec routine is now used for procedure and procvars
  1197. Revision 1.165 1999/10/21 16:41:41 florian
  1198. * problems with readln fixed: esi wasn't restored correctly when
  1199. reading ordinal fields of objects futher the register allocation
  1200. didn't take care of the extra register when reading ordinal values
  1201. * enumerations can now be used in constant indexes of properties
  1202. Revision 1.164 1999/10/14 14:57:52 florian
  1203. - removed the hcodegen use in the new cg, use cgbase instead
  1204. Revision 1.163 1999/10/06 17:39:14 peter
  1205. * fixed stabs writting for forward types
  1206. Revision 1.162 1999/10/03 19:44:42 peter
  1207. * removed objpasunit reference, tvarrec is now searched in systemunit
  1208. where it already was located
  1209. Revision 1.161 1999/10/01 11:18:02 peter
  1210. * class/record type forward checking fixed
  1211. Revision 1.159 1999/10/01 10:05:42 peter
  1212. + procedure directive support in const declarations, fixes bug 232
  1213. }