pstatmnt.pas 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262
  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. if (p.resultdef.typ in [objectdef,recorddef,classrefdef]) then
  441. begin
  442. newblock:=nil;
  443. valuenode:=nil;
  444. tempnode:=nil;
  445. { ignore nodes that don't add instructions in the tree }
  446. hp:=p;
  447. while { equal type conversions }
  448. (
  449. (hp.nodetype=typeconvn) and
  450. (ttypeconvnode(hp).convtype=tc_equal)
  451. ) or
  452. { constant array index }
  453. (
  454. (hp.nodetype=vecn) and
  455. (tvecnode(hp).right.nodetype=ordconstn)
  456. ) do
  457. hp:=tunarynode(hp).left;
  458. if (hp.nodetype=loadn) and
  459. (
  460. (tloadnode(hp).symtable=current_procinfo.procdef.localst) or
  461. (tloadnode(hp).symtable=current_procinfo.procdef.parast) or
  462. (tloadnode(hp).symtable.symtabletype in [staticsymtable,globalsymtable])
  463. ) and
  464. { MacPas objects are mapped to classes, and the MacPas compilers
  465. interpret with-statements with MacPas objects the same way
  466. as records (the object referenced by the with-statement
  467. must remain constant)
  468. }
  469. not(is_class(hp.resultdef) and
  470. (m_mac in current_settings.modeswitches)) then
  471. begin
  472. { simple load, we can reference direct }
  473. refnode:=p;
  474. end
  475. else
  476. begin
  477. calltempnode:=nil;
  478. { complex load, load in temp first }
  479. newblock:=internalstatements(newstatement);
  480. { when we can't take the address of p, load it in a temp }
  481. { since we may need its address later on }
  482. if not valid_for_addr(p,false) then
  483. begin
  484. calltempnode:=ctempcreatenode.create(p.resultdef,p.resultdef.size,tt_persistent,true);
  485. addstatement(newstatement,calltempnode);
  486. addstatement(newstatement,cassignmentnode.create(
  487. ctemprefnode.create(calltempnode),
  488. p));
  489. p:=ctemprefnode.create(calltempnode);
  490. typecheckpass(p);
  491. end;
  492. { classes and interfaces have implicit dereferencing }
  493. hasimplicitderef:=is_class_or_interface(p.resultdef) or
  494. (p.resultdef.typ = classrefdef);
  495. if hasimplicitderef then
  496. hdef:=p.resultdef
  497. else
  498. hdef:=tpointerdef.create(p.resultdef);
  499. { load address of the value in a temp }
  500. tempnode:=ctempcreatenode.create_withnode(hdef,sizeof(pint),tt_persistent,true,p);
  501. typecheckpass(tempnode);
  502. valuenode:=p;
  503. refnode:=ctemprefnode.create(tempnode);
  504. fillchar(refnode.fileinfo,sizeof(tfileposinfo),0);
  505. { add address call for valuenode and deref for refnode if this
  506. is not done implicitly }
  507. if not hasimplicitderef then
  508. begin
  509. valuenode:=caddrnode.create_internal_nomark(valuenode);
  510. refnode:=cderefnode.create(refnode);
  511. fillchar(refnode.fileinfo,sizeof(tfileposinfo),0);
  512. end;
  513. addstatement(newstatement,tempnode);
  514. addstatement(newstatement,cassignmentnode.create(
  515. ctemprefnode.create(tempnode),
  516. valuenode));
  517. typecheckpass(refnode);
  518. end;
  519. withsymtablelist:=TFPObjectList.create(true);
  520. case p.resultdef.typ of
  521. objectdef :
  522. begin
  523. { push symtables of all parents in reverse order }
  524. pushobjchild(tobjectdef(p.resultdef),tobjectdef(p.resultdef).childof);
  525. { push object symtable }
  526. st:=twithsymtable.Create(tobjectdef(p.resultdef),tobjectdef(p.resultdef).symtable.SymList,refnode);
  527. symtablestack.push(st);
  528. withsymtablelist.add(st);
  529. end;
  530. classrefdef :
  531. begin
  532. { push symtables of all parents in reverse order }
  533. pushobjchild(tobjectdef(tclassrefdef(p.resultdef).pointeddef),tobjectdef(tclassrefdef(p.resultdef).pointeddef).childof);
  534. { push object symtable }
  535. st:=twithsymtable.Create(tobjectdef(tclassrefdef(p.resultdef).pointeddef),tobjectdef(tclassrefdef(p.resultdef).pointeddef).symtable.SymList,refnode);
  536. symtablestack.push(st);
  537. withsymtablelist.add(st);
  538. end;
  539. recorddef :
  540. begin
  541. st:=twithsymtable.create(trecorddef(p.resultdef),trecorddef(p.resultdef).symtable.SymList,refnode);
  542. symtablestack.push(st);
  543. withsymtablelist.add(st);
  544. end;
  545. else
  546. internalerror(200601271);
  547. end;
  548. if try_to_consume(_COMMA) then
  549. p:=_with_statement()
  550. else
  551. begin
  552. consume(_DO);
  553. if token<>_SEMICOLON then
  554. p:=statement
  555. else
  556. p:=cnothingnode.create;
  557. end;
  558. { remove symtables in reverse order from the stack }
  559. for i:=withsymtablelist.count-1 downto 0 do
  560. symtablestack.pop(TSymtable(withsymtablelist[i]));
  561. withsymtablelist.free;
  562. // p:=cwithnode.create(right,twithsymtable(withsymtable),levelcount,refnode);
  563. { Finalize complex withnode with destroy of temp }
  564. if assigned(newblock) then
  565. begin
  566. addstatement(newstatement,p);
  567. if assigned(tempnode) then
  568. addstatement(newstatement,ctempdeletenode.create(tempnode));
  569. if assigned(calltempnode) then
  570. addstatement(newstatement,ctempdeletenode.create(calltempnode));
  571. p:=newblock;
  572. end;
  573. result:=p;
  574. end
  575. else
  576. begin
  577. p.free;
  578. Message(parser_e_false_with_expr);
  579. { try to recover from error }
  580. if try_to_consume(_COMMA) then
  581. begin
  582. hp:=_with_statement();
  583. if (hp=nil) then; { remove warning about unused }
  584. end
  585. else
  586. begin
  587. consume(_DO);
  588. { ignore all }
  589. if token<>_SEMICOLON then
  590. statement;
  591. end;
  592. result:=nil;
  593. end;
  594. end;
  595. function with_statement : tnode;
  596. begin
  597. consume(_WITH);
  598. with_statement:=_with_statement();
  599. end;
  600. function raise_statement : tnode;
  601. var
  602. p,pobj,paddr,pframe : tnode;
  603. begin
  604. pobj:=nil;
  605. paddr:=nil;
  606. pframe:=nil;
  607. consume(_RAISE);
  608. if not(token in endtokens) then
  609. begin
  610. { object }
  611. pobj:=comp_expr(true);
  612. if try_to_consume(_AT) then
  613. begin
  614. paddr:=comp_expr(true);
  615. if try_to_consume(_COMMA) then
  616. pframe:=comp_expr(true);
  617. end;
  618. end
  619. else
  620. begin
  621. if (block_type<>bt_except) then
  622. Message(parser_e_no_reraise_possible);
  623. end;
  624. p:=craisenode.create(pobj,paddr,pframe);
  625. raise_statement:=p;
  626. end;
  627. function try_statement : tnode;
  628. var
  629. p_try_block,p_finally_block,first,last,
  630. p_default,p_specific,hp : tnode;
  631. ot : tDef;
  632. sym : tlocalvarsym;
  633. old_block_type : tblock_type;
  634. excepTSymtable : TSymtable;
  635. objname,objrealname : TIDString;
  636. srsym : tsym;
  637. srsymtable : TSymtable;
  638. oldcurrent_exceptblock: integer;
  639. begin
  640. include(current_procinfo.flags,pi_uses_exceptions);
  641. p_default:=nil;
  642. p_specific:=nil;
  643. { read statements to try }
  644. consume(_TRY);
  645. first:=nil;
  646. inc(exceptblockcounter);
  647. oldcurrent_exceptblock := current_exceptblock;
  648. current_exceptblock := exceptblockcounter;
  649. while (token<>_FINALLY) and (token<>_EXCEPT) do
  650. begin
  651. if first=nil then
  652. begin
  653. last:=cstatementnode.create(statement,nil);
  654. first:=last;
  655. end
  656. else
  657. begin
  658. tstatementnode(last).right:=cstatementnode.create(statement,nil);
  659. last:=tstatementnode(last).right;
  660. end;
  661. if not try_to_consume(_SEMICOLON) then
  662. break;
  663. consume_emptystats;
  664. end;
  665. p_try_block:=cblocknode.create(first);
  666. if try_to_consume(_FINALLY) then
  667. begin
  668. inc(exceptblockcounter);
  669. current_exceptblock := exceptblockcounter;
  670. p_finally_block:=statements_til_end;
  671. try_statement:=ctryfinallynode.create(p_try_block,p_finally_block);
  672. end
  673. else
  674. begin
  675. consume(_EXCEPT);
  676. old_block_type:=block_type;
  677. block_type:=bt_except;
  678. inc(exceptblockcounter);
  679. current_exceptblock := exceptblockcounter;
  680. ot:=generrordef;
  681. p_specific:=nil;
  682. if (idtoken=_ON) then
  683. { catch specific exceptions }
  684. begin
  685. repeat
  686. consume(_ON);
  687. if token=_ID then
  688. begin
  689. objname:=pattern;
  690. objrealname:=orgpattern;
  691. { can't use consume_sym here, because we need already
  692. to check for the colon }
  693. searchsym(objname,srsym,srsymtable);
  694. consume(_ID);
  695. { is a explicit name for the exception given ? }
  696. if try_to_consume(_COLON) then
  697. begin
  698. consume_sym(srsym,srsymtable);
  699. if (srsym.typ=typesym) and
  700. is_class(ttypesym(srsym).typedef) then
  701. begin
  702. ot:=ttypesym(srsym).typedef;
  703. sym:=tlocalvarsym.create(objrealname,vs_value,ot,[]);
  704. end
  705. else
  706. begin
  707. sym:=tlocalvarsym.create(objrealname,vs_value,generrordef,[]);
  708. if (srsym.typ=typesym) then
  709. Message1(type_e_class_type_expected,ttypesym(srsym).typedef.typename)
  710. else
  711. Message1(type_e_class_type_expected,ot.typename);
  712. end;
  713. excepTSymtable:=tstt_excepTSymtable.create;
  714. excepTSymtable.insert(sym);
  715. symtablestack.push(excepTSymtable);
  716. end
  717. else
  718. begin
  719. { check if type is valid, must be done here because
  720. with "e: Exception" the e is not necessary }
  721. if srsym=nil then
  722. begin
  723. identifier_not_found(objrealname);
  724. srsym:=generrorsym;
  725. end;
  726. { support unit.identifier }
  727. if srsym.typ=unitsym then
  728. begin
  729. consume(_POINT);
  730. searchsym_in_module(tunitsym(srsym).module,pattern,srsym,srsymtable);
  731. if srsym=nil then
  732. begin
  733. identifier_not_found(orgpattern);
  734. srsym:=generrorsym;
  735. end;
  736. consume(_ID);
  737. end;
  738. { check if type is valid, must be done here because
  739. with "e: Exception" the e is not necessary }
  740. if (srsym.typ=typesym) and
  741. is_class(ttypesym(srsym).typedef) then
  742. ot:=ttypesym(srsym).typedef
  743. else
  744. begin
  745. ot:=generrordef;
  746. if (srsym.typ=typesym) then
  747. Message1(type_e_class_type_expected,ttypesym(srsym).typedef.typename)
  748. else
  749. Message1(type_e_class_type_expected,ot.typename);
  750. end;
  751. excepTSymtable:=nil;
  752. end;
  753. end
  754. else
  755. consume(_ID);
  756. consume(_DO);
  757. hp:=connode.create(nil,statement);
  758. if ot.typ=errordef then
  759. begin
  760. hp.free;
  761. hp:=cerrornode.create;
  762. end;
  763. if p_specific=nil then
  764. begin
  765. last:=hp;
  766. p_specific:=last;
  767. end
  768. else
  769. begin
  770. tonnode(last).left:=hp;
  771. last:=tonnode(last).left;
  772. end;
  773. { set the informations }
  774. { only if the creation of the onnode was succesful, it's possible }
  775. { that last and hp are errornodes (JM) }
  776. if last.nodetype = onn then
  777. begin
  778. tonnode(last).excepttype:=tobjectdef(ot);
  779. tonnode(last).excepTSymtable:=excepTSymtable;
  780. end;
  781. { remove exception symtable }
  782. if assigned(excepTSymtable) then
  783. begin
  784. symtablestack.pop(excepTSymtable);
  785. if last.nodetype <> onn then
  786. excepTSymtable.free;
  787. end;
  788. if not try_to_consume(_SEMICOLON) then
  789. break;
  790. consume_emptystats;
  791. until (token in [_END,_ELSE]);
  792. if try_to_consume(_ELSE) then
  793. begin
  794. { catch the other exceptions }
  795. p_default:=statements_til_end;
  796. end
  797. else
  798. consume(_END);
  799. end
  800. else
  801. begin
  802. { catch all exceptions }
  803. p_default:=statements_til_end;
  804. end;
  805. block_type:=old_block_type;
  806. try_statement:=ctryexceptnode.create(p_try_block,p_specific,p_default);
  807. end;
  808. current_exceptblock := oldcurrent_exceptblock;
  809. end;
  810. function _asm_statement : tnode;
  811. var
  812. asmstat : tasmnode;
  813. Marker : tai;
  814. reg : tregister;
  815. asmreader : tbaseasmreader;
  816. begin
  817. Inside_asm_statement:=true;
  818. if assigned(asmmodeinfos[current_settings.asmmode]) then
  819. begin
  820. asmreader:=asmmodeinfos[current_settings.asmmode]^.casmreader.create;
  821. asmstat:=casmnode.create(asmreader.assemble as TAsmList);
  822. asmreader.free;
  823. end
  824. else
  825. Message(parser_f_assembler_reader_not_supported);
  826. { Mark procedure that it has assembler blocks }
  827. include(current_procinfo.flags,pi_has_assembler_block);
  828. { Read first the _ASM statement }
  829. consume(_ASM);
  830. { END is read, got a list of changed registers? }
  831. if try_to_consume(_LECKKLAMMER) then
  832. begin
  833. {$ifdef cpunofpu}
  834. asmstat.used_regs_fpu:=[0..first_int_imreg-1];
  835. {$else cpunofpu}
  836. asmstat.used_regs_fpu:=[0..first_fpu_imreg-1];
  837. {$endif cpunofpu}
  838. if token<>_RECKKLAMMER then
  839. begin
  840. if po_assembler in current_procinfo.procdef.procoptions then
  841. Message(parser_w_register_list_ignored);
  842. repeat
  843. { it's possible to specify the modified registers }
  844. reg:=std_regnum_search(lower(pattern));
  845. if reg<>NR_NO then
  846. begin
  847. if (getregtype(reg)=R_INTREGISTER) and not(po_assembler in current_procinfo.procdef.procoptions) then
  848. include(asmstat.used_regs_int,getsupreg(reg));
  849. end
  850. else
  851. Message(asmr_e_invalid_register);
  852. consume(_CSTRING);
  853. if not try_to_consume(_COMMA) then
  854. break;
  855. until false;
  856. end;
  857. consume(_RECKKLAMMER);
  858. end
  859. else
  860. begin
  861. asmstat.used_regs_int:=paramanager.get_volatile_registers_int(current_procinfo.procdef.proccalloption);
  862. asmstat.used_regs_fpu:=paramanager.get_volatile_registers_fpu(current_procinfo.procdef.proccalloption);
  863. end;
  864. { mark the start and the end of the assembler block
  865. this is needed for the optimizer }
  866. If Assigned(AsmStat.p_asm) Then
  867. Begin
  868. Marker := Tai_Marker.Create(mark_AsmBlockStart);
  869. AsmStat.p_asm.Insert(Marker);
  870. Marker := Tai_Marker.Create(mark_AsmBlockEnd);
  871. AsmStat.p_asm.Concat(Marker);
  872. End;
  873. Inside_asm_statement:=false;
  874. _asm_statement:=asmstat;
  875. end;
  876. function statement : tnode;
  877. var
  878. p : tnode;
  879. code : tnode;
  880. filepos : tfileposinfo;
  881. srsym : tsym;
  882. srsymtable : TSymtable;
  883. s : TIDString;
  884. begin
  885. filepos:=current_tokenpos;
  886. case token of
  887. _GOTO :
  888. begin
  889. if not(cs_support_goto in current_settings.moduleswitches)then
  890. Message(sym_e_goto_and_label_not_supported);
  891. consume(_GOTO);
  892. if (token<>_INTCONST) and (token<>_ID) then
  893. begin
  894. Message(sym_e_label_not_found);
  895. code:=cerrornode.create;
  896. end
  897. else
  898. begin
  899. if token=_ID then
  900. consume_sym(srsym,srsymtable)
  901. else
  902. begin
  903. searchsym(pattern,srsym,srsymtable);
  904. if srsym=nil then
  905. begin
  906. identifier_not_found(pattern);
  907. srsym:=generrorsym;
  908. srsymtable:=nil;
  909. end;
  910. consume(token);
  911. end;
  912. if srsym.typ<>labelsym then
  913. begin
  914. Message(sym_e_id_is_no_label_id);
  915. code:=cerrornode.create;
  916. end
  917. else
  918. begin
  919. { goto is only allowed to labels within the current scope }
  920. if srsym.owner<>current_procinfo.procdef.localst then
  921. CGMessage(parser_e_goto_outside_proc);
  922. code:=cgotonode.create(tlabelsym(srsym));
  923. tgotonode(code).labelsym:=tlabelsym(srsym);
  924. { set flag that this label is used }
  925. tlabelsym(srsym).used:=true;
  926. end;
  927. end;
  928. end;
  929. _BEGIN :
  930. code:=statement_block(_BEGIN);
  931. _IF :
  932. code:=if_statement;
  933. _CASE :
  934. code:=case_statement;
  935. _REPEAT :
  936. code:=repeat_statement;
  937. _WHILE :
  938. code:=while_statement;
  939. _FOR :
  940. code:=for_statement;
  941. _WITH :
  942. code:=with_statement;
  943. _TRY :
  944. code:=try_statement;
  945. _RAISE :
  946. code:=raise_statement;
  947. { semicolons,else until and end are ignored }
  948. _SEMICOLON,
  949. _ELSE,
  950. _UNTIL,
  951. _END:
  952. code:=cnothingnode.create;
  953. _FAIL :
  954. begin
  955. if (current_procinfo.procdef.proctypeoption<>potype_constructor) then
  956. Message(parser_e_fail_only_in_constructor);
  957. consume(_FAIL);
  958. code:=call_fail_node;
  959. end;
  960. _ASM :
  961. code:=_asm_statement;
  962. _EOF :
  963. Message(scan_f_end_of_file);
  964. else
  965. begin
  966. p:=expr;
  967. { save the pattern here for latter usage, the label could be "000",
  968. even if we read an expression, the pattern is still valid if it's really
  969. a label (FK)
  970. if you want to mess here, take care of
  971. tests/webtbs/tw3546.pp
  972. }
  973. s:=pattern;
  974. { When a colon follows a intconst then transform it into a label }
  975. if (p.nodetype=ordconstn) and
  976. try_to_consume(_COLON) then
  977. begin
  978. p.free;
  979. searchsym(s,srsym,srsymtable);
  980. if assigned(srsym) and
  981. (srsym.typ=labelsym) then
  982. begin
  983. if tlabelsym(srsym).defined then
  984. Message(sym_e_label_already_defined);
  985. tlabelsym(srsym).defined:=true;
  986. p:=clabelnode.create(nil,tlabelsym(srsym));
  987. tlabelsym(srsym).code:=p;
  988. end
  989. else
  990. begin
  991. Message1(sym_e_label_used_and_not_defined,s);
  992. p:=cnothingnode.create;
  993. end;
  994. end;
  995. if p.nodetype=labeln then
  996. begin
  997. { the pointer to the following instruction }
  998. { isn't a very clean way }
  999. if token in endtokens then
  1000. tlabelnode(p).left:=cnothingnode.create
  1001. else
  1002. tlabelnode(p).left:=statement();
  1003. { be sure to have left also typecheckpass }
  1004. typecheckpass(tlabelnode(p).left);
  1005. end
  1006. else
  1007. { change a load of a procvar to a call. this is also
  1008. supported in fpc mode }
  1009. if p.nodetype in [vecn,derefn,typeconvn,subscriptn,loadn] then
  1010. maybe_call_procvar(p,false);
  1011. { blockn support because a read/write is changed into a blocknode }
  1012. { with a separate statement for each read/write operation (JM) }
  1013. { the same is true for val() if the third parameter is not 32 bit }
  1014. if not(p.nodetype in [nothingn,errorn,calln,ifn,assignn,breakn,inlinen,
  1015. continuen,labeln,blockn,exitn]) or
  1016. ((p.nodetype=inlinen) and
  1017. not is_void(p.resultdef)) then
  1018. Message(parser_e_illegal_expression);
  1019. { Specify that we don't use the value returned by the call.
  1020. This is used for :
  1021. - dispose of temp stack space
  1022. - dispose on FPU stack }
  1023. if (p.nodetype=calln) then
  1024. exclude(tcallnode(p).callnodeflags,cnf_return_value_used);
  1025. code:=p;
  1026. end;
  1027. end;
  1028. if assigned(code) then
  1029. begin
  1030. typecheckpass(code);
  1031. code.fileinfo:=filepos;
  1032. end;
  1033. statement:=code;
  1034. end;
  1035. function statement_block(starttoken : ttoken) : tnode;
  1036. var
  1037. first,last : tnode;
  1038. filepos : tfileposinfo;
  1039. begin
  1040. first:=nil;
  1041. filepos:=current_tokenpos;
  1042. consume(starttoken);
  1043. while not(token in [_END,_FINALIZATION]) do
  1044. begin
  1045. if first=nil then
  1046. begin
  1047. last:=cstatementnode.create(statement,nil);
  1048. first:=last;
  1049. end
  1050. else
  1051. begin
  1052. tstatementnode(last).right:=cstatementnode.create(statement,nil);
  1053. last:=tstatementnode(last).right;
  1054. end;
  1055. if (token in [_END,_FINALIZATION]) then
  1056. break
  1057. else
  1058. begin
  1059. { if no semicolon, then error and go on }
  1060. if token<>_SEMICOLON then
  1061. begin
  1062. consume(_SEMICOLON);
  1063. consume_all_until(_SEMICOLON);
  1064. end;
  1065. consume(_SEMICOLON);
  1066. end;
  1067. consume_emptystats;
  1068. end;
  1069. { don't consume the finalization token, it is consumed when
  1070. reading the finalization block, but allow it only after
  1071. an initalization ! }
  1072. if (starttoken<>_INITIALIZATION) or (token<>_FINALIZATION) then
  1073. consume(_END);
  1074. last:=cblocknode.create(first);
  1075. last.fileinfo:=filepos;
  1076. statement_block:=last;
  1077. end;
  1078. function assembler_block : tnode;
  1079. var
  1080. p : tnode;
  1081. {$ifndef arm}
  1082. locals : longint;
  1083. {$endif arm}
  1084. srsym : tsym;
  1085. begin
  1086. { Rename the funcret so that recursive calls are possible }
  1087. if not is_void(current_procinfo.procdef.returndef) then
  1088. begin
  1089. srsym:=TSym(current_procinfo.procdef.localst.Find(current_procinfo.procdef.procsym.name));
  1090. if assigned(srsym) then
  1091. srsym.realname:='$hiddenresult';
  1092. end;
  1093. { delphi uses register calling for assembler methods }
  1094. if (m_delphi in current_settings.modeswitches) and
  1095. (po_assembler in current_procinfo.procdef.procoptions) and
  1096. not(po_hascallingconvention in current_procinfo.procdef.procoptions) then
  1097. current_procinfo.procdef.proccalloption:=pocall_register;
  1098. { force the asm statement }
  1099. if token<>_ASM then
  1100. consume(_ASM);
  1101. include(current_procinfo.flags,pi_is_assembler);
  1102. p:=_asm_statement;
  1103. {$ifndef sparc}
  1104. {$ifndef arm}
  1105. if (po_assembler in current_procinfo.procdef.procoptions) then
  1106. begin
  1107. { set the framepointer to esp for assembler functions when the
  1108. following conditions are met:
  1109. - if the are no local variables and parameters (except the allocated result)
  1110. - no reference to the result variable (refcount<=1)
  1111. - result is not stored as parameter
  1112. - target processor has optional frame pointer save
  1113. (vm, i386, vm only currently)
  1114. }
  1115. locals:=tabstractlocalsymtable(current_procinfo.procdef.parast).count_locals;
  1116. if (current_procinfo.procdef.localst.symtabletype=localsymtable) then
  1117. inc(locals,tabstractlocalsymtable(current_procinfo.procdef.localst).count_locals);
  1118. if (locals=0) and
  1119. (current_procinfo.procdef.owner.symtabletype<>ObjectSymtable) and
  1120. (not assigned(current_procinfo.procdef.funcretsym) or
  1121. (tabstractvarsym(current_procinfo.procdef.funcretsym).refs<=1)) and
  1122. not(paramanager.ret_in_param(current_procinfo.procdef.returndef,current_procinfo.procdef.proccalloption)) then
  1123. begin
  1124. { Only need to set the framepointer, the locals will
  1125. be inserted with the correct reference in tcgasmnode.pass_generate_code }
  1126. current_procinfo.framepointer:=NR_STACK_POINTER_REG;
  1127. end;
  1128. end;
  1129. {$endif arm}
  1130. {$endif sparc}
  1131. { Flag the result as assigned when it is returned in a
  1132. register.
  1133. }
  1134. if assigned(current_procinfo.procdef.funcretsym) and
  1135. (not paramanager.ret_in_param(current_procinfo.procdef.returndef,current_procinfo.procdef.proccalloption)) then
  1136. tabstractvarsym(current_procinfo.procdef.funcretsym).varstate:=vs_initialised;
  1137. { because the END is already read we need to get the
  1138. last_endtoken_filepos here (PFV) }
  1139. last_endtoken_filepos:=current_tokenpos;
  1140. assembler_block:=p;
  1141. end;
  1142. end.