pdecl.pas 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Does declaration (but not type) parsing for Free Pascal
  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 pdecl;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. { global }
  22. globtype,
  23. { symtable }
  24. symsym,
  25. { pass_1 }
  26. node;
  27. function readconstant(const orgname:string;const filepos:tfileposinfo):tconstsym;
  28. procedure const_dec;
  29. procedure label_dec;
  30. procedure type_dec;
  31. procedure types_dec;
  32. procedure var_dec;
  33. procedure threadvar_dec;
  34. procedure property_dec;
  35. procedure resourcestring_dec;
  36. implementation
  37. uses
  38. { common }
  39. cutils,cclasses,
  40. { global }
  41. globals,tokens,verbose,widestr,constexp,
  42. systems,
  43. { aasm }
  44. aasmbase,aasmtai,aasmdata,fmodule,
  45. { symtable }
  46. symconst,symbase,symtype,symdef,symtable,paramgr,defutil,
  47. { pass 1 }
  48. nmat,nadd,ncal,nset,ncnv,ninl,ncon,nld,nflw,nobj,
  49. { codegen }
  50. ncgutil,
  51. { parser }
  52. scanner,
  53. pbase,pexpr,ptype,ptconst,pdecsub,pdecvar,pdecobj,
  54. { cpu-information }
  55. cpuinfo
  56. ;
  57. function readconstant(const orgname:string;const filepos:tfileposinfo):tconstsym;
  58. var
  59. hp : tconstsym;
  60. p : tnode;
  61. ps : pconstset;
  62. pd : pbestreal;
  63. pg : pguid;
  64. sp : pchar;
  65. pw : pcompilerwidestring;
  66. storetokenpos : tfileposinfo;
  67. begin
  68. readconstant:=nil;
  69. if orgname='' then
  70. internalerror(9584582);
  71. hp:=nil;
  72. p:=comp_expr(true);
  73. storetokenpos:=current_tokenpos;
  74. current_tokenpos:=filepos;
  75. case p.nodetype of
  76. ordconstn:
  77. begin
  78. if p.resultdef.typ=pointerdef then
  79. hp:=tconstsym.create_ordptr(orgname,constpointer,tordconstnode(p).value.uvalue,p.resultdef)
  80. else
  81. hp:=tconstsym.create_ord(orgname,constord,tordconstnode(p).value,p.resultdef);
  82. end;
  83. stringconstn:
  84. begin
  85. if is_wide_or_unicode_string(p.resultdef) then
  86. begin
  87. initwidestring(pw);
  88. copywidestring(pcompilerwidestring(tstringconstnode(p).value_str),pw);
  89. hp:=tconstsym.create_wstring(orgname,constwstring,pw);
  90. end
  91. else
  92. begin
  93. getmem(sp,tstringconstnode(p).len+1);
  94. move(tstringconstnode(p).value_str^,sp^,tstringconstnode(p).len+1);
  95. hp:=tconstsym.create_string(orgname,conststring,sp,tstringconstnode(p).len);
  96. end;
  97. end;
  98. realconstn :
  99. begin
  100. new(pd);
  101. pd^:=trealconstnode(p).value_real;
  102. hp:=tconstsym.create_ptr(orgname,constreal,pd,p.resultdef);
  103. end;
  104. setconstn :
  105. begin
  106. new(ps);
  107. ps^:=tsetconstnode(p).value_set^;
  108. hp:=tconstsym.create_ptr(orgname,constset,ps,p.resultdef);
  109. end;
  110. pointerconstn :
  111. begin
  112. hp:=tconstsym.create_ordptr(orgname,constpointer,tpointerconstnode(p).value,p.resultdef);
  113. end;
  114. niln :
  115. begin
  116. hp:=tconstsym.create_ord(orgname,constnil,0,p.resultdef);
  117. end;
  118. typen :
  119. begin
  120. if is_interface(p.resultdef) then
  121. begin
  122. if assigned(tobjectdef(p.resultdef).iidguid) then
  123. begin
  124. new(pg);
  125. pg^:=tobjectdef(p.resultdef).iidguid^;
  126. hp:=tconstsym.create_ptr(orgname,constguid,pg,p.resultdef);
  127. end
  128. else
  129. Message1(parser_e_interface_has_no_guid,tobjectdef(p.resultdef).objrealname^);
  130. end
  131. else
  132. Message(parser_e_illegal_expression);
  133. end;
  134. else
  135. Message(parser_e_illegal_expression);
  136. end;
  137. current_tokenpos:=storetokenpos;
  138. p.free;
  139. readconstant:=hp;
  140. end;
  141. procedure const_dec;
  142. var
  143. orgname : TIDString;
  144. hdef : tdef;
  145. sym : tsym;
  146. dummysymoptions : tsymoptions;
  147. storetokenpos,filepos : tfileposinfo;
  148. old_block_type : tblock_type;
  149. skipequal : boolean;
  150. tclist : tasmlist;
  151. varspez : tvarspez;
  152. begin
  153. consume(_CONST);
  154. old_block_type:=block_type;
  155. block_type:=bt_const;
  156. repeat
  157. orgname:=orgpattern;
  158. filepos:=current_tokenpos;
  159. consume(_ID);
  160. case token of
  161. _EQUAL:
  162. begin
  163. consume(_EQUAL);
  164. sym:=readconstant(orgname,filepos);
  165. { Support hint directives }
  166. dummysymoptions:=[];
  167. try_consume_hintdirective(dummysymoptions);
  168. if assigned(sym) then
  169. begin
  170. sym.symoptions:=sym.symoptions+dummysymoptions;
  171. symtablestack.top.insert(sym);
  172. end;
  173. consume(_SEMICOLON);
  174. end;
  175. _COLON:
  176. begin
  177. { set the blocktype first so a consume also supports a
  178. caret, to support const s : ^string = nil }
  179. block_type:=bt_const_type;
  180. consume(_COLON);
  181. read_anon_type(hdef,false);
  182. block_type:=bt_const;
  183. skipequal:=false;
  184. { create symbol }
  185. storetokenpos:=current_tokenpos;
  186. current_tokenpos:=filepos;
  187. if not (cs_typed_const_writable in current_settings.localswitches) then
  188. varspez:=vs_const
  189. else
  190. varspez:=vs_value;
  191. sym:=tstaticvarsym.create(orgname,varspez,hdef,[]);
  192. current_tokenpos:=storetokenpos;
  193. symtablestack.top.insert(sym);
  194. { procvar can have proc directives, but not type references }
  195. if (hdef.typ=procvardef) and
  196. (hdef.typesym=nil) then
  197. begin
  198. { support p : procedure;stdcall=nil; }
  199. if try_to_consume(_SEMICOLON) then
  200. begin
  201. if check_proc_directive(true) then
  202. parse_var_proc_directives(sym)
  203. else
  204. begin
  205. Message(parser_e_proc_directive_expected);
  206. skipequal:=true;
  207. end;
  208. end
  209. else
  210. { support p : procedure stdcall=nil; }
  211. begin
  212. if check_proc_directive(true) then
  213. parse_var_proc_directives(sym);
  214. end;
  215. { add default calling convention }
  216. handle_calling_convention(tabstractprocdef(hdef));
  217. end;
  218. if not skipequal then
  219. begin
  220. { get init value }
  221. consume(_EQUAL);
  222. if (cs_typed_const_writable in current_settings.localswitches) then
  223. tclist:=current_asmdata.asmlists[al_rotypedconsts]
  224. else
  225. tclist:=current_asmdata.asmlists[al_typedconsts];
  226. read_typed_const(tclist,tstaticvarsym(sym));
  227. end;
  228. end;
  229. else
  230. { generate an error }
  231. consume(_EQUAL);
  232. end;
  233. until token<>_ID;
  234. block_type:=old_block_type;
  235. end;
  236. procedure label_dec;
  237. begin
  238. consume(_LABEL);
  239. if not(cs_support_goto in current_settings.moduleswitches) then
  240. Message(sym_e_goto_and_label_not_supported);
  241. repeat
  242. if not(token in [_ID,_INTCONST]) then
  243. consume(_ID)
  244. else
  245. begin
  246. if token=_ID then
  247. symtablestack.top.insert(tlabelsym.create(orgpattern))
  248. else
  249. symtablestack.top.insert(tlabelsym.create(pattern));
  250. consume(token);
  251. end;
  252. if token<>_SEMICOLON then consume(_COMMA);
  253. until not(token in [_ID,_INTCONST]);
  254. consume(_SEMICOLON);
  255. end;
  256. procedure types_dec;
  257. procedure get_objc_class_or_protocol_external_status(od: tobjectdef);
  258. begin
  259. { Objective-C classes can be external -> all messages inside are
  260. external (defined at the class level instead of per method, so
  261. that you cannot define some methods as external and some not)
  262. }
  263. if (token=_ID) and
  264. (idtoken=_EXTERNAL) then
  265. begin
  266. consume(_EXTERNAL);
  267. if (token=_ID) and
  268. (idtoken=_NAME) then
  269. begin
  270. consume(_NAME);
  271. od.objextname:=stringdup(get_stringconst);
  272. end
  273. else
  274. od.objextname:=stringdup(od.objrealname^);
  275. consume(_SEMICOLON);
  276. od.make_all_methods_external;
  277. include(od.objectoptions,oo_is_external);
  278. end
  279. else { or also allow "public name 'x'"? }
  280. od.objextname:=stringdup(od.objrealname^);
  281. end;
  282. function parse_generic_parameters:TFPObjectList;
  283. var
  284. generictype : ttypesym;
  285. begin
  286. result:=TFPObjectList.Create(false);
  287. repeat
  288. if token=_ID then
  289. begin
  290. generictype:=ttypesym.create(orgpattern,cundefinedtype);
  291. include(generictype.symoptions,sp_generic_para);
  292. result.add(generictype);
  293. end;
  294. consume(_ID);
  295. until not try_to_consume(_COMMA) ;
  296. end;
  297. var
  298. typename,orgtypename : TIDString;
  299. newtype : ttypesym;
  300. sym : tsym;
  301. srsymtable : TSymtable;
  302. hdef : tdef;
  303. defpos,storetokenpos : tfileposinfo;
  304. old_block_type : tblock_type;
  305. objecttype : tobjecttyp;
  306. isgeneric,
  307. isunique,
  308. istyperenaming : boolean;
  309. generictypelist : TFPObjectList;
  310. generictokenbuf : tdynamicarray;
  311. vmtbuilder : TVMTBuilder;
  312. begin
  313. old_block_type:=block_type;
  314. block_type:=bt_type;
  315. repeat
  316. defpos:=current_tokenpos;
  317. istyperenaming:=false;
  318. generictypelist:=nil;
  319. generictokenbuf:=nil;
  320. { generic declaration? }
  321. isgeneric:=try_to_consume(_GENERIC);
  322. typename:=pattern;
  323. orgtypename:=orgpattern;
  324. consume(_ID);
  325. { Generic type declaration? }
  326. if isgeneric then
  327. begin
  328. consume(_LSHARPBRACKET);
  329. generictypelist:=parse_generic_parameters;
  330. consume(_RSHARPBRACKET);
  331. end;
  332. consume(_EQUAL);
  333. { support 'ttype=type word' syntax }
  334. isunique:=try_to_consume(_TYPE);
  335. { MacPas object model is more like Delphi's than like TP's, but }
  336. { uses the object keyword instead of class }
  337. if (m_mac in current_settings.modeswitches) and
  338. (token = _OBJECT) then
  339. token := _CLASS;
  340. { Start recording a generic template }
  341. if assigned(generictypelist) then
  342. begin
  343. generictokenbuf:=tdynamicarray.create(256);
  344. current_scanner.startrecordtokens(generictokenbuf);
  345. end;
  346. { is the type already defined? }
  347. searchsym(typename,sym,srsymtable);
  348. newtype:=nil;
  349. { found a symbol with this name? }
  350. if assigned(sym) then
  351. begin
  352. if (sym.typ=typesym) then
  353. begin
  354. if ((token=_CLASS) or
  355. (token=_INTERFACE) or
  356. (token=_DISPINTERFACE) or
  357. (token=_OBJCCLASS) or
  358. (token=_OBJCPROTOCOL)) and
  359. (assigned(ttypesym(sym).typedef)) and
  360. is_class_or_interface_or_dispinterface_or_objc(ttypesym(sym).typedef) and
  361. (oo_is_forward in tobjectdef(ttypesym(sym).typedef).objectoptions) then
  362. begin
  363. case token of
  364. _CLASS :
  365. objecttype:=odt_class;
  366. _INTERFACE :
  367. if current_settings.interfacetype=it_interfacecom then
  368. objecttype:=odt_interfacecom
  369. else
  370. objecttype:=odt_interfacecorba;
  371. _DISPINTERFACE :
  372. objecttype:=odt_dispinterface;
  373. _OBJCCLASS :
  374. objecttype:=odt_objcclass;
  375. _OBJCPROTOCOL :
  376. objecttype:=odt_objcprotocol;
  377. else
  378. internalerror(200811072);
  379. end;
  380. consume(token);
  381. { we can ignore the result, the definition is modified }
  382. object_dec(objecttype,orgtypename,nil,nil,tobjectdef(ttypesym(sym).typedef));
  383. newtype:=ttypesym(sym);
  384. hdef:=newtype.typedef;
  385. end
  386. else
  387. message1(parser_h_type_redef,orgtypename);
  388. end;
  389. end;
  390. { no old type reused ? Then insert this new type }
  391. if not assigned(newtype) then
  392. begin
  393. { insert the new type first with an errordef, so that
  394. referencing the type before it's really set it
  395. will give an error (PFV) }
  396. hdef:=generrordef;
  397. storetokenpos:=current_tokenpos;
  398. newtype:=ttypesym.create(orgtypename,hdef);
  399. symtablestack.top.insert(newtype);
  400. current_tokenpos:=defpos;
  401. current_tokenpos:=storetokenpos;
  402. { read the type definition }
  403. read_named_type(hdef,orgtypename,nil,generictypelist,false);
  404. { update the definition of the type }
  405. if assigned(hdef) then
  406. begin
  407. if assigned(hdef.typesym) then
  408. istyperenaming:=true;
  409. if isunique then
  410. begin
  411. if is_objc_class_or_protocol(hdef) then
  412. Message(parser_e_no_objc_unique);
  413. hdef:=tstoreddef(hdef).getcopy;
  414. { fix name, it is used e.g. for tables }
  415. if is_class_or_interface_or_dispinterface(hdef) then
  416. with tobjectdef(hdef) do
  417. begin
  418. stringdispose(objname);
  419. stringdispose(objrealname);
  420. objrealname:=stringdup(orgtypename);
  421. objname:=stringdup(upper(orgtypename));
  422. end;
  423. include(hdef.defoptions,df_unique);
  424. end;
  425. if not assigned(hdef.typesym) then
  426. hdef.typesym:=newtype;
  427. end;
  428. newtype.typedef:=hdef;
  429. { KAZ: handle TGUID declaration in system unit }
  430. if (cs_compilesystem in current_settings.moduleswitches) and not assigned(rec_tguid) and
  431. (typename='TGUID') and { name: TGUID and size=16 bytes that is 128 bits }
  432. assigned(hdef) and (hdef.typ=recorddef) and (hdef.size=16) then
  433. rec_tguid:=trecorddef(hdef);
  434. end;
  435. if assigned(hdef) then
  436. begin
  437. case hdef.typ of
  438. pointerdef :
  439. begin
  440. try_consume_hintdirective(newtype.symoptions);
  441. consume(_SEMICOLON);
  442. if try_to_consume(_FAR) then
  443. begin
  444. tpointerdef(hdef).is_far:=true;
  445. consume(_SEMICOLON);
  446. end;
  447. end;
  448. procvardef :
  449. begin
  450. { in case of type renaming, don't parse proc directives }
  451. if istyperenaming then
  452. begin
  453. try_consume_hintdirective(newtype.symoptions);
  454. consume(_SEMICOLON);
  455. end
  456. else
  457. begin
  458. if not check_proc_directive(true) then
  459. begin
  460. try_consume_hintdirective(newtype.symoptions);
  461. consume(_SEMICOLON);
  462. end;
  463. parse_var_proc_directives(tsym(newtype));
  464. handle_calling_convention(tprocvardef(hdef));
  465. if try_consume_hintdirective(newtype.symoptions) then
  466. consume(_SEMICOLON);
  467. end;
  468. end;
  469. objectdef :
  470. begin
  471. try_consume_hintdirective(newtype.symoptions);
  472. consume(_SEMICOLON);
  473. { we have to know whether the class or protocol is
  474. external before the vmt is built, because some errors/
  475. hints depend on this }
  476. if is_objc_class_or_protocol(hdef) then
  477. get_objc_class_or_protocol_external_status(tobjectdef(hdef));
  478. { Build VMT indexes, skip for type renaming and forward classes }
  479. if (hdef.typesym=newtype) and
  480. not(oo_is_forward in tobjectdef(hdef).objectoptions) and
  481. not(df_generic in hdef.defoptions) then
  482. begin
  483. vmtbuilder:=TVMTBuilder.Create(tobjectdef(hdef));
  484. vmtbuilder.generate_vmt;
  485. vmtbuilder.free;
  486. end;
  487. { In case of an objcclass, verify that all methods have a message
  488. name set. We only check this now, because message names can be set
  489. during the protocol (interface) mapping. At the same time, set the
  490. mangled names (these depend on the "external" name of the class),
  491. and mark private fields of external classes as "used" (to avoid
  492. bogus notes about them being unused)
  493. }
  494. if is_objc_class_or_protocol(hdef) then
  495. tobjectdef(hdef).finish_objc_data;
  496. end;
  497. recorddef :
  498. begin
  499. try_consume_hintdirective(newtype.symoptions);
  500. consume(_SEMICOLON);
  501. end;
  502. else
  503. begin
  504. try_consume_hintdirective(newtype.symoptions);
  505. consume(_SEMICOLON);
  506. end;
  507. end;
  508. end;
  509. if isgeneric and not(hdef.typ in [objectdef,recorddef]) then
  510. message(parser_e_cant_create_generics_of_this_type);
  511. { Stop recording a generic template }
  512. if assigned(generictypelist) then
  513. begin
  514. current_scanner.stoprecordtokens;
  515. tstoreddef(hdef).generictokenbuf:=generictokenbuf;
  516. { Generic is never a type renaming }
  517. hdef.typesym:=newtype;
  518. end;
  519. if assigned(generictypelist) then
  520. generictypelist.free;
  521. until token<>_ID;
  522. resolve_forward_types;
  523. block_type:=old_block_type;
  524. end;
  525. { reads a type declaration to the symbol table }
  526. procedure type_dec;
  527. begin
  528. consume(_TYPE);
  529. types_dec;
  530. end;
  531. procedure var_dec;
  532. { parses variable declarations and inserts them in }
  533. { the top symbol table of symtablestack }
  534. begin
  535. consume(_VAR);
  536. read_var_decls([]);
  537. end;
  538. procedure property_dec;
  539. var
  540. old_block_type : tblock_type;
  541. begin
  542. consume(_PROPERTY);
  543. if not(symtablestack.top.symtabletype in [staticsymtable,globalsymtable]) then
  544. message(parser_e_resourcestring_only_sg);
  545. old_block_type:=block_type;
  546. block_type:=bt_const;
  547. repeat
  548. read_property_dec(nil);
  549. consume(_SEMICOLON);
  550. until token<>_ID;
  551. block_type:=old_block_type;
  552. end;
  553. procedure threadvar_dec;
  554. { parses thread variable declarations and inserts them in }
  555. { the top symbol table of symtablestack }
  556. begin
  557. consume(_THREADVAR);
  558. if not(symtablestack.top.symtabletype in [staticsymtable,globalsymtable]) then
  559. message(parser_e_threadvars_only_sg);
  560. read_var_decls([vd_threadvar]);
  561. end;
  562. procedure resourcestring_dec;
  563. var
  564. orgname : TIDString;
  565. p : tnode;
  566. dummysymoptions : tsymoptions;
  567. storetokenpos,filepos : tfileposinfo;
  568. old_block_type : tblock_type;
  569. sp : pchar;
  570. sym : tsym;
  571. begin
  572. consume(_RESOURCESTRING);
  573. if not(symtablestack.top.symtabletype in [staticsymtable,globalsymtable]) then
  574. message(parser_e_resourcestring_only_sg);
  575. old_block_type:=block_type;
  576. block_type:=bt_const;
  577. repeat
  578. orgname:=orgpattern;
  579. filepos:=current_tokenpos;
  580. consume(_ID);
  581. case token of
  582. _EQUAL:
  583. begin
  584. consume(_EQUAL);
  585. p:=comp_expr(true);
  586. storetokenpos:=current_tokenpos;
  587. current_tokenpos:=filepos;
  588. sym:=nil;
  589. case p.nodetype of
  590. ordconstn:
  591. begin
  592. if is_constcharnode(p) then
  593. begin
  594. getmem(sp,2);
  595. sp[0]:=chr(tordconstnode(p).value.svalue);
  596. sp[1]:=#0;
  597. sym:=tconstsym.create_string(orgname,constresourcestring,sp,1);
  598. end
  599. else
  600. Message(parser_e_illegal_expression);
  601. end;
  602. stringconstn:
  603. with Tstringconstnode(p) do
  604. begin
  605. getmem(sp,len+1);
  606. move(value_str^,sp^,len+1);
  607. sym:=tconstsym.create_string(orgname,constresourcestring,sp,len);
  608. end;
  609. else
  610. Message(parser_e_illegal_expression);
  611. end;
  612. current_tokenpos:=storetokenpos;
  613. { Support hint directives }
  614. dummysymoptions:=[];
  615. try_consume_hintdirective(dummysymoptions);
  616. if assigned(sym) then
  617. begin
  618. sym.symoptions:=sym.symoptions+dummysymoptions;
  619. symtablestack.top.insert(sym);
  620. end;
  621. consume(_SEMICOLON);
  622. p.free;
  623. end;
  624. else consume(_EQUAL);
  625. end;
  626. until token<>_ID;
  627. block_type:=old_block_type;
  628. end;
  629. end.