hcgdata.pas 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  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. 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);
  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-[po_abstractmethod,po_overridingmethod])<>
  374. (hp^.procoptions-[po_abstractmethod,po_overridingmethod])) then
  375. Message1(parser_e_header_dont_match_forward,_c^.objname^+'.'+_name);
  376. { check, if the overridden directive is set }
  377. { (povirtualmethod is set! }
  378. { class ? }
  379. if _c^.is_class and
  380. not(po_overridingmethod in hp^.procoptions) then
  381. begin
  382. { warn only if it is the first time,
  383. we hide the method }
  384. if _c=hp^._class then
  385. Message1(parser_w_should_use_override,_c^.objname^+'.'+_name);
  386. newentry;
  387. exit;
  388. end;
  389. { error, if the return types aren't equal }
  390. if not(is_equal(procdefcoll^.data^.retdef,hp^.retdef)) and
  391. not((procdefcoll^.data^.retdef^.deftype=objectdef) and
  392. (hp^.retdef^.deftype=objectdef) and
  393. (pobjectdef(procdefcoll^.data^.retdef)^.is_class) and
  394. (pobjectdef(hp^.retdef)^.is_class) and
  395. (pobjectdef(hp^.retdef)^.is_related(pobjectdef(procdefcoll^.data^.retdef)))) then
  396. Message1(parser_e_overloaded_methodes_not_same_ret,_c^.objname^+'.'+_name);
  397. { now set the number }
  398. hp^.extnumber:=procdefcoll^.data^.extnumber;
  399. { and exchange }
  400. procdefcoll^.data:=hp;
  401. stored:=true;
  402. end; { same parameters }
  403. procdefcoll:=procdefcoll^.next;
  404. end;
  405. { if it isn't saved in the list }
  406. { we create a new entry }
  407. if not(stored) then
  408. begin
  409. new(procdefcoll);
  410. procdefcoll^.data:=hp;
  411. procdefcoll^.next:=symcoll^.data;
  412. symcoll^.data:=procdefcoll;
  413. { if the method is virtual ... }
  414. if (po_virtualmethod in hp^.procoptions) then
  415. begin
  416. { ... it will get a number }
  417. hp^.extnumber:=nextvirtnumber;
  418. inc(nextvirtnumber);
  419. end;
  420. { check, if a method should be overridden }
  421. if (po_overridingmethod in hp^.procoptions) then
  422. Message1(parser_e_nothing_to_be_overridden,_c^.objname^+'.'+_name);
  423. end;
  424. hp:=hp^.nextoverloaded;
  425. end;
  426. exit;
  427. end;
  428. symcoll:=symcoll^.next;
  429. end;
  430. newentry;
  431. end;
  432. end;
  433. procedure genvmt(list : paasmoutput;_class : pobjectdef);
  434. procedure do_genvmt(p : pobjectdef);
  435. begin
  436. { start with the base class }
  437. if assigned(p^.childof) then
  438. do_genvmt(p^.childof);
  439. { walk through all public syms }
  440. { I had to change that to solve bug0260 (PM)}
  441. {_c:=_class;}
  442. _c:=p;
  443. { Florian, please check if you agree (PM) }
  444. p^.symtable^.foreach({$ifndef TP}@{$endif}eachsym);
  445. end;
  446. var
  447. symcoll : psymcoll;
  448. procdefcoll : pprocdefcoll;
  449. i : longint;
  450. begin
  451. wurzel:=nil;
  452. nextvirtnumber:=0;
  453. has_constructor:=false;
  454. has_virtual_method:=false;
  455. { generates a tree of all used methods }
  456. do_genvmt(_class);
  457. if has_virtual_method and not(has_constructor) then
  458. Message1(parser_w_virtual_without_constructor,_class^.objname^);
  459. { generates the VMT }
  460. { walk trough all numbers for virtual methods and search }
  461. { the method }
  462. for i:=0 to nextvirtnumber-1 do
  463. begin
  464. symcoll:=wurzel;
  465. { walk trough all symbols }
  466. while assigned(symcoll) do
  467. begin
  468. { walk trough all methods }
  469. procdefcoll:=symcoll^.data;
  470. while assigned(procdefcoll) do
  471. begin
  472. { writes the addresses to the VMT }
  473. { but only this which are declared as virtual }
  474. if procdefcoll^.data^.extnumber=i then
  475. begin
  476. if (po_virtualmethod in procdefcoll^.data^.procoptions) then
  477. begin
  478. { if a method is abstract, then is also the }
  479. { class abstract and it's not allow to }
  480. { generates an instance }
  481. if (po_abstractmethod in procdefcoll^.data^.procoptions) then
  482. begin
  483. {$ifdef INCLUDEOK}
  484. include(_class^.objectoptions,oo_has_abstract);
  485. {$else}
  486. _class^.objectoptions:=_class^.objectoptions+[oo_has_abstract];
  487. {$endif}
  488. list^.concat(new(pai_const_symbol,initname('FPC_ABSTRACTERROR')));
  489. end
  490. else
  491. begin
  492. list^.concat(new(pai_const_symbol,
  493. initname(procdefcoll^.data^.mangledname)));
  494. end;
  495. end;
  496. end;
  497. procdefcoll:=procdefcoll^.next;
  498. end;
  499. symcoll:=symcoll^.next;
  500. end;
  501. end;
  502. { disposes the above generated tree }
  503. symcoll:=wurzel;
  504. while assigned(symcoll) do
  505. begin
  506. wurzel:=symcoll^.next;
  507. stringdispose(symcoll^.name);
  508. procdefcoll:=symcoll^.data;
  509. while assigned(procdefcoll) do
  510. begin
  511. symcoll^.data:=procdefcoll^.next;
  512. dispose(procdefcoll);
  513. procdefcoll:=symcoll^.data;
  514. end;
  515. dispose(symcoll);
  516. symcoll:=wurzel;
  517. end;
  518. end;
  519. end.
  520. {
  521. $Log$
  522. Revision 1.18 1999-10-26 12:30:41 peter
  523. * const parameter is now checked
  524. * better and generic check if a node can be used for assigning
  525. * export fixes
  526. * procvar equal works now (it never had worked at least from 0.99.8)
  527. * defcoll changed to linkedlist with pparaitem so it can easily be
  528. walked both directions
  529. Revision 1.17 1999/09/13 16:23:42 peter
  530. * remvoed unused var
  531. Revision 1.16 1999/09/12 14:50:50 florian
  532. + implemented creation of methodname/address tables
  533. Revision 1.15 1999/09/01 13:44:56 florian
  534. * fixed writing of class rtti: vmt offset were written wrong
  535. Revision 1.14 1999/08/03 22:02:52 peter
  536. * moved bitmask constants to sets
  537. * some other type/const renamings
  538. Revision 1.13 1999/07/11 20:10:23 peter
  539. * merged
  540. Revision 1.12 1999/07/08 10:40:37 peter
  541. * merged
  542. Revision 1.11 1999/06/15 13:27:06 pierre
  543. * bug0260 fixed
  544. Revision 1.10.2.2 1999/07/11 20:07:38 peter
  545. * message crash fixed
  546. * no error if self is used with non-string message
  547. Revision 1.10.2.1 1999/07/08 10:38:32 peter
  548. * fixed insertint
  549. Revision 1.10 1999/06/02 22:44:07 pierre
  550. * previous wrong log corrected
  551. Revision 1.9 1999/06/02 22:25:33 pierre
  552. * changed $ifdef FPC @ into $ifndef TP
  553. Revision 1.8 1999/06/01 14:45:49 peter
  554. * @procvar is now always needed for FPC
  555. Revision 1.7 1999/05/27 19:44:30 peter
  556. * removed oldasm
  557. * plabel -> pasmlabel
  558. * -a switches to source writing automaticly
  559. * assembler readers OOPed
  560. * asmsymbol automaticly external
  561. * jumptables and other label fixes for asm readers
  562. Revision 1.6 1999/05/21 13:55:00 peter
  563. * NEWLAB for label as symbol
  564. Revision 1.5 1999/05/17 21:57:07 florian
  565. * new temporary ansistring handling
  566. Revision 1.4 1999/05/13 21:59:27 peter
  567. * removed oldppu code
  568. * warning if objpas is loaded from uses
  569. * first things for new deref writing
  570. Revision 1.3 1999/04/26 13:31:34 peter
  571. * release storenumber,double_checksum
  572. Revision 1.2 1999/04/21 09:43:37 peter
  573. * storenumber works
  574. * fixed some typos in double_checksum
  575. + incompatible types type1 and type2 message (with storenumber)
  576. Revision 1.1 1999/03/24 23:17:00 peter
  577. * fixed bugs 212,222,225,227,229,231,233
  578. }