pstatmnt.pas 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389
  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,defutil,defcmp,
  37. paramgr,
  38. { pass 1 }
  39. pass_1,htypechk,
  40. nutils,nbas,nmat,nadd,ncal,nmem,nset,ncnv,ninl,ncon,nld,nflw,
  41. { parser }
  42. scanner,
  43. pbase,pexpr,
  44. { codegen }
  45. tgobj,rgobj,cgbase
  46. ,ncgutil
  47. ,radirect
  48. {$ifdef i386}
  49. {$ifndef NoRa386Int}
  50. ,ra386int
  51. {$endif NoRa386Int}
  52. {$ifndef NoRa386Att}
  53. ,ra386att
  54. {$endif NoRa386Att}
  55. {$else}
  56. ,rasm
  57. {$endif i386}
  58. ;
  59. function statement : tnode;forward;
  60. function if_statement : tnode;
  61. var
  62. ex,if_a,else_a : tnode;
  63. begin
  64. consume(_IF);
  65. ex:=comp_expr(true);
  66. consume(_THEN);
  67. if token<>_ELSE then
  68. if_a:=statement
  69. else
  70. if_a:=nil;
  71. if try_to_consume(_ELSE) then
  72. else_a:=statement
  73. else
  74. else_a:=nil;
  75. if_statement:=genloopnode(ifn,ex,if_a,else_a,false);
  76. end;
  77. { creates a block (list) of statements, til the next END token }
  78. function statements_til_end : tnode;
  79. var
  80. first,last : tstatementnode;
  81. begin
  82. first:=nil;
  83. while token<>_END do
  84. begin
  85. if first=nil then
  86. begin
  87. last:=cstatementnode.create(statement,nil);
  88. first:=last;
  89. end
  90. else
  91. begin
  92. last.right:=cstatementnode.create(statement,nil);
  93. last:=tstatementnode(last.right);
  94. end;
  95. if not try_to_consume(_SEMICOLON) then
  96. break;
  97. consume_emptystats;
  98. end;
  99. consume(_END);
  100. statements_til_end:=cblocknode.create(first,true);
  101. end;
  102. function case_statement : tnode;
  103. var
  104. { contains the label number of currently parsed case block }
  105. aktcaselabel : tasmlabel;
  106. firstlabel : boolean;
  107. root : pcaserecord;
  108. { the typ of the case expression }
  109. casedef : tdef;
  110. procedure newcaselabel(l,h : TConstExprInt;first:boolean);
  111. var
  112. hcaselabel : pcaserecord;
  113. procedure insertlabel(var p : pcaserecord);
  114. begin
  115. if p=nil then p:=hcaselabel
  116. else
  117. if (p^._low>hcaselabel^._low) and
  118. (p^._low>hcaselabel^._high) then
  119. if (hcaselabel^.statement = p^.statement) and
  120. (p^._low = hcaselabel^._high + 1) then
  121. begin
  122. p^._low := hcaselabel^._low;
  123. dispose(hcaselabel);
  124. end
  125. else
  126. insertlabel(p^.less)
  127. else
  128. if (p^._high<hcaselabel^._low) and
  129. (p^._high<hcaselabel^._high) then
  130. if (hcaselabel^.statement = p^.statement) and
  131. (p^._high+1 = hcaselabel^._low) then
  132. begin
  133. p^._high := hcaselabel^._high;
  134. dispose(hcaselabel);
  135. end
  136. else
  137. insertlabel(p^.greater)
  138. else Message(parser_e_double_caselabel);
  139. end;
  140. begin
  141. new(hcaselabel);
  142. hcaselabel^.less:=nil;
  143. hcaselabel^.greater:=nil;
  144. hcaselabel^.statement:=aktcaselabel;
  145. hcaselabel^.firstlabel:=first;
  146. objectlibrary.getlabel(hcaselabel^._at);
  147. hcaselabel^._low:=l;
  148. hcaselabel^._high:=h;
  149. insertlabel(root);
  150. end;
  151. var
  152. code,caseexpr,p,instruc,elseblock : tnode;
  153. hl1,hl2 : TConstExprInt;
  154. casedeferror : boolean;
  155. begin
  156. consume(_CASE);
  157. caseexpr:=comp_expr(true);
  158. { determines result type }
  159. {$ifndef newra}
  160. rg.cleartempgen;
  161. {$endif}
  162. do_resulttypepass(caseexpr);
  163. casedeferror:=false;
  164. casedef:=caseexpr.resulttype.def;
  165. if (not assigned(casedef)) or
  166. not(is_ordinal(casedef)) then
  167. begin
  168. CGMessage(type_e_ordinal_expr_expected);
  169. { create a correct tree }
  170. caseexpr.free;
  171. caseexpr:=cordconstnode.create(0,u32bittype,false);
  172. { set error flag so no rangechecks are done }
  173. casedeferror:=true;
  174. end;
  175. consume(_OF);
  176. inc(statement_level);
  177. root:=nil;
  178. instruc:=nil;
  179. repeat
  180. objectlibrary.getlabel(aktcaselabel);
  181. firstlabel:=true;
  182. { maybe an instruction has more case labels }
  183. repeat
  184. p:=expr;
  185. if is_widechar(casedef) then
  186. begin
  187. if (p.nodetype=rangen) then
  188. begin
  189. trangenode(p).left:=ctypeconvnode.create(trangenode(p).left,cwidechartype);
  190. trangenode(p).right:=ctypeconvnode.create(trangenode(p).right,cwidechartype);
  191. do_resulttypepass(trangenode(p).left);
  192. do_resulttypepass(trangenode(p).right);
  193. end
  194. else
  195. begin
  196. p:=ctypeconvnode.create(p,cwidechartype);
  197. do_resulttypepass(p);
  198. end;
  199. end;
  200. hl1:=0;
  201. hl2:=0;
  202. if (p.nodetype=rangen) then
  203. begin
  204. { type checking for case statements }
  205. if is_subequal(casedef, trangenode(p).left.resulttype.def) and
  206. is_subequal(casedef, trangenode(p).right.resulttype.def) then
  207. begin
  208. hl1:=get_ordinal_value(trangenode(p).left);
  209. hl2:=get_ordinal_value(trangenode(p).right);
  210. if hl1>hl2 then
  211. CGMessage(parser_e_case_lower_less_than_upper_bound);
  212. if not casedeferror then
  213. begin
  214. testrange(casedef,hl1,false);
  215. testrange(casedef,hl2,false);
  216. end;
  217. end
  218. else
  219. CGMessage(parser_e_case_mismatch);
  220. newcaselabel(hl1,hl2,firstlabel);
  221. end
  222. else
  223. begin
  224. { type checking for case statements }
  225. if not is_subequal(casedef, p.resulttype.def) then
  226. CGMessage(parser_e_case_mismatch);
  227. hl1:=get_ordinal_value(p);
  228. if not casedeferror then
  229. testrange(casedef,hl1,false);
  230. newcaselabel(hl1,hl1,firstlabel);
  231. end;
  232. p.free;
  233. if token=_COMMA then
  234. consume(_COMMA)
  235. else
  236. break;
  237. firstlabel:=false;
  238. until false;
  239. consume(_COLON);
  240. { handles instruction block }
  241. p:=clabelnode.createcase(aktcaselabel,statement);
  242. { concats instruction }
  243. instruc:=cstatementnode.create(p,instruc);
  244. if not(token in [_ELSE,_OTHERWISE,_END]) then
  245. consume(_SEMICOLON);
  246. until (token in [_ELSE,_OTHERWISE,_END]);
  247. if (token in [_ELSE,_OTHERWISE]) then
  248. begin
  249. if not try_to_consume(_ELSE) then
  250. consume(_OTHERWISE);
  251. elseblock:=statements_til_end;
  252. end
  253. else
  254. begin
  255. elseblock:=nil;
  256. consume(_END);
  257. end;
  258. dec(statement_level);
  259. code:=ccasenode.create(caseexpr,instruc,root);
  260. tcasenode(code).elseblock:=elseblock;
  261. case_statement:=code;
  262. end;
  263. function repeat_statement : tnode;
  264. var
  265. first,last,p_e : tnode;
  266. begin
  267. consume(_REPEAT);
  268. first:=nil;
  269. inc(statement_level);
  270. while token<>_UNTIL do
  271. begin
  272. if first=nil then
  273. begin
  274. last:=cstatementnode.create(statement,nil);
  275. first:=last;
  276. end
  277. else
  278. begin
  279. tstatementnode(last).right:=cstatementnode.create(statement,nil);
  280. last:=tstatementnode(last).right;
  281. end;
  282. if not try_to_consume(_SEMICOLON) then
  283. break;
  284. consume_emptystats;
  285. end;
  286. consume(_UNTIL);
  287. dec(statement_level);
  288. first:=cblocknode.create(first,true);
  289. p_e:=comp_expr(true);
  290. repeat_statement:=genloopnode(whilerepeatn,p_e,first,nil,true);
  291. end;
  292. function while_statement : tnode;
  293. var
  294. p_e,p_a : tnode;
  295. begin
  296. consume(_WHILE);
  297. p_e:=comp_expr(true);
  298. consume(_DO);
  299. p_a:=statement;
  300. while_statement:=genloopnode(whilerepeatn,p_e,p_a,nil,false);
  301. end;
  302. function for_statement : tnode;
  303. var
  304. p_e,tovalue,p_a : tnode;
  305. backward : boolean;
  306. begin
  307. { parse loop header }
  308. consume(_FOR);
  309. p_e:=expr;
  310. if token=_DOWNTO then
  311. begin
  312. consume(_DOWNTO);
  313. backward:=true;
  314. end
  315. else
  316. begin
  317. consume(_TO);
  318. backward:=false;
  319. end;
  320. tovalue:=comp_expr(true);
  321. consume(_DO);
  322. { ... now the instruction }
  323. p_a:=statement;
  324. for_statement:=genloopnode(forn,p_e,tovalue,p_a,backward);
  325. end;
  326. function _with_statement : tnode;
  327. var
  328. right,p : tnode;
  329. i,levelcount : longint;
  330. withsymtable,symtab : tsymtable;
  331. obj : tobjectdef;
  332. hp : tnode;
  333. newblock : tblocknode;
  334. newstatement : tstatementnode;
  335. loadp : ttempcreatenode;
  336. refp : tnode;
  337. htype : ttype;
  338. hasimplicitderef : boolean;
  339. begin
  340. p:=comp_expr(true);
  341. do_resulttypepass(p);
  342. set_varstate(p,false);
  343. right:=nil;
  344. if (not codegenerror) and
  345. (p.resulttype.def.deftype in [objectdef,recorddef]) then
  346. begin
  347. newblock:=nil;
  348. { ignore nodes that don't add instructions in the tree }
  349. hp:=p;
  350. while { equal type conversions }
  351. (
  352. (hp.nodetype=typeconvn) and
  353. (ttypeconvnode(hp).convtype=tc_equal)
  354. ) or
  355. { constant array index }
  356. (
  357. (hp.nodetype=vecn) and
  358. (tvecnode(hp).right.nodetype=ordconstn)
  359. ) do
  360. hp:=tunarynode(hp).left;
  361. if (hp.nodetype=loadn) and
  362. (
  363. (tloadnode(hp).symtable=current_procdef.localst) or
  364. (tloadnode(hp).symtable=current_procdef.parast) or
  365. (tloadnode(hp).symtable.symtabletype in [staticsymtable,globalsymtable])
  366. ) then
  367. begin
  368. { simple load, we can reference direct }
  369. loadp:=nil;
  370. refp:=p;
  371. end
  372. else
  373. begin
  374. { complex load, load in temp first }
  375. newblock:=internalstatements(newstatement,false);
  376. { classes and interfaces have implicit dereferencing }
  377. hasimplicitderef:=is_class_or_interface(p.resulttype.def);
  378. if hasimplicitderef then
  379. htype:=p.resulttype
  380. else
  381. htype.setdef(tpointerdef.create(p.resulttype));
  382. loadp:=ctempcreatenode.create(htype,POINTER_SIZE,true);
  383. resulttypepass(loadp);
  384. if hasimplicitderef then
  385. begin
  386. hp:=p;
  387. refp:=ctemprefnode.create(loadp);
  388. end
  389. else
  390. begin
  391. hp:=caddrnode.create(p);
  392. refp:=cderefnode.create(ctemprefnode.create(loadp));
  393. end;
  394. addstatement(newstatement,loadp);
  395. addstatement(newstatement,cassignmentnode.create(
  396. ctemprefnode.create(loadp),
  397. hp));
  398. resulttypepass(refp);
  399. end;
  400. case p.resulttype.def.deftype of
  401. objectdef :
  402. begin
  403. obj:=tobjectdef(p.resulttype.def);
  404. withsymtable:=twithsymtable.Create(obj,obj.symtable.symsearch,refp);
  405. { include also all parent symtables }
  406. levelcount:=1;
  407. obj:=obj.childof;
  408. symtab:=withsymtable;
  409. while assigned(obj) do
  410. begin
  411. symtab.next:=twithsymtable.create(obj,obj.symtable.symsearch,refp);
  412. symtab:=symtab.next;
  413. obj:=obj.childof;
  414. inc(levelcount);
  415. end;
  416. symtab.next:=symtablestack;
  417. symtablestack:=withsymtable;
  418. end;
  419. recorddef :
  420. begin
  421. symtab:=trecorddef(p.resulttype.def).symtable;
  422. levelcount:=1;
  423. withsymtable:=twithsymtable.create(trecorddef(p.resulttype.def),symtab.symsearch,refp);
  424. withsymtable.next:=symtablestack;
  425. symtablestack:=withsymtable;
  426. end;
  427. end;
  428. if try_to_consume(_COMMA) then
  429. right:=_with_statement{$ifdef FPCPROCVAR}(){$endif}
  430. else
  431. begin
  432. consume(_DO);
  433. if token<>_SEMICOLON then
  434. right:=statement
  435. else
  436. right:=cerrornode.create;
  437. end;
  438. { remove symtables from the stack }
  439. for i:=1 to levelcount do
  440. symtablestack:=symtablestack.next;
  441. p:=cwithnode.create(right,twithsymtable(withsymtable),levelcount,refp);
  442. { Finalize complex withnode with destroy of temp }
  443. if assigned(newblock) then
  444. begin
  445. addstatement(newstatement,p);
  446. addstatement(newstatement,ctempdeletenode.create(loadp));
  447. p:=newblock;
  448. end;
  449. _with_statement:=p;
  450. end
  451. else
  452. begin
  453. Message(parser_e_false_with_expr);
  454. { try to recover from error }
  455. if try_to_consume(_COMMA) then
  456. begin
  457. hp:=_with_statement{$ifdef FPCPROCVAR}(){$endif};
  458. if (hp=nil) then; { remove warning about unused }
  459. end
  460. else
  461. begin
  462. consume(_DO);
  463. { ignore all }
  464. if token<>_SEMICOLON then
  465. statement;
  466. end;
  467. _with_statement:=nil;
  468. end;
  469. end;
  470. function with_statement : tnode;
  471. begin
  472. consume(_WITH);
  473. with_statement:=_with_statement;
  474. end;
  475. function raise_statement : tnode;
  476. var
  477. p,pobj,paddr,pframe : tnode;
  478. begin
  479. pobj:=nil;
  480. paddr:=nil;
  481. pframe:=nil;
  482. consume(_RAISE);
  483. if not(token in endtokens) then
  484. begin
  485. { object }
  486. pobj:=comp_expr(true);
  487. if try_to_consume(_AT) then
  488. begin
  489. paddr:=comp_expr(true);
  490. if try_to_consume(_COMMA) then
  491. pframe:=comp_expr(true);
  492. end;
  493. end
  494. else
  495. begin
  496. if (block_type<>bt_except) then
  497. Message(parser_e_no_reraise_possible);
  498. end;
  499. p:=craisenode.create(pobj,paddr,pframe);
  500. raise_statement:=p;
  501. end;
  502. function try_statement : tnode;
  503. var
  504. p_try_block,p_finally_block,first,last,
  505. p_default,p_specific,hp : tnode;
  506. ot : ttype;
  507. sym : tvarsym;
  508. old_block_type : tblock_type;
  509. exceptsymtable : tsymtable;
  510. objname,objrealname : stringid;
  511. srsym : tsym;
  512. srsymtable : tsymtable;
  513. oldaktexceptblock: integer;
  514. begin
  515. include(current_procinfo.flags,pi_uses_exceptions);
  516. p_default:=nil;
  517. p_specific:=nil;
  518. { read statements to try }
  519. consume(_TRY);
  520. first:=nil;
  521. inc(exceptblockcounter);
  522. oldaktexceptblock := aktexceptblock;
  523. aktexceptblock := exceptblockcounter;
  524. inc(statement_level);
  525. while (token<>_FINALLY) and (token<>_EXCEPT) do
  526. begin
  527. if first=nil then
  528. begin
  529. last:=cstatementnode.create(statement,nil);
  530. first:=last;
  531. end
  532. else
  533. begin
  534. tstatementnode(last).right:=cstatementnode.create(statement,nil);
  535. last:=tstatementnode(last).right;
  536. end;
  537. if not try_to_consume(_SEMICOLON) then
  538. break;
  539. consume_emptystats;
  540. end;
  541. p_try_block:=cblocknode.create(first,true);
  542. if try_to_consume(_FINALLY) then
  543. begin
  544. inc(exceptblockcounter);
  545. aktexceptblock := exceptblockcounter;
  546. p_finally_block:=statements_til_end;
  547. try_statement:=ctryfinallynode.create(p_try_block,p_finally_block);
  548. dec(statement_level);
  549. end
  550. else
  551. begin
  552. consume(_EXCEPT);
  553. old_block_type:=block_type;
  554. block_type:=bt_except;
  555. inc(exceptblockcounter);
  556. aktexceptblock := exceptblockcounter;
  557. ot:=generrortype;
  558. p_specific:=nil;
  559. if (idtoken=_ON) then
  560. { catch specific exceptions }
  561. begin
  562. repeat
  563. consume(_ID);
  564. if token=_ID then
  565. begin
  566. objname:=pattern;
  567. objrealname:=orgpattern;
  568. { can't use consume_sym here, because we need already
  569. to check for the colon }
  570. searchsym(objname,srsym,srsymtable);
  571. consume(_ID);
  572. { is a explicit name for the exception given ? }
  573. if try_to_consume(_COLON) then
  574. begin
  575. consume_sym(srsym,srsymtable);
  576. if (srsym.typ=typesym) and
  577. is_class(ttypesym(srsym).restype.def) then
  578. begin
  579. ot:=ttypesym(srsym).restype;
  580. sym:=tvarsym.create(objrealname,vs_value,ot);
  581. end
  582. else
  583. begin
  584. sym:=tvarsym.create(objrealname,vs_value,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:=tstt_exceptsymtable.create;
  591. exceptsymtable.insert(sym);
  592. { insert the exception symtable stack }
  593. exceptsymtable.next:=symtablestack;
  594. symtablestack:=exceptsymtable;
  595. end
  596. else
  597. begin
  598. { check if type is valid, must be done here because
  599. with "e: Exception" the e is not necessary }
  600. if srsym=nil then
  601. begin
  602. identifier_not_found(objrealname);
  603. srsym:=generrorsym;
  604. end;
  605. { support unit.identifier }
  606. if srsym.typ=unitsym then
  607. begin
  608. consume(_POINT);
  609. srsym:=searchsymonlyin(tunitsym(srsym).unitsymtable,pattern);
  610. if srsym=nil then
  611. begin
  612. identifier_not_found(orgpattern);
  613. srsym:=generrorsym;
  614. end;
  615. consume(_ID);
  616. end;
  617. { check if type is valid, must be done here because
  618. with "e: Exception" the e is not necessary }
  619. if (srsym.typ=typesym) and
  620. is_class(ttypesym(srsym).restype.def) then
  621. ot:=ttypesym(srsym).restype
  622. else
  623. begin
  624. ot:=generrortype;
  625. if (srsym.typ=typesym) then
  626. Message1(type_e_class_type_expected,ttypesym(srsym).restype.def.typename)
  627. else
  628. Message1(type_e_class_type_expected,ot.def.typename);
  629. end;
  630. exceptsymtable:=nil;
  631. end;
  632. end
  633. else
  634. consume(_ID);
  635. consume(_DO);
  636. hp:=connode.create(nil,statement);
  637. if ot.def.deftype=errordef then
  638. begin
  639. hp.free;
  640. hp:=cerrornode.create;
  641. end;
  642. if p_specific=nil then
  643. begin
  644. last:=hp;
  645. p_specific:=last;
  646. end
  647. else
  648. begin
  649. tonnode(last).left:=hp;
  650. last:=tonnode(last).left;
  651. end;
  652. { set the informations }
  653. { only if the creation of the onnode was succesful, it's possible }
  654. { that last and hp are errornodes (JM) }
  655. if last.nodetype = onn then
  656. begin
  657. tonnode(last).excepttype:=tobjectdef(ot.def);
  658. tonnode(last).exceptsymtable:=exceptsymtable;
  659. end;
  660. { remove exception symtable }
  661. if assigned(exceptsymtable) then
  662. begin
  663. symtablestack:=symtablestack.next;
  664. if last.nodetype <> onn then
  665. exceptsymtable.free;
  666. end;
  667. if not try_to_consume(_SEMICOLON) then
  668. break;
  669. consume_emptystats;
  670. until (token in [_END,_ELSE]);
  671. if try_to_consume(_ELSE) then
  672. begin
  673. { catch the other exceptions }
  674. p_default:=statements_til_end;
  675. end
  676. else
  677. consume(_END);
  678. end
  679. else
  680. begin
  681. { catch all exceptions }
  682. p_default:=statements_til_end;
  683. end;
  684. dec(statement_level);
  685. block_type:=old_block_type;
  686. try_statement:=ctryexceptnode.create(p_try_block,p_specific,p_default);
  687. end;
  688. aktexceptblock := oldaktexceptblock;
  689. end;
  690. function _asm_statement : tnode;
  691. var
  692. asmstat : tasmnode;
  693. Marker : tai;
  694. r : tregister;
  695. found : boolean;
  696. hs : string;
  697. begin
  698. Inside_asm_statement:=true;
  699. case aktasmmode of
  700. asmmode_none : ; { just be there to allow to compile a compiler without
  701. any assembler readers }
  702. {$ifdef i386}
  703. {$ifndef NoRA386Att}
  704. asmmode_i386_att:
  705. asmstat:=tasmnode(ra386att.assemble);
  706. {$endif NoRA386Att}
  707. {$ifndef NoRA386Int}
  708. asmmode_i386_intel:
  709. asmstat:=tasmnode(ra386int.assemble);
  710. {$endif NoRA386Int}
  711. {$else not i386}
  712. asmmode_standard:
  713. asmstat:=tasmnode(rasm.assemble);
  714. {$endif i386}
  715. asmmode_direct:
  716. begin
  717. if not target_asm.allowdirect then
  718. Message(parser_f_direct_assembler_not_allowed);
  719. if (current_procdef.proccalloption=pocall_inline) then
  720. Begin
  721. Message1(parser_w_not_supported_for_inline,'direct asm');
  722. Message(parser_w_inlining_disabled);
  723. current_procdef.proccalloption:=pocall_fpccall;
  724. End;
  725. asmstat:=tasmnode(radirect.assemble);
  726. end;
  727. else
  728. Message(parser_f_assembler_reader_not_supported);
  729. end;
  730. { Read first the _ASM statement }
  731. consume(_ASM);
  732. { END is read }
  733. if try_to_consume(_LECKKLAMMER) then
  734. begin
  735. if token<>_RECKKLAMMER then
  736. begin
  737. repeat
  738. { it's possible to specify the modified registers }
  739. hs:=upper(pattern);
  740. found:=false;
  741. for r.enum:=firstreg to lastreg do
  742. if hs=upper(std_reg2str[r.enum]) then
  743. begin
  744. include(rg.usedinproc,r.enum);
  745. include(rg.usedbyproc,r.enum);
  746. found:=true;
  747. break;
  748. end;
  749. if not(found) then
  750. Message(asmr_e_invalid_register);
  751. consume(_CSTRING);
  752. if not try_to_consume(_COMMA) then
  753. break;
  754. until false;
  755. end;
  756. consume(_RECKKLAMMER);
  757. end
  758. else
  759. begin
  760. rg.usedbyproc := ALL_REGISTERS;
  761. rg.usedinproc := ALL_REGISTERS;
  762. end;
  763. { mark the start and the end of the assembler block
  764. this is needed for the optimizer }
  765. If Assigned(AsmStat.p_asm) Then
  766. Begin
  767. Marker := Tai_Marker.Create(AsmBlockStart);
  768. AsmStat.p_asm.Insert(Marker);
  769. Marker := Tai_Marker.Create(AsmBlockEnd);
  770. AsmStat.p_asm.Concat(Marker);
  771. End;
  772. Inside_asm_statement:=false;
  773. _asm_statement:=asmstat;
  774. end;
  775. function statement : tnode;
  776. var
  777. p : tnode;
  778. code : tnode;
  779. filepos : tfileposinfo;
  780. srsym : tsym;
  781. srsymtable : tsymtable;
  782. s : stringid;
  783. begin
  784. filepos:=akttokenpos;
  785. case token of
  786. _GOTO :
  787. begin
  788. if not(cs_support_goto in aktmoduleswitches)then
  789. Message(sym_e_goto_and_label_not_supported);
  790. consume(_GOTO);
  791. if (token<>_INTCONST) and (token<>_ID) then
  792. begin
  793. Message(sym_e_label_not_found);
  794. code:=cerrornode.create;
  795. end
  796. else
  797. begin
  798. if token=_ID then
  799. consume_sym(srsym,srsymtable)
  800. else
  801. begin
  802. searchsym(pattern,srsym,srsymtable);
  803. if srsym=nil then
  804. begin
  805. identifier_not_found(pattern);
  806. srsym:=generrorsym;
  807. srsymtable:=nil;
  808. end;
  809. consume(token);
  810. end;
  811. if srsym.typ<>labelsym then
  812. begin
  813. Message(sym_e_id_is_no_label_id);
  814. code:=cerrornode.create;
  815. end
  816. else
  817. begin
  818. code:=cgotonode.create(tlabelsym(srsym));
  819. tgotonode(code).labsym:=tlabelsym(srsym);
  820. { set flag that this label is used }
  821. tlabelsym(srsym).used:=true;
  822. end;
  823. end;
  824. end;
  825. _BEGIN :
  826. code:=statement_block(_BEGIN);
  827. _IF :
  828. code:=if_statement;
  829. _CASE :
  830. code:=case_statement;
  831. _REPEAT :
  832. code:=repeat_statement;
  833. _WHILE :
  834. code:=while_statement;
  835. _FOR :
  836. code:=for_statement;
  837. _WITH :
  838. code:=with_statement;
  839. _TRY :
  840. code:=try_statement;
  841. _RAISE :
  842. code:=raise_statement;
  843. { semicolons,else until and end are ignored }
  844. _SEMICOLON,
  845. _ELSE,
  846. _UNTIL,
  847. _END:
  848. code:=cnothingnode.create;
  849. _FAIL :
  850. begin
  851. if (current_procdef.proctypeoption<>potype_constructor) then
  852. Message(parser_e_fail_only_in_constructor);
  853. consume(_FAIL);
  854. code:=call_fail_node;
  855. end;
  856. _ASM :
  857. code:=_asm_statement;
  858. _EOF :
  859. Message(scan_f_end_of_file);
  860. else
  861. begin
  862. p:=expr;
  863. { When a colon follows a intconst then transform it into a label }
  864. if try_to_consume(_COLON) then
  865. begin
  866. s:=tostr(tordconstnode(p).value);
  867. p.free;
  868. searchsym(s,srsym,srsymtable);
  869. if assigned(srsym) then
  870. begin
  871. if tlabelsym(srsym).defined then
  872. Message(sym_e_label_already_defined);
  873. tlabelsym(srsym).defined:=true;
  874. p:=clabelnode.create(tlabelsym(srsym),nil);
  875. end
  876. else
  877. begin
  878. identifier_not_found(s);
  879. p:=cnothingnode.create;
  880. end;
  881. end;
  882. if p.nodetype=labeln then
  883. begin
  884. { the pointer to the following instruction }
  885. { isn't a very clean way }
  886. tlabelnode(p).left:=statement{$ifdef FPCPROCVAR}(){$endif};
  887. { be sure to have left also resulttypepass }
  888. resulttypepass(tlabelnode(p).left);
  889. end;
  890. { blockn support because a read/write is changed into a blocknode }
  891. { with a separate statement for each read/write operation (JM) }
  892. { the same is true for val() if the third parameter is not 32 bit }
  893. if not(p.nodetype in [nothingn,calln,ifn,assignn,breakn,inlinen,
  894. continuen,labeln,blockn,exitn]) then
  895. Message(cg_e_illegal_expression);
  896. { specify that we don't use the value returned by the call }
  897. { Question : can this be also improtant
  898. for inlinen ??
  899. it is used for :
  900. - dispose of temp stack space
  901. - dispose on FPU stack }
  902. if p.nodetype=calln then
  903. exclude(p.flags,nf_return_value_used);
  904. code:=p;
  905. end;
  906. end;
  907. if assigned(code) then
  908. code.set_tree_filepos(filepos);
  909. statement:=code;
  910. end;
  911. function statement_block(starttoken : ttoken) : tnode;
  912. var
  913. first,last : tnode;
  914. filepos : tfileposinfo;
  915. begin
  916. first:=nil;
  917. filepos:=akttokenpos;
  918. consume(starttoken);
  919. inc(statement_level);
  920. while not(token in [_END,_FINALIZATION]) do
  921. begin
  922. if first=nil then
  923. begin
  924. last:=cstatementnode.create(statement,nil);
  925. first:=last;
  926. end
  927. else
  928. begin
  929. tstatementnode(last).right:=cstatementnode.create(statement,nil);
  930. last:=tstatementnode(last).right;
  931. end;
  932. if (token in [_END,_FINALIZATION]) then
  933. break
  934. else
  935. begin
  936. { if no semicolon, then error and go on }
  937. if token<>_SEMICOLON then
  938. begin
  939. consume(_SEMICOLON);
  940. consume_all_until(_SEMICOLON);
  941. end;
  942. consume(_SEMICOLON);
  943. end;
  944. consume_emptystats;
  945. end;
  946. { don't consume the finalization token, it is consumed when
  947. reading the finalization block, but allow it only after
  948. an initalization ! }
  949. if (starttoken<>_INITIALIZATION) or (token<>_FINALIZATION) then
  950. consume(_END);
  951. dec(statement_level);
  952. last:=cblocknode.create(first,true);
  953. last.set_tree_filepos(filepos);
  954. statement_block:=last;
  955. end;
  956. function assembler_block : tnode;
  957. {# Optimize the assembler block by removing all references
  958. which are via the frame pointer by replacing them with
  959. references via the stack pointer.
  960. This is only available to certain cpu targets where
  961. the frame pointer saving must be done explicitly.
  962. }
  963. procedure OptimizeFramePointer(p:tasmnode);
  964. var
  965. hp : tai;
  966. parafixup,
  967. i : longint;
  968. begin
  969. { replace framepointer with stackpointer }
  970. current_procinfo.framepointer.enum:=R_INTREGISTER;
  971. current_procinfo.framepointer.number:=NR_STACK_POINTER_REG;
  972. { set the right value for parameters }
  973. dec(current_procdef.parast.address_fixup,pointer_size);
  974. { replace all references to parameters in the instructions,
  975. the parameters can be identified by the parafixup option
  976. that is set. For normal user coded [ebp+4] this field is not
  977. set }
  978. parafixup:=current_procdef.parast.address_fixup;
  979. hp:=tai(p.p_asm.first);
  980. while assigned(hp) do
  981. begin
  982. if hp.typ=ait_instruction then
  983. begin
  984. { fixup the references }
  985. for i:=1 to taicpu(hp).ops do
  986. begin
  987. with taicpu(hp).oper[i-1] do
  988. if typ=top_ref then
  989. begin
  990. case ref^.options of
  991. ref_parafixup :
  992. begin
  993. ref^.offsetfixup:=parafixup;
  994. ref^.base.enum:=R_INTREGISTER;
  995. ref^.base.number:=NR_STACK_POINTER_REG;
  996. end;
  997. end;
  998. end;
  999. end;
  1000. end;
  1001. hp:=tai(hp.next);
  1002. end;
  1003. end;
  1004. {$ifdef CHECKFORPUSH}
  1005. function UsesPush(p:tasmnode):boolean;
  1006. var
  1007. hp : tai;
  1008. begin
  1009. hp:=tai(p.p_asm.first);
  1010. while assigned(hp) do
  1011. begin
  1012. if (hp.typ=ait_instruction) and
  1013. (taicpu(hp).opcode=A_PUSH) then
  1014. begin
  1015. UsesPush:=true;
  1016. exit;
  1017. end;
  1018. hp:=tai(hp.next);
  1019. end;
  1020. UsesPush:=false;
  1021. end;
  1022. {$endif CHECKFORPUSH}
  1023. var
  1024. p : tnode;
  1025. begin
  1026. { Rename the funcret so that recursive calls are possible }
  1027. if not is_void(current_procdef.rettype.def) then
  1028. symtablestack.rename(current_procdef.resultname,'$hiddenresult');
  1029. { force the asm statement }
  1030. if token<>_ASM then
  1031. consume(_ASM);
  1032. include(current_procinfo.flags,pi_is_assembler);
  1033. p:=_asm_statement;
  1034. { set the framepointer to esp for assembler functions when the
  1035. following conditions are met:
  1036. - if the are no local variables (except the allocated result)
  1037. - if the are no parameters
  1038. - no reference to the result variable (refcount<=1)
  1039. - result is not stored as parameter
  1040. - target processor has optional frame pointer save
  1041. (vm, i386, vm only currently)
  1042. }
  1043. if (po_assembler in current_procdef.procoptions) and
  1044. {$ifndef powerpc}
  1045. { is this really necessary??? }
  1046. (current_procdef.parast.datasize=0) and
  1047. {$endif powerpc}
  1048. (current_procdef.localst.datasize=current_procdef.rettype.def.size) and
  1049. (current_procdef.owner.symtabletype<>objectsymtable) and
  1050. (not assigned(current_procdef.funcretsym) or
  1051. (tvarsym(current_procdef.funcretsym).refcount<=1)) and
  1052. not(paramanager.ret_in_param(current_procdef.rettype.def,current_procdef.proccalloption)) then
  1053. begin
  1054. { we don't need to allocate space for the locals }
  1055. current_procdef.localst.datasize:=0;
  1056. current_procinfo.firsttemp_offset:=0;
  1057. { only for cpus with different frame- and stack pointer the code must be changed }
  1058. if (NR_STACK_POINTER_REG<>NR_FRAME_POINTER_REG)
  1059. {$ifdef CHECKFORPUSH}
  1060. and not(UsesPush(tasmnode(p)))
  1061. {$endif CHECKFORPUSH}
  1062. then
  1063. OptimizeFramePointer(tasmnode(p));
  1064. end;
  1065. { Flag the result as assigned when it is returned in a
  1066. register.
  1067. }
  1068. if assigned(current_procdef.funcretsym) and
  1069. (not paramanager.ret_in_param(current_procdef.rettype.def,current_procdef.proccalloption)) then
  1070. tvarsym(current_procdef.funcretsym).varstate:=vs_assigned;
  1071. { because the END is already read we need to get the
  1072. last_endtoken_filepos here (PFV) }
  1073. last_endtoken_filepos:=akttokenpos;
  1074. assembler_block:=p;
  1075. end;
  1076. end.
  1077. {
  1078. $Log$
  1079. Revision 1.98 2003-05-13 19:14:41 peter
  1080. * failn removed
  1081. * inherited result code check moven to pexpr
  1082. Revision 1.97 2003/05/11 14:45:12 peter
  1083. * tloadnode does not support objectsymtable,withsymtable anymore
  1084. * withnode cleanup
  1085. * direct with rewritten to use temprefnode
  1086. Revision 1.96 2003/05/09 17:47:03 peter
  1087. * self moved to hidden parameter
  1088. * removed hdisposen,hnewn,selfn
  1089. Revision 1.95 2003/04/30 22:15:59 florian
  1090. * some 64 bit adaptions in ncgadd
  1091. * x86-64 now uses ncgadd
  1092. * tparamanager.ret_in_acc doesn't return true anymore for a void-def
  1093. Revision 1.94 2003/04/27 11:21:34 peter
  1094. * aktprocdef renamed to current_procdef
  1095. * procinfo renamed to current_procinfo
  1096. * procinfo will now be stored in current_module so it can be
  1097. cleaned up properly
  1098. * gen_main_procsym changed to create_main_proc and release_main_proc
  1099. to also generate a tprocinfo structure
  1100. * fixed unit implicit initfinal
  1101. Revision 1.93 2003/04/27 07:29:50 peter
  1102. * current_procdef cleanup, current_procdef is now always nil when parsing
  1103. a new procdef declaration
  1104. * aktprocsym removed
  1105. * lexlevel removed, use symtable.symtablelevel instead
  1106. * implicit init/final code uses the normal genentry/genexit
  1107. * funcret state checking updated for new funcret handling
  1108. Revision 1.92 2003/04/26 11:30:59 florian
  1109. * fixed the powerpc to work with the new function result handling
  1110. Revision 1.91 2003/04/25 20:59:34 peter
  1111. * removed funcretn,funcretsym, function result is now in varsym
  1112. and aliases for result and function name are added using absolutesym
  1113. * vs_hidden parameter for funcret passed in parameter
  1114. * vs_hidden fixes
  1115. * writenode changed to printnode and released from extdebug
  1116. * -vp option added to generate a tree.log with the nodetree
  1117. * nicer printnode for statements, callnode
  1118. Revision 1.90 2002/04/25 20:15:40 florian
  1119. * block nodes within expressions shouldn't release the used registers,
  1120. fixed using a flag till the new rg is ready
  1121. Revision 1.89 2003/04/25 08:25:26 daniel
  1122. * Ifdefs around a lot of calls to cleartempgen
  1123. * Fixed registers that are allocated but not freed in several nodes
  1124. * Tweak to register allocator to cause less spills
  1125. * 8-bit registers now interfere with esi,edi and ebp
  1126. Compiler can now compile rtl successfully when using new register
  1127. allocator
  1128. Revision 1.88 2003/03/28 19:16:57 peter
  1129. * generic constructor working for i386
  1130. * remove fixed self register
  1131. * esi added as address register for i386
  1132. Revision 1.87 2003/03/17 18:55:30 peter
  1133. * allow more tokens instead of only semicolon after inherited
  1134. Revision 1.86 2003/02/19 22:00:14 daniel
  1135. * Code generator converted to new register notation
  1136. - Horribily outdated todo.txt removed
  1137. Revision 1.85 2003/01/08 18:43:56 daniel
  1138. * Tregister changed into a record
  1139. Revision 1.84 2003/01/01 21:05:24 peter
  1140. * fixed assembler methods stackpointer optimization that was
  1141. broken after the previous change
  1142. Revision 1.83 2002/12/29 18:59:34 peter
  1143. * fixed parsing of declarations before asm statement
  1144. Revision 1.82 2002/12/27 18:18:56 peter
  1145. * check for else after empty raise statement
  1146. Revision 1.81 2002/11/27 02:37:14 peter
  1147. * case statement inlining added
  1148. * fixed inlining of write()
  1149. * switched statementnode left and right parts so the statements are
  1150. processed in the correct order when getcopy is used. This is
  1151. required for tempnodes
  1152. Revision 1.80 2002/11/25 17:43:22 peter
  1153. * splitted defbase in defutil,symutil,defcmp
  1154. * merged isconvertable and is_equal into compare_defs(_ext)
  1155. * made operator search faster by walking the list only once
  1156. Revision 1.79 2002/11/18 17:31:58 peter
  1157. * pass proccalloption to ret_in_xxx and push_xxx functions
  1158. Revision 1.78 2002/09/07 19:34:08 florian
  1159. + tcg.direction is used now
  1160. Revision 1.77 2002/09/07 15:25:07 peter
  1161. * old logs removed and tabs fixed
  1162. Revision 1.76 2002/09/07 12:16:03 carl
  1163. * second part bug report 1996 fix, testrange in cordconstnode
  1164. only called if option is set (also make parsing a tiny faster)
  1165. Revision 1.75 2002/09/02 18:40:52 peter
  1166. * fixed parsing of register names with lowercase
  1167. Revision 1.74 2002/09/01 14:43:12 peter
  1168. * fixed direct assembler for i386
  1169. Revision 1.73 2002/08/25 19:25:20 peter
  1170. * sym.insert_in_data removed
  1171. * symtable.insertvardata/insertconstdata added
  1172. * removed insert_in_data call from symtable.insert, it needs to be
  1173. called separatly. This allows to deref the address calculation
  1174. * procedures now calculate the parast addresses after the procedure
  1175. directives are parsed. This fixes the cdecl parast problem
  1176. * push_addr_param has an extra argument that specifies if cdecl is used
  1177. or not
  1178. Revision 1.72 2002/08/17 09:23:40 florian
  1179. * first part of procinfo rewrite
  1180. Revision 1.71 2002/08/16 14:24:58 carl
  1181. * issameref() to test if two references are the same (then emit no opcodes)
  1182. + ret_in_reg to replace ret_in_acc
  1183. (fix some register allocation bugs at the same time)
  1184. + save_std_register now has an extra parameter which is the
  1185. usedinproc registers
  1186. Revision 1.70 2002/08/11 14:32:27 peter
  1187. * renamed current_library to objectlibrary
  1188. Revision 1.69 2002/08/11 13:24:12 peter
  1189. * saving of asmsymbols in ppu supported
  1190. * asmsymbollist global is removed and moved into a new class
  1191. tasmlibrarydata that will hold the info of a .a file which
  1192. corresponds with a single module. Added librarydata to tmodule
  1193. to keep the library info stored for the module. In the future the
  1194. objectfiles will also be stored to the tasmlibrarydata class
  1195. * all getlabel/newasmsymbol and friends are moved to the new class
  1196. Revision 1.68 2002/08/10 14:46:30 carl
  1197. + moved target_cpu_string to cpuinfo
  1198. * renamed asmmode enum.
  1199. * assembler reader has now less ifdef's
  1200. * move from nppcmem.pas -> ncgmem.pas vec. node.
  1201. Revision 1.67 2002/08/09 19:11:44 carl
  1202. + reading of used registers in assembler routines is now
  1203. cpu-independent
  1204. Revision 1.66 2002/08/06 20:55:22 florian
  1205. * first part of ppc calling conventions fix
  1206. Revision 1.65 2002/07/28 20:45:22 florian
  1207. + added direct assembler reader for PowerPC
  1208. Revision 1.64 2002/07/20 11:57:56 florian
  1209. * types.pas renamed to defbase.pas because D6 contains a types
  1210. unit so this would conflicts if D6 programms are compiled
  1211. + Willamette/SSE2 instructions to assembler added
  1212. Revision 1.63 2002/07/19 11:41:36 daniel
  1213. * State tracker work
  1214. * The whilen and repeatn are now completely unified into whilerepeatn. This
  1215. allows the state tracker to change while nodes automatically into
  1216. repeat nodes.
  1217. * Resulttypepass improvements to the notn. 'not not a' is optimized away and
  1218. 'not(a>b)' is optimized into 'a<=b'.
  1219. * Resulttypepass improvements to the whilerepeatn. 'while not a' is optimized
  1220. by removing the notn and later switchting the true and falselabels. The
  1221. same is done with 'repeat until not a'.
  1222. Revision 1.62 2002/07/16 15:34:20 florian
  1223. * exit is now a syssym instead of a keyword
  1224. Revision 1.61 2002/07/11 14:41:28 florian
  1225. * start of the new generic parameter handling
  1226. Revision 1.60 2002/07/04 20:43:01 florian
  1227. * first x86-64 patches
  1228. Revision 1.59 2002/07/01 18:46:25 peter
  1229. * internal linker
  1230. * reorganized aasm layer
  1231. Revision 1.58 2002/05/18 13:34:13 peter
  1232. * readded missing revisions
  1233. Revision 1.57 2002/05/16 19:46:44 carl
  1234. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  1235. + try to fix temp allocation (still in ifdef)
  1236. + generic constructor calls
  1237. + start of tassembler / tmodulebase class cleanup
  1238. }