pstatmnt.pas 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. Does the parsing of the statements
  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 pstatmnt;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. tokens,node;
  23. function statement_block(starttoken : ttoken) : tnode;
  24. { reads an assembler block }
  25. function assembler_block : tnode;
  26. implementation
  27. uses
  28. { common }
  29. cutils,
  30. { global }
  31. globtype,globals,verbose,
  32. systems,cpuinfo,
  33. { aasm }
  34. cpubase,aasmbase,aasmtai,aasmcpu,
  35. { symtable }
  36. symconst,symbase,symtype,symdef,symsym,symtable,defbase,paramgr,
  37. { pass 1 }
  38. pass_1,htypechk,
  39. nbas,nmat,nadd,ncal,nmem,nset,ncnv,ninl,ncon,nld,nflw,
  40. { parser }
  41. scanner,
  42. pbase,pexpr,
  43. { codegen }
  44. rgobj,cgbase
  45. {$ifdef i386}
  46. {$ifndef NoRa386Int}
  47. ,ra386int
  48. {$endif NoRa386Int}
  49. {$ifndef NoRa386Att}
  50. ,ra386att
  51. {$endif NoRa386Att}
  52. {$ifndef NoRa386Dir}
  53. ,ra386dir
  54. {$endif NoRa386Dir}
  55. {$endif i386}
  56. {$ifdef powerpc}
  57. {$ifndef NoRaPPCDir}
  58. ,rappcdir
  59. {$endif NoRaPPCDir}
  60. {$endif powerpc}
  61. {$ifdef x86_64}
  62. {$ifndef NoRax86Dir}
  63. ,rax86dir
  64. {$endif NoRax86Dir}
  65. {$endif i386}
  66. {$ifdef m68k}
  67. {$ifndef NoRa68kMot}
  68. ,ra68kmot
  69. {$endif NoRa68kMot}
  70. {$endif m68k}
  71. { codegen }
  72. {$ifdef newcg}
  73. ,cgbase
  74. {$endif newcg}
  75. ;
  76. function statement : tnode;forward;
  77. function if_statement : tnode;
  78. var
  79. ex,if_a,else_a : tnode;
  80. begin
  81. consume(_IF);
  82. ex:=comp_expr(true);
  83. consume(_THEN);
  84. if token<>_ELSE then
  85. if_a:=statement
  86. else
  87. if_a:=nil;
  88. if try_to_consume(_ELSE) then
  89. else_a:=statement
  90. else
  91. else_a:=nil;
  92. if_statement:=genloopnode(ifn,ex,if_a,else_a,false);
  93. end;
  94. { creates a block (list) of statements, til the next END token }
  95. function statements_til_end : tnode;
  96. var
  97. first,last : tstatementnode;
  98. begin
  99. first:=nil;
  100. while token<>_END do
  101. begin
  102. if first=nil then
  103. begin
  104. last:=cstatementnode.create(nil,statement);
  105. first:=last;
  106. end
  107. else
  108. begin
  109. last.left:=cstatementnode.create(nil,statement);
  110. last:=tstatementnode(last.left);
  111. end;
  112. if not try_to_consume(_SEMICOLON) then
  113. break;
  114. consume_emptystats;
  115. end;
  116. consume(_END);
  117. statements_til_end:=cblocknode.create(first);
  118. end;
  119. function case_statement : tnode;
  120. var
  121. { contains the label number of currently parsed case block }
  122. aktcaselabel : tasmlabel;
  123. firstlabel : boolean;
  124. root : pcaserecord;
  125. { the typ of the case expression }
  126. casedef : tdef;
  127. procedure newcaselabel(l,h : TConstExprInt;first:boolean);
  128. var
  129. hcaselabel : pcaserecord;
  130. procedure insertlabel(var p : pcaserecord);
  131. begin
  132. if p=nil then p:=hcaselabel
  133. else
  134. if (p^._low>hcaselabel^._low) and
  135. (p^._low>hcaselabel^._high) then
  136. if (hcaselabel^.statement = p^.statement) and
  137. (p^._low = hcaselabel^._high + 1) then
  138. begin
  139. p^._low := hcaselabel^._low;
  140. dispose(hcaselabel);
  141. end
  142. else
  143. insertlabel(p^.less)
  144. else
  145. if (p^._high<hcaselabel^._low) and
  146. (p^._high<hcaselabel^._high) then
  147. if (hcaselabel^.statement = p^.statement) and
  148. (p^._high+1 = hcaselabel^._low) then
  149. begin
  150. p^._high := hcaselabel^._high;
  151. dispose(hcaselabel);
  152. end
  153. else
  154. insertlabel(p^.greater)
  155. else Message(parser_e_double_caselabel);
  156. end;
  157. begin
  158. new(hcaselabel);
  159. hcaselabel^.less:=nil;
  160. hcaselabel^.greater:=nil;
  161. hcaselabel^.statement:=aktcaselabel;
  162. hcaselabel^.firstlabel:=first;
  163. getlabel(hcaselabel^._at);
  164. hcaselabel^._low:=l;
  165. hcaselabel^._high:=h;
  166. insertlabel(root);
  167. end;
  168. var
  169. code,caseexpr,p,instruc,elseblock : tnode;
  170. hl1,hl2 : TConstExprInt;
  171. casedeferror : boolean;
  172. begin
  173. consume(_CASE);
  174. caseexpr:=comp_expr(true);
  175. { determines result type }
  176. rg.cleartempgen;
  177. do_resulttypepass(caseexpr);
  178. casedeferror:=false;
  179. casedef:=caseexpr.resulttype.def;
  180. if (not assigned(casedef)) or
  181. not(is_ordinal(casedef)) then
  182. begin
  183. CGMessage(type_e_ordinal_expr_expected);
  184. { create a correct tree }
  185. caseexpr.free;
  186. caseexpr:=cordconstnode.create(0,u32bittype);
  187. { set error flag so no rangechecks are done }
  188. casedeferror:=true;
  189. end;
  190. consume(_OF);
  191. inc(statement_level);
  192. root:=nil;
  193. instruc:=nil;
  194. repeat
  195. getlabel(aktcaselabel);
  196. firstlabel:=true;
  197. { maybe an instruction has more case labels }
  198. repeat
  199. p:=expr;
  200. if is_widechar(casedef) then
  201. begin
  202. if (p.nodetype=rangen) then
  203. begin
  204. trangenode(p).left:=ctypeconvnode.create(trangenode(p).left,cwidechartype);
  205. trangenode(p).right:=ctypeconvnode.create(trangenode(p).right,cwidechartype);
  206. do_resulttypepass(trangenode(p).left);
  207. do_resulttypepass(trangenode(p).right);
  208. end
  209. else
  210. begin
  211. p:=ctypeconvnode.create(p,cwidechartype);
  212. do_resulttypepass(p);
  213. end;
  214. end;
  215. hl1:=0;
  216. hl2:=0;
  217. if (p.nodetype=rangen) then
  218. begin
  219. { type checking for case statements }
  220. if is_subequal(casedef, trangenode(p).left.resulttype.def) and
  221. is_subequal(casedef, trangenode(p).right.resulttype.def) then
  222. begin
  223. hl1:=get_ordinal_value(trangenode(p).left);
  224. hl2:=get_ordinal_value(trangenode(p).right);
  225. if hl1>hl2 then
  226. CGMessage(parser_e_case_lower_less_than_upper_bound);
  227. if not casedeferror then
  228. begin
  229. testrange(casedef,hl1,false);
  230. testrange(casedef,hl2,false);
  231. end;
  232. end
  233. else
  234. CGMessage(parser_e_case_mismatch);
  235. newcaselabel(hl1,hl2,firstlabel);
  236. end
  237. else
  238. begin
  239. { type checking for case statements }
  240. if not is_subequal(casedef, p.resulttype.def) then
  241. CGMessage(parser_e_case_mismatch);
  242. hl1:=get_ordinal_value(p);
  243. if not casedeferror then
  244. testrange(casedef,hl1,false);
  245. newcaselabel(hl1,hl1,firstlabel);
  246. end;
  247. p.free;
  248. if token=_COMMA then
  249. consume(_COMMA)
  250. else
  251. break;
  252. firstlabel:=false;
  253. until false;
  254. consume(_COLON);
  255. { handles instruction block }
  256. p:=clabelnode.createcase(aktcaselabel,statement);
  257. { concats instruction }
  258. instruc:=cstatementnode.create(instruc,p);
  259. if not((token=_ELSE) or (token=_OTHERWISE) or (token=_END)) then
  260. consume(_SEMICOLON);
  261. until (token=_ELSE) or (token=_OTHERWISE) or (token=_END);
  262. if (token=_ELSE) or (token=_OTHERWISE) then
  263. begin
  264. if not try_to_consume(_ELSE) then
  265. consume(_OTHERWISE);
  266. elseblock:=statements_til_end;
  267. end
  268. else
  269. begin
  270. elseblock:=nil;
  271. consume(_END);
  272. end;
  273. dec(statement_level);
  274. code:=ccasenode.create(caseexpr,instruc,root);
  275. tcasenode(code).elseblock:=elseblock;
  276. case_statement:=code;
  277. end;
  278. function repeat_statement : tnode;
  279. var
  280. first,last,p_e : tnode;
  281. begin
  282. consume(_REPEAT);
  283. first:=nil;
  284. inc(statement_level);
  285. while token<>_UNTIL do
  286. begin
  287. if first=nil then
  288. begin
  289. last:=cstatementnode.create(nil,statement);
  290. first:=last;
  291. end
  292. else
  293. begin
  294. tstatementnode(last).left:=cstatementnode.create(nil,statement);
  295. last:=tstatementnode(last).left;
  296. end;
  297. if not try_to_consume(_SEMICOLON) then
  298. break;
  299. consume_emptystats;
  300. end;
  301. consume(_UNTIL);
  302. dec(statement_level);
  303. first:=cblocknode.create(first);
  304. p_e:=comp_expr(true);
  305. repeat_statement:=genloopnode(whilerepeatn,p_e,first,nil,true);
  306. end;
  307. function while_statement : tnode;
  308. var
  309. p_e,p_a : tnode;
  310. begin
  311. consume(_WHILE);
  312. p_e:=comp_expr(true);
  313. consume(_DO);
  314. p_a:=statement;
  315. while_statement:=genloopnode(whilerepeatn,p_e,p_a,nil,false);
  316. end;
  317. function for_statement : tnode;
  318. var
  319. p_e,tovalue,p_a : tnode;
  320. backward : boolean;
  321. begin
  322. { parse loop header }
  323. consume(_FOR);
  324. p_e:=expr;
  325. if token=_DOWNTO then
  326. begin
  327. consume(_DOWNTO);
  328. backward:=true;
  329. end
  330. else
  331. begin
  332. consume(_TO);
  333. backward:=false;
  334. end;
  335. tovalue:=comp_expr(true);
  336. consume(_DO);
  337. { ... now the instruction }
  338. p_a:=statement;
  339. for_statement:=genloopnode(forn,p_e,tovalue,p_a,backward);
  340. end;
  341. function _with_statement : tnode;
  342. var
  343. right,p : tnode;
  344. i,levelcount : longint;
  345. withsymtable,symtab : tsymtable;
  346. obj : tobjectdef;
  347. hp : tnode;
  348. begin
  349. p:=comp_expr(true);
  350. do_resulttypepass(p);
  351. set_varstate(p,false);
  352. right:=nil;
  353. if (not codegenerror) and
  354. (p.resulttype.def.deftype in [objectdef,recorddef]) then
  355. begin
  356. case p.resulttype.def.deftype of
  357. objectdef : begin
  358. obj:=tobjectdef(p.resulttype.def);
  359. symtab:=twithsymtable.Create(obj,obj.symtable.symsearch);
  360. withsymtable:=symtab;
  361. if (p.nodetype=loadn) and
  362. (tloadnode(p).symtable=aktprocdef.localst) then
  363. twithsymtable(symtab).direct_with:=true;
  364. twithsymtable(symtab).withrefnode:=p;
  365. levelcount:=1;
  366. obj:=obj.childof;
  367. while assigned(obj) do
  368. begin
  369. symtab.next:=twithsymtable.create(obj,obj.symtable.symsearch);
  370. symtab:=symtab.next;
  371. if (p.nodetype=loadn) and
  372. (tloadnode(p).symtable=aktprocdef.localst) then
  373. twithsymtable(symtab).direct_with:=true;
  374. twithsymtable(symtab).withrefnode:=p;
  375. obj:=obj.childof;
  376. inc(levelcount);
  377. end;
  378. symtab.next:=symtablestack;
  379. symtablestack:=withsymtable;
  380. end;
  381. recorddef : begin
  382. symtab:=trecorddef(p.resulttype.def).symtable;
  383. levelcount:=1;
  384. withsymtable:=twithsymtable.create(trecorddef(p.resulttype.def),symtab.symsearch);
  385. if (p.nodetype=loadn) and
  386. (tloadnode(p).symtable=aktprocdef.localst) then
  387. twithsymtable(withsymtable).direct_with:=true;
  388. twithsymtable(withsymtable).withrefnode:=p;
  389. withsymtable.next:=symtablestack;
  390. symtablestack:=withsymtable;
  391. end;
  392. end;
  393. if token=_COMMA then
  394. begin
  395. consume(_COMMA);
  396. right:=_with_statement{$ifdef FPCPROCVAR}(){$endif};
  397. end
  398. else
  399. begin
  400. consume(_DO);
  401. if token<>_SEMICOLON then
  402. right:=statement
  403. else
  404. right:=cerrornode.create;
  405. end;
  406. for i:=1 to levelcount do
  407. symtablestack:=symtablestack.next;
  408. _with_statement:=cwithnode.create(twithsymtable(withsymtable),p,right,levelcount);
  409. end
  410. else
  411. begin
  412. Message(parser_e_false_with_expr);
  413. { try to recover from error }
  414. if token=_COMMA then
  415. begin
  416. consume(_COMMA);
  417. hp:=_with_statement{$ifdef FPCPROCVAR}(){$endif};
  418. if (hp=nil) then; { remove warning about unused }
  419. end
  420. else
  421. begin
  422. consume(_DO);
  423. { ignore all }
  424. if token<>_SEMICOLON then
  425. statement;
  426. end;
  427. _with_statement:=nil;
  428. end;
  429. end;
  430. function with_statement : tnode;
  431. begin
  432. consume(_WITH);
  433. with_statement:=_with_statement;
  434. end;
  435. function raise_statement : tnode;
  436. var
  437. p,pobj,paddr,pframe : tnode;
  438. begin
  439. pobj:=nil;
  440. paddr:=nil;
  441. pframe:=nil;
  442. consume(_RAISE);
  443. if not(token in [_SEMICOLON,_END]) then
  444. begin
  445. { object }
  446. pobj:=comp_expr(true);
  447. if try_to_consume(_AT) then
  448. begin
  449. paddr:=comp_expr(true);
  450. if try_to_consume(_COMMA) then
  451. pframe:=comp_expr(true);
  452. end;
  453. end
  454. else
  455. begin
  456. if (block_type<>bt_except) then
  457. Message(parser_e_no_reraise_possible);
  458. end;
  459. p:=craisenode.create(pobj,paddr,pframe);
  460. raise_statement:=p;
  461. end;
  462. function try_statement : tnode;
  463. var
  464. p_try_block,p_finally_block,first,last,
  465. p_default,p_specific,hp : tnode;
  466. ot : ttype;
  467. sym : tvarsym;
  468. old_block_type : tblock_type;
  469. exceptsymtable : tsymtable;
  470. objname,objrealname : stringid;
  471. srsym : tsym;
  472. srsymtable : tsymtable;
  473. oldaktexceptblock: integer;
  474. begin
  475. procinfo^.flags:=procinfo^.flags or pi_uses_exceptions;
  476. p_default:=nil;
  477. p_specific:=nil;
  478. { read statements to try }
  479. consume(_TRY);
  480. first:=nil;
  481. inc(exceptblockcounter);
  482. oldaktexceptblock := aktexceptblock;
  483. aktexceptblock := exceptblockcounter;
  484. inc(statement_level);
  485. while (token<>_FINALLY) and (token<>_EXCEPT) do
  486. begin
  487. if first=nil then
  488. begin
  489. last:=cstatementnode.create(nil,statement);
  490. first:=last;
  491. end
  492. else
  493. begin
  494. tstatementnode(last).left:=cstatementnode.create(nil,statement);
  495. last:=tstatementnode(last).left;
  496. end;
  497. if not try_to_consume(_SEMICOLON) then
  498. break;
  499. consume_emptystats;
  500. end;
  501. p_try_block:=cblocknode.create(first);
  502. if try_to_consume(_FINALLY) then
  503. begin
  504. inc(exceptblockcounter);
  505. aktexceptblock := exceptblockcounter;
  506. p_finally_block:=statements_til_end;
  507. try_statement:=ctryfinallynode.create(p_try_block,p_finally_block);
  508. dec(statement_level);
  509. end
  510. else
  511. begin
  512. consume(_EXCEPT);
  513. old_block_type:=block_type;
  514. block_type:=bt_except;
  515. inc(exceptblockcounter);
  516. aktexceptblock := exceptblockcounter;
  517. ot:=generrortype;
  518. p_specific:=nil;
  519. if (idtoken=_ON) then
  520. { catch specific exceptions }
  521. begin
  522. repeat
  523. consume(_ID);
  524. if token=_ID then
  525. begin
  526. objname:=pattern;
  527. objrealname:=orgpattern;
  528. { can't use consume_sym here, because we need already
  529. to check for the colon }
  530. searchsym(objname,srsym,srsymtable);
  531. consume(_ID);
  532. { is a explicit name for the exception given ? }
  533. if try_to_consume(_COLON) then
  534. begin
  535. consume_sym(srsym,srsymtable);
  536. if (srsym.typ=typesym) and
  537. is_class(ttypesym(srsym).restype.def) then
  538. begin
  539. ot:=ttypesym(srsym).restype;
  540. sym:=tvarsym.create(objrealname,ot);
  541. end
  542. else
  543. begin
  544. sym:=tvarsym.create(objrealname,generrortype);
  545. if (srsym.typ=typesym) then
  546. Message1(type_e_class_type_expected,ttypesym(srsym).restype.def.typename)
  547. else
  548. Message1(type_e_class_type_expected,ot.def.typename);
  549. end;
  550. exceptsymtable:=tstt_exceptsymtable.create;
  551. exceptsymtable.insert(sym);
  552. { insert the exception symtable stack }
  553. exceptsymtable.next:=symtablestack;
  554. symtablestack:=exceptsymtable;
  555. end
  556. else
  557. begin
  558. { check if type is valid, must be done here because
  559. with "e: Exception" the e is not necessary }
  560. if srsym=nil then
  561. begin
  562. identifier_not_found(objrealname);
  563. srsym:=generrorsym;
  564. end;
  565. { support unit.identifier }
  566. if srsym.typ=unitsym then
  567. begin
  568. consume(_POINT);
  569. srsym:=searchsymonlyin(tunitsym(srsym).unitsymtable,pattern);
  570. if srsym=nil then
  571. begin
  572. identifier_not_found(orgpattern);
  573. srsym:=generrorsym;
  574. end;
  575. consume(_ID);
  576. end;
  577. { check if type is valid, must be done here because
  578. with "e: Exception" the e is not necessary }
  579. if (srsym.typ=typesym) and
  580. is_class(ttypesym(srsym).restype.def) then
  581. ot:=ttypesym(srsym).restype
  582. else
  583. begin
  584. ot:=generrortype;
  585. if (srsym.typ=typesym) then
  586. Message1(type_e_class_type_expected,ttypesym(srsym).restype.def.typename)
  587. else
  588. Message1(type_e_class_type_expected,ot.def.typename);
  589. end;
  590. exceptsymtable:=nil;
  591. end;
  592. end
  593. else
  594. consume(_ID);
  595. consume(_DO);
  596. hp:=connode.create(nil,statement);
  597. if ot.def.deftype=errordef then
  598. begin
  599. hp.free;
  600. hp:=cerrornode.create;
  601. end;
  602. if p_specific=nil then
  603. begin
  604. last:=hp;
  605. p_specific:=last;
  606. end
  607. else
  608. begin
  609. tonnode(last).left:=hp;
  610. last:=tonnode(last).left;
  611. end;
  612. { set the informations }
  613. { only if the creation of the onnode was succesful, it's possible }
  614. { that last and hp are errornodes (JM) }
  615. if last.nodetype = onn then
  616. begin
  617. tonnode(last).excepttype:=tobjectdef(ot.def);
  618. tonnode(last).exceptsymtable:=exceptsymtable;
  619. end;
  620. { remove exception symtable }
  621. if assigned(exceptsymtable) then
  622. begin
  623. dellexlevel;
  624. if last.nodetype <> onn then
  625. exceptsymtable.free;
  626. end;
  627. if not try_to_consume(_SEMICOLON) then
  628. break;
  629. consume_emptystats;
  630. until (token=_END) or (token=_ELSE);
  631. if token=_ELSE then
  632. { catch the other exceptions }
  633. begin
  634. consume(_ELSE);
  635. p_default:=statements_til_end;
  636. end
  637. else
  638. consume(_END);
  639. end
  640. else
  641. { catch all exceptions }
  642. begin
  643. p_default:=statements_til_end;
  644. end;
  645. dec(statement_level);
  646. block_type:=old_block_type;
  647. try_statement:=ctryexceptnode.create(p_try_block,p_specific,p_default);
  648. end;
  649. aktexceptblock := oldaktexceptblock;
  650. end;
  651. function _asm_statement : tnode;
  652. var
  653. asmstat : tasmnode;
  654. Marker : tai;
  655. r : tregister;
  656. found : boolean;
  657. begin
  658. Inside_asm_statement:=true;
  659. case aktasmmode of
  660. asmmode_none : ; { just be there to allow to a compile without
  661. any assembler readers }
  662. {$ifdef i386}
  663. {$ifndef NoRA386Att}
  664. asmmode_i386_att:
  665. asmstat:=tasmnode(ra386att.assemble);
  666. {$endif NoRA386Att}
  667. {$ifndef NoRA386Int}
  668. asmmode_i386_intel:
  669. asmstat:=tasmnode(ra386int.assemble);
  670. {$endif NoRA386Int}
  671. {$ifndef NoRA386Dir}
  672. asmmode_i386_direct:
  673. begin
  674. if not target_asm.allowdirect then
  675. Message(parser_f_direct_assembler_not_allowed);
  676. if (aktprocdef.proccalloption=pocall_inline) then
  677. Begin
  678. Message1(parser_w_not_supported_for_inline,'direct asm');
  679. Message(parser_w_inlining_disabled);
  680. aktprocdef.proccalloption:=pocall_fpccall;
  681. End;
  682. asmstat:=tasmnode(ra386dir.assemble);
  683. end;
  684. {$endif NoRA386Dir}
  685. {$endif}
  686. {$ifdef x86_64}
  687. {$ifndef NoRA386Dir}
  688. asmmode_i386_direct:
  689. begin
  690. if not target_asm.allowdirect then
  691. Message(parser_f_direct_assembler_not_allowed);
  692. if (aktprocdef.proccalloption=pocall_inline) then
  693. Begin
  694. Message1(parser_w_not_supported_for_inline,'direct asm');
  695. Message(parser_w_inlining_disabled);
  696. aktprocdef.proccalloption:=pocall_fpccall;
  697. End;
  698. asmstat:=tasmnode(rax86dir.assemble);
  699. end;
  700. {$endif NoRA386Dir}
  701. {$endif x86_64}
  702. {$ifdef powerpc}
  703. {$ifndef NoRAPPCDir}
  704. asmmode_ppc_direct:
  705. begin
  706. if not target_asm.allowdirect then
  707. Message(parser_f_direct_assembler_not_allowed);
  708. if (aktprocdef.proccalloption=pocall_inline) then
  709. Begin
  710. Message1(parser_w_not_supported_for_inline,'direct asm');
  711. Message(parser_w_inlining_disabled);
  712. aktprocdef.proccalloption:=pocall_fpccall;
  713. End;
  714. asmstat:=tasmnode(rappcdir.assemble);
  715. end;
  716. {$endif NoRAPPCDir}
  717. {$endif powerpc}
  718. {$ifdef m68k}
  719. {$ifndef NoRA68kMot}
  720. asmmode_m68k_mot:
  721. asmstat:=tasmnode(ra68kmot.assemble);
  722. {$endif NoRA68kMot}
  723. {$endif}
  724. else
  725. Message(parser_f_assembler_reader_not_supported);
  726. end;
  727. { Read first the _ASM statement }
  728. consume(_ASM);
  729. { END is read }
  730. if try_to_consume(_LECKKLAMMER) then
  731. begin
  732. { it's possible to specify the modified registers }
  733. include(asmstat.flags,nf_object_preserved);
  734. if token<>_RECKKLAMMER then
  735. repeat
  736. { uppercase, because it's a CSTRING }
  737. uppervar(pattern);
  738. {$ifdef i386}
  739. if pattern='EAX' then
  740. include(rg.usedinproc,R_EAX)
  741. else if pattern='EBX' then
  742. include(rg.usedinproc,R_EBX)
  743. else if pattern='ECX' then
  744. include(rg.usedinproc,R_ECX)
  745. else if pattern='EDX' then
  746. include(rg.usedinproc,R_EDX)
  747. else if pattern='ESI' then
  748. begin
  749. include(rg.usedinproc,R_ESI);
  750. exclude(asmstat.flags,nf_object_preserved);
  751. end
  752. else if pattern='EDI' then
  753. include(rg.usedinproc,R_EDI)
  754. else consume(_RECKKLAMMER);
  755. {$endif i386}
  756. {$ifdef x86_64}
  757. if pattern='RAX' then
  758. include(usedinproc,R_RAX)
  759. else if pattern='RBX' then
  760. include(usedinproc,R_RBX)
  761. else if pattern='RCX' then
  762. include(usedinproc,R_RCX)
  763. else if pattern='RDX' then
  764. include(usedinproc,R_RDX)
  765. else if pattern='RSI' then
  766. begin
  767. include(usedinproc,R_RSI);
  768. exclude(asmstat.flags,nf_object_preserved);
  769. end
  770. else if pattern='RDI' then
  771. include(usedinproc,R_RDI)
  772. else consume(_RECKKLAMMER);
  773. {$endif x86_64}
  774. {$ifdef m68k}
  775. if pattern='D0' then
  776. include(rg.usedinproc,R_D0)
  777. else if pattern='D1' then
  778. include(rg.usedinproc,R_D1)
  779. else if pattern='D2' then
  780. include(rg.usedinproc,R_D2)
  781. else if pattern='D3' then
  782. include(rg.usedinproc,R_D3)
  783. else if pattern='D4' then
  784. include(rg.usedinproc,R_D4)
  785. else if pattern='D5' then
  786. include(rg.usedinproc,R_D5)
  787. else if pattern='D6' then
  788. include(rg.usedinproc,R_D6)
  789. else if pattern='D7' then
  790. include(rg.usedinproc,R_D7)
  791. else if pattern='A0' then
  792. include(rg.usedinproc,R_A0)
  793. else if pattern='A1' then
  794. include(rg.usedinproc,R_A1)
  795. else if pattern='A2' then
  796. include(rg.usedinproc,R_A2)
  797. else if pattern='A3' then
  798. include(rg.usedinproc,R_A3)
  799. else if pattern='A4' then
  800. include(rg.usedinproc,R_A4)
  801. else if pattern='A5' then
  802. include(rg.usedinproc,R_A5)
  803. else consume(_RECKKLAMMER);
  804. {$endif m68k}
  805. {$ifdef powerpc}
  806. found:=false;
  807. for r:=low(tregister) to high(tregister) do
  808. if pattern=upper(std_reg2str[r]) then
  809. begin
  810. include(rg.usedinproc,r);
  811. include(rg.usedbyproc,r);
  812. found:=true;
  813. break;
  814. end;
  815. if not(found) then
  816. consume(_RECKKLAMMER);
  817. {$endif powerpc}
  818. {$IFDEF SPARC}
  819. if pattern<>'' then
  820. internalerror(200108251)
  821. else consume(_RECKKLAMMER);
  822. {$ENDIF SPARC}
  823. consume(_CSTRING);
  824. if not try_to_consume(_COMMA) then
  825. break;
  826. until false;
  827. consume(_RECKKLAMMER);
  828. end
  829. else
  830. begin
  831. rg.usedbyproc := ALL_REGISTERS;
  832. rg.usedinproc := ALL_REGISTERS;
  833. end;
  834. { mark the start and the end of the assembler block
  835. this is needed for the optimizer }
  836. If Assigned(AsmStat.p_asm) Then
  837. Begin
  838. Marker := Tai_Marker.Create(AsmBlockStart);
  839. AsmStat.p_asm.Insert(Marker);
  840. Marker := Tai_Marker.Create(AsmBlockEnd);
  841. AsmStat.p_asm.Concat(Marker);
  842. End;
  843. Inside_asm_statement:=false;
  844. _asm_statement:=asmstat;
  845. end;
  846. function statement : tnode;
  847. var
  848. p : tnode;
  849. code : tnode;
  850. filepos : tfileposinfo;
  851. srsym : tsym;
  852. srsymtable : tsymtable;
  853. s : stringid;
  854. begin
  855. filepos:=akttokenpos;
  856. case token of
  857. _GOTO :
  858. begin
  859. if not(cs_support_goto in aktmoduleswitches)then
  860. Message(sym_e_goto_and_label_not_supported);
  861. consume(_GOTO);
  862. if (token<>_INTCONST) and (token<>_ID) then
  863. begin
  864. Message(sym_e_label_not_found);
  865. code:=cerrornode.create;
  866. end
  867. else
  868. begin
  869. if token=_ID then
  870. consume_sym(srsym,srsymtable)
  871. else
  872. begin
  873. searchsym(pattern,srsym,srsymtable);
  874. if srsym=nil then
  875. begin
  876. identifier_not_found(pattern);
  877. srsym:=generrorsym;
  878. srsymtable:=nil;
  879. end;
  880. consume(token);
  881. end;
  882. if srsym.typ<>labelsym then
  883. begin
  884. Message(sym_e_id_is_no_label_id);
  885. code:=cerrornode.create;
  886. end
  887. else
  888. begin
  889. code:=cgotonode.create(tlabelsym(srsym));
  890. tgotonode(code).labsym:=tlabelsym(srsym);
  891. { set flag that this label is used }
  892. tlabelsym(srsym).used:=true;
  893. end;
  894. end;
  895. end;
  896. _BEGIN :
  897. code:=statement_block(_BEGIN);
  898. _IF :
  899. code:=if_statement;
  900. _CASE :
  901. code:=case_statement;
  902. _REPEAT :
  903. code:=repeat_statement;
  904. _WHILE :
  905. code:=while_statement;
  906. _FOR :
  907. code:=for_statement;
  908. _WITH :
  909. code:=with_statement;
  910. _TRY :
  911. code:=try_statement;
  912. _RAISE :
  913. code:=raise_statement;
  914. { semicolons,else until and end are ignored }
  915. _SEMICOLON,
  916. _ELSE,
  917. _UNTIL,
  918. _END:
  919. code:=cnothingnode.create;
  920. _FAIL :
  921. begin
  922. if (aktprocdef.proctypeoption<>potype_constructor) then
  923. Message(parser_e_fail_only_in_constructor);
  924. consume(_FAIL);
  925. code:=cfailnode.create;
  926. end;
  927. _ASM :
  928. code:=_asm_statement;
  929. _EOF :
  930. Message(scan_f_end_of_file);
  931. else
  932. begin
  933. p:=expr;
  934. { When a colon follows a intconst then transform it into a label }
  935. if try_to_consume(_COLON) then
  936. begin
  937. s:=tostr(tordconstnode(p).value);
  938. p.free;
  939. searchsym(s,srsym,srsymtable);
  940. if assigned(srsym) then
  941. begin
  942. if tlabelsym(srsym).defined then
  943. Message(sym_e_label_already_defined);
  944. tlabelsym(srsym).defined:=true;
  945. p:=clabelnode.create(tlabelsym(srsym),nil);
  946. end
  947. else
  948. begin
  949. identifier_not_found(s);
  950. p:=cnothingnode.create;
  951. end;
  952. end;
  953. if p.nodetype=labeln then
  954. begin
  955. { the pointer to the following instruction }
  956. { isn't a very clean way }
  957. tlabelnode(p).left:=statement{$ifdef FPCPROCVAR}(){$endif};
  958. { be sure to have left also resulttypepass }
  959. resulttypepass(tlabelnode(p).left);
  960. end;
  961. { blockn support because a read/write is changed into a blocknode }
  962. { with a separate statement for each read/write operation (JM) }
  963. { the same is true for val() if the third parameter is not 32 bit }
  964. if not(p.nodetype in [nothingn,calln,assignn,breakn,inlinen,
  965. continuen,labeln,blockn,exitn]) then
  966. Message(cg_e_illegal_expression);
  967. { specify that we don't use the value returned by the call }
  968. { Question : can this be also improtant
  969. for inlinen ??
  970. it is used for :
  971. - dispose of temp stack space
  972. - dispose on FPU stack }
  973. if p.nodetype=calln then
  974. exclude(p.flags,nf_return_value_used);
  975. code:=p;
  976. end;
  977. end;
  978. if assigned(code) then
  979. code.set_tree_filepos(filepos);
  980. statement:=code;
  981. end;
  982. function statement_block(starttoken : ttoken) : tnode;
  983. var
  984. first,last : tnode;
  985. filepos : tfileposinfo;
  986. begin
  987. first:=nil;
  988. filepos:=akttokenpos;
  989. consume(starttoken);
  990. inc(statement_level);
  991. while not(token in [_END,_FINALIZATION]) do
  992. begin
  993. if first=nil then
  994. begin
  995. last:=cstatementnode.create(nil,statement);
  996. first:=last;
  997. end
  998. else
  999. begin
  1000. tstatementnode(last).left:=cstatementnode.create(nil,statement);
  1001. last:=tstatementnode(last).left;
  1002. end;
  1003. if (token in [_END,_FINALIZATION]) then
  1004. break
  1005. else
  1006. begin
  1007. { if no semicolon, then error and go on }
  1008. if token<>_SEMICOLON then
  1009. begin
  1010. consume(_SEMICOLON);
  1011. consume_all_until(_SEMICOLON);
  1012. end;
  1013. consume(_SEMICOLON);
  1014. end;
  1015. consume_emptystats;
  1016. end;
  1017. { don't consume the finalization token, it is consumed when
  1018. reading the finalization block, but allow it only after
  1019. an initalization ! }
  1020. if (starttoken<>_INITIALIZATION) or (token<>_FINALIZATION) then
  1021. consume(_END);
  1022. dec(statement_level);
  1023. last:=cblocknode.create(first);
  1024. last.set_tree_filepos(filepos);
  1025. statement_block:=last;
  1026. end;
  1027. function assembler_block : tnode;
  1028. {# Optimize the assembler block by removing all references
  1029. which are via the frame pointer by replacing them with
  1030. references via the stack pointer.
  1031. This is only available to certain cpu targets where
  1032. the frame pointer saving must be done explicitly.
  1033. }
  1034. procedure OptimizeFramePointer(p:tasmnode);
  1035. var
  1036. hp : tai;
  1037. parafixup,
  1038. i : longint;
  1039. begin
  1040. { replace framepointer with stackpointer }
  1041. procinfo^.framepointer:=STACK_POINTER_REG;
  1042. { set the right value for parameters }
  1043. dec(aktprocdef.parast.address_fixup,pointer_size);
  1044. dec(procinfo^.para_offset,pointer_size);
  1045. { replace all references to parameters in the instructions,
  1046. the parameters can be identified by the parafixup option
  1047. that is set. For normal user coded [ebp+4] this field is not
  1048. set }
  1049. parafixup:=aktprocdef.parast.address_fixup;
  1050. hp:=tai(p.p_asm.first);
  1051. while assigned(hp) do
  1052. begin
  1053. if hp.typ=ait_instruction then
  1054. begin
  1055. { fixup the references }
  1056. for i:=1 to taicpu(hp).ops do
  1057. begin
  1058. with taicpu(hp).oper[i-1] do
  1059. if typ=top_ref then
  1060. begin
  1061. case ref^.options of
  1062. ref_parafixup :
  1063. begin
  1064. ref^.offsetfixup:=parafixup;
  1065. ref^.base:=STACK_POINTER_REG;
  1066. end;
  1067. end;
  1068. end;
  1069. end;
  1070. end;
  1071. hp:=tai(hp.next);
  1072. end;
  1073. end;
  1074. {$ifdef CHECKFORPUSH}
  1075. function UsesPush(p:tasmnode):boolean;
  1076. var
  1077. hp : tai;
  1078. begin
  1079. hp:=tai(p.p_asm.first);
  1080. while assigned(hp) do
  1081. begin
  1082. if (hp.typ=ait_instruction) and
  1083. (taicpu(hp).opcode=A_PUSH) then
  1084. begin
  1085. UsesPush:=true;
  1086. exit;
  1087. end;
  1088. hp:=tai(hp.next);
  1089. end;
  1090. UsesPush:=false;
  1091. end;
  1092. {$endif CHECKFORPUSH}
  1093. var
  1094. p : tnode;
  1095. haslocals,hasparas : boolean;
  1096. begin
  1097. { retrieve info about locals and paras before a result
  1098. is inserted in the symtable }
  1099. haslocals:=(aktprocdef.localst.datasize>0);
  1100. hasparas:=(aktprocdef.parast.datasize>0);
  1101. { temporary space is set, while the BEGIN of the procedure }
  1102. if symtablestack.symtabletype=localsymtable then
  1103. procinfo^.firsttemp_offset := -symtablestack.datasize
  1104. else
  1105. procinfo^.firsttemp_offset := 0;
  1106. { assembler code does not allocate }
  1107. { space for the return value }
  1108. if not is_void(aktprocdef.rettype.def) then
  1109. begin
  1110. aktprocdef.funcretsym:=tfuncretsym.create(aktprocsym.name,aktprocdef.rettype);
  1111. { insert in local symtable }
  1112. { but with another name, so that recursive calls are possible }
  1113. symtablestack.insert(aktprocdef.funcretsym);
  1114. symtablestack.rename(aktprocdef.funcretsym.name,'$result');
  1115. { update the symtablesize back to 0 if there were no locals }
  1116. if not haslocals then
  1117. symtablestack.datasize:=0;
  1118. { set the used flag for the return }
  1119. if paramanager.ret_in_acc(aktprocdef.rettype.def) then
  1120. include(rg.usedinproc,accumulator);
  1121. end;
  1122. { force the asm statement }
  1123. if token<>_ASM then
  1124. consume(_ASM);
  1125. procinfo^.Flags := procinfo^.Flags Or pi_is_assembler;
  1126. p:=_asm_statement;
  1127. { set the framepointer to esp for assembler functions when the
  1128. following conditions are met:
  1129. - if the are no local variables
  1130. - no reference to the result variable (refcount<=1)
  1131. - result is not stored as parameter
  1132. - target processor has optional frame pointer save
  1133. (vm, i386, vm only currently)
  1134. }
  1135. if (po_assembler in aktprocdef.procoptions) and
  1136. (not haslocals) and
  1137. (not hasparas) and
  1138. (aktprocdef.owner.symtabletype<>objectsymtable) and
  1139. (not assigned(aktprocdef.funcretsym) or
  1140. (tfuncretsym(aktprocdef.funcretsym).refcount<=1)) and
  1141. not(paramanager.ret_in_param(aktprocdef.rettype.def)) and
  1142. (target_cpu in [cpu_i386,cpu_m68k,cpu_vm])
  1143. {$ifdef CHECKFORPUSH}
  1144. and not(UsesPush(tasmnode(p)))
  1145. {$endif CHECKFORPUSH}
  1146. then
  1147. OptimizeFramePointer(tasmnode(p));
  1148. { Flag the result as assigned when it is returned in the
  1149. accumulator or on the fpu stack }
  1150. if assigned(aktprocdef.funcretsym) and
  1151. (is_fpu(aktprocdef.rettype.def) or
  1152. paramanager.ret_in_acc(aktprocdef.rettype.def)) then
  1153. tfuncretsym(aktprocdef.funcretsym).funcretstate:=vs_assigned;
  1154. { because the END is already read we need to get the
  1155. last_endtoken_filepos here (PFV) }
  1156. last_endtoken_filepos:=akttokenpos;
  1157. assembler_block:=p;
  1158. end;
  1159. end.
  1160. {
  1161. $Log$
  1162. Revision 1.66 2002-08-06 20:55:22 florian
  1163. * first part of ppc calling conventions fix
  1164. Revision 1.65 2002/07/28 20:45:22 florian
  1165. + added direct assembler reader for PowerPC
  1166. Revision 1.64 2002/07/20 11:57:56 florian
  1167. * types.pas renamed to defbase.pas because D6 contains a types
  1168. unit so this would conflicts if D6 programms are compiled
  1169. + Willamette/SSE2 instructions to assembler added
  1170. Revision 1.63 2002/07/19 11:41:36 daniel
  1171. * State tracker work
  1172. * The whilen and repeatn are now completely unified into whilerepeatn. This
  1173. allows the state tracker to change while nodes automatically into
  1174. repeat nodes.
  1175. * Resulttypepass improvements to the notn. 'not not a' is optimized away and
  1176. 'not(a>b)' is optimized into 'a<=b'.
  1177. * Resulttypepass improvements to the whilerepeatn. 'while not a' is optimized
  1178. by removing the notn and later switchting the true and falselabels. The
  1179. same is done with 'repeat until not a'.
  1180. Revision 1.62 2002/07/16 15:34:20 florian
  1181. * exit is now a syssym instead of a keyword
  1182. Revision 1.61 2002/07/11 14:41:28 florian
  1183. * start of the new generic parameter handling
  1184. Revision 1.60 2002/07/04 20:43:01 florian
  1185. * first x86-64 patches
  1186. Revision 1.59 2002/07/01 18:46:25 peter
  1187. * internal linker
  1188. * reorganized aasm layer
  1189. Revision 1.58 2002/05/18 13:34:13 peter
  1190. * readded missing revisions
  1191. Revision 1.57 2002/05/16 19:46:44 carl
  1192. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  1193. + try to fix temp allocation (still in ifdef)
  1194. + generic constructor calls
  1195. + start of tassembler / tmodulebase class cleanup
  1196. Revision 1.55 2002/05/06 19:56:42 carl
  1197. + added more patches from Mazen for SPARC port
  1198. Revision 1.54 2002/04/21 19:02:05 peter
  1199. * removed newn and disposen nodes, the code is now directly
  1200. inlined from pexpr
  1201. * -an option that will write the secondpass nodes to the .s file, this
  1202. requires EXTDEBUG define to actually write the info
  1203. * fixed various internal errors and crashes due recent code changes
  1204. Revision 1.53 2002/04/20 21:32:24 carl
  1205. + generic FPC_CHECKPOINTER
  1206. + first parameter offset in stack now portable
  1207. * rename some constants
  1208. + move some cpu stuff to other units
  1209. - remove unused constents
  1210. * fix stacksize for some targets
  1211. * fix generic size problems which depend now on EXTEND_SIZE constant
  1212. Revision 1.52 2002/04/16 16:11:17 peter
  1213. * using inherited; without a parent having the same function
  1214. will do nothing like delphi
  1215. Revision 1.51 2002/04/15 19:01:28 carl
  1216. + target_info.size_of_pointer -> pointer_Size
  1217. Revision 1.50 2002/04/14 16:53:54 carl
  1218. + asm statement uses ALL_REGISTERS
  1219. Revision 1.49 2002/03/31 20:26:36 jonas
  1220. + a_loadfpu_* and a_loadmm_* methods in tcg
  1221. * register allocation is now handled by a class and is mostly processor
  1222. independent (+rgobj.pas and i386/rgcpu.pas)
  1223. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  1224. * some small improvements and fixes to the optimizer
  1225. * some register allocation fixes
  1226. * some fpuvaroffset fixes in the unary minus node
  1227. * push/popusedregisters is now called rg.save/restoreusedregisters and
  1228. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  1229. also better optimizable)
  1230. * fixed and optimized register saving/restoring for new/dispose nodes
  1231. * LOC_FPU locations now also require their "register" field to be set to
  1232. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  1233. - list field removed of the tnode class because it's not used currently
  1234. and can cause hard-to-find bugs
  1235. Revision 1.48 2002/03/11 19:10:28 peter
  1236. * Regenerated with updated fpcmake
  1237. Revision 1.47 2002/03/04 17:54:59 peter
  1238. * allow oridinal labels again
  1239. Revision 1.46 2002/01/29 21:32:03 peter
  1240. * allow accessing locals in other lexlevel when the current assembler
  1241. routine doesn't have locals.
  1242. Revision 1.45 2002/01/24 18:25:49 peter
  1243. * implicit result variable generation for assembler routines
  1244. * removed m_tp modeswitch, use m_tp7 or not(m_fpc) instead
  1245. }