pdecvar.pas 62 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Parses variable declarations. Used for var statement and record
  4. definitions
  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 pdecvar;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. symsym,symdef;
  23. type
  24. tvar_dec_option=(vd_record,vd_object,vd_threadvar);
  25. tvar_dec_options=set of tvar_dec_option;
  26. function read_property_dec(aclass:tobjectdef):tpropertysym;
  27. procedure read_var_decls(options:Tvar_dec_options);
  28. procedure read_record_fields(options:Tvar_dec_options);
  29. procedure read_public_and_external(vs: tabstractvarsym);
  30. implementation
  31. uses
  32. SysUtils,
  33. { common }
  34. cutils,cclasses,
  35. { global }
  36. globtype,globals,tokens,verbose,constexp,
  37. systems,
  38. { symtable }
  39. symconst,symbase,symtype,symtable,defutil,defcmp,
  40. fmodule,htypechk,
  41. { pass 1 }
  42. node,pass_1,aasmdata,
  43. nmat,nadd,ncal,nset,ncnv,ninl,ncon,nld,nflw,nmem,nutils,
  44. { codegen }
  45. ncgutil,
  46. { parser }
  47. scanner,
  48. pbase,pexpr,ptype,ptconst,pdecsub,
  49. { link }
  50. import
  51. ;
  52. function read_property_dec(aclass:tobjectdef):tpropertysym;
  53. { convert a node tree to symlist and return the last
  54. symbol }
  55. function parse_symlist(pl:tpropaccesslist;var def:tdef):boolean;
  56. var
  57. idx : longint;
  58. sym : tsym;
  59. srsymtable : TSymtable;
  60. st : TSymtable;
  61. p : tnode;
  62. begin
  63. result:=true;
  64. def:=nil;
  65. if token=_ID then
  66. begin
  67. if assigned(aclass) then
  68. sym:=search_class_member(aclass,pattern)
  69. else
  70. searchsym(pattern,sym,srsymtable);
  71. if assigned(sym) then
  72. begin
  73. case sym.typ of
  74. fieldvarsym :
  75. begin
  76. if (symtablestack.top.currentvisibility<>vis_private) then
  77. addsymref(sym);
  78. pl.addsym(sl_load,sym);
  79. def:=tfieldvarsym(sym).vardef;
  80. end;
  81. procsym :
  82. begin
  83. if (symtablestack.top.currentvisibility<>vis_private) then
  84. addsymref(sym);
  85. pl.addsym(sl_call,sym);
  86. end;
  87. else
  88. begin
  89. Message1(parser_e_illegal_field_or_method,orgpattern);
  90. def:=generrordef;
  91. result:=false;
  92. end;
  93. end;
  94. end
  95. else
  96. begin
  97. Message1(parser_e_illegal_field_or_method,orgpattern);
  98. def:=generrordef;
  99. result:=false;
  100. end;
  101. consume(_ID);
  102. repeat
  103. case token of
  104. _ID,
  105. _SEMICOLON :
  106. begin
  107. break;
  108. end;
  109. _POINT :
  110. begin
  111. consume(_POINT);
  112. if assigned(def) then
  113. begin
  114. st:=def.GetSymtable(gs_record);
  115. if assigned(st) then
  116. begin
  117. sym:=tsym(st.Find(pattern));
  118. if not(assigned(sym)) and is_object(def) then
  119. sym:=search_class_member(tobjectdef(def),pattern);
  120. if assigned(sym) then
  121. begin
  122. pl.addsym(sl_subscript,sym);
  123. case sym.typ of
  124. fieldvarsym :
  125. def:=tfieldvarsym(sym).vardef;
  126. else
  127. begin
  128. Message1(sym_e_illegal_field,orgpattern);
  129. result:=false;
  130. end;
  131. end;
  132. end
  133. else
  134. begin
  135. Message1(sym_e_illegal_field,orgpattern);
  136. result:=false;
  137. end;
  138. end
  139. else
  140. begin
  141. Message(parser_e_invalid_qualifier);
  142. result:=false;
  143. end;
  144. end
  145. else
  146. begin
  147. Message(parser_e_invalid_qualifier);
  148. result:=false;
  149. end;
  150. consume(_ID);
  151. end;
  152. _LECKKLAMMER :
  153. begin
  154. consume(_LECKKLAMMER);
  155. repeat
  156. if def.typ=arraydef then
  157. begin
  158. idx:=0;
  159. p:=comp_expr(true);
  160. if (not codegenerror) then
  161. begin
  162. if (p.nodetype=ordconstn) then
  163. begin
  164. { type/range checking }
  165. inserttypeconv(p,tarraydef(def).rangedef);
  166. if (Tordconstnode(p).value<int64(low(longint))) or
  167. (Tordconstnode(p).value>int64(high(longint))) then
  168. message(parser_e_array_range_out_of_bounds)
  169. else
  170. idx:=Tordconstnode(p).value.svalue
  171. end
  172. else
  173. Message(type_e_ordinal_expr_expected)
  174. end;
  175. pl.addconst(sl_vec,idx,p.resultdef);
  176. p.free;
  177. def:=tarraydef(def).elementdef;
  178. end
  179. else
  180. begin
  181. Message(parser_e_invalid_qualifier);
  182. result:=false;
  183. end;
  184. until not try_to_consume(_COMMA);
  185. consume(_RECKKLAMMER);
  186. end;
  187. else
  188. begin
  189. Message(parser_e_ill_property_access_sym);
  190. result:=false;
  191. break;
  192. end;
  193. end;
  194. until false;
  195. end
  196. else
  197. begin
  198. Message(parser_e_ill_property_access_sym);
  199. result:=false;
  200. end;
  201. end;
  202. function allow_default_property(p : tpropertysym) : boolean;
  203. begin
  204. allow_default_property:=
  205. (is_ordinal(p.propdef) or
  206. {$ifndef cpu64bitaddr}
  207. is_64bitint(p.propdef) or
  208. {$endif cpu64bitaddr}
  209. is_class(p.propdef) or
  210. is_single(p.propdef) or
  211. (p.propdef.typ in [classrefdef,pointerdef]) or
  212. is_smallset(p.propdef)
  213. ) and not
  214. (
  215. (p.propdef.typ=arraydef) and
  216. (ppo_indexed in p.propoptions)
  217. ) and not
  218. (ppo_hasparameters in p.propoptions);
  219. end;
  220. var
  221. sym : tsym;
  222. srsymtable: tsymtable;
  223. p : tpropertysym;
  224. overriden : tsym;
  225. varspez : tvarspez;
  226. hdef : tdef;
  227. arraytype : tdef;
  228. def : tdef;
  229. pt : tnode;
  230. sc : TFPObjectList;
  231. paranr : word;
  232. i : longint;
  233. ImplIntf : TImplementedInterface;
  234. found : boolean;
  235. hreadparavs,
  236. hparavs : tparavarsym;
  237. storedprocdef,
  238. readprocdef,
  239. writeprocdef : tprocvardef;
  240. begin
  241. { Generate temp procvardefs to search for matching read/write
  242. procedures. the readprocdef will store all definitions }
  243. paranr:=0;
  244. readprocdef:=tprocvardef.create(normal_function_level);
  245. writeprocdef:=tprocvardef.create(normal_function_level);
  246. storedprocdef:=tprocvardef.create(normal_function_level);
  247. { make it method pointers }
  248. if assigned(aclass) then
  249. begin
  250. include(readprocdef.procoptions,po_methodpointer);
  251. include(writeprocdef.procoptions,po_methodpointer);
  252. include(storedprocdef.procoptions,po_methodpointer);
  253. end;
  254. { method for stored must return boolean }
  255. storedprocdef.returndef:=booltype;
  256. if token<>_ID then
  257. begin
  258. consume(_ID);
  259. consume(_SEMICOLON);
  260. exit;
  261. end;
  262. { Generate propertysym and insert in symtablestack }
  263. p:=tpropertysym.create(orgpattern);
  264. p.visibility:=symtablestack.top.currentvisibility;
  265. p.default:=longint($80000000);
  266. symtablestack.top.insert(p);
  267. consume(_ID);
  268. { property parameters ? }
  269. if try_to_consume(_LECKKLAMMER) then
  270. begin
  271. if (p.visibility=vis_published) and
  272. not (m_delphi in current_settings.modeswitches) then
  273. Message(parser_e_cant_publish_that_property);
  274. { create a list of the parameters }
  275. symtablestack.push(readprocdef.parast);
  276. sc:=TFPObjectList.create(false);
  277. inc(testcurobject);
  278. repeat
  279. if try_to_consume(_VAR) then
  280. varspez:=vs_var
  281. else if try_to_consume(_CONST) then
  282. varspez:=vs_const
  283. else if (m_out in current_settings.modeswitches) and try_to_consume(_OUT) then
  284. varspez:=vs_out
  285. else
  286. varspez:=vs_value;
  287. sc.clear;
  288. repeat
  289. inc(paranr);
  290. hreadparavs:=tparavarsym.create(orgpattern,10*paranr,varspez,generrordef,[]);
  291. readprocdef.parast.insert(hreadparavs);
  292. sc.add(hreadparavs);
  293. consume(_ID);
  294. until not try_to_consume(_COMMA);
  295. if try_to_consume(_COLON) then
  296. begin
  297. if try_to_consume(_ARRAY) then
  298. begin
  299. consume(_OF);
  300. { define range and type of range }
  301. hdef:=tarraydef.create(0,-1,s32inttype);
  302. { define field type }
  303. single_type(arraytype,false);
  304. tarraydef(hdef).elementdef:=arraytype;
  305. end
  306. else
  307. single_type(hdef,false);
  308. end
  309. else
  310. hdef:=cformaltype;
  311. for i:=0 to sc.count-1 do
  312. begin
  313. hreadparavs:=tparavarsym(sc[i]);
  314. hreadparavs.vardef:=hdef;
  315. { also update the writeprocdef }
  316. hparavs:=tparavarsym.create(hreadparavs.realname,hreadparavs.paranr,vs_value,hdef,[]);
  317. writeprocdef.parast.insert(hparavs);
  318. end;
  319. until not try_to_consume(_SEMICOLON);
  320. sc.free;
  321. dec(testcurobject);
  322. symtablestack.pop(readprocdef.parast);
  323. consume(_RECKKLAMMER);
  324. { the parser need to know if a property has parameters, the
  325. index parameter doesn't count (PFV) }
  326. if paranr>0 then
  327. include(p.propoptions,ppo_hasparameters);
  328. end;
  329. { overriden property ? }
  330. { force property interface
  331. there is a property parameter
  332. a global property }
  333. if (token=_COLON) or (paranr>0) or (aclass=nil) then
  334. begin
  335. consume(_COLON);
  336. single_type(p.propdef,false);
  337. if (idtoken=_INDEX) then
  338. begin
  339. consume(_INDEX);
  340. pt:=comp_expr(true);
  341. { Only allow enum and integer indexes. Convert all integer
  342. values to s32int to be compatible with delphi, because the
  343. procedure matching requires equal parameters }
  344. if is_constnode(pt) and
  345. is_ordinal(pt.resultdef)
  346. {$ifndef cpu64bitaddr}
  347. and (not is_64bitint(pt.resultdef))
  348. {$endif cpu64bitaddr}
  349. then
  350. begin
  351. if is_integer(pt.resultdef) then
  352. inserttypeconv_internal(pt,s32inttype);
  353. p.index:=tordconstnode(pt).value.svalue;
  354. end
  355. else
  356. begin
  357. Message(parser_e_invalid_property_index_value);
  358. p.index:=0;
  359. end;
  360. p.indexdef:=pt.resultdef;
  361. include(p.propoptions,ppo_indexed);
  362. { concat a longint to the para templates }
  363. inc(paranr);
  364. hparavs:=tparavarsym.create('$index',10*paranr,vs_value,p.indexdef,[]);
  365. readprocdef.parast.insert(hparavs);
  366. hparavs:=tparavarsym.create('$index',10*paranr,vs_value,p.indexdef,[]);
  367. writeprocdef.parast.insert(hparavs);
  368. hparavs:=tparavarsym.create('$index',10*paranr,vs_value,p.indexdef,[]);
  369. storedprocdef.parast.insert(hparavs);
  370. pt.free;
  371. end;
  372. end
  373. else
  374. begin
  375. { do an property override }
  376. overriden:=search_class_member(aclass.childof,p.name);
  377. if assigned(overriden) and
  378. (overriden.typ=propertysym) and
  379. not(is_dispinterface(aclass)) then
  380. begin
  381. p.overridenpropsym:=tpropertysym(overriden);
  382. { inherit all type related entries }
  383. p.indexdef:=tpropertysym(overriden).indexdef;
  384. p.propdef:=tpropertysym(overriden).propdef;
  385. p.index:=tpropertysym(overriden).index;
  386. p.default:=tpropertysym(overriden).default;
  387. p.propoptions:=tpropertysym(overriden).propoptions;
  388. end
  389. else
  390. begin
  391. p.propdef:=generrordef;
  392. message(parser_e_no_property_found_to_override);
  393. end;
  394. end;
  395. if ((p.visibility=vis_published) or is_dispinterface(aclass)) and
  396. not(p.propdef.is_publishable) then
  397. begin
  398. Message(parser_e_cant_publish_that_property);
  399. p.visibility:=vis_public;
  400. end;
  401. if not(is_dispinterface(aclass)) then
  402. begin
  403. if try_to_consume(_READ) then
  404. begin
  405. p.propaccesslist[palt_read].clear;
  406. if parse_symlist(p.propaccesslist[palt_read],def) then
  407. begin
  408. sym:=p.propaccesslist[palt_read].firstsym^.sym;
  409. case sym.typ of
  410. procsym :
  411. begin
  412. { read is function returning the type of the property }
  413. readprocdef.returndef:=p.propdef;
  414. { Insert hidden parameters }
  415. handle_calling_convention(readprocdef);
  416. { search procdefs matching readprocdef }
  417. { we ignore hidden stuff here because the property access symbol might have
  418. non default calling conventions which might change the hidden stuff;
  419. see tw3216.pp (FK) }
  420. p.propaccesslist[palt_read].procdef:=Tprocsym(sym).Find_procdef_bypara(readprocdef.paras,p.propdef,[cpo_allowdefaults,cpo_ignorehidden]);
  421. if not assigned(p.propaccesslist[palt_read].procdef) then
  422. Message(parser_e_ill_property_access_sym);
  423. end;
  424. fieldvarsym :
  425. begin
  426. if not assigned(def) then
  427. internalerror(200310071);
  428. if compare_defs(def,p.propdef,nothingn)>=te_equal then
  429. begin
  430. { property parameters are allowed if this is
  431. an indexed property, because the index is then
  432. the parameter.
  433. Note: In the help of Kylix it is written
  434. that it isn't allowed, but the compiler accepts it (PFV) }
  435. if (ppo_hasparameters in p.propoptions) then
  436. Message(parser_e_ill_property_access_sym);
  437. end
  438. else
  439. IncompatibleTypes(def,p.propdef);
  440. end;
  441. else
  442. Message(parser_e_ill_property_access_sym);
  443. end;
  444. end;
  445. end;
  446. if try_to_consume(_WRITE) then
  447. begin
  448. p.propaccesslist[palt_write].clear;
  449. if parse_symlist(p.propaccesslist[palt_write],def) then
  450. begin
  451. sym:=p.propaccesslist[palt_write].firstsym^.sym;
  452. case sym.typ of
  453. procsym :
  454. begin
  455. { write is a procedure with an extra value parameter
  456. of the of the property }
  457. writeprocdef.returndef:=voidtype;
  458. inc(paranr);
  459. hparavs:=tparavarsym.create('$value',10*paranr,vs_value,p.propdef,[]);
  460. writeprocdef.parast.insert(hparavs);
  461. { Insert hidden parameters }
  462. handle_calling_convention(writeprocdef);
  463. { search procdefs matching writeprocdef }
  464. p.propaccesslist[palt_write].procdef:=Tprocsym(sym).Find_procdef_bypara(writeprocdef.paras,writeprocdef.returndef,[cpo_allowdefaults]);
  465. if not assigned(p.propaccesslist[palt_write].procdef) then
  466. Message(parser_e_ill_property_access_sym);
  467. end;
  468. fieldvarsym :
  469. begin
  470. if not assigned(def) then
  471. internalerror(200310072);
  472. if compare_defs(def,p.propdef,nothingn)>=te_equal then
  473. begin
  474. { property parameters are allowed if this is
  475. an indexed property, because the index is then
  476. the parameter.
  477. Note: In the help of Kylix it is written
  478. that it isn't allowed, but the compiler accepts it (PFV) }
  479. if (ppo_hasparameters in p.propoptions) then
  480. Message(parser_e_ill_property_access_sym);
  481. end
  482. else
  483. IncompatibleTypes(def,p.propdef);
  484. end;
  485. else
  486. Message(parser_e_ill_property_access_sym);
  487. end;
  488. end;
  489. end;
  490. end
  491. else
  492. begin
  493. if try_to_consume(_READONLY) then
  494. begin
  495. end
  496. else if try_to_consume(_WRITEONLY) then
  497. begin
  498. end;
  499. if try_to_consume(_DISPID) then
  500. begin
  501. pt:=comp_expr(true);
  502. if is_constintnode(pt) then
  503. // tprocdef(pd).extnumber:=tordconstnode(pt).value
  504. else
  505. Message(parser_e_dispid_must_be_ord_const);
  506. pt.free;
  507. end;
  508. end;
  509. if assigned(aclass) and not(is_dispinterface(aclass)) then
  510. begin
  511. { ppo_stored is default on for not overriden properties }
  512. if not assigned(p.overridenpropsym) then
  513. include(p.propoptions,ppo_stored);
  514. if try_to_consume(_STORED) then
  515. begin
  516. include(p.propoptions,ppo_stored);
  517. p.propaccesslist[palt_stored].clear;
  518. case token of
  519. _ID:
  520. begin
  521. { in the case that idtoken=_DEFAULT }
  522. { we have to do nothing except }
  523. { setting ppo_stored, it's the same }
  524. { as stored true }
  525. if idtoken<>_DEFAULT then
  526. begin
  527. { parse_symlist cannot deal with constsyms, and
  528. we also don't want to put constsyms in symlists
  529. since they have to be evaluated immediately rather
  530. than each time the property is accessed
  531. The proper fix would be to always create a parse tree
  532. and then convert that one, if appropriate, to a symlist.
  533. Currently, we e.g. don't support any constant expressions
  534. yet either here, while Delphi does.
  535. }
  536. { make sure we don't let constants mask class fields/
  537. methods
  538. }
  539. if (not assigned(aclass) or
  540. (search_class_member(aclass,pattern)=nil)) and
  541. searchsym(pattern,sym,srsymtable) and
  542. (sym.typ = constsym) then
  543. begin
  544. addsymref(sym);
  545. if not is_boolean(tconstsym(sym).constdef) then
  546. Message(parser_e_stored_property_must_be_boolean)
  547. else if (tconstsym(sym).value.valueord=0) then
  548. { same as for _FALSE }
  549. exclude(p.propoptions,ppo_stored)
  550. else
  551. { same as for _TRUE }
  552. p.default:=longint($80000000);
  553. consume(_ID);
  554. end
  555. else if parse_symlist(p.propaccesslist[palt_stored],def) then
  556. begin
  557. sym:=p.propaccesslist[palt_stored].firstsym^.sym;
  558. case sym.typ of
  559. procsym :
  560. begin
  561. { Insert hidden parameters }
  562. handle_calling_convention(storedprocdef);
  563. p.propaccesslist[palt_stored].procdef:=Tprocsym(sym).Find_procdef_bypara(storedprocdef.paras,storedprocdef.returndef,[cpo_allowdefaults,cpo_ignorehidden]);
  564. if not assigned(p.propaccesslist[palt_stored].procdef) then
  565. message(parser_e_ill_property_storage_sym);
  566. end;
  567. fieldvarsym :
  568. begin
  569. if not assigned(def) then
  570. internalerror(200310073);
  571. if (ppo_hasparameters in p.propoptions) or
  572. not(is_boolean(def)) then
  573. Message(parser_e_stored_property_must_be_boolean);
  574. end;
  575. else
  576. Message(parser_e_ill_property_access_sym);
  577. end;
  578. end;
  579. end;
  580. end;
  581. _FALSE:
  582. begin
  583. consume(_FALSE);
  584. exclude(p.propoptions,ppo_stored);
  585. end;
  586. _TRUE:
  587. begin
  588. p.default:=longint($80000000);
  589. consume(_TRUE);
  590. end;
  591. end;
  592. end;
  593. end;
  594. if try_to_consume(_DEFAULT) then
  595. begin
  596. if not allow_default_property(p) then
  597. begin
  598. Message(parser_e_property_cant_have_a_default_value);
  599. { Error recovery }
  600. pt:=comp_expr(true);
  601. pt.free;
  602. end
  603. else
  604. begin
  605. { Get the result of the default, the firstpass is
  606. needed to support values like -1 }
  607. pt:=comp_expr(true);
  608. if (p.propdef.typ=setdef) and
  609. (pt.nodetype=arrayconstructorn) then
  610. begin
  611. arrayconstructor_to_set(pt);
  612. do_typecheckpass(pt);
  613. end;
  614. inserttypeconv(pt,p.propdef);
  615. if not(is_constnode(pt)) then
  616. Message(parser_e_property_default_value_must_const);
  617. { Set default value }
  618. case pt.nodetype of
  619. setconstn :
  620. p.default:=plongint(tsetconstnode(pt).value_set)^;
  621. ordconstn :
  622. if (Tordconstnode(pt).value<int64(low(longint))) or
  623. (Tordconstnode(pt).value>int64(high(cardinal))) then
  624. message(parser_e_range_check_error)
  625. else
  626. p.default:=longint(tordconstnode(pt).value.svalue);
  627. niln :
  628. p.default:=0;
  629. realconstn:
  630. p.default:=longint(single(trealconstnode(pt).value_real));
  631. end;
  632. pt.free;
  633. end;
  634. end
  635. else if try_to_consume(_NODEFAULT) then
  636. begin
  637. p.default:=longint($80000000);
  638. end;
  639. (*
  640. else {if allow_default_property(p) then
  641. begin
  642. p.default:=longint($80000000);
  643. end;
  644. *)
  645. { Parse possible "implements" keyword }
  646. if try_to_consume(_IMPLEMENTS) then
  647. begin
  648. single_type(def,false);
  649. if not(is_interface(def)) then
  650. message(parser_e_class_implements_must_be_interface);
  651. if is_interface(p.propdef) then
  652. begin
  653. if compare_defs(def,p.propdef,nothingn)<te_equal then
  654. begin
  655. message2(parser_e_implements_must_have_correct_type,def.GetTypeName,p.propdef.GetTypeName);
  656. exit;
  657. end;
  658. end
  659. else if is_class(p.propdef) then
  660. begin
  661. ImplIntf:=tobjectdef(p.propdef).find_implemented_interface(tobjectdef(def));
  662. if assigned(ImplIntf) then
  663. begin
  664. if compare_defs(ImplIntf.IntfDef,def,nothingn)<te_equal then
  665. begin
  666. message2(parser_e_implements_must_have_correct_type,ImplIntf.IntfDef.GetTypeName,def.GetTypeName);
  667. exit;
  668. end;
  669. end
  670. else
  671. begin
  672. message2(parser_e_class_doesnt_implement_interface,p.propdef.GetTypeName,def.GetTypeName);
  673. exit;
  674. end;
  675. end
  676. else
  677. begin
  678. message(parser_e_implements_must_be_class_or_interface);
  679. exit;
  680. end;
  681. if not assigned(p.propaccesslist[palt_read].firstsym) then
  682. begin
  683. message(parser_e_implements_must_read_specifier);
  684. exit;
  685. end;
  686. if assigned(p.propaccesslist[palt_write].firstsym) then
  687. begin
  688. message(parser_e_implements_must_not_have_write_specifier);
  689. exit;
  690. end;
  691. if assigned(p.propaccesslist[palt_stored].firstsym) then
  692. begin
  693. message(parser_e_implements_must_not_have_stored_specifier);
  694. exit;
  695. end;
  696. found:=false;
  697. for i:=0 to aclass.ImplementedInterfaces.Count-1 do
  698. begin
  699. ImplIntf:=TImplementedInterface(aclass.ImplementedInterfaces[i]);
  700. if compare_defs(def,ImplIntf.IntfDef,nothingn)>=te_equal then
  701. begin
  702. found:=true;
  703. break;
  704. end;
  705. end;
  706. if found then
  707. begin
  708. ImplIntf.ImplementsGetter:=p;
  709. case p.propaccesslist[palt_read].firstsym^.sym.typ of
  710. procsym :
  711. begin
  712. if (po_virtualmethod in tprocdef(p.propaccesslist[palt_read].procdef).procoptions) then
  713. ImplIntf.IType:=etVirtualMethodResult
  714. else
  715. ImplIntf.IType:=etStaticMethodResult;
  716. end;
  717. fieldvarsym :
  718. ImplIntf.IType:=etFieldValue;
  719. else
  720. internalerror(200802161);
  721. end;
  722. end
  723. else
  724. message1(parser_e_implements_uses_non_implemented_interface,def.GetTypeName);
  725. end;
  726. { remove temporary procvardefs }
  727. readprocdef.owner.deletedef(readprocdef);
  728. writeprocdef.owner.deletedef(writeprocdef);
  729. result:=p;
  730. end;
  731. function maybe_parse_proc_directives(def:tdef):boolean;
  732. var
  733. newtype : ttypesym;
  734. begin
  735. result:=false;
  736. { Process procvar directives before = and ; }
  737. if (def.typ=procvardef) and
  738. (def.typesym=nil) and
  739. check_proc_directive(true) then
  740. begin
  741. newtype:=ttypesym.create('unnamed',def);
  742. parse_var_proc_directives(tsym(newtype));
  743. newtype.typedef:=nil;
  744. def.typesym:=nil;
  745. newtype.free;
  746. result:=true;
  747. end;
  748. end;
  749. const
  750. variantrecordlevel : longint = 0;
  751. procedure read_public_and_external_sc(sc:TFPObjectList);
  752. var
  753. vs: tabstractvarsym;
  754. begin
  755. { only allowed for one var }
  756. vs:=tabstractvarsym(sc[0]);
  757. if sc.count>1 then
  758. Message(parser_e_absolute_only_one_var);
  759. read_public_and_external(vs);
  760. end;
  761. procedure read_public_and_external(vs: tabstractvarsym);
  762. var
  763. is_dll,
  764. is_cdecl,
  765. is_external_var,
  766. is_weak_external,
  767. is_public_var : boolean;
  768. dll_name,
  769. C_name : string;
  770. begin
  771. { only allowed for one var }
  772. { only allow external and public on global symbols }
  773. if vs.typ<>staticvarsym then
  774. begin
  775. Message(parser_e_no_local_var_external);
  776. exit;
  777. end;
  778. { defaults }
  779. is_dll:=false;
  780. is_cdecl:=false;
  781. is_external_var:=false;
  782. is_public_var:=false;
  783. C_name:=vs.realname;
  784. { macpas specific handling due to some switches}
  785. if (m_mac in current_settings.modeswitches) then
  786. begin
  787. if (cs_external_var in current_settings.localswitches) then
  788. begin {The effect of this is the same as if cvar; external; has been given as directives.}
  789. is_cdecl:=true;
  790. is_external_var:=true;
  791. end
  792. else if (cs_externally_visible in current_settings.localswitches) then
  793. begin {The effect of this is the same as if cvar has been given as directives and it's made public.}
  794. is_cdecl:=true;
  795. is_public_var:=true;
  796. end;
  797. end;
  798. { cdecl }
  799. if try_to_consume(_CVAR) then
  800. begin
  801. consume(_SEMICOLON);
  802. is_cdecl:=true;
  803. end;
  804. { external }
  805. is_weak_external:=try_to_consume(_WEAKEXTERNAL);
  806. if is_weak_external or
  807. try_to_consume(_EXTERNAL) then
  808. begin
  809. is_external_var:=true;
  810. if not is_cdecl then
  811. begin
  812. if idtoken<>_NAME then
  813. begin
  814. is_dll:=true;
  815. dll_name:=get_stringconst;
  816. if ExtractFileExt(dll_name)='' then
  817. dll_name:=ChangeFileExt(dll_name,target_info.sharedlibext);
  818. end;
  819. if try_to_consume(_NAME) then
  820. C_name:=get_stringconst;
  821. end;
  822. consume(_SEMICOLON);
  823. end;
  824. { export or public }
  825. if idtoken in [_EXPORT,_PUBLIC] then
  826. begin
  827. consume(_ID);
  828. if is_external_var then
  829. Message(parser_e_not_external_and_export)
  830. else
  831. is_public_var:=true;
  832. if try_to_consume(_NAME) then
  833. C_name:=get_stringconst;
  834. consume(_SEMICOLON);
  835. end;
  836. { Windows uses an indirect reference using import tables }
  837. if is_dll and
  838. (target_info.system in system_all_windows) then
  839. include(vs.varoptions,vo_is_dll_var);
  840. { Add C _ prefix }
  841. if is_cdecl or
  842. (
  843. is_dll and
  844. (target_info.system in systems_darwin)
  845. ) then
  846. C_Name := target_info.Cprefix+C_Name;
  847. if is_public_var then
  848. begin
  849. include(vs.varoptions,vo_is_public);
  850. vs.varregable := vr_none;
  851. { mark as referenced }
  852. inc(vs.refs);
  853. end;
  854. { now we can insert it in the import lib if its a dll, or
  855. add it to the externals }
  856. if is_external_var then
  857. begin
  858. if vo_is_typed_const in vs.varoptions then
  859. Message(parser_e_initialized_not_for_external);
  860. include(vs.varoptions,vo_is_external);
  861. if (is_weak_external) then
  862. begin
  863. if not(target_info.system in system_weak_linking) then
  864. message(parser_e_weak_external_not_supported);
  865. include(vs.varoptions,vo_is_weak_external);
  866. end;
  867. vs.varregable := vr_none;
  868. if is_dll then
  869. current_module.AddExternalImport(dll_name,C_Name,0,true,false)
  870. else
  871. if tf_has_dllscanner in target_info.flags then
  872. current_module.dllscannerinputlist.Add(vs.mangledname,vs);
  873. end;
  874. { Set the assembler name }
  875. tstaticvarsym(vs).set_mangledname(C_Name);
  876. end;
  877. procedure read_var_decls(options:Tvar_dec_options);
  878. procedure read_default_value(sc : TFPObjectList);
  879. var
  880. vs : tabstractnormalvarsym;
  881. tcsym : tstaticvarsym;
  882. begin
  883. vs:=tabstractnormalvarsym(sc[0]);
  884. if sc.count>1 then
  885. Message(parser_e_initialized_only_one_var);
  886. if vo_is_thread_var in vs.varoptions then
  887. Message(parser_e_initialized_not_for_threadvar);
  888. consume(_EQUAL);
  889. case vs.typ of
  890. localvarsym :
  891. begin
  892. tcsym:=tstaticvarsym.create('$default'+vs.realname,vs_const,vs.vardef,[]);
  893. include(tcsym.symoptions,sp_internal);
  894. vs.defaultconstsym:=tcsym;
  895. symtablestack.top.insert(tcsym);
  896. read_typed_const(current_asmdata.asmlists[al_typedconsts],tcsym);
  897. end;
  898. staticvarsym :
  899. begin
  900. read_typed_const(current_asmdata.asmlists[al_typedconsts],tstaticvarsym(vs));
  901. end;
  902. else
  903. internalerror(200611051);
  904. end;
  905. vs.varstate:=vs_initialised;
  906. end;
  907. {$ifdef gpc_mode}
  908. procedure read_gpc_name(sc : TFPObjectList);
  909. var
  910. vs : tabstractnormalvarsym;
  911. C_Name : string;
  912. begin
  913. consume(_ID);
  914. C_Name:=get_stringconst;
  915. vs:=tabstractnormalvarsym(sc[0]);
  916. if sc.count>1 then
  917. Message(parser_e_absolute_only_one_var);
  918. if vs.typ=staticvarsym then
  919. begin
  920. tstaticvarsym(vs).set_mangledname(C_Name);
  921. include(vs.varoptions,vo_is_external);
  922. end
  923. else
  924. Message(parser_e_no_local_var_external);
  925. end;
  926. {$endif}
  927. procedure read_absolute(sc : TFPObjectList);
  928. var
  929. vs : tabstractvarsym;
  930. abssym : tabsolutevarsym;
  931. pt,hp : tnode;
  932. st : tsymtable;
  933. begin
  934. abssym:=nil;
  935. { only allowed for one var }
  936. vs:=tabstractvarsym(sc[0]);
  937. if sc.count>1 then
  938. Message(parser_e_absolute_only_one_var);
  939. if vo_is_typed_const in vs.varoptions then
  940. Message(parser_e_initialized_not_for_external);
  941. { parse the rest }
  942. pt:=expr;
  943. { check allowed absolute types }
  944. if (pt.nodetype=stringconstn) or
  945. (is_constcharnode(pt)) then
  946. begin
  947. abssym:=tabsolutevarsym.create(vs.realname,vs.vardef);
  948. abssym.fileinfo:=vs.fileinfo;
  949. if pt.nodetype=stringconstn then
  950. abssym.asmname:=stringdup(strpas(tstringconstnode(pt).value_str))
  951. else
  952. abssym.asmname:=stringdup(chr(tordconstnode(pt).value.svalue));
  953. consume(token);
  954. abssym.abstyp:=toasm;
  955. end
  956. { address }
  957. else if is_constintnode(pt) then
  958. begin
  959. abssym:=tabsolutevarsym.create(vs.realname,vs.vardef);
  960. abssym.fileinfo:=vs.fileinfo;
  961. abssym.abstyp:=toaddr;
  962. {$ifndef cpu64bitaddr}
  963. { on 64 bit systems, abssym.addroffset is a qword and hence this
  964. test is useless (value is a 64 bit entity) and will always fail
  965. for positive values (since int64(high(abssym.addroffset))=-1
  966. }
  967. if (Tordconstnode(pt).value<int64(low(abssym.addroffset))) or
  968. (Tordconstnode(pt).value>int64(high(abssym.addroffset))) then
  969. message(parser_e_range_check_error)
  970. else
  971. {$endif}
  972. abssym.addroffset:=Tordconstnode(pt).value.svalue;
  973. {$ifdef i386}
  974. abssym.absseg:=false;
  975. if (target_info.system in [system_i386_go32v2,system_i386_watcom]) and
  976. try_to_consume(_COLON) then
  977. begin
  978. pt.free;
  979. pt:=expr;
  980. if is_constintnode(pt) then
  981. begin
  982. if (Tordconstnode(pt).value<int64(low(abssym.addroffset))) or
  983. (Tordconstnode(pt).value>int64(high(abssym.addroffset))) then
  984. message(parser_e_range_check_error)
  985. else
  986. abssym.addroffset:=abssym.addroffset shl 4+tordconstnode(pt).value.svalue;
  987. abssym.absseg:=true;
  988. end
  989. else
  990. Message(type_e_ordinal_expr_expected);
  991. end;
  992. {$endif i386}
  993. end
  994. { variable }
  995. else
  996. begin
  997. { we have to be able to take the address of the absolute
  998. expression
  999. }
  1000. valid_for_addr(pt,true);
  1001. { remove subscriptn before checking for loadn }
  1002. hp:=pt;
  1003. while (hp.nodetype in [subscriptn,typeconvn,vecn]) do
  1004. begin
  1005. { check for implicit dereferencing and reject it }
  1006. if (hp.nodetype in [subscriptn,vecn]) then
  1007. begin
  1008. if (tunarynode(hp).left.resultdef.typ in [pointerdef,classrefdef]) then
  1009. break;
  1010. { catch, e.g., 'var b: char absolute pchar_var[5];"
  1011. (pchar_var[5] is a pchar_2_string typeconv ->
  1012. the vecn only sees an array of char)
  1013. I don't know if all of these type conversions are
  1014. possible, but they're definitely all bad.
  1015. }
  1016. if (tunarynode(hp).left.nodetype=typeconvn) and
  1017. (ttypeconvnode(tunarynode(hp).left).convtype in
  1018. [tc_pchar_2_string,tc_pointer_2_array,
  1019. tc_intf_2_string,tc_intf_2_guid,
  1020. tc_dynarray_2_variant,tc_interface_2_variant,
  1021. tc_array_2_dynarray]) then
  1022. break;
  1023. if (tunarynode(hp).left.resultdef.typ=stringdef) and
  1024. not(tstringdef(tunarynode(hp).left.resultdef).stringtype in [st_shortstring,st_longstring]) then
  1025. break;
  1026. if (tunarynode(hp).left.resultdef.typ=objectdef) and
  1027. (tobjectdef(tunarynode(hp).left.resultdef).objecttype<>odt_object) then
  1028. break;
  1029. if is_dynamic_array(tunarynode(hp).left.resultdef) then
  1030. break;
  1031. end;
  1032. hp:=tunarynode(hp).left;
  1033. end;
  1034. if (hp.nodetype=loadn) then
  1035. begin
  1036. { we should check the result type of loadn }
  1037. if not (tloadnode(hp).symtableentry.typ in [fieldvarsym,staticvarsym,localvarsym,paravarsym]) then
  1038. Message(parser_e_absolute_only_to_var_or_const);
  1039. abssym:=tabsolutevarsym.create(vs.realname,vs.vardef);
  1040. abssym.fileinfo:=vs.fileinfo;
  1041. abssym.abstyp:=tovar;
  1042. abssym.ref:=node_to_propaccesslist(pt);
  1043. { if the sizes are different, can't be a regvar since you }
  1044. { can't be "absolute upper 8 bits of a register" (except }
  1045. { if its a record field of the same size of a record }
  1046. { regvar, but in that case pt.resultdef.size will have }
  1047. { the same size since it refers to the field and not to }
  1048. { the whole record -- which is why we use pt and not hp) }
  1049. { we can't take the size of an open array }
  1050. if is_open_array(pt.resultdef) or
  1051. (vs.vardef.size <> pt.resultdef.size) then
  1052. make_not_regable(pt,[ra_addr_regable]);
  1053. end
  1054. else
  1055. Message(parser_e_absolute_only_to_var_or_const);
  1056. end;
  1057. pt.free;
  1058. { replace old varsym with the new absolutevarsym }
  1059. if assigned(abssym) then
  1060. begin
  1061. st:=vs.owner;
  1062. vs.owner.Delete(vs);
  1063. st.insert(abssym);
  1064. sc[0]:=abssym;
  1065. end;
  1066. end;
  1067. var
  1068. sc : TFPObjectList;
  1069. vs : tabstractvarsym;
  1070. hdef : tdef;
  1071. i : longint;
  1072. semicoloneaten,
  1073. allowdefaultvalue,
  1074. hasdefaultvalue : boolean;
  1075. hintsymoptions : tsymoptions;
  1076. old_block_type : tblock_type;
  1077. begin
  1078. old_block_type:=block_type;
  1079. block_type:=bt_var;
  1080. { Force an expected ID error message }
  1081. if not (token in [_ID,_CASE,_END]) then
  1082. consume(_ID);
  1083. { read vars }
  1084. sc:=TFPObjectList.create(false);
  1085. while (token=_ID) do
  1086. begin
  1087. semicoloneaten:=false;
  1088. hasdefaultvalue:=false;
  1089. allowdefaultvalue:=true;
  1090. sc.clear;
  1091. repeat
  1092. if (token = _ID) then
  1093. begin
  1094. case symtablestack.top.symtabletype of
  1095. localsymtable :
  1096. vs:=tlocalvarsym.create(orgpattern,vs_value,generrordef,[]);
  1097. staticsymtable,
  1098. globalsymtable :
  1099. begin
  1100. vs:=tstaticvarsym.create(orgpattern,vs_value,generrordef,[]);
  1101. if vd_threadvar in options then
  1102. include(vs.varoptions,vo_is_thread_var);
  1103. end;
  1104. else
  1105. internalerror(200411064);
  1106. end;
  1107. sc.add(vs);
  1108. symtablestack.top.insert(vs);
  1109. end;
  1110. consume(_ID);
  1111. until not try_to_consume(_COMMA);
  1112. { read variable type def }
  1113. block_type:=bt_var_type;
  1114. consume(_COLON);
  1115. {$ifdef gpc_mode}
  1116. if (m_gpc in current_settings.modeswitches) and
  1117. (token=_ID) and
  1118. (orgpattern='__asmname__') then
  1119. read_gpc_name(sc);
  1120. {$endif}
  1121. read_anon_type(hdef,false);
  1122. for i:=0 to sc.count-1 do
  1123. begin
  1124. vs:=tabstractvarsym(sc[i]);
  1125. vs.vardef:=hdef;
  1126. end;
  1127. block_type:=bt_var;
  1128. { Process procvar directives }
  1129. if maybe_parse_proc_directives(hdef) then
  1130. semicoloneaten:=true;
  1131. { check for absolute }
  1132. if try_to_consume(_ABSOLUTE) then
  1133. begin
  1134. read_absolute(sc);
  1135. allowdefaultvalue:=false;
  1136. end;
  1137. { Check for EXTERNAL etc directives before a semicolon }
  1138. if (idtoken in [_EXPORT,_EXTERNAL,_WEAKEXTERNAL,_PUBLIC,_CVAR]) then
  1139. begin
  1140. read_public_and_external_sc(sc);
  1141. allowdefaultvalue:=false;
  1142. semicoloneaten:=true;
  1143. end;
  1144. { try to parse the hint directives }
  1145. hintsymoptions:=[];
  1146. try_consume_hintdirective(hintsymoptions);
  1147. for i:=0 to sc.count-1 do
  1148. begin
  1149. vs:=tabstractvarsym(sc[i]);
  1150. vs.symoptions := vs.symoptions + hintsymoptions;
  1151. end;
  1152. { Handling of Delphi typed const = initialized vars }
  1153. if allowdefaultvalue and
  1154. (token=_EQUAL) and
  1155. not(m_tp7 in current_settings.modeswitches) and
  1156. (symtablestack.top.symtabletype<>parasymtable) then
  1157. begin
  1158. { Add calling convention for procvar }
  1159. if (hdef.typ=procvardef) and
  1160. (hdef.typesym=nil) then
  1161. handle_calling_convention(tprocvardef(hdef));
  1162. read_default_value(sc);
  1163. hasdefaultvalue:=true;
  1164. end
  1165. else
  1166. begin
  1167. if not(semicoloneaten) then
  1168. consume(_SEMICOLON);
  1169. end;
  1170. { Support calling convention for procvars after semicolon }
  1171. if not(hasdefaultvalue) and
  1172. (hdef.typ=procvardef) and
  1173. (hdef.typesym=nil) then
  1174. begin
  1175. { Parse procvar directives after ; }
  1176. maybe_parse_proc_directives(hdef);
  1177. { Add calling convention for procvar }
  1178. handle_calling_convention(tprocvardef(hdef));
  1179. { Handling of Delphi typed const = initialized vars }
  1180. if (token=_EQUAL) and
  1181. not(m_tp7 in current_settings.modeswitches) and
  1182. (symtablestack.top.symtabletype<>parasymtable) then
  1183. begin
  1184. read_default_value(sc);
  1185. hasdefaultvalue:=true;
  1186. end;
  1187. end;
  1188. { Check for EXTERNAL etc directives or, in macpas, if cs_external_var is set}
  1189. if (
  1190. (
  1191. (idtoken in [_EXPORT,_EXTERNAL,_WEAKEXTERNAL,_PUBLIC,_CVAR]) and
  1192. (m_cvar_support in current_settings.modeswitches)
  1193. ) or
  1194. (
  1195. (m_mac in current_settings.modeswitches) and
  1196. (
  1197. (cs_external_var in current_settings.localswitches) or
  1198. (cs_externally_visible in current_settings.localswitches)
  1199. )
  1200. )
  1201. ) then
  1202. read_public_and_external_sc(sc);
  1203. { allocate normal variable (non-external and non-typed-const) staticvarsyms }
  1204. for i:=0 to sc.count-1 do
  1205. begin
  1206. vs:=tabstractvarsym(sc[i]);
  1207. if (vs.typ=staticvarsym) and
  1208. not(vo_is_typed_const in vs.varoptions) and
  1209. not(vo_is_external in vs.varoptions) then
  1210. insertbssdata(tstaticvarsym(vs));
  1211. end;
  1212. end;
  1213. block_type:=old_block_type;
  1214. { free the list }
  1215. sc.free;
  1216. end;
  1217. procedure read_record_fields(options:Tvar_dec_options);
  1218. var
  1219. sc : TFPObjectList;
  1220. i : longint;
  1221. hs,sorg : string;
  1222. hdef,casetype : tdef;
  1223. { maxsize contains the max. size of a variant }
  1224. { startvarrec contains the start of the variant part of a record }
  1225. maxsize, startvarrecsize : longint;
  1226. usedalign,
  1227. maxalignment,startvarrecalign,
  1228. maxpadalign, startpadalign: shortint;
  1229. pt : tnode;
  1230. fieldvs : tfieldvarsym;
  1231. hstaticvs : tstaticvarsym;
  1232. vs : tabstractvarsym;
  1233. srsym : tsym;
  1234. srsymtable : TSymtable;
  1235. visibility : tvisibility;
  1236. recst : tabstractrecordsymtable;
  1237. unionsymtable : trecordsymtable;
  1238. offset : longint;
  1239. uniondef : trecorddef;
  1240. hintsymoptions : tsymoptions;
  1241. semicoloneaten: boolean;
  1242. {$if defined(powerpc) or defined(powerpc64)}
  1243. tempdef: tdef;
  1244. is_first_field: boolean;
  1245. {$endif powerpc or powerpc64}
  1246. begin
  1247. recst:=tabstractrecordsymtable(symtablestack.top);
  1248. {$if defined(powerpc) or defined(powerpc64)}
  1249. is_first_field := true;
  1250. {$endif powerpc or powerpc64}
  1251. { Force an expected ID error message }
  1252. if not (token in [_ID,_CASE,_END]) then
  1253. consume(_ID);
  1254. { read vars }
  1255. sc:=TFPObjectList.create(false);
  1256. while (token=_ID) and
  1257. not((vd_object in options) and
  1258. (idtoken in [_PUBLIC,_PRIVATE,_PUBLISHED,_PROTECTED,_STRICT])) do
  1259. begin
  1260. visibility:=symtablestack.top.currentvisibility;
  1261. semicoloneaten:=false;
  1262. sc.clear;
  1263. repeat
  1264. sorg:=orgpattern;
  1265. if token=_ID then
  1266. begin
  1267. vs:=tfieldvarsym.create(sorg,vs_value,generrordef,[]);
  1268. sc.add(vs);
  1269. recst.insert(vs);
  1270. end;
  1271. consume(_ID);
  1272. until not try_to_consume(_COMMA);
  1273. consume(_COLON);
  1274. { Don't search in the recordsymtable for types }
  1275. if ([df_generic,df_specialization]*tdef(recst.defowner).defoptions=[]) then
  1276. symtablestack.pop(recst);
  1277. read_anon_type(hdef,false);
  1278. if ([df_generic,df_specialization]*tdef(recst.defowner).defoptions=[]) then
  1279. symtablestack.push(recst);
  1280. { Process procvar directives }
  1281. if maybe_parse_proc_directives(hdef) then
  1282. semicoloneaten:=true;
  1283. {$if defined(powerpc) or defined(powerpc64)}
  1284. { from gcc/gcc/config/rs6000/rs6000.h:
  1285. /* APPLE LOCAL begin Macintosh alignment 2002-1-22 ff */
  1286. /* Return the alignment of a struct based on the Macintosh PowerPC
  1287. alignment rules. In general the alignment of a struct is
  1288. determined by the greatest alignment of its elements. However, the
  1289. PowerPC rules cause the alignment of a struct to peg at word
  1290. alignment except when the first field has greater than word
  1291. (32-bit) alignment, in which case the alignment is determined by
  1292. the alignment of the first field. */
  1293. }
  1294. if (target_info.system in [system_powerpc_darwin, system_powerpc_macos, system_powerpc64_darwin]) and
  1295. is_first_field and
  1296. (symtablestack.top.symtabletype=recordsymtable) and
  1297. (trecordsymtable(symtablestack.top).usefieldalignment=C_alignment) then
  1298. begin
  1299. tempdef:=hdef;
  1300. while tempdef.typ=arraydef do
  1301. tempdef:=tarraydef(tempdef).elementdef;
  1302. if tempdef.typ<>recorddef then
  1303. maxpadalign:=tempdef.alignment
  1304. else
  1305. maxpadalign:=trecorddef(tempdef).padalignment;
  1306. if (maxpadalign>4) and
  1307. (maxpadalign>trecordsymtable(symtablestack.top).padalignment) then
  1308. trecordsymtable(symtablestack.top).padalignment:=maxpadalign;
  1309. is_first_field:=false;
  1310. end;
  1311. {$endif powerpc or powerpc64}
  1312. { types that use init/final are not allowed in variant parts, but
  1313. classes are allowed }
  1314. if (variantrecordlevel>0) and
  1315. (hdef.needs_inittable and not is_class(hdef)) then
  1316. Message(parser_e_cant_use_inittable_here);
  1317. { try to parse the hint directives }
  1318. hintsymoptions:=[];
  1319. try_consume_hintdirective(hintsymoptions);
  1320. { update variable type and hints }
  1321. for i:=0 to sc.count-1 do
  1322. begin
  1323. fieldvs:=tfieldvarsym(sc[i]);
  1324. fieldvs.vardef:=hdef;
  1325. { insert any additional hint directives }
  1326. fieldvs.symoptions := fieldvs.symoptions + hintsymoptions;
  1327. end;
  1328. { Records and objects can't have default values }
  1329. { for a record there doesn't need to be a ; before the END or ) }
  1330. if not(token in [_END,_RKLAMMER]) and
  1331. not(semicoloneaten) then
  1332. consume(_SEMICOLON);
  1333. { Parse procvar directives after ; }
  1334. maybe_parse_proc_directives(hdef);
  1335. { Add calling convention for procvar }
  1336. if (hdef.typ=procvardef) and
  1337. (hdef.typesym=nil) then
  1338. handle_calling_convention(tprocvardef(hdef));
  1339. { Check for STATIC directive }
  1340. if (vd_object in options) and
  1341. (cs_static_keyword in current_settings.moduleswitches) and
  1342. (try_to_consume(_STATIC)) then
  1343. begin
  1344. { add static flag and staticvarsyms }
  1345. for i:=0 to sc.count-1 do
  1346. begin
  1347. fieldvs:=tfieldvarsym(sc[i]);
  1348. include(fieldvs.symoptions,sp_static);
  1349. hstaticvs:=tstaticvarsym.create('$'+lower(symtablestack.top.name^)+'_'+fieldvs.name,vs_value,hdef,[]);
  1350. recst.defowner.owner.insert(hstaticvs);
  1351. insertbssdata(hstaticvs);
  1352. end;
  1353. consume(_SEMICOLON);
  1354. end;
  1355. if (visibility=vis_published) and
  1356. not(is_class(hdef)) then
  1357. begin
  1358. Message(parser_e_cant_publish_that);
  1359. visibility:=vis_public;
  1360. end;
  1361. if (visibility=vis_published) and
  1362. not(oo_can_have_published in tobjectdef(hdef).objectoptions) and
  1363. not(m_delphi in current_settings.modeswitches) then
  1364. begin
  1365. Message(parser_e_only_publishable_classes_can_be_published);
  1366. visibility:=vis_public;
  1367. end;
  1368. { Generate field in the recordsymtable }
  1369. for i:=0 to sc.count-1 do
  1370. begin
  1371. fieldvs:=tfieldvarsym(sc[i]);
  1372. { static data fields are already inserted in the globalsymtable }
  1373. if not(sp_static in fieldvs.symoptions) then
  1374. recst.addfield(fieldvs,visibility);
  1375. end;
  1376. end;
  1377. { Check for Case }
  1378. if (vd_record in options) and
  1379. try_to_consume(_CASE) then
  1380. begin
  1381. maxsize:=0;
  1382. maxalignment:=0;
  1383. maxpadalign:=0;
  1384. { including a field declaration? }
  1385. fieldvs:=nil;
  1386. sorg:=orgpattern;
  1387. hs:=pattern;
  1388. searchsym(hs,srsym,srsymtable);
  1389. if not(assigned(srsym) and (srsym.typ in [typesym,unitsym])) then
  1390. begin
  1391. consume(_ID);
  1392. consume(_COLON);
  1393. fieldvs:=tfieldvarsym.create(sorg,vs_value,generrordef,[]);
  1394. symtablestack.top.insert(fieldvs);
  1395. end;
  1396. read_anon_type(casetype,true);
  1397. if assigned(fieldvs) then
  1398. begin
  1399. fieldvs.vardef:=casetype;
  1400. recst.addfield(fieldvs,recst.currentvisibility);
  1401. end;
  1402. if not(is_ordinal(casetype))
  1403. {$ifndef cpu64bitaddr}
  1404. or is_64bitint(casetype)
  1405. {$endif cpu64bitaddr}
  1406. then
  1407. Message(type_e_ordinal_expr_expected);
  1408. consume(_OF);
  1409. UnionSymtable:=trecordsymtable.create(current_settings.packrecords);
  1410. UnionDef:=trecorddef.create(unionsymtable);
  1411. uniondef.isunion:=true;
  1412. startvarrecsize:=UnionSymtable.datasize;
  1413. { align the bitpacking to the next byte }
  1414. UnionSymtable.datasize:=startvarrecsize;
  1415. startvarrecalign:=UnionSymtable.fieldalignment;
  1416. startpadalign:=Unionsymtable.padalignment;
  1417. symtablestack.push(UnionSymtable);
  1418. repeat
  1419. repeat
  1420. pt:=comp_expr(true);
  1421. if not(pt.nodetype=ordconstn) then
  1422. Message(parser_e_illegal_expression);
  1423. if try_to_consume(_POINTPOINT) then
  1424. pt:=crangenode.create(pt,comp_expr(true));
  1425. pt.free;
  1426. if token=_COMMA then
  1427. consume(_COMMA)
  1428. else
  1429. break;
  1430. until false;
  1431. consume(_COLON);
  1432. { read the vars }
  1433. consume(_LKLAMMER);
  1434. inc(variantrecordlevel);
  1435. if token<>_RKLAMMER then
  1436. read_record_fields([vd_record]);
  1437. dec(variantrecordlevel);
  1438. consume(_RKLAMMER);
  1439. { calculates maximal variant size }
  1440. maxsize:=max(maxsize,unionsymtable.datasize);
  1441. maxalignment:=max(maxalignment,unionsymtable.fieldalignment);
  1442. maxpadalign:=max(maxpadalign,unionsymtable.padalignment);
  1443. { the items of the next variant are overlayed }
  1444. unionsymtable.datasize:=startvarrecsize;
  1445. unionsymtable.fieldalignment:=startvarrecalign;
  1446. unionsymtable.padalignment:=startpadalign;
  1447. if (token<>_END) and (token<>_RKLAMMER) then
  1448. consume(_SEMICOLON)
  1449. else
  1450. break;
  1451. until (token=_END) or (token=_RKLAMMER);
  1452. symtablestack.pop(UnionSymtable);
  1453. { at last set the record size to that of the biggest variant }
  1454. unionsymtable.datasize:=maxsize;
  1455. unionsymtable.fieldalignment:=maxalignment;
  1456. unionsymtable.addalignmentpadding;
  1457. {$if defined(powerpc) or defined(powerpc64)}
  1458. { parent inherits the alignment padding if the variant is the first "field" of the parent record/variant }
  1459. if (target_info.system in [system_powerpc_darwin, system_powerpc_macos, system_powerpc64_darwin]) and
  1460. is_first_field and
  1461. (recst.usefieldalignment=C_alignment) and
  1462. (maxpadalign>recst.padalignment) then
  1463. recst.padalignment:=maxpadalign;
  1464. {$endif powerpc or powerpc64}
  1465. { Align the offset where the union symtable is added }
  1466. case recst.usefieldalignment of
  1467. { allow the unionsymtable to be aligned however it wants }
  1468. { (within the global min/max limits) }
  1469. 0, { default }
  1470. C_alignment:
  1471. usedalign:=used_align(unionsymtable.recordalignment,current_settings.alignment.recordalignmin,current_settings.alignment.maxCrecordalign);
  1472. { 1 byte alignment if we are bitpacked }
  1473. bit_alignment:
  1474. usedalign:=1;
  1475. { otherwise alignment at the packrecords alignment of the }
  1476. { current record }
  1477. else
  1478. usedalign:=used_align(recst.fieldalignment,current_settings.alignment.recordalignmin,current_settings.alignment.recordalignmax);
  1479. end;
  1480. offset:=align(recst.datasize,usedalign);
  1481. recst.datasize:=offset+unionsymtable.datasize;
  1482. if unionsymtable.recordalignment>recst.fieldalignment then
  1483. recst.fieldalignment:=unionsymtable.recordalignment;
  1484. trecordsymtable(recst).insertunionst(Unionsymtable,offset);
  1485. uniondef.owner.deletedef(uniondef);
  1486. end;
  1487. { free the list }
  1488. sc.free;
  1489. {$ifdef powerpc}
  1490. is_first_field := false;
  1491. {$endif powerpc}
  1492. end;
  1493. end.