pdecl.pas 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  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. hdef:=tstoreddef(hdef).getcopy;
  412. { fix name, it is used e.g. for tables }
  413. if is_class_or_interface_or_dispinterface_or_objc(hdef) then
  414. with tobjectdef(hdef) do
  415. begin
  416. stringdispose(objname);
  417. stringdispose(objrealname);
  418. objrealname:=stringdup(orgtypename);
  419. objname:=stringdup(upper(orgtypename));
  420. end;
  421. include(hdef.defoptions,df_unique);
  422. end;
  423. if not assigned(hdef.typesym) then
  424. hdef.typesym:=newtype;
  425. end;
  426. newtype.typedef:=hdef;
  427. { KAZ: handle TGUID declaration in system unit }
  428. if (cs_compilesystem in current_settings.moduleswitches) and not assigned(rec_tguid) and
  429. (typename='TGUID') and { name: TGUID and size=16 bytes that is 128 bits }
  430. assigned(hdef) and (hdef.typ=recorddef) and (hdef.size=16) then
  431. rec_tguid:=trecorddef(hdef);
  432. end;
  433. if assigned(hdef) then
  434. begin
  435. case hdef.typ of
  436. pointerdef :
  437. begin
  438. try_consume_hintdirective(newtype.symoptions);
  439. consume(_SEMICOLON);
  440. if try_to_consume(_FAR) then
  441. begin
  442. tpointerdef(hdef).is_far:=true;
  443. consume(_SEMICOLON);
  444. end;
  445. end;
  446. procvardef :
  447. begin
  448. { in case of type renaming, don't parse proc directives }
  449. if istyperenaming then
  450. begin
  451. try_consume_hintdirective(newtype.symoptions);
  452. consume(_SEMICOLON);
  453. end
  454. else
  455. begin
  456. if not check_proc_directive(true) then
  457. begin
  458. try_consume_hintdirective(newtype.symoptions);
  459. consume(_SEMICOLON);
  460. end;
  461. parse_var_proc_directives(tsym(newtype));
  462. handle_calling_convention(tprocvardef(hdef));
  463. if try_consume_hintdirective(newtype.symoptions) then
  464. consume(_SEMICOLON);
  465. end;
  466. end;
  467. objectdef :
  468. begin
  469. try_consume_hintdirective(newtype.symoptions);
  470. consume(_SEMICOLON);
  471. { we have to know whether the class or protocol is
  472. external before the vmt is built, because some errors/
  473. hints depend on this }
  474. if is_objc_class_or_protocol(hdef) then
  475. get_objc_class_or_protocol_external_status(tobjectdef(hdef));
  476. { Build VMT indexes, skip for type renaming and forward classes }
  477. if (hdef.typesym=newtype) and
  478. not(oo_is_forward in tobjectdef(hdef).objectoptions) and
  479. not(df_generic in hdef.defoptions) then
  480. begin
  481. vmtbuilder:=TVMTBuilder.Create(tobjectdef(hdef));
  482. vmtbuilder.generate_vmt;
  483. vmtbuilder.free;
  484. end;
  485. { In case of an objcclass, verify that all methods have a message
  486. name set. We only check this now, because message names can be set
  487. during the protocol (interface) mapping. At the same time, set the
  488. mangled names.
  489. }
  490. if is_objc_class_or_protocol(hdef) then
  491. tobjectdef(hdef).check_and_finish_messages;
  492. end;
  493. recorddef :
  494. begin
  495. try_consume_hintdirective(newtype.symoptions);
  496. consume(_SEMICOLON);
  497. end;
  498. else
  499. begin
  500. try_consume_hintdirective(newtype.symoptions);
  501. consume(_SEMICOLON);
  502. end;
  503. end;
  504. end;
  505. if isgeneric and not(hdef.typ in [objectdef,recorddef]) then
  506. message(parser_e_cant_create_generics_of_this_type);
  507. { Stop recording a generic template }
  508. if assigned(generictypelist) then
  509. begin
  510. current_scanner.stoprecordtokens;
  511. tstoreddef(hdef).generictokenbuf:=generictokenbuf;
  512. { Generic is never a type renaming }
  513. hdef.typesym:=newtype;
  514. end;
  515. if assigned(generictypelist) then
  516. generictypelist.free;
  517. until token<>_ID;
  518. resolve_forward_types;
  519. block_type:=old_block_type;
  520. end;
  521. { reads a type declaration to the symbol table }
  522. procedure type_dec;
  523. begin
  524. consume(_TYPE);
  525. types_dec;
  526. end;
  527. procedure var_dec;
  528. { parses variable declarations and inserts them in }
  529. { the top symbol table of symtablestack }
  530. begin
  531. consume(_VAR);
  532. read_var_decls([]);
  533. end;
  534. procedure property_dec;
  535. var
  536. old_block_type : tblock_type;
  537. begin
  538. consume(_PROPERTY);
  539. if not(symtablestack.top.symtabletype in [staticsymtable,globalsymtable]) then
  540. message(parser_e_resourcestring_only_sg);
  541. old_block_type:=block_type;
  542. block_type:=bt_const;
  543. repeat
  544. read_property_dec(nil);
  545. consume(_SEMICOLON);
  546. until token<>_ID;
  547. block_type:=old_block_type;
  548. end;
  549. procedure threadvar_dec;
  550. { parses thread variable declarations and inserts them in }
  551. { the top symbol table of symtablestack }
  552. begin
  553. consume(_THREADVAR);
  554. if not(symtablestack.top.symtabletype in [staticsymtable,globalsymtable]) then
  555. message(parser_e_threadvars_only_sg);
  556. read_var_decls([vd_threadvar]);
  557. end;
  558. procedure resourcestring_dec;
  559. var
  560. orgname : TIDString;
  561. p : tnode;
  562. dummysymoptions : tsymoptions;
  563. storetokenpos,filepos : tfileposinfo;
  564. old_block_type : tblock_type;
  565. sp : pchar;
  566. sym : tsym;
  567. begin
  568. consume(_RESOURCESTRING);
  569. if not(symtablestack.top.symtabletype in [staticsymtable,globalsymtable]) then
  570. message(parser_e_resourcestring_only_sg);
  571. old_block_type:=block_type;
  572. block_type:=bt_const;
  573. repeat
  574. orgname:=orgpattern;
  575. filepos:=current_tokenpos;
  576. consume(_ID);
  577. case token of
  578. _EQUAL:
  579. begin
  580. consume(_EQUAL);
  581. p:=comp_expr(true);
  582. storetokenpos:=current_tokenpos;
  583. current_tokenpos:=filepos;
  584. sym:=nil;
  585. case p.nodetype of
  586. ordconstn:
  587. begin
  588. if is_constcharnode(p) then
  589. begin
  590. getmem(sp,2);
  591. sp[0]:=chr(tordconstnode(p).value.svalue);
  592. sp[1]:=#0;
  593. sym:=tconstsym.create_string(orgname,constresourcestring,sp,1);
  594. end
  595. else
  596. Message(parser_e_illegal_expression);
  597. end;
  598. stringconstn:
  599. with Tstringconstnode(p) do
  600. begin
  601. getmem(sp,len+1);
  602. move(value_str^,sp^,len+1);
  603. sym:=tconstsym.create_string(orgname,constresourcestring,sp,len);
  604. end;
  605. else
  606. Message(parser_e_illegal_expression);
  607. end;
  608. current_tokenpos:=storetokenpos;
  609. { Support hint directives }
  610. dummysymoptions:=[];
  611. try_consume_hintdirective(dummysymoptions);
  612. if assigned(sym) then
  613. begin
  614. sym.symoptions:=sym.symoptions+dummysymoptions;
  615. symtablestack.top.insert(sym);
  616. end;
  617. consume(_SEMICOLON);
  618. p.free;
  619. end;
  620. else consume(_EQUAL);
  621. end;
  622. until token<>_ID;
  623. block_type:=old_block_type;
  624. end;
  625. end.