pstatmnt.pas 44 KB

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