hcgdata.pas 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. {
  2. $Id$
  3. Copyright (c) 1996-98 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. pt : pprocdeftree;
  219. l : pasmlabel;
  220. begin
  221. if (psym(p)^.typ=procsym) and (sp_published in psym(p)^.symoptions) then
  222. begin
  223. hp:=pprocsym(p)^.definition;
  224. if assigned(hp^.nextoverloaded) then
  225. internalerror(1209992);
  226. getlabel(l);
  227. consts^.concat(new(pai_label,init(l)));
  228. consts^.concat(new(pai_const,init_8bit(length(p^.name))));
  229. consts^.concat(new(pai_string,init(p^.name)));
  230. datasegment^.concat(new(pai_const_symbol,init(l)));
  231. datasegment^.concat(new(pai_const_symbol,initname(hp^.mangledname)));
  232. end;
  233. end;
  234. function genpublishedmethodstable(_class : pobjectdef) : pasmlabel;
  235. var
  236. l : pasmlabel;
  237. begin
  238. count:=0;
  239. _class^.symtable^.foreach({$ifndef TP}@{$endif}do_count);
  240. if count>0 then
  241. begin
  242. getlabel(l);
  243. datasegment^.concat(new(pai_label,init(l)));
  244. datasegment^.concat(new(pai_const,init_32bit(count)));
  245. _class^.symtable^.foreach({$ifndef TP}@{$endif}genpubmethodtableentry);
  246. genpublishedmethodstable:=l;
  247. end
  248. else
  249. genpublishedmethodstable:=nil;
  250. end;
  251. {*****************************************************************************
  252. VMT
  253. *****************************************************************************}
  254. type
  255. pprocdefcoll = ^tprocdefcoll;
  256. tprocdefcoll = record
  257. next : pprocdefcoll;
  258. data : pprocdef;
  259. end;
  260. psymcoll = ^tsymcoll;
  261. tsymcoll = record
  262. next : psymcoll;
  263. name : pstring;
  264. data : pprocdefcoll;
  265. end;
  266. var
  267. wurzel : psymcoll;
  268. nextvirtnumber : longint;
  269. _c : pobjectdef;
  270. has_constructor,has_virtual_method : boolean;
  271. procedure eachsym(sym : pnamedindexobject);{$ifndef FPC}far;{$endif FPC}
  272. var
  273. procdefcoll : pprocdefcoll;
  274. hp : pprocdef;
  275. symcoll : psymcoll;
  276. _name : string;
  277. stored : boolean;
  278. { creates a new entry in the procsym list }
  279. procedure newentry;
  280. begin
  281. { if not, generate a new symbol item }
  282. new(symcoll);
  283. symcoll^.name:=stringdup(sym^.name);
  284. symcoll^.next:=wurzel;
  285. symcoll^.data:=nil;
  286. wurzel:=symcoll;
  287. hp:=pprocsym(sym)^.definition;
  288. { inserts all definitions }
  289. while assigned(hp) do
  290. begin
  291. new(procdefcoll);
  292. procdefcoll^.data:=hp;
  293. procdefcoll^.next:=symcoll^.data;
  294. symcoll^.data:=procdefcoll;
  295. { if it's a virtual method }
  296. if (po_virtualmethod in hp^.procoptions) then
  297. begin
  298. { then it gets a number ... }
  299. hp^.extnumber:=nextvirtnumber;
  300. { and we inc the number }
  301. inc(nextvirtnumber);
  302. has_virtual_method:=true;
  303. end;
  304. if (hp^.proctypeoption=potype_constructor) then
  305. has_constructor:=true;
  306. { check, if a method should be overridden }
  307. if (po_overridingmethod in hp^.procoptions) then
  308. Message1(parser_e_nothing_to_be_overridden,_c^.objname^+'.'+_name);
  309. { next overloaded method }
  310. hp:=hp^.nextoverloaded;
  311. end;
  312. end;
  313. begin
  314. { put only sub routines into the VMT }
  315. if psym(sym)^.typ=procsym then
  316. begin
  317. _name:=sym^.name;
  318. symcoll:=wurzel;
  319. while assigned(symcoll) do
  320. begin
  321. { does the symbol already exist in the list ? }
  322. if _name=symcoll^.name^ then
  323. begin
  324. { walk through all defs of the symbol }
  325. hp:=pprocsym(sym)^.definition;
  326. while assigned(hp) do
  327. begin
  328. { compare with all stored definitions }
  329. procdefcoll:=symcoll^.data;
  330. stored:=false;
  331. while assigned(procdefcoll) do
  332. begin
  333. { compare parameters }
  334. if equal_paras(procdefcoll^.data^.para1,hp^.para1,false) and
  335. (
  336. (po_virtualmethod in procdefcoll^.data^.procoptions) or
  337. (po_virtualmethod in hp^.procoptions)
  338. ) then
  339. begin { same parameters }
  340. { wenn sie gleich sind }
  341. { und eine davon virtual deklariert ist }
  342. { Fehler falls nur eine VIRTUAL }
  343. if (po_virtualmethod in procdefcoll^.data^.procoptions)<>
  344. (po_virtualmethod in hp^.procoptions) then
  345. begin
  346. { in classes, we hide the old method }
  347. if _c^.is_class then
  348. begin
  349. { warn only if it is the first time,
  350. we hide the method }
  351. if _c=hp^._class then
  352. Message1(parser_w_should_use_override,_c^.objname^+'.'+_name);
  353. newentry;
  354. exit;
  355. end
  356. else
  357. if _c=hp^._class then
  358. begin
  359. if (po_virtualmethod in procdefcoll^.data^.procoptions) then
  360. Message1(parser_w_overloaded_are_not_both_virtual,_c^.objname^+'.'+_name)
  361. else
  362. Message1(parser_w_overloaded_are_not_both_non_virtual,
  363. _c^.objname^+'.'+_name);
  364. newentry;
  365. exit;
  366. end;
  367. end
  368. else
  369. { the flags have to match }
  370. { except abstract and override }
  371. { only if both are virtual !! }
  372. if (procdefcoll^.data^.proccalloptions<>hp^.proccalloptions) or
  373. (procdefcoll^.data^.proctypeoption<>hp^.proctypeoption) or
  374. ((procdefcoll^.data^.procoptions-[po_abstractmethod,po_overridingmethod])<>
  375. (hp^.procoptions-[po_abstractmethod,po_overridingmethod])) 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^.retdef,hp^.retdef)) and
  392. not((procdefcoll^.data^.retdef^.deftype=objectdef) and
  393. (hp^.retdef^.deftype=objectdef) and
  394. (pobjectdef(procdefcoll^.data^.retdef)^.is_class) and
  395. (pobjectdef(hp^.retdef)^.is_class) and
  396. (pobjectdef(hp^.retdef)^.is_related(pobjectdef(procdefcoll^.data^.retdef)))) then
  397. Message1(parser_e_overloaded_methodes_not_same_ret,_c^.objname^+'.'+_name);
  398. { now set the number }
  399. hp^.extnumber:=procdefcoll^.data^.extnumber;
  400. { and exchange }
  401. procdefcoll^.data:=hp;
  402. stored:=true;
  403. end; { same parameters }
  404. procdefcoll:=procdefcoll^.next;
  405. end;
  406. { if it isn't saved in the list }
  407. { we create a new entry }
  408. if not(stored) then
  409. begin
  410. new(procdefcoll);
  411. procdefcoll^.data:=hp;
  412. procdefcoll^.next:=symcoll^.data;
  413. symcoll^.data:=procdefcoll;
  414. { if the method is virtual ... }
  415. if (po_virtualmethod in hp^.procoptions) then
  416. begin
  417. { ... it will get a number }
  418. hp^.extnumber:=nextvirtnumber;
  419. inc(nextvirtnumber);
  420. end;
  421. { check, if a method should be overridden }
  422. if (po_overridingmethod in hp^.procoptions) then
  423. Message1(parser_e_nothing_to_be_overridden,_c^.objname^+'.'+_name);
  424. end;
  425. hp:=hp^.nextoverloaded;
  426. end;
  427. exit;
  428. end;
  429. symcoll:=symcoll^.next;
  430. end;
  431. newentry;
  432. end;
  433. end;
  434. procedure genvmt(list : paasmoutput;_class : pobjectdef);
  435. procedure do_genvmt(p : pobjectdef);
  436. begin
  437. { start with the base class }
  438. if assigned(p^.childof) then
  439. do_genvmt(p^.childof);
  440. { walk through all public syms }
  441. { I had to change that to solve bug0260 (PM)}
  442. {_c:=_class;}
  443. _c:=p;
  444. { Florian, please check if you agree (PM) }
  445. p^.symtable^.foreach({$ifndef TP}@{$endif}eachsym);
  446. end;
  447. var
  448. symcoll : psymcoll;
  449. procdefcoll : pprocdefcoll;
  450. i : longint;
  451. begin
  452. wurzel:=nil;
  453. nextvirtnumber:=0;
  454. has_constructor:=false;
  455. has_virtual_method:=false;
  456. { generates a tree of all used methods }
  457. do_genvmt(_class);
  458. if has_virtual_method and not(has_constructor) then
  459. Message1(parser_w_virtual_without_constructor,_class^.objname^);
  460. { generates the VMT }
  461. { walk trough all numbers for virtual methods and search }
  462. { the method }
  463. for i:=0 to nextvirtnumber-1 do
  464. begin
  465. symcoll:=wurzel;
  466. { walk trough all symbols }
  467. while assigned(symcoll) do
  468. begin
  469. { walk trough all methods }
  470. procdefcoll:=symcoll^.data;
  471. while assigned(procdefcoll) do
  472. begin
  473. { writes the addresses to the VMT }
  474. { but only this which are declared as virtual }
  475. if procdefcoll^.data^.extnumber=i then
  476. begin
  477. if (po_virtualmethod in procdefcoll^.data^.procoptions) then
  478. begin
  479. { if a method is abstract, then is also the }
  480. { class abstract and it's not allow to }
  481. { generates an instance }
  482. if (po_abstractmethod in procdefcoll^.data^.procoptions) then
  483. begin
  484. {$ifdef INCLUDEOK}
  485. include(_class^.objectoptions,oo_has_abstract);
  486. {$else}
  487. _class^.objectoptions:=_class^.objectoptions+[oo_has_abstract];
  488. {$endif}
  489. list^.concat(new(pai_const_symbol,initname('FPC_ABSTRACTERROR')));
  490. end
  491. else
  492. begin
  493. list^.concat(new(pai_const_symbol,
  494. initname(procdefcoll^.data^.mangledname)));
  495. end;
  496. end;
  497. end;
  498. procdefcoll:=procdefcoll^.next;
  499. end;
  500. symcoll:=symcoll^.next;
  501. end;
  502. end;
  503. { disposes the above generated tree }
  504. symcoll:=wurzel;
  505. while assigned(symcoll) do
  506. begin
  507. wurzel:=symcoll^.next;
  508. stringdispose(symcoll^.name);
  509. procdefcoll:=symcoll^.data;
  510. while assigned(procdefcoll) do
  511. begin
  512. symcoll^.data:=procdefcoll^.next;
  513. dispose(procdefcoll);
  514. procdefcoll:=symcoll^.data;
  515. end;
  516. dispose(symcoll);
  517. symcoll:=wurzel;
  518. end;
  519. end;
  520. end.
  521. {
  522. $Log$
  523. Revision 1.16 1999-09-12 14:50:50 florian
  524. + implemented creation of methodname/address tables
  525. Revision 1.15 1999/09/01 13:44:56 florian
  526. * fixed writing of class rtti: vmt offset were written wrong
  527. Revision 1.14 1999/08/03 22:02:52 peter
  528. * moved bitmask constants to sets
  529. * some other type/const renamings
  530. Revision 1.13 1999/07/11 20:10:23 peter
  531. * merged
  532. Revision 1.12 1999/07/08 10:40:37 peter
  533. * merged
  534. Revision 1.11 1999/06/15 13:27:06 pierre
  535. * bug0260 fixed
  536. Revision 1.10.2.2 1999/07/11 20:07:38 peter
  537. * message crash fixed
  538. * no error if self is used with non-string message
  539. Revision 1.10.2.1 1999/07/08 10:38:32 peter
  540. * fixed insertint
  541. Revision 1.10 1999/06/02 22:44:07 pierre
  542. * previous wrong log corrected
  543. Revision 1.9 1999/06/02 22:25:33 pierre
  544. * changed $ifdef FPC @ into $ifndef TP
  545. Revision 1.8 1999/06/01 14:45:49 peter
  546. * @procvar is now always needed for FPC
  547. Revision 1.7 1999/05/27 19:44:30 peter
  548. * removed oldasm
  549. * plabel -> pasmlabel
  550. * -a switches to source writing automaticly
  551. * assembler readers OOPed
  552. * asmsymbol automaticly external
  553. * jumptables and other label fixes for asm readers
  554. Revision 1.6 1999/05/21 13:55:00 peter
  555. * NEWLAB for label as symbol
  556. Revision 1.5 1999/05/17 21:57:07 florian
  557. * new temporary ansistring handling
  558. Revision 1.4 1999/05/13 21:59:27 peter
  559. * removed oldppu code
  560. * warning if objpas is loaded from uses
  561. * first things for new deref writing
  562. Revision 1.3 1999/04/26 13:31:34 peter
  563. * release storenumber,double_checksum
  564. Revision 1.2 1999/04/21 09:43:37 peter
  565. * storenumber works
  566. * fixed some typos in double_checksum
  567. + incompatible types type1 and type2 message (with storenumber)
  568. Revision 1.1 1999/03/24 23:17:00 peter
  569. * fixed bugs 212,222,225,227,229,231,233
  570. }