pdecl.pas 24 KB

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