pstatmnt.pas 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Does the parsing of the statements
  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 pstatmnt;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. tokens,node;
  22. function statement_block(starttoken : ttoken) : tnode;
  23. { reads an assembler block }
  24. function assembler_block : tnode;
  25. implementation
  26. uses
  27. { common }
  28. cutils,cclasses,
  29. { global }
  30. globtype,globals,verbose,constexp,
  31. systems,
  32. { aasm }
  33. cpubase,aasmbase,aasmtai,aasmdata,
  34. { symtable }
  35. symconst,symbase,symtype,symdef,symsym,symtable,defutil,defcmp,
  36. paramgr,symutil,
  37. { pass 1 }
  38. pass_1,htypechk,
  39. nutils,nbas,nmat,nadd,ncal,nmem,nset,ncnv,ninl,ncon,nld,nflw,
  40. { parser }
  41. scanner,
  42. pbase,pexpr,
  43. { codegen }
  44. procinfo,cgbase,
  45. { assembler reader }
  46. rabase
  47. ;
  48. function statement : tnode;forward;
  49. function if_statement : tnode;
  50. var
  51. ex,if_a,else_a : tnode;
  52. begin
  53. consume(_IF);
  54. ex:=comp_expr(true);
  55. consume(_THEN);
  56. if token<>_ELSE then
  57. if_a:=statement
  58. else
  59. if_a:=nil;
  60. if try_to_consume(_ELSE) then
  61. else_a:=statement
  62. else
  63. else_a:=nil;
  64. result:=cifnode.create(ex,if_a,else_a);
  65. end;
  66. { creates a block (list) of statements, til the next END token }
  67. function statements_til_end : tnode;
  68. var
  69. first,last : tstatementnode;
  70. begin
  71. first:=nil;
  72. while token<>_END do
  73. begin
  74. if first=nil then
  75. begin
  76. last:=cstatementnode.create(statement,nil);
  77. first:=last;
  78. end
  79. else
  80. begin
  81. last.right:=cstatementnode.create(statement,nil);
  82. last:=tstatementnode(last.right);
  83. end;
  84. if not try_to_consume(_SEMICOLON) then
  85. break;
  86. consume_emptystats;
  87. end;
  88. consume(_END);
  89. statements_til_end:=cblocknode.create(first);
  90. end;
  91. function case_statement : tnode;
  92. var
  93. casedef : tdef;
  94. caseexpr,p : tnode;
  95. blockid : longint;
  96. hl1,hl2 : TConstExprInt;
  97. casedeferror : boolean;
  98. casenode : tcasenode;
  99. begin
  100. consume(_CASE);
  101. caseexpr:=comp_expr(true);
  102. { determines result type }
  103. do_typecheckpass(caseexpr);
  104. { variants must be accepted, but first they must be converted to integer }
  105. if caseexpr.resultdef.typ=variantdef then
  106. begin
  107. caseexpr:=ctypeconvnode.create_internal(caseexpr,sinttype);
  108. do_typecheckpass(caseexpr);
  109. end;
  110. set_varstate(caseexpr,vs_read,[vsf_must_be_valid]);
  111. casedeferror:=false;
  112. casedef:=caseexpr.resultdef;
  113. if (not assigned(casedef)) or
  114. not(is_ordinal(casedef)) then
  115. begin
  116. CGMessage(type_e_ordinal_expr_expected);
  117. { create a correct tree }
  118. caseexpr.free;
  119. caseexpr:=cordconstnode.create(0,u32inttype,false);
  120. { set error flag so no rangechecks are done }
  121. casedeferror:=true;
  122. end;
  123. { Create casenode }
  124. casenode:=ccasenode.create(caseexpr);
  125. consume(_OF);
  126. { Parse all case blocks }
  127. blockid:=0;
  128. repeat
  129. { maybe an instruction has more case labels }
  130. repeat
  131. p:=expr;
  132. if is_widechar(casedef) then
  133. begin
  134. if (p.nodetype=rangen) then
  135. begin
  136. trangenode(p).left:=ctypeconvnode.create(trangenode(p).left,cwidechartype);
  137. trangenode(p).right:=ctypeconvnode.create(trangenode(p).right,cwidechartype);
  138. do_typecheckpass(trangenode(p).left);
  139. do_typecheckpass(trangenode(p).right);
  140. end
  141. else
  142. begin
  143. p:=ctypeconvnode.create(p,cwidechartype);
  144. do_typecheckpass(p);
  145. end;
  146. end;
  147. hl1:=0;
  148. hl2:=0;
  149. if (p.nodetype=rangen) then
  150. begin
  151. { type checking for case statements }
  152. if is_subequal(casedef, trangenode(p).left.resultdef) and
  153. is_subequal(casedef, trangenode(p).right.resultdef) then
  154. begin
  155. hl1:=get_ordinal_value(trangenode(p).left);
  156. hl2:=get_ordinal_value(trangenode(p).right);
  157. if hl1>hl2 then
  158. CGMessage(parser_e_case_lower_less_than_upper_bound);
  159. if not casedeferror then
  160. begin
  161. testrange(casedef,hl1,false);
  162. testrange(casedef,hl2,false);
  163. end;
  164. end
  165. else
  166. CGMessage(parser_e_case_mismatch);
  167. casenode.addlabel(blockid,hl1,hl2);
  168. end
  169. else
  170. begin
  171. { type checking for case statements }
  172. if not is_subequal(casedef, p.resultdef) then
  173. CGMessage(parser_e_case_mismatch);
  174. hl1:=get_ordinal_value(p);
  175. if not casedeferror then
  176. testrange(casedef,hl1,false);
  177. casenode.addlabel(blockid,hl1,hl1);
  178. end;
  179. p.free;
  180. if token=_COMMA then
  181. consume(_COMMA)
  182. else
  183. break;
  184. until false;
  185. consume(_COLON);
  186. { add instruction block }
  187. casenode.addblock(blockid,statement);
  188. { next block }
  189. inc(blockid);
  190. if not(token in [_ELSE,_OTHERWISE,_END]) then
  191. consume(_SEMICOLON);
  192. until (token in [_ELSE,_OTHERWISE,_END]);
  193. if (token in [_ELSE,_OTHERWISE]) then
  194. begin
  195. if not try_to_consume(_ELSE) then
  196. consume(_OTHERWISE);
  197. casenode.addelseblock(statements_til_end);
  198. end
  199. else
  200. consume(_END);
  201. result:=casenode;
  202. end;
  203. function repeat_statement : tnode;
  204. var
  205. first,last,p_e : tnode;
  206. begin
  207. consume(_REPEAT);
  208. first:=nil;
  209. while token<>_UNTIL do
  210. begin
  211. if first=nil then
  212. begin
  213. last:=cstatementnode.create(statement,nil);
  214. first:=last;
  215. end
  216. else
  217. begin
  218. tstatementnode(last).right:=cstatementnode.create(statement,nil);
  219. last:=tstatementnode(last).right;
  220. end;
  221. if not try_to_consume(_SEMICOLON) then
  222. break;
  223. consume_emptystats;
  224. end;
  225. consume(_UNTIL);
  226. first:=cblocknode.create(first);
  227. p_e:=comp_expr(true);
  228. result:=cwhilerepeatnode.create(p_e,first,false,true);
  229. end;
  230. function while_statement : tnode;
  231. var
  232. p_e,p_a : tnode;
  233. begin
  234. consume(_WHILE);
  235. p_e:=comp_expr(true);
  236. consume(_DO);
  237. p_a:=statement;
  238. result:=cwhilerepeatnode.create(p_e,p_a,true,false);
  239. end;
  240. function for_statement : tnode;
  241. procedure check_range(hp:tnode);
  242. begin
  243. {$ifndef cpu64bitaddr}
  244. if hp.nodetype=ordconstn then
  245. begin
  246. if (tordconstnode(hp).value<int64(low(longint))) or
  247. (tordconstnode(hp).value>high(longint)) then
  248. begin
  249. CGMessage(parser_e_range_check_error);
  250. { recover, prevent more warnings/errors }
  251. tordconstnode(hp).value:=0;
  252. end;
  253. end;
  254. {$endif not cpu64bitaddr}
  255. end;
  256. function for_loop_create(hloopvar: tnode): tnode;
  257. var
  258. hp,
  259. hblock,
  260. hto,hfrom : tnode;
  261. backward : boolean;
  262. loopvarsym : tabstractvarsym;
  263. begin
  264. { Check loop variable }
  265. loopvarsym:=nil;
  266. { variable must be an ordinal, int64 is not allowed for 32bit targets }
  267. if not(is_ordinal(hloopvar.resultdef))
  268. {$ifndef cpu64bitaddr}
  269. or is_64bitint(hloopvar.resultdef)
  270. {$endif not cpu64bitaddr}
  271. then
  272. MessagePos(hloopvar.fileinfo,type_e_ordinal_expr_expected);
  273. hp:=hloopvar;
  274. while assigned(hp) and
  275. (
  276. { record/object fields and array elements are allowed }
  277. { in tp7 mode only }
  278. (
  279. (m_tp7 in current_settings.modeswitches) and
  280. (
  281. ((hp.nodetype=subscriptn) and
  282. ((tsubscriptnode(hp).left.resultdef.typ=recorddef) or
  283. is_object(tsubscriptnode(hp).left.resultdef))
  284. ) or
  285. { constant array index }
  286. (
  287. (hp.nodetype=vecn) and
  288. is_constintnode(tvecnode(hp).right)
  289. )
  290. )
  291. ) or
  292. { equal typeconversions }
  293. (
  294. (hp.nodetype=typeconvn) and
  295. (ttypeconvnode(hp).convtype=tc_equal)
  296. )
  297. ) do
  298. begin
  299. { Use the recordfield for loopvarsym }
  300. if not assigned(loopvarsym) and
  301. (hp.nodetype=subscriptn) then
  302. loopvarsym:=tsubscriptnode(hp).vs;
  303. hp:=tunarynode(hp).left;
  304. end;
  305. if assigned(hp) and
  306. (hp.nodetype=loadn) then
  307. begin
  308. case tloadnode(hp).symtableentry.typ of
  309. staticvarsym,
  310. localvarsym,
  311. paravarsym :
  312. begin
  313. { we need a simple loadn:
  314. 1. The load must be in a global symtable or
  315. in the same level as the para of the current proc.
  316. 2. value variables (no const,out or var)
  317. 3. No threadvar, readonly or typedconst
  318. }
  319. if (
  320. (tloadnode(hp).symtable.symtablelevel=main_program_level) or
  321. (tloadnode(hp).symtable.symtablelevel=current_procinfo.procdef.parast.symtablelevel)
  322. ) and
  323. (tabstractvarsym(tloadnode(hp).symtableentry).varspez=vs_value) and
  324. ([vo_is_thread_var,vo_is_typed_const] * tabstractvarsym(tloadnode(hp).symtableentry).varoptions=[]) then
  325. begin
  326. { Assigning for-loop variable is only allowed in tp7 and macpas }
  327. if ([m_tp7,m_mac] * current_settings.modeswitches = []) then
  328. begin
  329. if not assigned(loopvarsym) then
  330. loopvarsym:=tabstractvarsym(tloadnode(hp).symtableentry);
  331. include(loopvarsym.varoptions,vo_is_loop_counter);
  332. end;
  333. end
  334. else
  335. begin
  336. { Typed const is allowed in tp7 }
  337. if not(m_tp7 in current_settings.modeswitches) or
  338. not(vo_is_typed_const in tabstractvarsym(tloadnode(hp).symtableentry).varoptions) then
  339. MessagePos(hp.fileinfo,type_e_illegal_count_var);
  340. end;
  341. end;
  342. else
  343. MessagePos(hp.fileinfo,type_e_illegal_count_var);
  344. end;
  345. end
  346. else
  347. MessagePos(hloopvar.fileinfo,type_e_illegal_count_var);
  348. hfrom:=comp_expr(true);
  349. if try_to_consume(_DOWNTO) then
  350. backward:=true
  351. else
  352. begin
  353. consume(_TO);
  354. backward:=false;
  355. end;
  356. hto:=comp_expr(true);
  357. consume(_DO);
  358. { Check if the constants fit in the range }
  359. check_range(hfrom);
  360. check_range(hto);
  361. { first set the varstate for from and to, so
  362. uses of loopvar in those expressions will also
  363. trigger a warning when it is not used yet. This
  364. needs to be done before the instruction block is
  365. parsed to have a valid hloopvar }
  366. typecheckpass(hfrom);
  367. set_varstate(hfrom,vs_read,[vsf_must_be_valid]);
  368. typecheckpass(hto);
  369. set_varstate(hto,vs_read,[vsf_must_be_valid]);
  370. typecheckpass(hloopvar);
  371. { in two steps, because vs_readwritten may turn on vsf_must_be_valid }
  372. { for some subnodes }
  373. set_varstate(hloopvar,vs_written,[]);
  374. set_varstate(hloopvar,vs_read,[vsf_must_be_valid]);
  375. { ... now the instruction block }
  376. hblock:=statement;
  377. { variable is not used for loop counter anymore }
  378. if assigned(loopvarsym) then
  379. exclude(loopvarsym.varoptions,vo_is_loop_counter);
  380. result:=cfornode.create(hloopvar,hfrom,hto,hblock,backward);
  381. end;
  382. function for_in_loop_create(hloopvar: tnode): tnode;
  383. var
  384. expr: tnode;
  385. begin
  386. expr := comp_expr(true);
  387. consume(_DO);
  388. set_varstate(hloopvar,vs_written,[]);
  389. set_varstate(hloopvar,vs_read,[vsf_must_be_valid]);
  390. result := create_for_in_loop(hloopvar, statement, expr);
  391. expr.free;
  392. end;
  393. var
  394. hloopvar: tnode;
  395. begin
  396. { parse loop header }
  397. consume(_FOR);
  398. hloopvar:=factor(false);
  399. valid_for_loopvar(hloopvar,true);
  400. if try_to_consume(_ASSIGNMENT) then
  401. result:=for_loop_create(hloopvar)
  402. else
  403. if try_to_consume(_IN) then
  404. result:=for_in_loop_create(hloopvar)
  405. else
  406. consume(_ASSIGNMENT); // fail
  407. end;
  408. function _with_statement : tnode;
  409. var
  410. p : tnode;
  411. i : longint;
  412. st : TSymtable;
  413. newblock : tblocknode;
  414. newstatement : tstatementnode;
  415. calltempnode,
  416. tempnode : ttempcreatenode;
  417. valuenode,
  418. hp,
  419. refnode : tnode;
  420. hdef : tdef;
  421. hasimplicitderef : boolean;
  422. withsymtablelist : TFPObjectList;
  423. procedure pushobjchild(withdef,obj:tobjectdef);
  424. begin
  425. if not assigned(obj) then
  426. exit;
  427. pushobjchild(withdef,obj.childof);
  428. { keep the original tobjectdef as owner, because that is used for
  429. visibility of the symtable }
  430. st:=twithsymtable.create(withdef,obj.symtable.SymList,refnode.getcopy);
  431. symtablestack.push(st);
  432. withsymtablelist.add(st);
  433. end;
  434. begin
  435. p:=comp_expr(true);
  436. do_typecheckpass(p);
  437. if (p.nodetype=vecn) and
  438. (nf_memseg in p.flags) then
  439. CGMessage(parser_e_no_with_for_variable_in_other_segments);
  440. { "with procvar" can never mean anything, so always try
  441. to call it in case it returns a record/object/... }
  442. maybe_call_procvar(p,false);
  443. if (p.resultdef.typ in [objectdef,recorddef,classrefdef]) then
  444. begin
  445. newblock:=nil;
  446. valuenode:=nil;
  447. tempnode:=nil;
  448. { ignore nodes that don't add instructions in the tree }
  449. hp:=p;
  450. while { equal type conversions }
  451. (
  452. (hp.nodetype=typeconvn) and
  453. (ttypeconvnode(hp).convtype=tc_equal)
  454. ) or
  455. { constant array index }
  456. (
  457. (hp.nodetype=vecn) and
  458. (tvecnode(hp).right.nodetype=ordconstn)
  459. ) do
  460. hp:=tunarynode(hp).left;
  461. if (hp.nodetype=loadn) and
  462. (
  463. (tloadnode(hp).symtable=current_procinfo.procdef.localst) or
  464. (tloadnode(hp).symtable=current_procinfo.procdef.parast) or
  465. (tloadnode(hp).symtable.symtabletype in [staticsymtable,globalsymtable])
  466. ) and
  467. { MacPas objects are mapped to classes, and the MacPas compilers
  468. interpret with-statements with MacPas objects the same way
  469. as records (the object referenced by the with-statement
  470. must remain constant)
  471. }
  472. not(is_class(hp.resultdef) and
  473. (m_mac in current_settings.modeswitches)) then
  474. begin
  475. { simple load, we can reference direct }
  476. refnode:=p;
  477. end
  478. else
  479. begin
  480. calltempnode:=nil;
  481. { complex load, load in temp first }
  482. newblock:=internalstatements(newstatement);
  483. { when we can't take the address of p, load it in a temp }
  484. { since we may need its address later on }
  485. if not valid_for_addr(p,false) then
  486. begin
  487. calltempnode:=ctempcreatenode.create(p.resultdef,p.resultdef.size,tt_persistent,true);
  488. addstatement(newstatement,calltempnode);
  489. addstatement(newstatement,cassignmentnode.create(
  490. ctemprefnode.create(calltempnode),
  491. p));
  492. p:=ctemprefnode.create(calltempnode);
  493. typecheckpass(p);
  494. end;
  495. { classes and interfaces have implicit dereferencing }
  496. hasimplicitderef:=is_class_or_interface(p.resultdef) or
  497. (p.resultdef.typ = classrefdef);
  498. if hasimplicitderef then
  499. hdef:=p.resultdef
  500. else
  501. hdef:=tpointerdef.create(p.resultdef);
  502. { load address of the value in a temp }
  503. tempnode:=ctempcreatenode.create_withnode(hdef,sizeof(pint),tt_persistent,true,p);
  504. typecheckpass(tempnode);
  505. valuenode:=p;
  506. refnode:=ctemprefnode.create(tempnode);
  507. fillchar(refnode.fileinfo,sizeof(tfileposinfo),0);
  508. { add address call for valuenode and deref for refnode if this
  509. is not done implicitly }
  510. if not hasimplicitderef then
  511. begin
  512. valuenode:=caddrnode.create_internal_nomark(valuenode);
  513. refnode:=cderefnode.create(refnode);
  514. fillchar(refnode.fileinfo,sizeof(tfileposinfo),0);
  515. end;
  516. addstatement(newstatement,tempnode);
  517. addstatement(newstatement,cassignmentnode.create(
  518. ctemprefnode.create(tempnode),
  519. valuenode));
  520. typecheckpass(refnode);
  521. end;
  522. withsymtablelist:=TFPObjectList.create(true);
  523. case p.resultdef.typ of
  524. objectdef :
  525. begin
  526. { push symtables of all parents in reverse order }
  527. pushobjchild(tobjectdef(p.resultdef),tobjectdef(p.resultdef).childof);
  528. { push object symtable }
  529. st:=twithsymtable.Create(tobjectdef(p.resultdef),tobjectdef(p.resultdef).symtable.SymList,refnode);
  530. symtablestack.push(st);
  531. withsymtablelist.add(st);
  532. end;
  533. classrefdef :
  534. begin
  535. { push symtables of all parents in reverse order }
  536. pushobjchild(tobjectdef(tclassrefdef(p.resultdef).pointeddef),tobjectdef(tclassrefdef(p.resultdef).pointeddef).childof);
  537. { push object symtable }
  538. st:=twithsymtable.Create(tobjectdef(tclassrefdef(p.resultdef).pointeddef),tobjectdef(tclassrefdef(p.resultdef).pointeddef).symtable.SymList,refnode);
  539. symtablestack.push(st);
  540. withsymtablelist.add(st);
  541. end;
  542. recorddef :
  543. begin
  544. st:=twithsymtable.create(trecorddef(p.resultdef),trecorddef(p.resultdef).symtable.SymList,refnode);
  545. symtablestack.push(st);
  546. withsymtablelist.add(st);
  547. end;
  548. else
  549. internalerror(200601271);
  550. end;
  551. if try_to_consume(_COMMA) then
  552. p:=_with_statement()
  553. else
  554. begin
  555. consume(_DO);
  556. if token<>_SEMICOLON then
  557. p:=statement
  558. else
  559. p:=cnothingnode.create;
  560. end;
  561. { remove symtables in reverse order from the stack }
  562. for i:=withsymtablelist.count-1 downto 0 do
  563. symtablestack.pop(TSymtable(withsymtablelist[i]));
  564. withsymtablelist.free;
  565. // p:=cwithnode.create(right,twithsymtable(withsymtable),levelcount,refnode);
  566. { Finalize complex withnode with destroy of temp }
  567. if assigned(newblock) then
  568. begin
  569. addstatement(newstatement,p);
  570. if assigned(tempnode) then
  571. addstatement(newstatement,ctempdeletenode.create(tempnode));
  572. if assigned(calltempnode) then
  573. addstatement(newstatement,ctempdeletenode.create(calltempnode));
  574. p:=newblock;
  575. end;
  576. result:=p;
  577. end
  578. else
  579. begin
  580. p.free;
  581. Message(parser_e_false_with_expr);
  582. { try to recover from error }
  583. if try_to_consume(_COMMA) then
  584. begin
  585. hp:=_with_statement();
  586. if (hp=nil) then; { remove warning about unused }
  587. end
  588. else
  589. begin
  590. consume(_DO);
  591. { ignore all }
  592. if token<>_SEMICOLON then
  593. statement;
  594. end;
  595. result:=nil;
  596. end;
  597. end;
  598. function with_statement : tnode;
  599. begin
  600. consume(_WITH);
  601. with_statement:=_with_statement();
  602. end;
  603. function raise_statement : tnode;
  604. var
  605. p,pobj,paddr,pframe : tnode;
  606. begin
  607. pobj:=nil;
  608. paddr:=nil;
  609. pframe:=nil;
  610. consume(_RAISE);
  611. if not(token in endtokens) then
  612. begin
  613. { object }
  614. pobj:=comp_expr(true);
  615. if try_to_consume(_AT) then
  616. begin
  617. paddr:=comp_expr(true);
  618. if try_to_consume(_COMMA) then
  619. pframe:=comp_expr(true);
  620. end;
  621. end
  622. else
  623. begin
  624. if (block_type<>bt_except) then
  625. Message(parser_e_no_reraise_possible);
  626. end;
  627. p:=craisenode.create(pobj,paddr,pframe);
  628. raise_statement:=p;
  629. end;
  630. function try_statement : tnode;
  631. var
  632. p_try_block,p_finally_block,first,last,
  633. p_default,p_specific,hp : tnode;
  634. ot : tDef;
  635. sym : tlocalvarsym;
  636. old_block_type : tblock_type;
  637. excepTSymtable : TSymtable;
  638. objname,objrealname : TIDString;
  639. srsym : tsym;
  640. srsymtable : TSymtable;
  641. oldcurrent_exceptblock: integer;
  642. begin
  643. include(current_procinfo.flags,pi_uses_exceptions);
  644. p_default:=nil;
  645. p_specific:=nil;
  646. { read statements to try }
  647. consume(_TRY);
  648. first:=nil;
  649. inc(exceptblockcounter);
  650. oldcurrent_exceptblock := current_exceptblock;
  651. current_exceptblock := exceptblockcounter;
  652. while (token<>_FINALLY) and (token<>_EXCEPT) do
  653. begin
  654. if first=nil then
  655. begin
  656. last:=cstatementnode.create(statement,nil);
  657. first:=last;
  658. end
  659. else
  660. begin
  661. tstatementnode(last).right:=cstatementnode.create(statement,nil);
  662. last:=tstatementnode(last).right;
  663. end;
  664. if not try_to_consume(_SEMICOLON) then
  665. break;
  666. consume_emptystats;
  667. end;
  668. p_try_block:=cblocknode.create(first);
  669. if try_to_consume(_FINALLY) then
  670. begin
  671. inc(exceptblockcounter);
  672. current_exceptblock := exceptblockcounter;
  673. p_finally_block:=statements_til_end;
  674. try_statement:=ctryfinallynode.create(p_try_block,p_finally_block);
  675. end
  676. else
  677. begin
  678. consume(_EXCEPT);
  679. old_block_type:=block_type;
  680. block_type:=bt_except;
  681. inc(exceptblockcounter);
  682. current_exceptblock := exceptblockcounter;
  683. ot:=generrordef;
  684. p_specific:=nil;
  685. if (idtoken=_ON) then
  686. { catch specific exceptions }
  687. begin
  688. repeat
  689. consume(_ON);
  690. if token=_ID then
  691. begin
  692. objname:=pattern;
  693. objrealname:=orgpattern;
  694. { can't use consume_sym here, because we need already
  695. to check for the colon }
  696. searchsym(objname,srsym,srsymtable);
  697. consume(_ID);
  698. { is a explicit name for the exception given ? }
  699. if try_to_consume(_COLON) then
  700. begin
  701. consume_sym(srsym,srsymtable);
  702. if (srsym.typ=typesym) and
  703. is_class(ttypesym(srsym).typedef) then
  704. begin
  705. ot:=ttypesym(srsym).typedef;
  706. sym:=tlocalvarsym.create(objrealname,vs_value,ot,[]);
  707. end
  708. else
  709. begin
  710. sym:=tlocalvarsym.create(objrealname,vs_value,generrordef,[]);
  711. if (srsym.typ=typesym) then
  712. Message1(type_e_class_type_expected,ttypesym(srsym).typedef.typename)
  713. else
  714. Message1(type_e_class_type_expected,ot.typename);
  715. end;
  716. excepTSymtable:=tstt_excepTSymtable.create;
  717. excepTSymtable.insert(sym);
  718. symtablestack.push(excepTSymtable);
  719. end
  720. else
  721. begin
  722. { check if type is valid, must be done here because
  723. with "e: Exception" the e is not necessary }
  724. if srsym=nil then
  725. begin
  726. identifier_not_found(objrealname);
  727. srsym:=generrorsym;
  728. end;
  729. { support unit.identifier }
  730. if srsym.typ=unitsym then
  731. begin
  732. consume(_POINT);
  733. searchsym_in_module(tunitsym(srsym).module,pattern,srsym,srsymtable);
  734. if srsym=nil then
  735. begin
  736. identifier_not_found(orgpattern);
  737. srsym:=generrorsym;
  738. end;
  739. consume(_ID);
  740. end;
  741. { check if type is valid, must be done here because
  742. with "e: Exception" the e is not necessary }
  743. if (srsym.typ=typesym) and
  744. is_class(ttypesym(srsym).typedef) then
  745. ot:=ttypesym(srsym).typedef
  746. else
  747. begin
  748. ot:=generrordef;
  749. if (srsym.typ=typesym) then
  750. Message1(type_e_class_type_expected,ttypesym(srsym).typedef.typename)
  751. else
  752. Message1(type_e_class_type_expected,ot.typename);
  753. end;
  754. excepTSymtable:=nil;
  755. end;
  756. end
  757. else
  758. consume(_ID);
  759. consume(_DO);
  760. hp:=connode.create(nil,statement);
  761. if ot.typ=errordef then
  762. begin
  763. hp.free;
  764. hp:=cerrornode.create;
  765. end;
  766. if p_specific=nil then
  767. begin
  768. last:=hp;
  769. p_specific:=last;
  770. end
  771. else
  772. begin
  773. tonnode(last).left:=hp;
  774. last:=tonnode(last).left;
  775. end;
  776. { set the informations }
  777. { only if the creation of the onnode was succesful, it's possible }
  778. { that last and hp are errornodes (JM) }
  779. if last.nodetype = onn then
  780. begin
  781. tonnode(last).excepttype:=tobjectdef(ot);
  782. tonnode(last).excepTSymtable:=excepTSymtable;
  783. end;
  784. { remove exception symtable }
  785. if assigned(excepTSymtable) then
  786. begin
  787. symtablestack.pop(excepTSymtable);
  788. if last.nodetype <> onn then
  789. excepTSymtable.free;
  790. end;
  791. if not try_to_consume(_SEMICOLON) then
  792. break;
  793. consume_emptystats;
  794. until (token in [_END,_ELSE]);
  795. if try_to_consume(_ELSE) then
  796. begin
  797. { catch the other exceptions }
  798. p_default:=statements_til_end;
  799. end
  800. else
  801. consume(_END);
  802. end
  803. else
  804. begin
  805. { catch all exceptions }
  806. p_default:=statements_til_end;
  807. end;
  808. block_type:=old_block_type;
  809. try_statement:=ctryexceptnode.create(p_try_block,p_specific,p_default);
  810. end;
  811. current_exceptblock := oldcurrent_exceptblock;
  812. end;
  813. function _asm_statement : tnode;
  814. var
  815. asmstat : tasmnode;
  816. Marker : tai;
  817. reg : tregister;
  818. asmreader : tbaseasmreader;
  819. begin
  820. Inside_asm_statement:=true;
  821. if assigned(asmmodeinfos[current_settings.asmmode]) then
  822. begin
  823. asmreader:=asmmodeinfos[current_settings.asmmode]^.casmreader.create;
  824. asmstat:=casmnode.create(asmreader.assemble as TAsmList);
  825. asmreader.free;
  826. end
  827. else
  828. Message(parser_f_assembler_reader_not_supported);
  829. { Mark procedure that it has assembler blocks }
  830. include(current_procinfo.flags,pi_has_assembler_block);
  831. { Read first the _ASM statement }
  832. consume(_ASM);
  833. { END is read, got a list of changed registers? }
  834. if try_to_consume(_LECKKLAMMER) then
  835. begin
  836. {$ifdef cpunofpu}
  837. asmstat.used_regs_fpu:=[0..first_int_imreg-1];
  838. {$else cpunofpu}
  839. asmstat.used_regs_fpu:=[0..first_fpu_imreg-1];
  840. {$endif cpunofpu}
  841. if token<>_RECKKLAMMER then
  842. begin
  843. if po_assembler in current_procinfo.procdef.procoptions then
  844. Message(parser_w_register_list_ignored);
  845. repeat
  846. { it's possible to specify the modified registers }
  847. reg:=std_regnum_search(lower(pattern));
  848. if reg<>NR_NO then
  849. begin
  850. if (getregtype(reg)=R_INTREGISTER) and not(po_assembler in current_procinfo.procdef.procoptions) then
  851. include(asmstat.used_regs_int,getsupreg(reg));
  852. end
  853. else
  854. Message(asmr_e_invalid_register);
  855. consume(_CSTRING);
  856. if not try_to_consume(_COMMA) then
  857. break;
  858. until false;
  859. end;
  860. consume(_RECKKLAMMER);
  861. end
  862. else
  863. begin
  864. asmstat.used_regs_int:=paramanager.get_volatile_registers_int(current_procinfo.procdef.proccalloption);
  865. asmstat.used_regs_fpu:=paramanager.get_volatile_registers_fpu(current_procinfo.procdef.proccalloption);
  866. end;
  867. { mark the start and the end of the assembler block
  868. this is needed for the optimizer }
  869. If Assigned(AsmStat.p_asm) Then
  870. Begin
  871. Marker := Tai_Marker.Create(mark_AsmBlockStart);
  872. AsmStat.p_asm.Insert(Marker);
  873. Marker := Tai_Marker.Create(mark_AsmBlockEnd);
  874. AsmStat.p_asm.Concat(Marker);
  875. End;
  876. Inside_asm_statement:=false;
  877. _asm_statement:=asmstat;
  878. end;
  879. function statement : tnode;
  880. var
  881. p : tnode;
  882. code : tnode;
  883. filepos : tfileposinfo;
  884. srsym : tsym;
  885. srsymtable : TSymtable;
  886. s : TIDString;
  887. begin
  888. filepos:=current_tokenpos;
  889. case token of
  890. _GOTO :
  891. begin
  892. if not(cs_support_goto in current_settings.moduleswitches)then
  893. Message(sym_e_goto_and_label_not_supported);
  894. consume(_GOTO);
  895. if (token<>_INTCONST) and (token<>_ID) then
  896. begin
  897. Message(sym_e_label_not_found);
  898. code:=cerrornode.create;
  899. end
  900. else
  901. begin
  902. if token=_ID then
  903. consume_sym(srsym,srsymtable)
  904. else
  905. begin
  906. searchsym(pattern,srsym,srsymtable);
  907. if srsym=nil then
  908. begin
  909. identifier_not_found(pattern);
  910. srsym:=generrorsym;
  911. srsymtable:=nil;
  912. end;
  913. consume(token);
  914. end;
  915. if srsym.typ<>labelsym then
  916. begin
  917. Message(sym_e_id_is_no_label_id);
  918. code:=cerrornode.create;
  919. end
  920. else
  921. begin
  922. { goto is only allowed to labels within the current scope }
  923. if srsym.owner<>current_procinfo.procdef.localst then
  924. CGMessage(parser_e_goto_outside_proc);
  925. code:=cgotonode.create(tlabelsym(srsym));
  926. tgotonode(code).labelsym:=tlabelsym(srsym);
  927. { set flag that this label is used }
  928. tlabelsym(srsym).used:=true;
  929. end;
  930. end;
  931. end;
  932. _BEGIN :
  933. code:=statement_block(_BEGIN);
  934. _IF :
  935. code:=if_statement;
  936. _CASE :
  937. code:=case_statement;
  938. _REPEAT :
  939. code:=repeat_statement;
  940. _WHILE :
  941. code:=while_statement;
  942. _FOR :
  943. code:=for_statement;
  944. _WITH :
  945. code:=with_statement;
  946. _TRY :
  947. code:=try_statement;
  948. _RAISE :
  949. code:=raise_statement;
  950. { semicolons,else until and end are ignored }
  951. _SEMICOLON,
  952. _ELSE,
  953. _UNTIL,
  954. _END:
  955. code:=cnothingnode.create;
  956. _FAIL :
  957. begin
  958. if (current_procinfo.procdef.proctypeoption<>potype_constructor) then
  959. Message(parser_e_fail_only_in_constructor);
  960. consume(_FAIL);
  961. code:=call_fail_node;
  962. end;
  963. _ASM :
  964. code:=_asm_statement;
  965. _EOF :
  966. Message(scan_f_end_of_file);
  967. else
  968. begin
  969. p:=expr;
  970. { save the pattern here for latter usage, the label could be "000",
  971. even if we read an expression, the pattern is still valid if it's really
  972. a label (FK)
  973. if you want to mess here, take care of
  974. tests/webtbs/tw3546.pp
  975. }
  976. s:=pattern;
  977. { When a colon follows a intconst then transform it into a label }
  978. if (p.nodetype=ordconstn) and
  979. try_to_consume(_COLON) then
  980. begin
  981. p.free;
  982. searchsym(s,srsym,srsymtable);
  983. if assigned(srsym) and
  984. (srsym.typ=labelsym) then
  985. begin
  986. if tlabelsym(srsym).defined then
  987. Message(sym_e_label_already_defined);
  988. tlabelsym(srsym).defined:=true;
  989. p:=clabelnode.create(nil,tlabelsym(srsym));
  990. tlabelsym(srsym).code:=p;
  991. end
  992. else
  993. begin
  994. Message1(sym_e_label_used_and_not_defined,s);
  995. p:=cnothingnode.create;
  996. end;
  997. end;
  998. if p.nodetype=labeln then
  999. begin
  1000. { the pointer to the following instruction }
  1001. { isn't a very clean way }
  1002. if token in endtokens then
  1003. tlabelnode(p).left:=cnothingnode.create
  1004. else
  1005. tlabelnode(p).left:=statement();
  1006. { be sure to have left also typecheckpass }
  1007. typecheckpass(tlabelnode(p).left);
  1008. end
  1009. else
  1010. { change a load of a procvar to a call. this is also
  1011. supported in fpc mode }
  1012. if p.nodetype in [vecn,derefn,typeconvn,subscriptn,loadn] then
  1013. maybe_call_procvar(p,false);
  1014. { blockn support because a read/write is changed into a blocknode }
  1015. { with a separate statement for each read/write operation (JM) }
  1016. { the same is true for val() if the third parameter is not 32 bit }
  1017. if not(p.nodetype in [nothingn,errorn,calln,ifn,assignn,breakn,inlinen,
  1018. continuen,labeln,blockn,exitn]) or
  1019. ((p.nodetype=inlinen) and
  1020. not is_void(p.resultdef)) then
  1021. Message(parser_e_illegal_expression);
  1022. { Specify that we don't use the value returned by the call.
  1023. This is used for :
  1024. - dispose of temp stack space
  1025. - dispose on FPU stack }
  1026. if (p.nodetype=calln) then
  1027. exclude(tcallnode(p).callnodeflags,cnf_return_value_used);
  1028. code:=p;
  1029. end;
  1030. end;
  1031. if assigned(code) then
  1032. begin
  1033. typecheckpass(code);
  1034. code.fileinfo:=filepos;
  1035. end;
  1036. statement:=code;
  1037. end;
  1038. function statement_block(starttoken : ttoken) : tnode;
  1039. var
  1040. first,last : tnode;
  1041. filepos : tfileposinfo;
  1042. begin
  1043. first:=nil;
  1044. filepos:=current_tokenpos;
  1045. consume(starttoken);
  1046. while not(token in [_END,_FINALIZATION]) do
  1047. begin
  1048. if first=nil then
  1049. begin
  1050. last:=cstatementnode.create(statement,nil);
  1051. first:=last;
  1052. end
  1053. else
  1054. begin
  1055. tstatementnode(last).right:=cstatementnode.create(statement,nil);
  1056. last:=tstatementnode(last).right;
  1057. end;
  1058. if (token in [_END,_FINALIZATION]) then
  1059. break
  1060. else
  1061. begin
  1062. { if no semicolon, then error and go on }
  1063. if token<>_SEMICOLON then
  1064. begin
  1065. consume(_SEMICOLON);
  1066. consume_all_until(_SEMICOLON);
  1067. end;
  1068. consume(_SEMICOLON);
  1069. end;
  1070. consume_emptystats;
  1071. end;
  1072. { don't consume the finalization token, it is consumed when
  1073. reading the finalization block, but allow it only after
  1074. an initalization ! }
  1075. if (starttoken<>_INITIALIZATION) or (token<>_FINALIZATION) then
  1076. consume(_END);
  1077. last:=cblocknode.create(first);
  1078. last.fileinfo:=filepos;
  1079. statement_block:=last;
  1080. end;
  1081. function assembler_block : tnode;
  1082. var
  1083. p : tnode;
  1084. {$ifndef arm}
  1085. locals : longint;
  1086. {$endif arm}
  1087. srsym : tsym;
  1088. begin
  1089. { Rename the funcret so that recursive calls are possible }
  1090. if not is_void(current_procinfo.procdef.returndef) then
  1091. begin
  1092. srsym:=TSym(current_procinfo.procdef.localst.Find(current_procinfo.procdef.procsym.name));
  1093. if assigned(srsym) then
  1094. srsym.realname:='$hiddenresult';
  1095. end;
  1096. { delphi uses register calling for assembler methods }
  1097. if (m_delphi in current_settings.modeswitches) and
  1098. (po_assembler in current_procinfo.procdef.procoptions) and
  1099. not(po_hascallingconvention in current_procinfo.procdef.procoptions) then
  1100. current_procinfo.procdef.proccalloption:=pocall_register;
  1101. { force the asm statement }
  1102. if token<>_ASM then
  1103. consume(_ASM);
  1104. include(current_procinfo.flags,pi_is_assembler);
  1105. p:=_asm_statement;
  1106. {$ifndef sparc}
  1107. {$ifndef arm}
  1108. if (po_assembler in current_procinfo.procdef.procoptions) then
  1109. begin
  1110. { set the framepointer to esp for assembler functions when the
  1111. following conditions are met:
  1112. - if the are no local variables and parameters (except the allocated result)
  1113. - no reference to the result variable (refcount<=1)
  1114. - result is not stored as parameter
  1115. - target processor has optional frame pointer save
  1116. (vm, i386, vm only currently)
  1117. }
  1118. locals:=tabstractlocalsymtable(current_procinfo.procdef.parast).count_locals;
  1119. if (current_procinfo.procdef.localst.symtabletype=localsymtable) then
  1120. inc(locals,tabstractlocalsymtable(current_procinfo.procdef.localst).count_locals);
  1121. if (locals=0) and
  1122. (current_procinfo.procdef.owner.symtabletype<>ObjectSymtable) and
  1123. (not assigned(current_procinfo.procdef.funcretsym) or
  1124. (tabstractvarsym(current_procinfo.procdef.funcretsym).refs<=1)) and
  1125. not(paramanager.ret_in_param(current_procinfo.procdef.returndef,current_procinfo.procdef.proccalloption)) then
  1126. begin
  1127. { Only need to set the framepointer, the locals will
  1128. be inserted with the correct reference in tcgasmnode.pass_generate_code }
  1129. current_procinfo.framepointer:=NR_STACK_POINTER_REG;
  1130. end;
  1131. end;
  1132. {$endif arm}
  1133. {$endif sparc}
  1134. { Flag the result as assigned when it is returned in a
  1135. register.
  1136. }
  1137. if assigned(current_procinfo.procdef.funcretsym) and
  1138. (not paramanager.ret_in_param(current_procinfo.procdef.returndef,current_procinfo.procdef.proccalloption)) then
  1139. tabstractvarsym(current_procinfo.procdef.funcretsym).varstate:=vs_initialised;
  1140. { because the END is already read we need to get the
  1141. last_endtoken_filepos here (PFV) }
  1142. last_endtoken_filepos:=current_tokenpos;
  1143. assembler_block:=p;
  1144. end;
  1145. end.