pstatmnt.pas 46 KB

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