pstatmnt.pas 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179
  1. {
  2. $Id$
  3. Copyright (c) 1998 by Florian Klaempfl
  4. Does the parsing of the statements
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit pstatmnt;
  19. interface
  20. uses tree;
  21. var
  22. { true, if we are in a except block }
  23. in_except_block : boolean;
  24. { reads a block }
  25. function block(islibrary : boolean) : ptree;
  26. { reads an assembler block }
  27. function assembler_block : ptree;
  28. implementation
  29. uses
  30. cobjects,scanner,globals,symtable,aasm,pass_1,
  31. types,hcodegen,files,verbose
  32. {$ifdef NEWPPU}
  33. ,ppu
  34. {$endif}
  35. { processor specific stuff }
  36. {$ifdef i386}
  37. ,i386
  38. ,rai386
  39. ,ratti386
  40. ,radi386
  41. ,tgeni386
  42. {$endif}
  43. {$ifdef m68k}
  44. ,m68k
  45. ,tgen68k
  46. ,ag68kmit
  47. ,ra68k
  48. ,ag68kgas
  49. ,ag68kmot
  50. {$endif}
  51. { parser specific stuff, be careful consume is also defined to }
  52. { read assembler tokens }
  53. ,pbase,pexpr,pdecl;
  54. const
  55. statement_level : longint = 0;
  56. function statement : ptree;forward;
  57. function if_statement : ptree;
  58. var
  59. ex,if_a,else_a : ptree;
  60. begin
  61. consume(_IF);
  62. ex:=comp_expr(true);
  63. consume(_THEN);
  64. if token<>_ELSE then
  65. if_a:=statement
  66. else
  67. if_a:=nil;
  68. if token=_ELSE then
  69. begin
  70. consume(_ELSE);
  71. else_a:=statement;
  72. end
  73. else
  74. else_a:=nil;
  75. if_statement:=genloopnode(ifn,ex,if_a,else_a,false);
  76. end;
  77. { creates a block (list) of statements, til the next END token }
  78. function statements_til_end : ptree;
  79. var
  80. first,last : ptree;
  81. begin
  82. first:=nil;
  83. while token<>_END do
  84. begin
  85. if first=nil then
  86. begin
  87. last:=gennode(statementn,nil,statement);
  88. first:=last;
  89. end
  90. else
  91. begin
  92. last^.left:=gennode(statementn,nil,statement);
  93. last:=last^.left;
  94. end;
  95. if token<>SEMICOLON then
  96. break
  97. else
  98. consume(SEMICOLON);
  99. while token=SEMICOLON do
  100. consume(SEMICOLON);
  101. end;
  102. consume(_END);
  103. statements_til_end:=gensinglenode(blockn,first);
  104. end;
  105. function case_statement : ptree;
  106. var
  107. { contains the label number of currently parsed case block }
  108. aktcaselabel : plabel;
  109. root : pcaserecord;
  110. { the typ of the case expression }
  111. casedef : pdef;
  112. procedure newcaselabel(l,h : longint);
  113. var
  114. hcaselabel : pcaserecord;
  115. procedure insertlabel(var p : pcaserecord);
  116. begin
  117. if p=nil then p:=hcaselabel
  118. else
  119. if (p^._low>hcaselabel^._low) and
  120. (p^._low>hcaselabel^._high) then
  121. insertlabel(p^.less)
  122. else if (p^._high<hcaselabel^._low) and
  123. (p^._high<hcaselabel^._high) then
  124. insertlabel(p^.greater)
  125. else Message(parser_e_double_caselabel);
  126. end;
  127. begin
  128. new(hcaselabel);
  129. hcaselabel^.less:=nil;
  130. hcaselabel^.greater:=nil;
  131. hcaselabel^.statement:=aktcaselabel;
  132. getlabel(hcaselabel^._at);
  133. hcaselabel^._low:=l;
  134. hcaselabel^._high:=h;
  135. insertlabel(root);
  136. end;
  137. var
  138. code,caseexpr,p,instruc,elseblock : ptree;
  139. hl1,hl2 : longint;
  140. ranges : boolean;
  141. begin
  142. consume(_CASE);
  143. caseexpr:=comp_expr(true);
  144. { determines result type }
  145. cleartempgen;
  146. do_firstpass(caseexpr);
  147. casedef:=caseexpr^.resulttype;
  148. if not(is_ordinal(casedef)) then
  149. Message(parser_e_ordinal_expected);
  150. consume(_OF);
  151. inc(statement_level);
  152. root:=nil;
  153. ranges:=false;
  154. instruc:=nil;
  155. repeat
  156. getlabel(aktcaselabel);
  157. {aktcaselabel^.is_used:=true; }
  158. { may be an instruction has more case labels }
  159. repeat
  160. p:=expr;
  161. cleartempgen;
  162. do_firstpass(p);
  163. if (p^.treetype=rangen) then
  164. begin
  165. { type checking for case statements }
  166. if not is_subequal(casedef, p^.left^.resulttype) then
  167. Message(parser_e_case_mismatch);
  168. { type checking for case statements }
  169. if not is_subequal(casedef, p^.right^.resulttype) then
  170. Message(parser_e_case_mismatch);
  171. hl1:=get_ordinal_value(p^.left);
  172. hl2:=get_ordinal_value(p^.right);
  173. testrange(casedef,hl1);
  174. testrange(casedef,hl2);
  175. newcaselabel(hl1,hl2);
  176. ranges:=true;
  177. end
  178. else
  179. begin
  180. { type checking for case statements }
  181. if not is_subequal(casedef, p^.resulttype) then
  182. Message(parser_e_case_mismatch);
  183. hl1:=get_ordinal_value(p);
  184. testrange(casedef,hl1);
  185. newcaselabel(hl1,hl1);
  186. end;
  187. disposetree(p);
  188. if token=COMMA then consume(COMMA)
  189. else break;
  190. until false;
  191. consume(COLON);
  192. { handles instruction block }
  193. p:=gensinglenode(labeln,statement);
  194. p^.labelnr:=aktcaselabel;
  195. { concats instruction }
  196. instruc:=gennode(statementn,instruc,p);
  197. if not((token=_ELSE) or (token=_OTHERWISE) or (token=_END)) then
  198. consume(SEMICOLON);
  199. until (token=_ELSE) or (token=_OTHERWISE) or (token=_END);
  200. if (token=_ELSE) or (token=_OTHERWISE) then
  201. begin
  202. if token=_ELSE then consume(_ELSE)
  203. else consume(_OTHERWISE);
  204. elseblock:=statements_til_end;
  205. end
  206. else
  207. begin
  208. elseblock:=nil;
  209. consume(_END);
  210. end;
  211. dec(statement_level);
  212. code:=gencasenode(caseexpr,instruc,root);
  213. code^.elseblock:=elseblock;
  214. case_statement:=code;
  215. end;
  216. function repeat_statement : ptree;
  217. var
  218. first,last,p_e : ptree;
  219. begin
  220. consume(_REPEAT);
  221. first:=nil;
  222. inc(statement_level);
  223. while token<>_UNTIL do
  224. begin
  225. if first=nil then
  226. begin
  227. last:=gennode(statementn,nil,statement);
  228. first:=last;
  229. end
  230. else
  231. begin
  232. last^.left:=gennode(statementn,nil,statement);
  233. last:=last^.left;
  234. end;
  235. if token<>SEMICOLON then
  236. break;
  237. consume(SEMICOLON);
  238. while token=SEMICOLON do
  239. consume(SEMICOLON);
  240. end;
  241. consume(_UNTIL);
  242. dec(statement_level);
  243. first:=gensinglenode(blockn,first);
  244. p_e:=comp_expr(true);
  245. repeat_statement:=genloopnode(repeatn,p_e,first,nil,false);
  246. end;
  247. function while_statement : ptree;
  248. var
  249. p_e,p_a : ptree;
  250. begin
  251. consume(_WHILE);
  252. p_e:=comp_expr(true);
  253. consume(_DO);
  254. p_a:=statement;
  255. while_statement:=genloopnode(whilen,p_e,p_a,nil,false);
  256. end;
  257. function for_statement : ptree;
  258. var
  259. p_e,tovalue,p_a : ptree;
  260. backward : boolean;
  261. begin
  262. { parse loop header }
  263. consume(_FOR);
  264. p_e:=expr;
  265. if token=_DOWNTO then
  266. begin
  267. consume(_DOWNTO);
  268. backward:=true;
  269. end
  270. else
  271. begin
  272. consume(_TO);
  273. backward:=false;
  274. end;
  275. tovalue:=comp_expr(true);
  276. consume(_DO);
  277. { ... now the instruction }
  278. p_a:=statement;
  279. for_statement:=genloopnode(forn,p_e,tovalue,p_a,backward);
  280. end;
  281. function _with_statement : ptree;
  282. var
  283. right,hp,p : ptree;
  284. i,levelcount : longint;
  285. withsymtable,symtab : psymtable;
  286. obj : pobjectdef;
  287. begin
  288. Must_be_valid:=false;
  289. p:=comp_expr(true);
  290. do_firstpass(p);
  291. right:=nil;
  292. case p^.resulttype^.deftype of
  293. objectdef : begin
  294. obj:=pobjectdef(p^.resulttype);
  295. levelcount:=0;
  296. while assigned(obj) do
  297. begin
  298. symtab:=obj^.publicsyms;
  299. withsymtable:=new(psymtable,init(symtable.withsymtable));
  300. withsymtable^.root:=symtab^.root;
  301. withsymtable^.next:=symtablestack;
  302. symtablestack:=withsymtable;
  303. obj:=obj^.childof;
  304. inc(levelcount);
  305. end;
  306. end;
  307. recorddef : begin
  308. symtab:=precdef(p^.resulttype)^.symtable;
  309. levelcount:=1;
  310. withsymtable:=new(psymtable,init(symtable.withsymtable));
  311. withsymtable^.root:=symtab^.root;
  312. withsymtable^.next:=symtablestack;
  313. symtablestack:=withsymtable;
  314. end;
  315. else
  316. begin
  317. Message(parser_e_false_with_expr);
  318. { try to recover from error }
  319. if token=COMMA then
  320. begin
  321. consume(COMMA);
  322. {$ifdef tp}
  323. hp:=_with_statement;
  324. {$else}
  325. hp:=_with_statement();
  326. {$endif}
  327. end
  328. else
  329. begin
  330. consume(_DO);
  331. { ignore all }
  332. if token<>SEMICOLON then
  333. statement;
  334. end;
  335. _with_statement:=nil;
  336. exit;
  337. end;
  338. end;
  339. if token=COMMA then
  340. begin
  341. consume(COMMA);
  342. {$ifdef tp}
  343. right:=_with_statement;
  344. {$else}
  345. right:=_with_statement();
  346. {$endif}
  347. end
  348. else
  349. begin
  350. consume(_DO);
  351. if token<>SEMICOLON then
  352. right:=statement
  353. else
  354. right:=nil;
  355. end;
  356. for i:=1 to levelcount do
  357. symtablestack:=symtablestack^.next;
  358. _with_statement:=genwithnode(withsymtable,p,right,levelcount);
  359. end;
  360. function with_statement : ptree;
  361. begin
  362. consume(_WITH);
  363. with_statement:=_with_statement;
  364. end;
  365. function raise_statement : ptree;
  366. var
  367. p1,p2 : ptree;
  368. begin
  369. p1:=nil;
  370. p2:=nil;
  371. consume(_RAISE);
  372. if token<>SEMICOLON then
  373. begin
  374. p1:=comp_expr(true);
  375. if (token=ID) and (pattern='AT') then
  376. begin
  377. consume(ID);
  378. p2:=comp_expr(true);
  379. end;
  380. end
  381. else
  382. begin
  383. if not(in_except_block) then
  384. Message(parser_e_no_reraise_possible);
  385. end;
  386. raise_statement:=gennode(raisen,p1,p2);
  387. end;
  388. function try_statement : ptree;
  389. var
  390. p_try_block,p_finally_block,first,last,
  391. p_default,e1,e2,p_specific : ptree;
  392. old_in_except_block : boolean;
  393. begin
  394. p_default:=nil;
  395. p_specific:=nil;
  396. { read statements to try }
  397. consume(_TRY);
  398. first:=nil;
  399. inc(statement_level);
  400. while (token<>_FINALLY) and (token<>_EXCEPT) do
  401. begin
  402. if first=nil then
  403. begin
  404. last:=gennode(statementn,nil,statement);
  405. first:=last;
  406. end
  407. else
  408. begin
  409. last^.left:=gennode(statementn,nil,statement);
  410. last:=last^.left;
  411. end;
  412. if token<>SEMICOLON then
  413. break;
  414. consume(SEMICOLON);
  415. emptystats;
  416. end;
  417. p_try_block:=gensinglenode(blockn,first);
  418. if token=_FINALLY then
  419. begin
  420. consume(_FINALLY);
  421. p_finally_block:=statements_til_end;
  422. try_statement:=gennode(tryfinallyn,p_try_block,p_finally_block);
  423. dec(statement_level);
  424. end
  425. else
  426. begin
  427. consume(_EXCEPT);
  428. old_in_except_block:=in_except_block;
  429. in_except_block:=true;
  430. if token=_ON then
  431. { catch specific exceptions }
  432. begin
  433. repeat
  434. consume(_ON);
  435. e1:=comp_expr(true);
  436. if token=COLON then
  437. begin
  438. consume(COLON);
  439. e2:=comp_expr(true);
  440. { !!!!! }
  441. end
  442. else
  443. begin
  444. { !!!!! }
  445. end;
  446. consume(_DO);
  447. statement;
  448. if token<>SEMICOLON then
  449. break;
  450. emptystats;
  451. until false;
  452. if token=_ELSE then
  453. { catch the other exceptions }
  454. begin
  455. consume(_ELSE);
  456. p_default:=statements_til_end;
  457. end;
  458. end
  459. else
  460. { catch all exceptions }
  461. begin
  462. p_default:=statements_til_end;
  463. end;
  464. dec(statement_level);
  465. in_except_block:=old_in_except_block;
  466. try_statement:=genloopnode(tryexceptn,p_try_block,p_specific,p_default,false);
  467. end;
  468. end;
  469. function exit_statement : ptree;
  470. var
  471. p : ptree;
  472. begin
  473. consume(_EXIT);
  474. if token=LKLAMMER then
  475. begin
  476. consume(LKLAMMER);
  477. p:=comp_expr(true);
  478. consume(RKLAMMER);
  479. if procinfo.retdef=pdef(voiddef) then
  480. Message(parser_e_void_function)
  481. else
  482. procinfo.funcret_is_valid:=true;
  483. end
  484. else
  485. p:=nil;
  486. exit_statement:=gensinglenode(exitn,p);
  487. end;
  488. {$ifdef i386}
  489. function _asm_statement : ptree;
  490. begin
  491. if (aktprocsym^.definition^.options and poinline)<>0 then
  492. Begin
  493. Comment(V_Warning,'asm statement inside inline procedure/function not yet supported');
  494. Comment(V_Warning,'inlining disabled');
  495. aktprocsym^.definition^.options:= aktprocsym^.definition^.options and not poinline;
  496. End;
  497. case aktasmmode of
  498. I386_ATT : _asm_statement:=ratti386.assemble;
  499. I386_INTEL : _asm_statement:=rai386.assemble;
  500. I386_DIRECT : _asm_statement:=radi386.assemble;
  501. else internalerror(30004);
  502. end;
  503. { Erst am Ende _ASM konsumieren, da der Scanner sonst die }
  504. { erste Assemblerstatement zu lesen versucht! }
  505. consume(_ASM);
  506. { (END is read) }
  507. if token=LECKKLAMMER then
  508. begin
  509. { it's possible to specify the modified registers }
  510. consume(LECKKLAMMER);
  511. if token<>RECKKLAMMER then
  512. repeat
  513. pattern:=upper(pattern);
  514. if pattern='EAX' then
  515. usedinproc:=usedinproc or ($80 shr byte(R_EAX))
  516. else if pattern='EBX' then
  517. usedinproc:=usedinproc or ($80 shr byte(R_EBX))
  518. else if pattern='ECX' then
  519. usedinproc:=usedinproc or ($80 shr byte(R_ECX))
  520. else if pattern='EDX' then
  521. usedinproc:=usedinproc or ($80 shr byte(R_EDX))
  522. else if pattern='ESI' then
  523. usedinproc:=usedinproc or ($80 shr byte(R_ESI))
  524. else if pattern='EDI' then
  525. usedinproc:=usedinproc or ($80 shr byte(R_EDI))
  526. else consume(RECKKLAMMER);
  527. consume(CSTRING);
  528. if token=COMMA then consume(COMMA)
  529. else break;
  530. until false;
  531. consume(RECKKLAMMER);
  532. end
  533. else usedinproc:=$ff;
  534. end;
  535. {$endif}
  536. {$ifdef m68k}
  537. function _asm_statement : ptree;
  538. begin
  539. _asm_statement:= ra68k.assemble;
  540. { Erst am Ende _ASM konsumieren, da der Scanner sonst die }
  541. { erste Assemblerstatement zu lesen versucht! }
  542. consume(_ASM);
  543. { (END is read) }
  544. if token=LECKKLAMMER then
  545. begin
  546. { it's possible to specify the modified registers }
  547. { we only check the registers which are not reserved }
  548. { and which can be used. This is done for future }
  549. { optimizations. }
  550. consume(LECKKLAMMER);
  551. if token<>RECKKLAMMER then
  552. repeat
  553. pattern:=upper(pattern);
  554. if pattern='D0' then
  555. usedinproc:=usedinproc or ($800 shr word(R_D0))
  556. else if pattern='D1' then
  557. usedinproc:=usedinproc or ($800 shr word(R_D1))
  558. else if pattern='D6' then
  559. usedinproc:=usedinproc or ($800 shr word(R_D6))
  560. else if pattern='A0' then
  561. usedinproc:=usedinproc or ($800 shr word(R_A0))
  562. else if pattern='A1' then
  563. usedinproc:=usedinproc or ($800 shr word(R_A1))
  564. else consume(RECKKLAMMER);
  565. consume(CSTRING);
  566. if token=COMMA then consume(COMMA)
  567. else break;
  568. until false;
  569. consume(RECKKLAMMER);
  570. end
  571. else usedinproc:=$ffff;
  572. end;
  573. {$endif}
  574. function new_dispose_statement : ptree;
  575. var
  576. p,p2 : ptree;
  577. ht : ttoken;
  578. again : boolean; { dummy for do_proc_call }
  579. destrukname : stringid;
  580. sym : psym;
  581. classh : pobjectdef;
  582. pd,pd2 : pdef;
  583. store_valid : boolean;
  584. tt : ttreetyp;
  585. begin
  586. ht:=token;
  587. if token=_NEW then consume(_NEW)
  588. else consume(_DISPOSE);
  589. if ht=_NEW then
  590. tt:=hnewn
  591. else
  592. tt:=hdisposen;
  593. consume(LKLAMMER);
  594. p:=comp_expr(true);
  595. { calc return type }
  596. cleartempgen;
  597. Store_valid := Must_be_valid;
  598. Must_be_valid := False;
  599. do_firstpass(p);
  600. Must_be_valid := Store_valid;
  601. {var o:Pobject;
  602. begin
  603. new(o,init); (*Also a valid new statement*)
  604. end;}
  605. if token=COMMA then
  606. begin
  607. { extended syntax of new and dispose }
  608. { function styled new is handled in factor }
  609. consume(COMMA);
  610. { destructors have no parameters }
  611. destrukname:=pattern;
  612. consume(ID);
  613. pd:=p^.resulttype;
  614. pd2:=pd;
  615. if (p^.resulttype = nil) or (pd^.deftype<>pointerdef) then
  616. begin
  617. Message(parser_e_pointer_type_expected);
  618. p:=factor(false);
  619. consume(RKLAMMER);
  620. new_dispose_statement:=genzeronode(errorn);
  621. exit;
  622. end;
  623. { first parameter must be an object or class }
  624. if ppointerdef(pd)^.definition^.deftype<>objectdef then
  625. begin
  626. Message(parser_e_pointer_to_class_expected);
  627. new_dispose_statement:=factor(false);
  628. consume_all_until(RKLAMMER);
  629. consume(RKLAMMER);
  630. exit;
  631. end;
  632. { check, if the first parameter is a pointer to a _class_ }
  633. classh:=pobjectdef(ppointerdef(pd)^.definition);
  634. if (classh^.options and oois_class)<>0 then
  635. begin
  636. Message(parser_e_no_new_or_dispose_for_classes);
  637. new_dispose_statement:=factor(false);
  638. { while token<>RKLAMMER do
  639. consume(token); }
  640. consume_all_until(RKLAMMER);
  641. consume(RKLAMMER);
  642. exit;
  643. end;
  644. { search cons-/destructor, also in parent classes }
  645. sym:=nil;
  646. while assigned(classh) do
  647. begin
  648. sym:=classh^.publicsyms^.search(pattern);
  649. srsymtable:=classh^.publicsyms;
  650. if assigned(sym) then
  651. break;
  652. classh:=classh^.childof;
  653. end;
  654. { the second parameter of new/dispose must be a call }
  655. { to a cons-/destructor }
  656. if (sym^.typ<>procsym) then
  657. begin
  658. Message(parser_e_expr_have_to_be_destructor_call);
  659. new_dispose_statement:=genzeronode(errorn);
  660. end
  661. else
  662. begin
  663. p2:=gensinglenode(tt,p);
  664. if ht=_NEW then
  665. begin
  666. { Constructors can take parameters.}
  667. p2^.resulttype:=ppointerdef(pd)^.definition;
  668. do_member_read(sym,p2,pd,again);
  669. end
  670. else
  671. { destructors can't.}
  672. p2:=genmethodcallnode(pprocsym(sym),srsymtable,p2);
  673. { we need the real called method }
  674. cleartempgen;
  675. do_firstpass(p2);
  676. if (ht=_NEW) and ((p2^.procdefinition^.options and poconstructor)=0) then
  677. Message(parser_e_expr_have_to_be_constructor_call);
  678. if (ht=_DISPOSE) and ((p2^.procdefinition^.options and podestructor)=0) then
  679. Message(parser_e_expr_have_to_be_destructor_call);
  680. if ht=_NEW then
  681. begin
  682. p2:=gennode(assignn,getcopy(p),gensinglenode(newn,p2));
  683. p2^.right^.resulttype:=pd2;
  684. end;
  685. new_dispose_statement:=p2;
  686. end;
  687. end
  688. else
  689. begin
  690. if (p^.resulttype=nil) or (p^.resulttype^.deftype<>pointerdef) then
  691. Begin
  692. Message(parser_e_pointer_type_expected);
  693. new_dispose_statement:=genzeronode(errorn);
  694. end
  695. else
  696. begin
  697. if (ppointerdef(p^.resulttype)^.definition^.deftype=objectdef) then
  698. Message(parser_w_use_extended_syntax_for_objects);
  699. case ht of
  700. _NEW : new_dispose_statement:=gensinglenode(simplenewn,p);
  701. _DISPOSE : new_dispose_statement:=gensinglenode(simpledisposen,p);
  702. end;
  703. end;
  704. end;
  705. consume(RKLAMMER);
  706. end;
  707. function statement_block : ptree;
  708. var
  709. first,last : ptree;
  710. filepos : tfileposinfo;
  711. begin
  712. first:=nil;
  713. filepos:=tokenpos;
  714. consume(_BEGIN);
  715. inc(statement_level);
  716. while token<>_END do
  717. begin
  718. if first=nil then
  719. begin
  720. last:=gennode(statementn,nil,statement);
  721. first:=last;
  722. end
  723. else
  724. begin
  725. last^.left:=gennode(statementn,nil,statement);
  726. last:=last^.left;
  727. end;
  728. if token=_END then
  729. break
  730. else
  731. begin
  732. { if no semicolon, then error and go on }
  733. if token<>SEMICOLON then
  734. begin
  735. consume(SEMICOLON);
  736. { while token<>SEMICOLON do
  737. consume(token); }
  738. consume_all_until(SEMICOLON);
  739. end;
  740. consume(SEMICOLON);
  741. end;
  742. emptystats;
  743. end;
  744. consume(_END);
  745. dec(statement_level);
  746. last:=gensinglenode(blockn,first);
  747. set_tree_filepos(last,filepos);
  748. statement_block:=last;
  749. end;
  750. function statement : ptree;
  751. var
  752. p : ptree;
  753. code : ptree;
  754. labelnr : plabel;
  755. filepos : tfileposinfo;
  756. label
  757. ready;
  758. begin
  759. filepos:=tokenpos;
  760. case token of
  761. _GOTO : begin
  762. if not(cs_support_goto in aktswitches)then
  763. Message(sym_e_goto_and_label_not_supported);
  764. consume(_GOTO);
  765. if (token<>INTCONST) and (token<>ID) then
  766. begin
  767. Message(sym_e_label_not_found);
  768. code:=genzeronode(errorn);
  769. end
  770. else
  771. begin
  772. getsym(pattern,true);
  773. consume(token);
  774. if srsym^.typ<>labelsym then
  775. begin
  776. Message(sym_e_id_is_no_label_id);
  777. code:=genzeronode(errorn);
  778. end
  779. else
  780. code:=genlabelnode(goton,
  781. plabelsym(srsym)^.number);
  782. end;
  783. end;
  784. _BEGIN : code:=statement_block;
  785. _IF : code:=if_statement;
  786. _CASE : code:=case_statement;
  787. _REPEAT : code:=repeat_statement;
  788. _WHILE : code:=while_statement;
  789. _FOR : code:=for_statement;
  790. _NEW,_DISPOSE : code:=new_dispose_statement;
  791. _WITH : code:=with_statement;
  792. _TRY : code:=try_statement;
  793. _RAISE : code:=raise_statement;
  794. { semicolons,else until and end are ignored }
  795. SEMICOLON,
  796. _ELSE,
  797. _UNTIL,
  798. _END : code:=genzeronode(niln);
  799. _CONTINUE : begin
  800. consume(_CONTINUE);
  801. code:=genzeronode(continuen);
  802. end;
  803. _FAIL : begin
  804. { internalerror(100); }
  805. if (aktprocsym^.definition^.options and poconstructor)=0 then
  806. Message(parser_e_fail_only_in_constructor);
  807. consume(_FAIL);
  808. code:=genzeronode(failn);
  809. end;
  810. {
  811. _BREAK:
  812. begin
  813. consume(_BREAK);
  814. code:=genzeronode(breakn);
  815. end;
  816. }
  817. _EXIT : code:=exit_statement;
  818. _ASM : begin
  819. code:=_asm_statement;
  820. end;
  821. else
  822. begin
  823. if (token=INTCONST) or
  824. ((token=ID) and
  825. not((cs_delphi2_compatible in aktswitches) and
  826. (pattern='RESULT'))) then
  827. begin
  828. getsym(pattern,false);
  829. lastsymknown:=true;
  830. lastsrsym:=srsym;
  831. { it is NOT necessarily the owner
  832. it can be a withsymtable !!! }
  833. lastsrsymtable:=srsymtable;
  834. if assigned(srsym) and (srsym^.typ=labelsym) then
  835. begin
  836. consume(token);
  837. consume(COLON);
  838. if plabelsym(srsym)^.defined then
  839. Message(sym_e_label_already_defined);
  840. plabelsym(srsym)^.defined:=true;
  841. { statement modifies srsym }
  842. labelnr:=plabelsym(srsym)^.number;
  843. lastsymknown:=false;
  844. { the pointer to the following instruction }
  845. { isn't a very clean way }
  846. {$ifdef tp}
  847. code:=gensinglenode(labeln,statement);
  848. {$else}
  849. code:=gensinglenode(labeln,statement());
  850. {$endif}
  851. code^.labelnr:=labelnr;
  852. { sorry, but there is a jump the easiest way }
  853. goto ready;
  854. end;
  855. end;
  856. p:=expr;
  857. if not(p^.treetype in [calln,assignn,breakn,inlinen,
  858. continuen]) then
  859. Message(cg_e_illegal_expression);
  860. { specify that we don't use the value returned by the call }
  861. { Question : can this be also improtant
  862. for inlinen ??
  863. it is used for :
  864. - dispose of temp stack space
  865. - dispose on FPU stack }
  866. if p^.treetype=calln then
  867. p^.return_value_used:=false;
  868. code:=p;
  869. end;
  870. end;
  871. ready:
  872. set_tree_filepos(code,filepos);
  873. statement:=code;
  874. end;
  875. function block(islibrary : boolean) : ptree;
  876. {$ifdef TEST_FUNCRET }
  877. var
  878. funcretsym : pfuncretsym;
  879. {$endif TEST_FUNCRET }
  880. begin
  881. {$ifdef TEST_FUNCRET }
  882. if procinfo.retdef<>pdef(voiddef) then
  883. begin
  884. { if the current is a function aktprocsym is non nil }
  885. { and there is a local symtable set }
  886. funcretsym:=new(pfuncretsym,init(aktprocsym^.name),@procinfo);
  887. { insert in local symtable }
  888. symtablestack^.insert(funcretsym);
  889. end;
  890. {$endif TEST_FUNCRET }
  891. read_declarations(islibrary);
  892. { temporary space is set, while the BEGIN of the procedure }
  893. if (symtablestack^.symtabletype=localsymtable) then
  894. procinfo.firsttemp := -symtablestack^.datasize
  895. else procinfo.firsttemp := 0;
  896. { space for the return value }
  897. { !!!!! this means that we can not set the return value
  898. in a subfunction !!!!! }
  899. { because we don't know yet where the address is }
  900. if procinfo.retdef<>pdef(voiddef) then
  901. begin
  902. if ret_in_acc(procinfo.retdef) or (procinfo.retdef^.deftype=floatdef) then
  903. { if (procinfo.retdef^.deftype=orddef) or
  904. (procinfo.retdef^.deftype=pointerdef) or
  905. (procinfo.retdef^.deftype=enumdef) or
  906. (procinfo.retdef^.deftype=procvardef) or
  907. (procinfo.retdef^.deftype=floatdef) or
  908. (
  909. (procinfo.retdef^.deftype=setdef) and
  910. (psetdef(procinfo.retdef)^.settype=smallset)
  911. ) then }
  912. begin
  913. {$ifdef TEST_FUNCRET }
  914. { the space has been set in the local symtable }
  915. procinfo.retoffset:=-funcretsym^.address;
  916. strdispose(funcretsym^._name);
  917. { lowercase name unreachable }
  918. { as it is handled differently }
  919. funcretsym^._name:=strpnew('func_result');
  920. {$else TEST_FUNCRET }
  921. { align func result at 4 byte }
  922. procinfo.retoffset:=
  923. -((-procinfo.firsttemp+(procinfo.retdef^.size+3)) div 4)*4;
  924. procinfo.firsttemp:=procinfo.retoffset;
  925. {$endif TEST_FUNCRET }
  926. if (procinfo.flags and pi_operator)<>0 then
  927. {opsym^.address:=procinfo.call_offset; is wrong PM }
  928. opsym^.address:=-procinfo.retoffset;
  929. { eax is modified by a function }
  930. {$ifdef i386}
  931. usedinproc:=usedinproc or ($80 shr byte(R_EAX))
  932. {$endif}
  933. {$ifdef m68k}
  934. usedinproc:=usedinproc or ($800 shr word(R_D0))
  935. {$endif}
  936. end;
  937. end;
  938. {Unit initialization?.}
  939. if (lexlevel=1) then
  940. if (token=_END) then
  941. begin
  942. consume(_END);
  943. block:=nil;
  944. end
  945. else
  946. begin
  947. current_module^.flags:=current_module^.flags or uf_init;
  948. block:=statement_block;
  949. end
  950. else
  951. block:=statement_block;
  952. end;
  953. function assembler_block : ptree;
  954. begin
  955. read_declarations(false);
  956. { temporary space is set, while the BEGIN of the procedure }
  957. if symtablestack^.symtabletype=localsymtable then
  958. procinfo.firsttemp := -symtablestack^.datasize
  959. else procinfo.firsttemp := 0;
  960. { assembler code does not allocate }
  961. { space for the return value }
  962. if procinfo.retdef<>pdef(voiddef) then
  963. begin
  964. if ret_in_acc(procinfo.retdef) then
  965. begin
  966. { in assembler code the result should be directly in %eax
  967. procinfo.retoffset:=procinfo.firsttemp-procinfo.retdef^.size;
  968. procinfo.firsttemp:=procinfo.retoffset; }
  969. {$ifdef i386}
  970. usedinproc:=usedinproc or ($80 shr byte(R_EAX))
  971. {$endif}
  972. {$ifdef m68k}
  973. usedinproc:=usedinproc or ($800 shr word(R_D0))
  974. {$endif}
  975. end
  976. else if not is_fpu(procinfo.retdef) then
  977. { should we allow assembler functions of big elements ? }
  978. Message(parser_e_asm_incomp_with_function_return);
  979. end;
  980. { set the framepointer to esp for assembler functions }
  981. { but only if the are no local variables }
  982. { added no parameter also (PM) }
  983. if ((aktprocsym^.definition^.options and poassembler)<>0) and
  984. (aktprocsym^.definition^.localst^.datasize=0) and
  985. (aktprocsym^.definition^.parast^.datasize=0) then
  986. begin
  987. {$ifdef i386}
  988. procinfo.framepointer:=R_ESP;
  989. {$endif}
  990. {$ifdef m68k}
  991. procinfo.framepointer:=R_SP;
  992. {$endif}
  993. { set the right value for parameters }
  994. dec(aktprocsym^.definition^.parast^.call_offset,sizeof(pointer));
  995. dec(procinfo.call_offset,sizeof(pointer));
  996. end;
  997. assembler_block:=_asm_statement;
  998. end;
  999. end.
  1000. {
  1001. $Log$
  1002. Revision 1.11 1998-05-20 09:42:35 pierre
  1003. + UseTokenInfo now default
  1004. * unit in interface uses and implementation uses gives error now
  1005. * only one error for unknown symbol (uses lastsymknown boolean)
  1006. the problem came from the label code !
  1007. + first inlined procedures and function work
  1008. (warning there might be allowed cases were the result is still wrong !!)
  1009. * UseBrower updated gives a global list of all position of all used symbols
  1010. with switch -gb
  1011. Revision 1.10 1998/05/11 13:07:56 peter
  1012. + $ifdef NEWPPU for the new ppuformat
  1013. + $define GDB not longer required
  1014. * removed all warnings and stripped some log comments
  1015. * no findfirst/findnext anymore to remove smartlink *.o files
  1016. Revision 1.9 1998/05/06 08:38:46 pierre
  1017. * better position info with UseTokenInfo
  1018. UseTokenInfo greatly simplified
  1019. + added check for changed tree after first time firstpass
  1020. (if we could remove all the cases were it happen
  1021. we could skip all firstpass if firstpasscount > 1)
  1022. Only with ExtDebug
  1023. Revision 1.8 1998/05/05 12:05:42 florian
  1024. * problems with properties fixed
  1025. * crash fixed: i:=l when i and l are undefined, was a problem with
  1026. implementation of private/protected
  1027. Revision 1.7 1998/05/01 16:38:46 florian
  1028. * handling of private and protected fixed
  1029. + change_keywords_to_tp implemented to remove
  1030. keywords which aren't supported by tp
  1031. * break and continue are now symbols of the system unit
  1032. + widestring, longstring and ansistring type released
  1033. Revision 1.6 1998/04/30 15:59:42 pierre
  1034. * GDB works again better :
  1035. correct type info in one pass
  1036. + UseTokenInfo for better source position
  1037. * fixed one remaining bug in scanner for line counts
  1038. * several little fixes
  1039. Revision 1.5 1998/04/29 10:33:59 pierre
  1040. + added some code for ansistring (not complete nor working yet)
  1041. * corrected operator overloading
  1042. * corrected nasm output
  1043. + started inline procedures
  1044. + added starstarn : use ** for exponentiation (^ gave problems)
  1045. + started UseTokenInfo cond to get accurate positions
  1046. Revision 1.4 1998/04/08 16:58:05 pierre
  1047. * several bugfixes
  1048. ADD ADC and AND are also sign extended
  1049. nasm output OK (program still crashes at end
  1050. and creates wrong assembler files !!)
  1051. procsym types sym in tdef removed !!
  1052. }