psub.pas 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl, Daniel Mantione
  4. Does the parsing and codegeneration at subroutine level
  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 psub;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. cclasses,globals,
  23. node,nbas,
  24. symdef,procinfo;
  25. type
  26. tcgprocinfo = class(tprocinfo)
  27. private
  28. procedure add_entry_exit_code;
  29. public
  30. { code for the subroutine as tree }
  31. code : tnode;
  32. { positions in the tree for init/final }
  33. entry_asmnode,
  34. loadpara_asmnode,
  35. exitlabel_asmnode,
  36. init_asmnode,
  37. final_asmnode : tasmnode;
  38. { list to store the procinfo's of the nested procedures }
  39. nestedprocs : tlinkedlist;
  40. constructor create(aparent:tprocinfo);override;
  41. destructor destroy;override;
  42. procedure generate_code;
  43. procedure resetprocdef;
  44. procedure add_to_symtablestack;
  45. procedure remove_from_symtablestack;
  46. procedure parse_body;
  47. end;
  48. procedure printnode_reset;
  49. { reads the declaration blocks }
  50. procedure read_declarations(islibrary : boolean);
  51. { reads declarations in the interface part of a unit }
  52. procedure read_interface_declarations;
  53. implementation
  54. uses
  55. { common }
  56. cutils,
  57. { global }
  58. globtype,tokens,verbose,comphook,
  59. systems,
  60. { aasm }
  61. cpubase,aasmbase,aasmtai,
  62. { symtable }
  63. symconst,symbase,symsym,symtype,symtable,defutil,
  64. paramgr,
  65. ppu,fmodule,
  66. { pass 1 }
  67. nutils,nld,ncal,ncon,nflw,nadd,ncnv,nmem,
  68. pass_1,
  69. {$ifdef state_tracking}
  70. nstate,
  71. {$endif state_tracking}
  72. { pass 2 }
  73. {$ifndef NOPASS2}
  74. pass_2,
  75. {$endif}
  76. { parser }
  77. scanner,
  78. pbase,pstatmnt,pdecl,pdecsub,pexports,
  79. { codegen }
  80. tgobj,cgobj,
  81. ncgutil,regvars
  82. {$ifdef arm}
  83. ,aasmcpu
  84. {$endif arm}
  85. {$ifndef NOOPT}
  86. {$ifdef i386}
  87. ,aopt386
  88. {$else i386}
  89. ,aoptcpu
  90. {$endif i386}
  91. {$endif}
  92. ;
  93. {****************************************************************************
  94. PROCEDURE/FUNCTION BODY PARSING
  95. ****************************************************************************}
  96. procedure initializevars(p:tnamedindexitem;arg:pointer);
  97. var
  98. b : tblocknode;
  99. begin
  100. if tsym(p).typ<>varsym then
  101. exit;
  102. with tvarsym(p) do
  103. begin
  104. if assigned(defaultconstsym) then
  105. begin
  106. b:=tblocknode(arg);
  107. b.left:=cstatementnode.create(
  108. cassignmentnode.create(
  109. cloadnode.create(tsym(p),tsym(p).owner),
  110. cloadnode.create(defaultconstsym,defaultconstsym.owner)),
  111. b.left);
  112. end;
  113. end;
  114. end;
  115. procedure check_finalize_paras(p : tnamedindexitem;arg:pointer);
  116. begin
  117. if (tsym(p).typ=varsym) and
  118. (tvarsym(p).varspez=vs_value) and
  119. not is_class(tvarsym(p).vartype.def) and
  120. tvarsym(p).vartype.def.needs_inittable then
  121. include(current_procinfo.flags,pi_needs_implicit_finally);
  122. end;
  123. procedure check_finalize_locals(p : tnamedindexitem;arg:pointer);
  124. begin
  125. case tsym(p).typ of
  126. varsym :
  127. begin
  128. if (tvarsym(p).refs>0) and
  129. not(vo_is_funcret in tvarsym(p).varoptions) and
  130. not(is_class(tvarsym(p).vartype.def)) and
  131. tvarsym(p).vartype.def.needs_inittable then
  132. include(current_procinfo.flags,pi_needs_implicit_finally);
  133. end;
  134. typedconstsym :
  135. begin
  136. if ttypedconstsym(p).typedconsttype.def.needs_inittable then
  137. include(current_procinfo.flags,pi_needs_implicit_finally);
  138. end;
  139. end;
  140. end;
  141. function block(islibrary : boolean) : tnode;
  142. begin
  143. { parse const,types and vars }
  144. read_declarations(islibrary);
  145. { do we have an assembler block without the po_assembler?
  146. we should allow this for Delphi compatibility (PFV) }
  147. if (token=_ASM) and (m_delphi in aktmodeswitches) then
  148. include(current_procinfo.procdef.procoptions,po_assembler);
  149. { Handle assembler block different }
  150. if (po_assembler in current_procinfo.procdef.procoptions) then
  151. begin
  152. block:=assembler_block;
  153. exit;
  154. end;
  155. {Unit initialization?.}
  156. if (
  157. assigned(current_procinfo.procdef.localst) and
  158. (current_procinfo.procdef.localst.symtablelevel=main_program_level) and
  159. (current_module.is_unit)
  160. ) or
  161. islibrary then
  162. begin
  163. if (token=_END) then
  164. begin
  165. consume(_END);
  166. { We need at least a node, else the entry/exit code is not
  167. generated and thus no PASCALMAIN symbol which we need (PFV) }
  168. if islibrary then
  169. block:=cnothingnode.create
  170. else
  171. block:=nil;
  172. end
  173. else
  174. begin
  175. if token=_INITIALIZATION then
  176. begin
  177. { The library init code is already called and does not
  178. need to be in the initfinal table (PFV) }
  179. if not islibrary then
  180. current_module.flags:=current_module.flags or uf_init;
  181. block:=statement_block(_INITIALIZATION);
  182. end
  183. else if (token=_FINALIZATION) then
  184. begin
  185. if (current_module.flags and uf_finalize)<>0 then
  186. block:=statement_block(_FINALIZATION)
  187. else
  188. begin
  189. { can we allow no INITIALIZATION for DLL ??
  190. I think it should work PM }
  191. block:=nil;
  192. exit;
  193. end;
  194. end
  195. else
  196. begin
  197. { The library init code is already called and does not
  198. need to be in the initfinal table (PFV) }
  199. if not islibrary then
  200. current_module.flags:=current_module.flags or uf_init;
  201. block:=statement_block(_BEGIN);
  202. end;
  203. end;
  204. end
  205. else
  206. begin
  207. block:=statement_block(_BEGIN);
  208. if symtablestack.symtabletype=localsymtable then
  209. symtablestack.foreach_static({$ifdef FPCPROCVAR}@{$endif}initializevars,block);
  210. end;
  211. end;
  212. {****************************************************************************
  213. PROCEDURE/FUNCTION COMPILING
  214. ****************************************************************************}
  215. procedure printnode_reset;
  216. begin
  217. assign(printnodefile,treelogfilename);
  218. {$I-}
  219. rewrite(printnodefile);
  220. {$I+}
  221. if ioresult<>0 then
  222. begin
  223. Comment(V_Error,'Error creating '+treelogfilename);
  224. exit;
  225. end;
  226. close(printnodefile);
  227. end;
  228. procedure printnode_procdef(pd:tprocdef);
  229. begin
  230. assign(printnodefile,treelogfilename);
  231. {$I-}
  232. append(printnodefile);
  233. if ioresult<>0 then
  234. rewrite(printnodefile);
  235. {$I+}
  236. if ioresult<>0 then
  237. begin
  238. Comment(V_Error,'Error creating '+treelogfilename);
  239. exit;
  240. end;
  241. writeln(printnodefile);
  242. writeln(printnodefile,'*******************************************************************************');
  243. writeln(printnodefile,current_procinfo.procdef.fullprocname(false));
  244. writeln(printnodefile,'*******************************************************************************');
  245. printnode(printnodefile,pd.inlininginfo^.code);
  246. close(printnodefile);
  247. end;
  248. function generate_bodyentry_block:tnode;
  249. var
  250. srsym : tsym;
  251. para : tcallparanode;
  252. newstatement : tstatementnode;
  253. htype : ttype;
  254. begin
  255. result:=internalstatements(newstatement);
  256. if assigned(current_procinfo.procdef._class) then
  257. begin
  258. { a constructor needs a help procedure }
  259. if (current_procinfo.procdef.proctypeoption=potype_constructor) then
  260. begin
  261. if is_class(current_procinfo.procdef._class) then
  262. begin
  263. include(current_procinfo.flags,pi_needs_implicit_finally);
  264. srsym:=search_class_member(current_procinfo.procdef._class,'NEWINSTANCE');
  265. if assigned(srsym) and
  266. (srsym.typ=procsym) then
  267. begin
  268. { if vmt<>0 then newinstance }
  269. addstatement(newstatement,cifnode.create(
  270. caddnode.create(unequaln,
  271. load_vmt_pointer_node,
  272. cnilnode.create),
  273. cassignmentnode.create(
  274. ctypeconvnode.create_explicit(
  275. load_self_pointer_node,
  276. voidpointertype),
  277. ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_vmt_pointer_node,[])),
  278. nil));
  279. end
  280. else
  281. internalerror(200305108);
  282. end
  283. else
  284. if is_object(current_procinfo.procdef._class) then
  285. begin
  286. htype.setdef(current_procinfo.procdef._class);
  287. htype.setdef(tpointerdef.create(htype));
  288. { parameter 3 : vmt_offset }
  289. { parameter 2 : address of pointer to vmt,
  290. this is required to allow setting the vmt to -1 to indicate
  291. that memory was allocated }
  292. { parameter 1 : self pointer }
  293. para:=ccallparanode.create(
  294. cordconstnode.create(current_procinfo.procdef._class.vmt_offset,s32inttype,false),
  295. ccallparanode.create(
  296. ctypeconvnode.create_explicit(
  297. load_vmt_pointer_node,
  298. voidpointertype),
  299. ccallparanode.create(
  300. ctypeconvnode.create_explicit(
  301. load_self_pointer_node,
  302. voidpointertype),
  303. nil)));
  304. addstatement(newstatement,cassignmentnode.create(
  305. ctypeconvnode.create_explicit(
  306. load_self_pointer_node,
  307. voidpointertype),
  308. ccallnode.createintern('fpc_help_constructor',para)));
  309. end
  310. else
  311. internalerror(200305103);
  312. { if self=nil then exit
  313. calling fail instead of exit is useless because
  314. there is nothing to dispose (PFV) }
  315. addstatement(newstatement,cifnode.create(
  316. caddnode.create(equaln,
  317. load_self_pointer_node,
  318. cnilnode.create),
  319. cexitnode.create(nil),
  320. nil));
  321. end;
  322. { maybe call BeforeDestruction for classes }
  323. if (current_procinfo.procdef.proctypeoption=potype_destructor) and
  324. is_class(current_procinfo.procdef._class) then
  325. begin
  326. srsym:=search_class_member(current_procinfo.procdef._class,'BEFOREDESTRUCTION');
  327. if assigned(srsym) and
  328. (srsym.typ=procsym) then
  329. begin
  330. { if vmt<>0 then beforedestruction }
  331. addstatement(newstatement,cifnode.create(
  332. caddnode.create(unequaln,
  333. load_vmt_pointer_node,
  334. cnilnode.create),
  335. ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[]),
  336. nil));
  337. end
  338. else
  339. internalerror(200305104);
  340. end;
  341. end;
  342. end;
  343. function generate_bodyexit_block:tnode;
  344. var
  345. srsym : tsym;
  346. para : tcallparanode;
  347. newstatement : tstatementnode;
  348. begin
  349. result:=internalstatements(newstatement);
  350. if assigned(current_procinfo.procdef._class) then
  351. begin
  352. { maybe call AfterConstruction for classes }
  353. if (current_procinfo.procdef.proctypeoption=potype_constructor) and
  354. is_class(current_procinfo.procdef._class) then
  355. begin
  356. srsym:=search_class_member(current_procinfo.procdef._class,'AFTERCONSTRUCTION');
  357. if assigned(srsym) and
  358. (srsym.typ=procsym) then
  359. begin
  360. { Self can be nil when fail is called }
  361. { if self<>nil and vmt<>nil then afterconstruction }
  362. addstatement(newstatement,cifnode.create(
  363. caddnode.create(andn,
  364. caddnode.create(unequaln,
  365. load_self_pointer_node,
  366. cnilnode.create),
  367. caddnode.create(unequaln,
  368. load_vmt_pointer_node,
  369. cnilnode.create)),
  370. ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[]),
  371. nil));
  372. end
  373. else
  374. internalerror(200305106);
  375. end;
  376. { a destructor needs a help procedure }
  377. if (current_procinfo.procdef.proctypeoption=potype_destructor) then
  378. begin
  379. if is_class(current_procinfo.procdef._class) then
  380. begin
  381. srsym:=search_class_member(current_procinfo.procdef._class,'FREEINSTANCE');
  382. if assigned(srsym) and
  383. (srsym.typ=procsym) then
  384. begin
  385. { if self<>0 and vmt=1 then freeinstance }
  386. addstatement(newstatement,cifnode.create(
  387. caddnode.create(andn,
  388. caddnode.create(unequaln,
  389. load_self_pointer_node,
  390. cnilnode.create),
  391. caddnode.create(equaln,
  392. ctypeconvnode.create(
  393. load_vmt_pointer_node,
  394. voidpointertype),
  395. cpointerconstnode.create(1,voidpointertype))),
  396. ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[]),
  397. nil));
  398. end
  399. else
  400. internalerror(200305108);
  401. end
  402. else
  403. if is_object(current_procinfo.procdef._class) then
  404. begin
  405. { finalize object data }
  406. if current_procinfo.procdef._class.needs_inittable then
  407. addstatement(newstatement,finalize_data_node(load_self_node));
  408. { parameter 3 : vmt_offset }
  409. { parameter 2 : pointer to vmt }
  410. { parameter 1 : self pointer }
  411. para:=ccallparanode.create(
  412. cordconstnode.create(current_procinfo.procdef._class.vmt_offset,s32inttype,false),
  413. ccallparanode.create(
  414. ctypeconvnode.create_explicit(
  415. load_vmt_pointer_node,
  416. voidpointertype),
  417. ccallparanode.create(
  418. ctypeconvnode.create_explicit(
  419. load_self_pointer_node,
  420. voidpointertype),
  421. nil)));
  422. addstatement(newstatement,
  423. ccallnode.createintern('fpc_help_destructor',para));
  424. end
  425. else
  426. internalerror(200305105);
  427. end;
  428. end;
  429. end;
  430. function generate_except_block:tnode;
  431. var
  432. pd : tprocdef;
  433. newstatement : tstatementnode;
  434. dummycall : tcallnode;
  435. begin
  436. generate_except_block:=internalstatements(newstatement);
  437. { a constructor needs call destructor (if available) when it
  438. is not inherited }
  439. if assigned(current_procinfo.procdef._class) and
  440. (current_procinfo.procdef.proctypeoption=potype_constructor) then
  441. begin
  442. pd:=current_procinfo.procdef._class.searchdestructor;
  443. if assigned(pd) then
  444. begin
  445. { if vmt<>0 then call destructor }
  446. addstatement(newstatement,cifnode.create(
  447. caddnode.create(unequaln,
  448. load_vmt_pointer_node,
  449. cnilnode.create),
  450. ccallnode.create(nil,tprocsym(pd.procsym),pd.procsym.owner,load_self_node,[]),
  451. nil));
  452. end;
  453. end
  454. else
  455. begin
  456. { no constructor }
  457. { must be the return value finalized before reraising the exception? }
  458. if (not is_void(current_procinfo.procdef.rettype.def)) and
  459. (current_procinfo.procdef.rettype.def.needs_inittable) and
  460. (not is_class(current_procinfo.procdef.rettype.def)) then
  461. addstatement(newstatement,finalize_data_node(load_result_node));
  462. end;
  463. end;
  464. {****************************************************************************
  465. TCGProcInfo
  466. ****************************************************************************}
  467. constructor tcgprocinfo.create(aparent:tprocinfo);
  468. begin
  469. inherited Create(aparent);
  470. nestedprocs:=tlinkedlist.create;
  471. end;
  472. destructor tcgprocinfo.destroy;
  473. begin
  474. nestedprocs.free;
  475. if assigned(code) then
  476. code.free;
  477. inherited destroy;
  478. end;
  479. procedure tcgprocinfo.add_entry_exit_code;
  480. var
  481. finalcode,
  482. bodyentrycode,
  483. bodyexitcode,
  484. exceptcode : tnode;
  485. newblock : tblocknode;
  486. codestatement,
  487. newstatement : tstatementnode;
  488. oldfilepos : tfileposinfo;
  489. begin
  490. oldfilepos:=aktfilepos;
  491. { Generate code/locations used at start of proc }
  492. aktfilepos:=entrypos;
  493. entry_asmnode:=casmnode.create_get_position;
  494. loadpara_asmnode:=casmnode.create_get_position;
  495. init_asmnode:=casmnode.create_get_position;
  496. bodyentrycode:=generate_bodyentry_block;
  497. { Generate code/locations used at end of proc }
  498. aktfilepos:=exitpos;
  499. exitlabel_asmnode:=casmnode.create_get_position;
  500. final_asmnode:=casmnode.create_get_position;
  501. bodyexitcode:=generate_bodyexit_block;
  502. { Generate procedure by combining init+body+final,
  503. depending on the implicit finally we need to add
  504. an try...finally...end wrapper }
  505. newblock:=internalstatements(newstatement);
  506. if (cs_implicit_exceptions in aktmoduleswitches) and
  507. (pi_needs_implicit_finally in flags) and
  508. { but it's useless in init/final code of units }
  509. not(procdef.proctypeoption in [potype_unitfinalize,potype_unitinit]) then
  510. begin
  511. { Generate special exception block only needed when
  512. implicit finaly is used }
  513. aktfilepos:=exitpos;
  514. exceptcode:=generate_except_block;
  515. { Generate code that will be in the try...finally }
  516. finalcode:=internalstatements(codestatement);
  517. addstatement(codestatement,bodyexitcode);
  518. addstatement(codestatement,final_asmnode);
  519. { Initialize before try...finally...end frame }
  520. addstatement(newstatement,loadpara_asmnode);
  521. addstatement(newstatement,entry_asmnode);
  522. addstatement(newstatement,init_asmnode);
  523. addstatement(newstatement,bodyentrycode);
  524. aktfilepos:=entrypos;
  525. addstatement(newstatement,ctryfinallynode.create_implicit(
  526. code,
  527. finalcode,
  528. exceptcode));
  529. addstatement(newstatement,exitlabel_asmnode);
  530. { set flag the implicit finally has been generated }
  531. include(flags,pi_has_implicit_finally);
  532. end
  533. else
  534. begin
  535. addstatement(newstatement,loadpara_asmnode);
  536. addstatement(newstatement,entry_asmnode);
  537. addstatement(newstatement,init_asmnode);
  538. addstatement(newstatement,bodyentrycode);
  539. addstatement(newstatement,code);
  540. addstatement(newstatement,exitlabel_asmnode);
  541. addstatement(newstatement,bodyexitcode);
  542. addstatement(newstatement,final_asmnode);
  543. end;
  544. do_firstpass(newblock);
  545. code:=newblock;
  546. aktfilepos:=oldfilepos;
  547. end;
  548. procedure clearrefs(p : tnamedindexitem;arg:pointer);
  549. begin
  550. if (tsym(p).typ=varsym) then
  551. if tvarsym(p).refs>1 then
  552. tvarsym(p).refs:=1;
  553. end;
  554. procedure tcgprocinfo.generate_code;
  555. var
  556. oldprocinfo : tprocinfo;
  557. oldaktmaxfpuregisters : longint;
  558. oldfilepos : tfileposinfo;
  559. templist : Taasmoutput;
  560. headertai : tai;
  561. begin
  562. { the initialization procedure can be empty, then we
  563. don't need to generate anything. When it was an empty
  564. procedure there would be at least a blocknode }
  565. if not assigned(code) then
  566. exit;
  567. { We need valid code }
  568. if Errorcount<>0 then
  569. exit;
  570. { The RA and Tempgen shall not be available yet }
  571. if assigned(tg) then
  572. internalerror(200309201);
  573. oldprocinfo:=current_procinfo;
  574. oldfilepos:=aktfilepos;
  575. oldaktmaxfpuregisters:=aktmaxfpuregisters;
  576. current_procinfo:=self;
  577. aktfilepos:=entrypos;
  578. { get new labels }
  579. aktbreaklabel:=nil;
  580. aktcontinuelabel:=nil;
  581. templist:=Taasmoutput.create;
  582. { add parast/localst to symtablestack }
  583. add_to_symtablestack;
  584. { when size optimization only count occurrence }
  585. if cs_littlesize in aktglobalswitches then
  586. cg.t_times:=1
  587. else
  588. { reference for repetition is 100 }
  589. cg.t_times:=100;
  590. { clear register count }
  591. symtablestack.foreach_static({$ifdef FPCPROCVAR}@{$endif}clearrefs,nil);
  592. symtablestack.next.foreach_static({$ifdef FPCPROCVAR}@{$endif}clearrefs,nil);
  593. { there's always a call to FPC_INITIALIZEUNITS/FPC_DO_EXIT in the main program }
  594. if (procdef.localst.symtablelevel=main_program_level) and
  595. (not current_module.is_unit) then
  596. include(flags,pi_do_call);
  597. { set implicit_finally flag when there are locals/paras to be finalized }
  598. current_procinfo.procdef.parast.foreach_static({$ifdef FPCPROCVAR}@{$endif}check_finalize_paras,nil);
  599. current_procinfo.procdef.localst.foreach_static({$ifdef FPCPROCVAR}@{$endif}check_finalize_locals,nil);
  600. { firstpass everything }
  601. flowcontrol:=[];
  602. do_firstpass(code);
  603. if code.registersfpu>0 then
  604. include(current_procinfo.flags,pi_uses_fpu);
  605. { add implicit entry and exit code }
  606. add_entry_exit_code;
  607. { only do secondpass if there are no errors }
  608. if ErrorCount=0 then
  609. begin
  610. { set the start offset to the start of the temp area in the stack }
  611. tg:=ttgobj.create;
  612. { Create register allocator }
  613. cg.init_register_allocators;
  614. set_first_temp_offset;
  615. generate_parameter_info;
  616. { Allocate space in temp/registers for parast and localst }
  617. aktfilepos:=entrypos;
  618. gen_alloc_parast(aktproccode,tparasymtable(procdef.parast));
  619. if procdef.localst.symtabletype=localsymtable then
  620. gen_alloc_localst(aktproccode,tlocalsymtable(procdef.localst));
  621. { Store temp offset for information about 'real' temps }
  622. tempstart:=tg.lasttemp;
  623. { Generate code to load register parameters in temps and insert local
  624. copies for values parameters. This must be done before the code for the
  625. body is generated because the localloc is updated.
  626. Note: The generated code will be inserted after the code generation of
  627. the body is finished, because only then the position is known }
  628. {$ifdef oldregvars}
  629. assign_regvars(code);
  630. {$endif oldreg}
  631. aktfilepos:=entrypos;
  632. gen_load_para_value(templist);
  633. { caller paraloc info is also necessary in the stackframe_entry
  634. code of the ppc (and possibly other processors) }
  635. if not procdef.has_paraloc_info then
  636. begin
  637. procdef.requiredargarea:=paramanager.create_paraloc_info(procdef,callerside);
  638. procdef.has_paraloc_info:=true;
  639. end;
  640. { generate code for the node tree }
  641. do_secondpass(code);
  642. aktproccode.concatlist(exprasmlist);
  643. {$ifdef i386}
  644. procdef.fpu_used:=code.registersfpu;
  645. {$endif i386}
  646. { The position of the loadpara_asmnode is now known }
  647. aktproccode.insertlistafter(loadpara_asmnode.currenttai,templist);
  648. { first generate entry and initialize code with the correct
  649. position and switches }
  650. aktfilepos:=entrypos;
  651. aktlocalswitches:=entryswitches;
  652. gen_entry_code(templist);
  653. aktproccode.insertlistafter(entry_asmnode.currenttai,templist);
  654. gen_initialize_code(templist,false);
  655. aktproccode.insertlistafter(init_asmnode.currenttai,templist);
  656. { now generate finalize and exit code with the correct position
  657. and switches }
  658. aktfilepos:=exitpos;
  659. aktlocalswitches:=exitswitches;
  660. gen_finalize_code(templist,false);
  661. { the finalcode must be concated if there was no position available,
  662. using insertlistafter will result in an insert at the start
  663. when currentai=nil }
  664. if assigned(final_asmnode.currenttai) then
  665. aktproccode.insertlistafter(final_asmnode.currenttai,templist)
  666. else
  667. aktproccode.concatlist(templist);
  668. { insert exit label at the correct position }
  669. cg.a_label(templist,aktexitlabel);
  670. if assigned(exitlabel_asmnode.currenttai) then
  671. aktproccode.insertlistafter(exitlabel_asmnode.currenttai,templist)
  672. else
  673. aktproccode.concatlist(templist);
  674. { exit code }
  675. gen_exit_code(templist);
  676. aktproccode.concatlist(templist);
  677. {$ifdef OLDREGVARS}
  678. { note: this must be done only after as much code as possible has }
  679. { been generated. The result is that when you ungetregister() a }
  680. { regvar, it will actually free the regvar (and alse free the }
  681. { the regvars at the same time). Doing this too early will }
  682. { confuse the register allocator, as the regvars will still be }
  683. { used. It should be done before loading the result regs (so }
  684. { they don't conflict with the regvars) and before }
  685. { gen_entry_code (that one has to be able to allocate the }
  686. { regvars again) (JM) }
  687. free_regvars(aktproccode);
  688. {$endif OLDREGVARS}
  689. { add code that will load the return value, this is not done
  690. for assembler routines when they didn't reference the result
  691. variable }
  692. gen_load_return_value(templist);
  693. aktproccode.concatlist(templist);
  694. { generate symbol and save end of header position }
  695. aktfilepos:=entrypos;
  696. gen_proc_symbol(templist);
  697. headertai:=tai(templist.last);
  698. { insert symbol }
  699. aktproccode.insertlist(templist);
  700. { Free space in temp/registers for parast and localst, must be
  701. done after gen_entry_code }
  702. aktfilepos:=exitpos;
  703. if procdef.localst.symtabletype=localsymtable then
  704. gen_free_localst(aktproccode,tlocalsymtable(procdef.localst));
  705. gen_free_parast(aktproccode,tparasymtable(procdef.parast));
  706. { The procedure body is finished, we can now
  707. allocate the registers }
  708. cg.do_register_allocation(aktproccode,headertai);
  709. { Add save and restore of used registers }
  710. aktfilepos:=entrypos;
  711. gen_save_used_regs(templist);
  712. aktproccode.insertlistafter(headertai,templist);
  713. aktfilepos:=exitpos;
  714. gen_restore_used_regs(aktproccode,procdef.funcret_paraloc[calleeside]);
  715. { Add entry code (stack allocation) after header }
  716. aktfilepos:=entrypos;
  717. gen_proc_entry_code(templist);
  718. aktproccode.insertlistafter(headertai,templist);
  719. { Add exit code at the end }
  720. aktfilepos:=exitpos;
  721. gen_proc_exit_code(templist);
  722. aktproccode.concatlist(templist);
  723. { check if the implicit finally has been generated. The flag
  724. should already be set in pass1 }
  725. if (cs_implicit_exceptions in aktmoduleswitches) and
  726. not(procdef.proctypeoption in [potype_unitfinalize,potype_unitinit]) and
  727. (pi_needs_implicit_finally in flags) and
  728. not(pi_has_implicit_finally in flags) then
  729. internalerror(200405231);
  730. {$ifndef NoOpt}
  731. if not(cs_no_regalloc in aktglobalswitches) then
  732. begin
  733. if (cs_optimize in aktglobalswitches) and
  734. { do not optimize pure assembler procedures }
  735. not(pi_is_assembler in flags) then
  736. optimize(aktproccode);
  737. end;
  738. {$endif NoOpt}
  739. { Add end symbol and debug info }
  740. aktfilepos:=exitpos;
  741. gen_proc_symbol_end(templist);
  742. aktproccode.concatlist(templist);
  743. {$ifdef ARM}
  744. insertpcrelativedata(aktproccode,aktlocaldata);
  745. {$endif ARM}
  746. { save local data (casetable) also in the same file }
  747. if assigned(aktlocaldata) and
  748. (not aktlocaldata.empty) then
  749. begin
  750. { because of the limited constant size of the arm, all data access is done pc relative }
  751. if target_info.cpu=cpu_arm then
  752. aktproccode.concatlist(aktlocaldata)
  753. else
  754. begin
  755. new_section(aktproccode,sec_data,lower(procdef.mangledname),0);
  756. aktproccode.concatlist(aktlocaldata);
  757. end;
  758. end;
  759. { add the procedure to the codesegment }
  760. new_section(codesegment,sec_code,lower(procdef.mangledname),aktalignment.procalign);
  761. codesegment.concatlist(aktproccode);
  762. { only now we can remove the temps }
  763. tg.resettempgen;
  764. { stop tempgen and ra }
  765. tg.free;
  766. cg.done_register_allocators;
  767. tg:=nil;
  768. end;
  769. { restore symtablestack }
  770. remove_from_symtablestack;
  771. { restore }
  772. templist.free;
  773. aktmaxfpuregisters:=oldaktmaxfpuregisters;
  774. aktfilepos:=oldfilepos;
  775. current_procinfo:=oldprocinfo;
  776. end;
  777. procedure tcgprocinfo.add_to_symtablestack;
  778. var
  779. _class,hp : tobjectdef;
  780. begin
  781. { insert symtables for the class, but only if it is no nested function }
  782. if assigned(procdef._class) and
  783. not(assigned(parent) and
  784. assigned(parent.procdef) and
  785. assigned(parent.procdef._class)) then
  786. begin
  787. { insert them in the reverse order }
  788. hp:=nil;
  789. repeat
  790. _class:=procdef._class;
  791. while _class.childof<>hp do
  792. _class:=_class.childof;
  793. hp:=_class;
  794. _class.symtable.next:=symtablestack;
  795. symtablestack:=_class.symtable;
  796. until hp=procdef._class;
  797. end;
  798. { insert parasymtable in symtablestack when parsing
  799. a function }
  800. if procdef.parast.symtablelevel>=normal_function_level then
  801. begin
  802. procdef.parast.next:=symtablestack;
  803. symtablestack:=procdef.parast;
  804. end;
  805. procdef.localst.next:=symtablestack;
  806. symtablestack:=procdef.localst;
  807. end;
  808. procedure tcgprocinfo.remove_from_symtablestack;
  809. begin
  810. { remove localst/parast }
  811. if procdef.parast.symtablelevel>=normal_function_level then
  812. symtablestack:=symtablestack.next.next
  813. else
  814. symtablestack:=symtablestack.next;
  815. { remove class member symbol tables }
  816. while symtablestack.symtabletype=objectsymtable do
  817. symtablestack:=symtablestack.next;
  818. end;
  819. procedure tcgprocinfo.resetprocdef;
  820. begin
  821. { the local symtables can be deleted, but the parast }
  822. { doesn't, (checking definitons when calling a }
  823. { function }
  824. { not for a inline procedure !! (PM) }
  825. { at lexlevel = 1 localst is the staticsymtable itself }
  826. { so no dispose here !! }
  827. { The localst is also needed for debuginfo }
  828. if assigned(code) and
  829. not(cs_debuginfo in aktmoduleswitches) and
  830. not(cs_browser in aktmoduleswitches) and
  831. (procdef.proccalloption<>pocall_inline) then
  832. begin
  833. if procdef.parast.symtablelevel>=normal_function_level then
  834. procdef.localst.free;
  835. procdef.localst:=nil;
  836. end;
  837. { remove code tree, if not inline procedure }
  838. if assigned(code) then
  839. begin
  840. { the inline procedure has already got a copy of the tree
  841. stored in current_procinfo.procdef.code }
  842. code.free;
  843. code:=nil;
  844. if (procdef.proccalloption<>pocall_inline) then
  845. procdef.inlininginfo^.code:=nil;
  846. end;
  847. end;
  848. procedure tcgprocinfo.parse_body;
  849. var
  850. oldprocinfo : tprocinfo;
  851. oldblock_type : tblock_type;
  852. begin
  853. oldprocinfo:=current_procinfo;
  854. oldblock_type:=block_type;
  855. { reset break and continue labels }
  856. block_type:=bt_body;
  857. current_procinfo:=self;
  858. { calculate the lexical level }
  859. if procdef.parast.symtablelevel>maxnesting then
  860. Message(parser_e_too_much_lexlevel);
  861. { static is also important for local procedures !! }
  862. if (po_staticmethod in procdef.procoptions) then
  863. allow_only_static:=true
  864. else if (procdef.parast.symtablelevel=normal_function_level) then
  865. allow_only_static:=false;
  866. {$ifdef state_tracking}
  867. { aktstate:=Tstate_storage.create;}
  868. {$endif state_tracking}
  869. { create a local symbol table for this routine }
  870. if not assigned(procdef.localst) then
  871. procdef.insert_localst;
  872. { add parast/localst to symtablestack }
  873. add_to_symtablestack;
  874. { constant symbols are inserted in this symboltable }
  875. constsymtable:=symtablestack;
  876. { save entry info }
  877. entrypos:=aktfilepos;
  878. entryswitches:=aktlocalswitches;
  879. { parse the code ... }
  880. code:=block(current_module.islibrary);
  881. { save exit info }
  882. exitswitches:=aktlocalswitches;
  883. exitpos:=last_endtoken_filepos;
  884. { the procedure is now defined }
  885. procdef.forwarddef:=false;
  886. if assigned(code) then
  887. begin
  888. { get a better entry point }
  889. entrypos:=code.fileinfo;
  890. { Finish type checking pass }
  891. do_resulttypepass(code);
  892. end;
  893. { Check for unused labels, forwards, symbols for procedures. Static
  894. symtable is checked in pmodules.
  895. The check must be done after the resulttypepass }
  896. if (Errorcount=0) and
  897. (tstoredsymtable(procdef.localst).symtabletype<>staticsymtable) then
  898. begin
  899. { check if forwards are resolved }
  900. tstoredsymtable(procdef.localst).check_forwards;
  901. { check if all labels are used }
  902. tstoredsymtable(procdef.localst).checklabels;
  903. { remove cross unit overloads }
  904. tstoredsymtable(procdef.localst).unchain_overloaded;
  905. { check for unused symbols, but only if there is no asm block }
  906. if not(pi_uses_asm in flags) then
  907. begin
  908. tstoredsymtable(procdef.localst).allsymbolsused;
  909. tstoredsymtable(procdef.parast).allsymbolsused;
  910. end;
  911. end;
  912. { store a copy of the original tree for inline, for
  913. normal procedures only store a reference to the
  914. current tree }
  915. if (procdef.proccalloption=pocall_inline) then
  916. begin
  917. procdef.inlininginfo^.code:=code.getcopy;
  918. procdef.inlininginfo^.flags:=current_procinfo.flags;
  919. end
  920. else
  921. procdef.inlininginfo^.code:=code;
  922. { Print the node to tree.log }
  923. if paraprintnodetree=1 then
  924. printnode_procdef(procdef);
  925. { ... remove symbol tables }
  926. remove_from_symtablestack;
  927. {$ifdef state_tracking}
  928. { aktstate.destroy;}
  929. {$endif state_tracking}
  930. { reset to normal non static function }
  931. if (procdef.parast.symtablelevel=normal_function_level) then
  932. allow_only_static:=false;
  933. current_procinfo:=oldprocinfo;
  934. block_type:=oldblock_type;
  935. end;
  936. {****************************************************************************
  937. PROCEDURE/FUNCTION PARSING
  938. ****************************************************************************}
  939. procedure check_init_paras(p:tnamedindexitem;arg:pointer);
  940. begin
  941. if tsym(p).typ<>varsym then
  942. exit;
  943. with tvarsym(p) do
  944. if (not is_class(vartype.def) and
  945. vartype.def.needs_inittable and
  946. (varspez in [vs_value,vs_out])) then
  947. include(current_procinfo.flags,pi_do_call);
  948. end;
  949. procedure read_proc;
  950. {
  951. Parses the procedure directives, then parses the procedure body, then
  952. generates the code for it
  953. }
  954. procedure do_generate_code(pi:tcgprocinfo);
  955. var
  956. hpi : tcgprocinfo;
  957. begin
  958. { generate code for this procedure }
  959. pi.generate_code;
  960. { process nested procs }
  961. hpi:=tcgprocinfo(pi.nestedprocs.first);
  962. while assigned(hpi) do
  963. begin
  964. do_generate_code(hpi);
  965. hpi:=tcgprocinfo(hpi.next);
  966. end;
  967. pi.resetprocdef;
  968. end;
  969. var
  970. old_current_procinfo : tprocinfo;
  971. oldconstsymtable : tsymtable;
  972. oldfailtokenmode : tmodeswitch;
  973. pdflags : tpdflags;
  974. pd : tprocdef;
  975. isnestedproc : boolean;
  976. begin
  977. { save old state }
  978. oldconstsymtable:=constsymtable;
  979. old_current_procinfo:=current_procinfo;
  980. { reset current_procinfo.procdef to nil to be sure that nothing is writing
  981. to an other procdef }
  982. current_procinfo:=nil;
  983. { parse procedure declaration }
  984. if assigned(old_current_procinfo) and
  985. assigned(old_current_procinfo.procdef) then
  986. pd:=parse_proc_dec(old_current_procinfo.procdef._class)
  987. else
  988. pd:=parse_proc_dec(nil);
  989. { set the default function options }
  990. if parse_only then
  991. begin
  992. pd.forwarddef:=true;
  993. { set also the interface flag, for better error message when the
  994. implementation doesn't much this header }
  995. pd.interfacedef:=true;
  996. include(pd.procoptions,po_public);
  997. pdflags:=[pd_interface];
  998. end
  999. else
  1000. begin
  1001. pdflags:=[pd_body];
  1002. if (not current_module.in_interface) then
  1003. include(pdflags,pd_implemen);
  1004. if (not current_module.is_unit) or
  1005. maybe_smartlink_symbol then
  1006. include(pd.procoptions,po_public);
  1007. pd.forwarddef:=false;
  1008. end;
  1009. { parse the directives that may follow }
  1010. parse_proc_directives(pd,pdflags);
  1011. { hint directives, these can be separated by semicolons here,
  1012. that needs to be handled here with a loop (PFV) }
  1013. while try_consume_hintdirective(pd.symoptions) do
  1014. Consume(_SEMICOLON);
  1015. { Set calling convention }
  1016. handle_calling_convention(pd);
  1017. { everything of the proc definition is known, we can now
  1018. calculate the parameters }
  1019. calc_parast(pd);
  1020. { search for forward declarations }
  1021. if not proc_add_definition(pd) then
  1022. begin
  1023. { A method must be forward defined (in the object declaration) }
  1024. if assigned(pd._class) and
  1025. (not assigned(old_current_procinfo.procdef._class)) then
  1026. begin
  1027. MessagePos1(pd.fileinfo,parser_e_header_dont_match_any_member,pd.fullprocname(false));
  1028. tprocsym(pd.procsym).write_parameter_lists(pd);
  1029. end
  1030. else
  1031. begin
  1032. { Give a better error if there is a forward def in the interface and only
  1033. a single implementation }
  1034. if (not pd.forwarddef) and
  1035. (not pd.interfacedef) and
  1036. (tprocsym(pd.procsym).procdef_count>1) and
  1037. tprocsym(pd.procsym).first_procdef.forwarddef and
  1038. tprocsym(pd.procsym).first_procdef.interfacedef and
  1039. not(tprocsym(pd.procsym).procdef_count>2) then
  1040. begin
  1041. MessagePos1(pd.fileinfo,parser_e_header_dont_match_forward,pd.fullprocname(false));
  1042. tprocsym(pd.procsym).write_parameter_lists(pd);
  1043. end;
  1044. end;
  1045. end;
  1046. { compile procedure when a body is needed }
  1047. if (pd_body in pdflags) then
  1048. begin
  1049. Message1(parser_d_procedure_start,pd.fullprocname(false));
  1050. { create a new procedure }
  1051. current_procinfo:=cprocinfo.create(old_current_procinfo);
  1052. current_module.procinfo:=current_procinfo;
  1053. current_procinfo.procdef:=pd;
  1054. isnestedproc:=(current_procinfo.procdef.parast.symtablelevel>normal_function_level);
  1055. { Insert mangledname }
  1056. pd.aliasnames.insert(pd.mangledname);
  1057. { Insert result variables in the localst }
  1058. insert_funcret_local(pd);
  1059. { check if there are para's which require initing -> set }
  1060. { pi_do_call (if not yet set) }
  1061. if not(pi_do_call in current_procinfo.flags) then
  1062. pd.parast.foreach_static({$ifdef FPCPROCVAR}@{$endif}check_init_paras,nil);
  1063. { set _FAIL as keyword if constructor }
  1064. if (pd.proctypeoption=potype_constructor) then
  1065. begin
  1066. oldfailtokenmode:=tokeninfo^[_FAIL].keyword;
  1067. tokeninfo^[_FAIL].keyword:=m_all;
  1068. end;
  1069. tcgprocinfo(current_procinfo).parse_body;
  1070. { When it's a nested procedure then defer the code generation,
  1071. when back at normal function level then generate the code
  1072. for all defered nested procedures and the current procedure }
  1073. if isnestedproc then
  1074. tcgprocinfo(current_procinfo.parent).nestedprocs.insert(current_procinfo)
  1075. else
  1076. begin
  1077. { We can't support inlining for procedures that have nested
  1078. procedures because the nested procedures use a fixed offset
  1079. for accessing locals in the parent procedure (PFV) }
  1080. if (current_procinfo.procdef.proccalloption=pocall_inline) and
  1081. (tcgprocinfo(current_procinfo).nestedprocs.count>0) then
  1082. begin
  1083. Message1(parser_w_not_supported_for_inline,'nested procedures');
  1084. Message(parser_w_inlining_disabled);
  1085. current_procinfo.procdef.proccalloption:=pocall_default;
  1086. end;
  1087. do_generate_code(tcgprocinfo(current_procinfo));
  1088. end;
  1089. { reset _FAIL as _SELF normal }
  1090. if (pd.proctypeoption=potype_constructor) then
  1091. tokeninfo^[_FAIL].keyword:=oldfailtokenmode;
  1092. { release procinfo }
  1093. if tprocinfo(current_module.procinfo)<>current_procinfo then
  1094. internalerror(200304274);
  1095. current_module.procinfo:=current_procinfo.parent;
  1096. if not isnestedproc then
  1097. current_procinfo.free;
  1098. consume(_SEMICOLON);
  1099. end;
  1100. { Restore old state }
  1101. constsymtable:=oldconstsymtable;
  1102. current_procinfo:=old_current_procinfo;
  1103. end;
  1104. {****************************************************************************
  1105. DECLARATION PARSING
  1106. ****************************************************************************}
  1107. { search in symtablestack for not complete classes }
  1108. procedure check_forward_class(p : tnamedindexitem;arg:pointer);
  1109. begin
  1110. if (tsym(p).typ=typesym) and
  1111. (ttypesym(p).restype.def.deftype=objectdef) and
  1112. (oo_is_forward in tobjectdef(ttypesym(p).restype.def).objectoptions) then
  1113. MessagePos1(tsym(p).fileinfo,sym_e_forward_type_not_resolved,tsym(p).realname);
  1114. end;
  1115. procedure read_declarations(islibrary : boolean);
  1116. begin
  1117. repeat
  1118. if not assigned(current_procinfo) then
  1119. internalerror(200304251);
  1120. case token of
  1121. _LABEL:
  1122. label_dec;
  1123. _CONST:
  1124. const_dec;
  1125. _TYPE:
  1126. type_dec;
  1127. _VAR:
  1128. var_dec;
  1129. _THREADVAR:
  1130. threadvar_dec;
  1131. _CONSTRUCTOR,
  1132. _DESTRUCTOR,
  1133. _FUNCTION,
  1134. _PROCEDURE,
  1135. _OPERATOR,
  1136. _CLASS:
  1137. read_proc;
  1138. _EXPORTS:
  1139. begin
  1140. if not(assigned(current_procinfo.procdef.localst)) or
  1141. (current_procinfo.procdef.localst.symtablelevel>main_program_level) or
  1142. (current_module.is_unit) then
  1143. begin
  1144. Message(parser_e_syntax_error);
  1145. consume_all_until(_SEMICOLON);
  1146. end
  1147. else if islibrary or
  1148. (target_info.system in [system_i386_WIN32,system_i386_wdosx,system_i386_Netware]) then
  1149. read_exports
  1150. else
  1151. begin
  1152. Message(parser_w_unsupported_feature);
  1153. consume(_BEGIN);
  1154. end;
  1155. end
  1156. else
  1157. begin
  1158. case idtoken of
  1159. _RESOURCESTRING :
  1160. resourcestring_dec;
  1161. _PROPERTY:
  1162. begin
  1163. if (m_fpc in aktmodeswitches) then
  1164. property_dec
  1165. else
  1166. break;
  1167. end;
  1168. else
  1169. break;
  1170. end;
  1171. end;
  1172. end;
  1173. until false;
  1174. { check for incomplete class definitions, this is only required
  1175. for fpc modes }
  1176. if (m_fpc in aktmodeswitches) then
  1177. symtablestack.foreach_static({$ifdef FPCPROCVAR}@{$endif}check_forward_class,nil);
  1178. end;
  1179. procedure read_interface_declarations;
  1180. begin
  1181. repeat
  1182. case token of
  1183. _CONST :
  1184. const_dec;
  1185. _TYPE :
  1186. type_dec;
  1187. _VAR :
  1188. var_dec;
  1189. _THREADVAR :
  1190. threadvar_dec;
  1191. _FUNCTION,
  1192. _PROCEDURE,
  1193. _OPERATOR :
  1194. read_proc;
  1195. else
  1196. begin
  1197. case idtoken of
  1198. _RESOURCESTRING :
  1199. resourcestring_dec;
  1200. _PROPERTY:
  1201. begin
  1202. if (m_fpc in aktmodeswitches) then
  1203. property_dec
  1204. else
  1205. break;
  1206. end;
  1207. else
  1208. break;
  1209. end;
  1210. end;
  1211. end;
  1212. until false;
  1213. { check for incomplete class definitions, this is only required
  1214. for fpc modes }
  1215. if (m_fpc in aktmodeswitches) then
  1216. symtablestack.foreach_static({$ifdef FPCPROCVAR}@{$endif}check_forward_class,nil);
  1217. end;
  1218. end.
  1219. {
  1220. $Log$
  1221. Revision 1.196 2004-06-20 08:55:30 florian
  1222. * logs truncated
  1223. Revision 1.195 2004/06/16 20:07:09 florian
  1224. * dwarf branch merged
  1225. Revision 1.194 2004/05/28 21:14:13 peter
  1226. * first load para's to temps before calling entry code (profile
  1227. Revision 1.193 2004/05/24 17:31:12 peter
  1228. * also check local typed const
  1229. Revision 1.192 2004/05/23 18:28:41 peter
  1230. * methodpointer is loaded into a temp when it was a calln
  1231. Revision 1.191 2004/05/23 15:06:21 peter
  1232. * implicit_finally flag must be set in pass1
  1233. * add check whether the implicit frame is generated when expected
  1234. }