hcgdata.pas 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl
  4. Routines for the code generation of data structures
  5. like VMT,Messages
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. unit hcgdata;
  20. interface
  21. uses
  22. symtable,aasm;
  23. { generates the message tables for a class }
  24. function genstrmsgtab(_class : pobjectdef) : pasmlabel;
  25. function genintmsgtab(_class : pobjectdef) : pasmlabel;
  26. { generates the method name table }
  27. function genpublishedmethodstable(_class : pobjectdef) : pasmlabel;
  28. { generates a VMT for _class }
  29. procedure genvmt(list : paasmoutput;_class : pobjectdef);
  30. implementation
  31. uses
  32. strings,cobjects,
  33. globtype,globals,verbose,
  34. symconst,types,
  35. hcodegen;
  36. {*****************************************************************************
  37. Message
  38. *****************************************************************************}
  39. type
  40. pprocdeftree = ^tprocdeftree;
  41. tprocdeftree = record
  42. p : pprocdef;
  43. nl : pasmlabel;
  44. l,r : pprocdeftree;
  45. end;
  46. var
  47. root : pprocdeftree;
  48. count : longint;
  49. procedure insertstr(p : pprocdeftree;var at : pprocdeftree);
  50. var
  51. i : longint;
  52. begin
  53. if at=nil then
  54. begin
  55. at:=p;
  56. inc(count);
  57. end
  58. else
  59. begin
  60. i:=strcomp(p^.p^.messageinf.str,at^.p^.messageinf.str);
  61. if i<0 then
  62. insertstr(p,at^.l)
  63. else if i>0 then
  64. insertstr(p,at^.r)
  65. else
  66. Message1(parser_e_duplicate_message_label,strpas(p^.p^.messageinf.str));
  67. end;
  68. end;
  69. procedure disposeprocdeftree(p : pprocdeftree);
  70. begin
  71. if assigned(p^.l) then
  72. disposeprocdeftree(p^.l);
  73. if assigned(p^.r) then
  74. disposeprocdeftree(p^.r);
  75. dispose(p);
  76. end;
  77. procedure insertmsgstr(p : pnamedindexobject);{$ifndef FPC}far;{$endif FPC}
  78. var
  79. hp : pprocdef;
  80. pt : pprocdeftree;
  81. begin
  82. if psym(p)^.typ=procsym then
  83. begin
  84. hp:=pprocsym(p)^.definition;
  85. while assigned(hp) do
  86. begin
  87. if (po_msgstr in hp^.procoptions) then
  88. begin
  89. new(pt);
  90. pt^.p:=hp;
  91. pt^.l:=nil;
  92. pt^.r:=nil;
  93. insertstr(pt,root);
  94. end;
  95. hp:=hp^.nextoverloaded;
  96. end;
  97. end;
  98. end;
  99. procedure insertint(p : pprocdeftree;var at : pprocdeftree);
  100. begin
  101. if at=nil then
  102. begin
  103. at:=p;
  104. inc(count);
  105. end
  106. else
  107. begin
  108. if p^.p^.messageinf.i<at^.p^.messageinf.i then
  109. insertint(p,at^.l)
  110. else if p^.p^.messageinf.i>at^.p^.messageinf.i then
  111. insertint(p,at^.r)
  112. else
  113. Message1(parser_e_duplicate_message_label,tostr(p^.p^.messageinf.i));
  114. end;
  115. end;
  116. procedure insertmsgint(p : pnamedindexobject);{$ifndef FPC}far;{$endif FPC}
  117. var
  118. hp : pprocdef;
  119. pt : pprocdeftree;
  120. begin
  121. if psym(p)^.typ=procsym then
  122. begin
  123. hp:=pprocsym(p)^.definition;
  124. while assigned(hp) do
  125. begin
  126. if (po_msgint in hp^.procoptions) then
  127. begin
  128. new(pt);
  129. pt^.p:=hp;
  130. pt^.l:=nil;
  131. pt^.r:=nil;
  132. insertint(pt,root);
  133. end;
  134. hp:=hp^.nextoverloaded;
  135. end;
  136. end;
  137. end;
  138. procedure writenames(p : pprocdeftree);
  139. begin
  140. getdatalabel(p^.nl);
  141. if assigned(p^.l) then
  142. writenames(p^.l);
  143. datasegment^.concat(new(pai_label,init(p^.nl)));
  144. datasegment^.concat(new(pai_const,init_8bit(strlen(p^.p^.messageinf.str))));
  145. datasegment^.concat(new(pai_string,init_pchar(p^.p^.messageinf.str)));
  146. if assigned(p^.r) then
  147. writenames(p^.r);
  148. end;
  149. procedure writestrentry(p : pprocdeftree);
  150. begin
  151. if assigned(p^.l) then
  152. writestrentry(p^.l);
  153. { write name label }
  154. datasegment^.concat(new(pai_const_symbol,init(p^.nl)));
  155. datasegment^.concat(new(pai_const_symbol,initname(p^.p^.mangledname)));
  156. if assigned(p^.r) then
  157. writestrentry(p^.r);
  158. end;
  159. function genstrmsgtab(_class : pobjectdef) : pasmlabel;
  160. var
  161. r : pasmlabel;
  162. begin
  163. root:=nil;
  164. count:=0;
  165. { insert all message handlers into a tree, sorted by name }
  166. _class^.symtable^.foreach({$ifndef TP}@{$endif}insertmsgstr);
  167. { write all names }
  168. if assigned(root) then
  169. writenames(root);
  170. { now start writing of the message string table }
  171. getdatalabel(r);
  172. datasegment^.concat(new(pai_label,init(r)));
  173. genstrmsgtab:=r;
  174. datasegment^.concat(new(pai_const,init_32bit(count)));
  175. if assigned(root) then
  176. begin
  177. writestrentry(root);
  178. disposeprocdeftree(root);
  179. end;
  180. end;
  181. procedure writeintentry(p : pprocdeftree);
  182. begin
  183. if assigned(p^.l) then
  184. writeintentry(p^.l);
  185. { write name label }
  186. datasegment^.concat(new(pai_const,init_32bit(p^.p^.messageinf.i)));
  187. datasegment^.concat(new(pai_const_symbol,initname(p^.p^.mangledname)));
  188. if assigned(p^.r) then
  189. writeintentry(p^.r);
  190. end;
  191. function genintmsgtab(_class : pobjectdef) : pasmlabel;
  192. var
  193. r : pasmlabel;
  194. begin
  195. root:=nil;
  196. count:=0;
  197. { insert all message handlers into a tree, sorted by name }
  198. _class^.symtable^.foreach({$ifndef TP}@{$endif}insertmsgint);
  199. { now start writing of the message string table }
  200. getdatalabel(r);
  201. datasegment^.concat(new(pai_label,init(r)));
  202. genintmsgtab:=r;
  203. datasegment^.concat(new(pai_const,init_32bit(count)));
  204. if assigned(root) then
  205. begin
  206. writeintentry(root);
  207. disposeprocdeftree(root);
  208. end;
  209. end;
  210. procedure do_count(p : pnamedindexobject);{$ifndef FPC}far;{$endif FPC}
  211. begin
  212. if (psym(p)^.typ=procsym) and (sp_published in psym(p)^.symoptions) then
  213. inc(count);
  214. end;
  215. procedure genpubmethodtableentry(p : pnamedindexobject);{$ifndef FPC}far;{$endif FPC}
  216. var
  217. hp : pprocdef;
  218. l : pasmlabel;
  219. begin
  220. if (psym(p)^.typ=procsym) and (sp_published in psym(p)^.symoptions) then
  221. begin
  222. hp:=pprocsym(p)^.definition;
  223. if assigned(hp^.nextoverloaded) then
  224. internalerror(1209992);
  225. getlabel(l);
  226. consts^.concat(new(pai_label,init(l)));
  227. consts^.concat(new(pai_const,init_8bit(length(p^.name))));
  228. consts^.concat(new(pai_string,init(p^.name)));
  229. datasegment^.concat(new(pai_const_symbol,init(l)));
  230. datasegment^.concat(new(pai_const_symbol,initname(hp^.mangledname)));
  231. end;
  232. end;
  233. function genpublishedmethodstable(_class : pobjectdef) : pasmlabel;
  234. var
  235. l : pasmlabel;
  236. begin
  237. count:=0;
  238. _class^.symtable^.foreach({$ifndef TP}@{$endif}do_count);
  239. if count>0 then
  240. begin
  241. getlabel(l);
  242. datasegment^.concat(new(pai_label,init(l)));
  243. datasegment^.concat(new(pai_const,init_32bit(count)));
  244. _class^.symtable^.foreach({$ifndef TP}@{$endif}genpubmethodtableentry);
  245. genpublishedmethodstable:=l;
  246. end
  247. else
  248. genpublishedmethodstable:=nil;
  249. end;
  250. {*****************************************************************************
  251. VMT
  252. *****************************************************************************}
  253. type
  254. pprocdefcoll = ^tprocdefcoll;
  255. tprocdefcoll = record
  256. next : pprocdefcoll;
  257. data : pprocdef;
  258. end;
  259. psymcoll = ^tsymcoll;
  260. tsymcoll = record
  261. next : psymcoll;
  262. name : pstring;
  263. data : pprocdefcoll;
  264. end;
  265. var
  266. wurzel : psymcoll;
  267. nextvirtnumber : longint;
  268. _c : pobjectdef;
  269. has_constructor,has_virtual_method : boolean;
  270. procedure eachsym(sym : pnamedindexobject);{$ifndef FPC}far;{$endif FPC}
  271. var
  272. procdefcoll : pprocdefcoll;
  273. hp : pprocdef;
  274. symcoll : psymcoll;
  275. _name : string;
  276. stored : boolean;
  277. { creates a new entry in the procsym list }
  278. procedure newentry;
  279. begin
  280. { if not, generate a new symbol item }
  281. new(symcoll);
  282. symcoll^.name:=stringdup(sym^.name);
  283. symcoll^.next:=wurzel;
  284. symcoll^.data:=nil;
  285. wurzel:=symcoll;
  286. hp:=pprocsym(sym)^.definition;
  287. { inserts all definitions }
  288. while assigned(hp) do
  289. begin
  290. new(procdefcoll);
  291. procdefcoll^.data:=hp;
  292. procdefcoll^.next:=symcoll^.data;
  293. symcoll^.data:=procdefcoll;
  294. { if it's a virtual method }
  295. if (po_virtualmethod in hp^.procoptions) then
  296. begin
  297. { then it gets a number ... }
  298. hp^.extnumber:=nextvirtnumber;
  299. { and we inc the number }
  300. inc(nextvirtnumber);
  301. has_virtual_method:=true;
  302. end;
  303. if (hp^.proctypeoption=potype_constructor) then
  304. has_constructor:=true;
  305. { check, if a method should be overridden }
  306. if (po_overridingmethod in hp^.procoptions) then
  307. Message1(parser_e_nothing_to_be_overridden,_c^.objname^+'.'+_name+hp^.demangled_paras);
  308. { next overloaded method }
  309. hp:=hp^.nextoverloaded;
  310. end;
  311. end;
  312. begin
  313. { put only sub routines into the VMT }
  314. if psym(sym)^.typ=procsym then
  315. begin
  316. _name:=sym^.name;
  317. symcoll:=wurzel;
  318. while assigned(symcoll) do
  319. begin
  320. { does the symbol already exist in the list ? }
  321. if _name=symcoll^.name^ then
  322. begin
  323. { walk through all defs of the symbol }
  324. hp:=pprocsym(sym)^.definition;
  325. while assigned(hp) do
  326. begin
  327. { compare with all stored definitions }
  328. procdefcoll:=symcoll^.data;
  329. stored:=false;
  330. while assigned(procdefcoll) do
  331. begin
  332. { compare parameters }
  333. if equal_paras(procdefcoll^.data^.para,hp^.para,false) and
  334. (
  335. (po_virtualmethod in procdefcoll^.data^.procoptions) or
  336. (po_virtualmethod in hp^.procoptions)
  337. ) then
  338. begin { same parameters }
  339. { wenn sie gleich sind }
  340. { und eine davon virtual deklariert ist }
  341. { Fehler falls nur eine VIRTUAL }
  342. if (po_virtualmethod in procdefcoll^.data^.procoptions)<>
  343. (po_virtualmethod in hp^.procoptions) then
  344. begin
  345. { in classes, we hide the old method }
  346. if _c^.is_class then
  347. begin
  348. { warn only if it is the first time,
  349. we hide the method }
  350. if _c=hp^._class then
  351. Message1(parser_w_should_use_override,_c^.objname^+'.'+_name);
  352. newentry;
  353. exit;
  354. end
  355. else
  356. if _c=hp^._class then
  357. begin
  358. if (po_virtualmethod in procdefcoll^.data^.procoptions) then
  359. Message1(parser_w_overloaded_are_not_both_virtual,_c^.objname^+'.'+_name)
  360. else
  361. Message1(parser_w_overloaded_are_not_both_non_virtual,
  362. _c^.objname^+'.'+_name);
  363. newentry;
  364. exit;
  365. end;
  366. end
  367. else
  368. { the flags have to match }
  369. { except abstract and override }
  370. { only if both are virtual !! }
  371. if (procdefcoll^.data^.proccalloptions<>hp^.proccalloptions) or
  372. (procdefcoll^.data^.proctypeoption<>hp^.proctypeoption) or
  373. ((procdefcoll^.data^.procoptions-
  374. [po_abstractmethod,po_overridingmethod,po_assembler])<>
  375. (hp^.procoptions-[po_abstractmethod,po_overridingmethod,po_assembler])) then
  376. Message1(parser_e_header_dont_match_forward,_c^.objname^+'.'+_name);
  377. { check, if the overridden directive is set }
  378. { (povirtualmethod is set! }
  379. { class ? }
  380. if _c^.is_class and
  381. not(po_overridingmethod in hp^.procoptions) then
  382. begin
  383. { warn only if it is the first time,
  384. we hide the method }
  385. if _c=hp^._class then
  386. Message1(parser_w_should_use_override,_c^.objname^+'.'+_name);
  387. newentry;
  388. exit;
  389. end;
  390. { error, if the return types aren't equal }
  391. if not(is_equal(procdefcoll^.data^.rettype.def,hp^.rettype.def)) and
  392. not((procdefcoll^.data^.rettype.def^.deftype=objectdef) and
  393. (hp^.rettype.def^.deftype=objectdef) and
  394. (pobjectdef(procdefcoll^.data^.rettype.def)^.is_class) and
  395. (pobjectdef(hp^.rettype.def)^.is_class) and
  396. (pobjectdef(hp^.rettype.def)^.is_related(
  397. pobjectdef(procdefcoll^.data^.rettype.def)))) then
  398. Message1(parser_e_overloaded_methodes_not_same_ret,_c^.objname^+'.'+_name);
  399. { now set the number }
  400. hp^.extnumber:=procdefcoll^.data^.extnumber;
  401. { and exchange }
  402. procdefcoll^.data:=hp;
  403. stored:=true;
  404. end; { same parameters }
  405. procdefcoll:=procdefcoll^.next;
  406. end;
  407. { if it isn't saved in the list }
  408. { we create a new entry }
  409. if not(stored) then
  410. begin
  411. new(procdefcoll);
  412. procdefcoll^.data:=hp;
  413. procdefcoll^.next:=symcoll^.data;
  414. symcoll^.data:=procdefcoll;
  415. { if the method is virtual ... }
  416. if (po_virtualmethod in hp^.procoptions) then
  417. begin
  418. { ... it will get a number }
  419. hp^.extnumber:=nextvirtnumber;
  420. inc(nextvirtnumber);
  421. end;
  422. { check, if a method should be overridden }
  423. if (po_overridingmethod in hp^.procoptions) then
  424. Message1(parser_e_nothing_to_be_overridden,_c^.objname^+'.'+_name+hp^.demangled_paras);
  425. end;
  426. hp:=hp^.nextoverloaded;
  427. end;
  428. exit;
  429. end;
  430. symcoll:=symcoll^.next;
  431. end;
  432. newentry;
  433. end;
  434. end;
  435. procedure genvmt(list : paasmoutput;_class : pobjectdef);
  436. procedure do_genvmt(p : pobjectdef);
  437. begin
  438. { start with the base class }
  439. if assigned(p^.childof) then
  440. do_genvmt(p^.childof);
  441. { walk through all public syms }
  442. { I had to change that to solve bug0260 (PM)}
  443. {_c:=_class;}
  444. _c:=p;
  445. { Florian, please check if you agree (PM) }
  446. p^.symtable^.foreach({$ifndef TP}@{$endif}eachsym);
  447. end;
  448. var
  449. symcoll : psymcoll;
  450. procdefcoll : pprocdefcoll;
  451. i : longint;
  452. begin
  453. wurzel:=nil;
  454. nextvirtnumber:=0;
  455. has_constructor:=false;
  456. has_virtual_method:=false;
  457. { generates a tree of all used methods }
  458. do_genvmt(_class);
  459. if has_virtual_method and not(has_constructor) then
  460. Message1(parser_w_virtual_without_constructor,_class^.objname^);
  461. { generates the VMT }
  462. { walk trough all numbers for virtual methods and search }
  463. { the method }
  464. for i:=0 to nextvirtnumber-1 do
  465. begin
  466. symcoll:=wurzel;
  467. { walk trough all symbols }
  468. while assigned(symcoll) do
  469. begin
  470. { walk trough all methods }
  471. procdefcoll:=symcoll^.data;
  472. while assigned(procdefcoll) do
  473. begin
  474. { writes the addresses to the VMT }
  475. { but only this which are declared as virtual }
  476. if procdefcoll^.data^.extnumber=i then
  477. begin
  478. if (po_virtualmethod in procdefcoll^.data^.procoptions) then
  479. begin
  480. { if a method is abstract, then is also the }
  481. { class abstract and it's not allow to }
  482. { generates an instance }
  483. if (po_abstractmethod in procdefcoll^.data^.procoptions) then
  484. begin
  485. {$ifdef INCLUDEOK}
  486. include(_class^.objectoptions,oo_has_abstract);
  487. {$else}
  488. _class^.objectoptions:=_class^.objectoptions+[oo_has_abstract];
  489. {$endif}
  490. list^.concat(new(pai_const_symbol,initname('FPC_ABSTRACTERROR')));
  491. end
  492. else
  493. begin
  494. list^.concat(new(pai_const_symbol,
  495. initname(procdefcoll^.data^.mangledname)));
  496. end;
  497. end;
  498. end;
  499. procdefcoll:=procdefcoll^.next;
  500. end;
  501. symcoll:=symcoll^.next;
  502. end;
  503. end;
  504. { disposes the above generated tree }
  505. symcoll:=wurzel;
  506. while assigned(symcoll) do
  507. begin
  508. wurzel:=symcoll^.next;
  509. stringdispose(symcoll^.name);
  510. procdefcoll:=symcoll^.data;
  511. while assigned(procdefcoll) do
  512. begin
  513. symcoll^.data:=procdefcoll^.next;
  514. dispose(procdefcoll);
  515. procdefcoll:=symcoll^.data;
  516. end;
  517. dispose(symcoll);
  518. symcoll:=wurzel;
  519. end;
  520. end;
  521. end.
  522. {
  523. $Log$
  524. Revision 1.23 2000-01-07 01:14:27 peter
  525. * updated copyright to 2000
  526. Revision 1.22 1999/12/02 19:22:16 peter
  527. * write also parameters for override info
  528. Revision 1.21 1999/12/01 12:42:32 peter
  529. * fixed bug 698
  530. * removed some notes about unused vars
  531. Revision 1.20 1999/11/30 10:40:43 peter
  532. + ttype, tsymlist
  533. Revision 1.19 1999/11/29 23:42:49 pierre
  534. * fix for form bug 555
  535. Revision 1.18 1999/10/26 12:30:41 peter
  536. * const parameter is now checked
  537. * better and generic check if a node can be used for assigning
  538. * export fixes
  539. * procvar equal works now (it never had worked at least from 0.99.8)
  540. * defcoll changed to linkedlist with pparaitem so it can easily be
  541. walked both directions
  542. Revision 1.17 1999/09/13 16:23:42 peter
  543. * remvoed unused var
  544. Revision 1.16 1999/09/12 14:50:50 florian
  545. + implemented creation of methodname/address tables
  546. Revision 1.15 1999/09/01 13:44:56 florian
  547. * fixed writing of class rtti: vmt offset were written wrong
  548. Revision 1.14 1999/08/03 22:02:52 peter
  549. * moved bitmask constants to sets
  550. * some other type/const renamings
  551. Revision 1.13 1999/07/11 20:10:23 peter
  552. * merged
  553. Revision 1.12 1999/07/08 10:40:37 peter
  554. * merged
  555. Revision 1.11 1999/06/15 13:27:06 pierre
  556. * bug0260 fixed
  557. Revision 1.10.2.2 1999/07/11 20:07:38 peter
  558. * message crash fixed
  559. * no error if self is used with non-string message
  560. Revision 1.10.2.1 1999/07/08 10:38:32 peter
  561. * fixed insertint
  562. Revision 1.10 1999/06/02 22:44:07 pierre
  563. * previous wrong log corrected
  564. Revision 1.9 1999/06/02 22:25:33 pierre
  565. * changed $ifdef FPC @ into $ifndef TP
  566. Revision 1.8 1999/06/01 14:45:49 peter
  567. * @procvar is now always needed for FPC
  568. Revision 1.7 1999/05/27 19:44:30 peter
  569. * removed oldasm
  570. * plabel -> pasmlabel
  571. * -a switches to source writing automaticly
  572. * assembler readers OOPed
  573. * asmsymbol automaticly external
  574. * jumptables and other label fixes for asm readers
  575. Revision 1.6 1999/05/21 13:55:00 peter
  576. * NEWLAB for label as symbol
  577. Revision 1.5 1999/05/17 21:57:07 florian
  578. * new temporary ansistring handling
  579. Revision 1.4 1999/05/13 21:59:27 peter
  580. * removed oldppu code
  581. * warning if objpas is loaded from uses
  582. * first things for new deref writing
  583. Revision 1.3 1999/04/26 13:31:34 peter
  584. * release storenumber,double_checksum
  585. Revision 1.2 1999/04/21 09:43:37 peter
  586. * storenumber works
  587. * fixed some typos in double_checksum
  588. + incompatible types type1 and type2 message (with storenumber)
  589. Revision 1.1 1999/03/24 23:17:00 peter
  590. * fixed bugs 212,222,225,227,229,231,233
  591. }