pparautl.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl, Daniel Mantione
  3. Helpers for dealing with subroutine parameters during parsing
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit pparautl;
  18. interface
  19. uses
  20. symdef;
  21. procedure insert_funcret_para(pd:tabstractprocdef);
  22. procedure insert_parentfp_para(pd:tabstractprocdef);
  23. procedure insert_self_and_vmt_para(pd:tabstractprocdef);
  24. procedure insert_funcret_local(pd:tprocdef);
  25. procedure insert_hidden_para(p:TObject;arg:pointer);
  26. procedure check_c_para(pd:Tabstractprocdef);
  27. implementation
  28. uses
  29. globals,globtype,verbose,systems,
  30. symconst,symtype,symbase,symsym,symtable,symcreat,defutil,
  31. paramgr;
  32. procedure insert_funcret_para(pd:tabstractprocdef);
  33. var
  34. storepos : tfileposinfo;
  35. vs : tparavarsym;
  36. paranr : word;
  37. begin
  38. if not(pd.proctypeoption in [potype_constructor,potype_destructor]) and
  39. not is_void(pd.returndef) and
  40. paramanager.ret_in_param(pd.returndef,pd.proccalloption) then
  41. begin
  42. storepos:=current_tokenpos;
  43. if pd.typ=procdef then
  44. current_tokenpos:=tprocdef(pd).fileinfo;
  45. {$if defined(i386)}
  46. { For left to right add it at the end to be delphi compatible.
  47. In the case of safecalls with safecal-exceptions support the
  48. funcret-para is (from the 'c'-point of view) a normal parameter
  49. which has to be added to the end of the parameter-list }
  50. if (pd.proccalloption in (pushleftright_pocalls)) or
  51. ((tf_safecall_exceptions in target_info.flags) and
  52. (pd.proccalloption=pocall_safecall)) then
  53. paranr:=paranr_result_leftright
  54. else
  55. {$elseif defined(x86) or defined(arm)}
  56. if (tf_safecall_exceptions in target_info.flags) and
  57. (pd.proccalloption = pocall_safecall) then
  58. paranr:=paranr_result_leftright
  59. else
  60. {$endif}
  61. paranr:=paranr_result;
  62. { Generate result variable accessing function result }
  63. vs:=tparavarsym.create('$result',paranr,vs_var,pd.returndef,[vo_is_funcret,vo_is_hidden_para]);
  64. pd.parast.insert(vs);
  65. { Store the this symbol as funcretsym for procedures }
  66. if pd.typ=procdef then
  67. tprocdef(pd).funcretsym:=vs;
  68. current_tokenpos:=storepos;
  69. end;
  70. end;
  71. procedure insert_parentfp_para(pd:tabstractprocdef);
  72. var
  73. storepos : tfileposinfo;
  74. vs : tparavarsym;
  75. paranr : longint;
  76. begin
  77. if pd.parast.symtablelevel>normal_function_level then
  78. begin
  79. storepos:=current_tokenpos;
  80. if pd.typ=procdef then
  81. current_tokenpos:=tprocdef(pd).fileinfo;
  82. { if no support for nested procvars is activated, use the old
  83. calling convention to pass the parent frame pointer for backwards
  84. compatibility }
  85. if not(m_nested_procvars in current_settings.modeswitches) then
  86. paranr:=paranr_parentfp
  87. { nested procvars require Delphi-style parentfp passing, see
  88. po_delphi_nested_cc declaration for more info }
  89. {$ifdef i386}
  90. else if (pd.proccalloption in pushleftright_pocalls) then
  91. paranr:=paranr_parentfp_delphi_cc_leftright
  92. {$endif i386}
  93. else
  94. paranr:=paranr_parentfp_delphi_cc;
  95. { Generate frame pointer. It can't be put in a register since it
  96. must be accessable from nested routines }
  97. if not(target_info.system in systems_fpnestedstruct) then
  98. begin
  99. vs:=tparavarsym.create('$parentfp',paranr,vs_value
  100. ,voidpointertype,[vo_is_parentfp,vo_is_hidden_para]);
  101. vs.varregable:=vr_none;
  102. end
  103. else
  104. begin
  105. if not assigned(tprocdef(pd.owner.defowner).parentfpstruct) then
  106. build_parentfpstruct(tprocdef(pd.owner.defowner));
  107. vs:=tparavarsym.create('$parentfp',paranr,vs_value
  108. ,tprocdef(pd.owner.defowner).parentfpstructptrtype,[vo_is_parentfp,vo_is_hidden_para]);
  109. end;
  110. pd.parast.insert(vs);
  111. current_tokenpos:=storepos;
  112. end;
  113. end;
  114. procedure insert_self_and_vmt_para(pd:tabstractprocdef);
  115. var
  116. storepos : tfileposinfo;
  117. vs : tparavarsym;
  118. hdef : tdef;
  119. selfdef : tabstractrecorddef;
  120. vsp : tvarspez;
  121. aliasvs : tabsolutevarsym;
  122. sl : tpropaccesslist;
  123. begin
  124. if (pd.typ=procdef) and
  125. is_objc_class_or_protocol(tprocdef(pd).struct) and
  126. (pd.parast.symtablelevel=normal_function_level) then
  127. begin
  128. { insert Objective-C self and selector parameters }
  129. vs:=tparavarsym.create('$_cmd',paranr_objc_cmd,vs_value,objc_seltype,[vo_is_msgsel,vo_is_hidden_para]);
  130. pd.parast.insert(vs);
  131. { make accessible to code }
  132. sl:=tpropaccesslist.create;
  133. sl.addsym(sl_load,vs);
  134. aliasvs:=tabsolutevarsym.create_ref('_CMD',objc_seltype,sl);
  135. include(aliasvs.varoptions,vo_is_msgsel);
  136. tlocalsymtable(tprocdef(pd).localst).insert(aliasvs);
  137. if (po_classmethod in pd.procoptions) then
  138. { compatible with what gcc does }
  139. hdef:=objc_idtype
  140. else
  141. hdef:=tprocdef(pd).struct;
  142. vs:=tparavarsym.create('$self',paranr_objc_self,vs_value,hdef,[vo_is_self,vo_is_hidden_para]);
  143. pd.parast.insert(vs);
  144. end
  145. else if (pd.typ=procvardef) and
  146. pd.is_methodpointer then
  147. begin
  148. { Generate self variable }
  149. vs:=tparavarsym.create('$self',paranr_self,vs_value,voidpointertype,[vo_is_self,vo_is_hidden_para]);
  150. pd.parast.insert(vs);
  151. end
  152. else
  153. begin
  154. if (pd.typ=procdef) and
  155. assigned(tprocdef(pd).struct) and
  156. (pd.parast.symtablelevel=normal_function_level) then
  157. begin
  158. { static class methods have no hidden self/vmt pointer }
  159. if pd.no_self_node then
  160. exit;
  161. storepos:=current_tokenpos;
  162. current_tokenpos:=tprocdef(pd).fileinfo;
  163. { Generate VMT variable for constructor/destructor }
  164. if (pd.proctypeoption in [potype_constructor,potype_destructor]) and
  165. not(is_cppclass(tprocdef(pd).struct) or
  166. is_record(tprocdef(pd).struct) or
  167. is_javaclass(tprocdef(pd).struct)) then
  168. begin
  169. { can't use classrefdef as type because inheriting
  170. will then always file because of a type mismatch }
  171. vs:=tparavarsym.create('$vmt',paranr_vmt,vs_value,voidpointertype,[vo_is_vmt,vo_is_hidden_para]);
  172. pd.parast.insert(vs);
  173. end;
  174. { for helpers the type of Self is equivalent to the extended
  175. type or equal to an instance of it }
  176. if is_objectpascal_helper(tprocdef(pd).struct) then
  177. selfdef:=tobjectdef(tprocdef(pd).struct).extendeddef
  178. else
  179. selfdef:=tprocdef(pd).struct;
  180. { Generate self variable, for classes we need
  181. to use the generic voidpointer to be compatible with
  182. methodpointers }
  183. vsp:=vs_value;
  184. if (po_staticmethod in pd.procoptions) or
  185. (po_classmethod in pd.procoptions) then
  186. hdef:=tclassrefdef.create(selfdef)
  187. else
  188. begin
  189. if is_object(selfdef) or is_record(selfdef) then
  190. vsp:=vs_var;
  191. hdef:=selfdef;
  192. end;
  193. vs:=tparavarsym.create('$self',paranr_self,vsp,hdef,[vo_is_self,vo_is_hidden_para]);
  194. pd.parast.insert(vs);
  195. current_tokenpos:=storepos;
  196. end;
  197. end;
  198. end;
  199. procedure insert_funcret_local(pd:tprocdef);
  200. var
  201. storepos : tfileposinfo;
  202. vs : tlocalvarsym;
  203. aliasvs : tabsolutevarsym;
  204. sl : tpropaccesslist;
  205. hs : string;
  206. begin
  207. { The result from constructors and destructors can't be accessed directly }
  208. if not(pd.proctypeoption in [potype_constructor,potype_destructor]) and
  209. not is_void(pd.returndef) then
  210. begin
  211. storepos:=current_tokenpos;
  212. current_tokenpos:=pd.fileinfo;
  213. { We need to insert a varsym for the result in the localst
  214. when it is returning in a register }
  215. if not paramanager.ret_in_param(pd.returndef,pd.proccalloption) then
  216. begin
  217. vs:=tlocalvarsym.create('$result',vs_value,pd.returndef,[vo_is_funcret]);
  218. pd.localst.insert(vs);
  219. pd.funcretsym:=vs;
  220. end;
  221. { insert the name of the procedure as alias for the function result,
  222. we can't use realname because that will not work for compilerprocs
  223. as the name is lowercase and unreachable from the code }
  224. if assigned(pd.resultname) then
  225. hs:=pd.resultname^
  226. else
  227. hs:=pd.procsym.name;
  228. sl:=tpropaccesslist.create;
  229. sl.addsym(sl_load,pd.funcretsym);
  230. aliasvs:=tabsolutevarsym.create_ref(hs,pd.returndef,sl);
  231. include(aliasvs.varoptions,vo_is_funcret);
  232. tlocalsymtable(pd.localst).insert(aliasvs);
  233. { insert result also if support is on }
  234. if (m_result in current_settings.modeswitches) then
  235. begin
  236. sl:=tpropaccesslist.create;
  237. sl.addsym(sl_load,pd.funcretsym);
  238. aliasvs:=tabsolutevarsym.create_ref('RESULT',pd.returndef,sl);
  239. include(aliasvs.varoptions,vo_is_funcret);
  240. include(aliasvs.varoptions,vo_is_result);
  241. tlocalsymtable(pd.localst).insert(aliasvs);
  242. end;
  243. current_tokenpos:=storepos;
  244. end;
  245. end;
  246. procedure insert_hidden_para(p:TObject;arg:pointer);
  247. var
  248. hvs : tparavarsym;
  249. pd : tabstractprocdef absolute arg;
  250. begin
  251. if (tsym(p).typ<>paravarsym) then
  252. exit;
  253. with tparavarsym(p) do
  254. begin
  255. { We need a local copy for a value parameter when only the
  256. address is pushed. Open arrays and Array of Const are
  257. an exception because they are allocated at runtime and the
  258. address that is pushed is patched }
  259. if (varspez=vs_value) and
  260. paramanager.push_addr_param(varspez,vardef,pd.proccalloption) and
  261. not(is_open_array(vardef) or
  262. is_array_of_const(vardef)) then
  263. include(varoptions,vo_has_local_copy);
  264. { needs high parameter ? }
  265. if paramanager.push_high_param(varspez,vardef,pd.proccalloption) then
  266. begin
  267. hvs:=tparavarsym.create('$high'+name,paranr+1,vs_const,sinttype,[vo_is_high_para,vo_is_hidden_para]);
  268. hvs.symoptions:=[];
  269. owner.insert(hvs);
  270. end
  271. else
  272. begin
  273. { Give a warning that cdecl routines does not include high()
  274. support }
  275. if (pd.proccalloption in cdecl_pocalls) and
  276. paramanager.push_high_param(varspez,vardef,pocall_default) then
  277. begin
  278. if is_open_string(vardef) then
  279. MessagePos(fileinfo,parser_w_cdecl_no_openstring);
  280. if not(po_external in pd.procoptions) and
  281. (pd.typ<>procvardef) and
  282. not is_objc_class_or_protocol(tprocdef(pd).struct) then
  283. if is_array_of_const(vardef) then
  284. MessagePos(fileinfo,parser_e_varargs_need_cdecl_and_external)
  285. else
  286. MessagePos(fileinfo,parser_w_cdecl_has_no_high);
  287. end;
  288. if (vardef.typ=formaldef) and (Tformaldef(vardef).typed) then
  289. begin
  290. hvs:=tparavarsym.create('$typinfo'+name,paranr+1,vs_const,voidpointertype,
  291. [vo_is_typinfo_para,vo_is_hidden_para]);
  292. owner.insert(hvs);
  293. end;
  294. end;
  295. end;
  296. end;
  297. procedure check_c_para(pd:Tabstractprocdef);
  298. var
  299. i,
  300. lastparaidx : longint;
  301. sym : TSym;
  302. begin
  303. lastparaidx:=pd.parast.SymList.Count-1;
  304. for i:=0 to pd.parast.SymList.Count-1 do
  305. begin
  306. sym:=tsym(pd.parast.SymList[i]);
  307. if (sym.typ=paravarsym) and
  308. (tparavarsym(sym).vardef.typ=arraydef) then
  309. begin
  310. if not is_variant_array(tparavarsym(sym).vardef) and
  311. not is_array_of_const(tparavarsym(sym).vardef) and
  312. (tparavarsym(sym).varspez<>vs_var) then
  313. MessagePos(tparavarsym(sym).fileinfo,parser_h_c_arrays_are_references);
  314. if is_array_of_const(tparavarsym(sym).vardef) and
  315. (i<lastparaidx) and
  316. (tsym(pd.parast.SymList[i+1]).typ=paravarsym) and
  317. not(vo_is_high_para in tparavarsym(pd.parast.SymList[i+1]).varoptions) then
  318. MessagePos(tparavarsym(sym).fileinfo,parser_e_C_array_of_const_must_be_last);
  319. end;
  320. end;
  321. end;
  322. end.