pstatmnt.pas 44 KB

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