pstatmnt.pas 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 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. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. tokens,node;
  23. function statement_block(starttoken : ttoken) : tnode;
  24. { reads an assembler block }
  25. function assembler_block : tnode;
  26. implementation
  27. uses
  28. { common }
  29. cutils,
  30. { global }
  31. globtype,globals,verbose,
  32. systems,cpuinfo,
  33. { aasm }
  34. cpubase,aasmbase,aasmtai,aasmcpu,
  35. { symtable }
  36. symconst,symbase,symtype,symdef,symsym,symtable,defbase,paramgr,
  37. { pass 1 }
  38. pass_1,htypechk,
  39. nbas,nmat,nadd,ncal,nmem,nset,ncnv,ninl,ncon,nld,nflw,
  40. { parser }
  41. scanner,
  42. pbase,pexpr,
  43. { codegen }
  44. rgobj,cgbase
  45. ,radirect
  46. {$ifdef i386}
  47. {$ifndef NoRa386Int}
  48. ,ra386int
  49. {$endif NoRa386Int}
  50. {$ifndef NoRa386Att}
  51. ,ra386att
  52. {$endif NoRa386Att}
  53. {$else}
  54. ,rasm
  55. {$endif i386}
  56. ;
  57. function statement : tnode;forward;
  58. function if_statement : tnode;
  59. var
  60. ex,if_a,else_a : tnode;
  61. begin
  62. consume(_IF);
  63. ex:=comp_expr(true);
  64. consume(_THEN);
  65. if token<>_ELSE then
  66. if_a:=statement
  67. else
  68. if_a:=nil;
  69. if try_to_consume(_ELSE) then
  70. else_a:=statement
  71. else
  72. else_a:=nil;
  73. if_statement:=genloopnode(ifn,ex,if_a,else_a,false);
  74. end;
  75. { creates a block (list) of statements, til the next END token }
  76. function statements_til_end : tnode;
  77. var
  78. first,last : tstatementnode;
  79. begin
  80. first:=nil;
  81. while token<>_END do
  82. begin
  83. if first=nil then
  84. begin
  85. last:=cstatementnode.create(nil,statement);
  86. first:=last;
  87. end
  88. else
  89. begin
  90. last.left:=cstatementnode.create(nil,statement);
  91. last:=tstatementnode(last.left);
  92. end;
  93. if not try_to_consume(_SEMICOLON) then
  94. break;
  95. consume_emptystats;
  96. end;
  97. consume(_END);
  98. statements_til_end:=cblocknode.create(first);
  99. end;
  100. function case_statement : tnode;
  101. var
  102. { contains the label number of currently parsed case block }
  103. aktcaselabel : tasmlabel;
  104. firstlabel : boolean;
  105. root : pcaserecord;
  106. { the typ of the case expression }
  107. casedef : tdef;
  108. procedure newcaselabel(l,h : TConstExprInt;first:boolean);
  109. var
  110. hcaselabel : pcaserecord;
  111. procedure insertlabel(var p : pcaserecord);
  112. begin
  113. if p=nil then p:=hcaselabel
  114. else
  115. if (p^._low>hcaselabel^._low) and
  116. (p^._low>hcaselabel^._high) then
  117. if (hcaselabel^.statement = p^.statement) and
  118. (p^._low = hcaselabel^._high + 1) then
  119. begin
  120. p^._low := hcaselabel^._low;
  121. dispose(hcaselabel);
  122. end
  123. else
  124. insertlabel(p^.less)
  125. else
  126. if (p^._high<hcaselabel^._low) and
  127. (p^._high<hcaselabel^._high) then
  128. if (hcaselabel^.statement = p^.statement) and
  129. (p^._high+1 = hcaselabel^._low) then
  130. begin
  131. p^._high := hcaselabel^._high;
  132. dispose(hcaselabel);
  133. end
  134. else
  135. insertlabel(p^.greater)
  136. else Message(parser_e_double_caselabel);
  137. end;
  138. begin
  139. new(hcaselabel);
  140. hcaselabel^.less:=nil;
  141. hcaselabel^.greater:=nil;
  142. hcaselabel^.statement:=aktcaselabel;
  143. hcaselabel^.firstlabel:=first;
  144. getlabel(hcaselabel^._at);
  145. hcaselabel^._low:=l;
  146. hcaselabel^._high:=h;
  147. insertlabel(root);
  148. end;
  149. var
  150. code,caseexpr,p,instruc,elseblock : tnode;
  151. hl1,hl2 : TConstExprInt;
  152. casedeferror : boolean;
  153. begin
  154. consume(_CASE);
  155. caseexpr:=comp_expr(true);
  156. { determines result type }
  157. rg.cleartempgen;
  158. do_resulttypepass(caseexpr);
  159. casedeferror:=false;
  160. casedef:=caseexpr.resulttype.def;
  161. if (not assigned(casedef)) or
  162. not(is_ordinal(casedef)) then
  163. begin
  164. CGMessage(type_e_ordinal_expr_expected);
  165. { create a correct tree }
  166. caseexpr.free;
  167. caseexpr:=cordconstnode.create(0,u32bittype);
  168. { set error flag so no rangechecks are done }
  169. casedeferror:=true;
  170. end;
  171. consume(_OF);
  172. inc(statement_level);
  173. root:=nil;
  174. instruc:=nil;
  175. repeat
  176. getlabel(aktcaselabel);
  177. firstlabel:=true;
  178. { maybe an instruction has more case labels }
  179. repeat
  180. p:=expr;
  181. if is_widechar(casedef) then
  182. begin
  183. if (p.nodetype=rangen) then
  184. begin
  185. trangenode(p).left:=ctypeconvnode.create(trangenode(p).left,cwidechartype);
  186. trangenode(p).right:=ctypeconvnode.create(trangenode(p).right,cwidechartype);
  187. do_resulttypepass(trangenode(p).left);
  188. do_resulttypepass(trangenode(p).right);
  189. end
  190. else
  191. begin
  192. p:=ctypeconvnode.create(p,cwidechartype);
  193. do_resulttypepass(p);
  194. end;
  195. end;
  196. hl1:=0;
  197. hl2:=0;
  198. if (p.nodetype=rangen) then
  199. begin
  200. { type checking for case statements }
  201. if is_subequal(casedef, trangenode(p).left.resulttype.def) and
  202. is_subequal(casedef, trangenode(p).right.resulttype.def) then
  203. begin
  204. hl1:=get_ordinal_value(trangenode(p).left);
  205. hl2:=get_ordinal_value(trangenode(p).right);
  206. if hl1>hl2 then
  207. CGMessage(parser_e_case_lower_less_than_upper_bound);
  208. if not casedeferror then
  209. begin
  210. testrange(casedef,hl1,false);
  211. testrange(casedef,hl2,false);
  212. end;
  213. end
  214. else
  215. CGMessage(parser_e_case_mismatch);
  216. newcaselabel(hl1,hl2,firstlabel);
  217. end
  218. else
  219. begin
  220. { type checking for case statements }
  221. if not is_subequal(casedef, p.resulttype.def) then
  222. CGMessage(parser_e_case_mismatch);
  223. hl1:=get_ordinal_value(p);
  224. if not casedeferror then
  225. testrange(casedef,hl1,false);
  226. newcaselabel(hl1,hl1,firstlabel);
  227. end;
  228. p.free;
  229. if token=_COMMA then
  230. consume(_COMMA)
  231. else
  232. break;
  233. firstlabel:=false;
  234. until false;
  235. consume(_COLON);
  236. { handles instruction block }
  237. p:=clabelnode.createcase(aktcaselabel,statement);
  238. { concats instruction }
  239. instruc:=cstatementnode.create(instruc,p);
  240. if not((token=_ELSE) or (token=_OTHERWISE) or (token=_END)) then
  241. consume(_SEMICOLON);
  242. until (token=_ELSE) or (token=_OTHERWISE) or (token=_END);
  243. if (token=_ELSE) or (token=_OTHERWISE) then
  244. begin
  245. if not try_to_consume(_ELSE) then
  246. consume(_OTHERWISE);
  247. elseblock:=statements_til_end;
  248. end
  249. else
  250. begin
  251. elseblock:=nil;
  252. consume(_END);
  253. end;
  254. dec(statement_level);
  255. code:=ccasenode.create(caseexpr,instruc,root);
  256. tcasenode(code).elseblock:=elseblock;
  257. case_statement:=code;
  258. end;
  259. function repeat_statement : tnode;
  260. var
  261. first,last,p_e : tnode;
  262. begin
  263. consume(_REPEAT);
  264. first:=nil;
  265. inc(statement_level);
  266. while token<>_UNTIL do
  267. begin
  268. if first=nil then
  269. begin
  270. last:=cstatementnode.create(nil,statement);
  271. first:=last;
  272. end
  273. else
  274. begin
  275. tstatementnode(last).left:=cstatementnode.create(nil,statement);
  276. last:=tstatementnode(last).left;
  277. end;
  278. if not try_to_consume(_SEMICOLON) then
  279. break;
  280. consume_emptystats;
  281. end;
  282. consume(_UNTIL);
  283. dec(statement_level);
  284. first:=cblocknode.create(first);
  285. p_e:=comp_expr(true);
  286. repeat_statement:=genloopnode(whilerepeatn,p_e,first,nil,true);
  287. end;
  288. function while_statement : tnode;
  289. var
  290. p_e,p_a : tnode;
  291. begin
  292. consume(_WHILE);
  293. p_e:=comp_expr(true);
  294. consume(_DO);
  295. p_a:=statement;
  296. while_statement:=genloopnode(whilerepeatn,p_e,p_a,nil,false);
  297. end;
  298. function for_statement : tnode;
  299. var
  300. p_e,tovalue,p_a : tnode;
  301. backward : boolean;
  302. begin
  303. { parse loop header }
  304. consume(_FOR);
  305. p_e:=expr;
  306. if token=_DOWNTO then
  307. begin
  308. consume(_DOWNTO);
  309. backward:=true;
  310. end
  311. else
  312. begin
  313. consume(_TO);
  314. backward:=false;
  315. end;
  316. tovalue:=comp_expr(true);
  317. consume(_DO);
  318. { ... now the instruction }
  319. p_a:=statement;
  320. for_statement:=genloopnode(forn,p_e,tovalue,p_a,backward);
  321. end;
  322. function _with_statement : tnode;
  323. var
  324. right,p : tnode;
  325. i,levelcount : longint;
  326. withsymtable,symtab : tsymtable;
  327. obj : tobjectdef;
  328. hp : tnode;
  329. begin
  330. p:=comp_expr(true);
  331. do_resulttypepass(p);
  332. set_varstate(p,false);
  333. right:=nil;
  334. if (not codegenerror) and
  335. (p.resulttype.def.deftype in [objectdef,recorddef]) then
  336. begin
  337. case p.resulttype.def.deftype of
  338. objectdef : begin
  339. obj:=tobjectdef(p.resulttype.def);
  340. symtab:=twithsymtable.Create(obj,obj.symtable.symsearch);
  341. withsymtable:=symtab;
  342. if (p.nodetype=loadn) and
  343. (tloadnode(p).symtable=aktprocdef.localst) then
  344. twithsymtable(symtab).direct_with:=true;
  345. twithsymtable(symtab).withrefnode:=p;
  346. levelcount:=1;
  347. obj:=obj.childof;
  348. while assigned(obj) do
  349. begin
  350. symtab.next:=twithsymtable.create(obj,obj.symtable.symsearch);
  351. symtab:=symtab.next;
  352. if (p.nodetype=loadn) and
  353. (tloadnode(p).symtable=aktprocdef.localst) then
  354. twithsymtable(symtab).direct_with:=true;
  355. twithsymtable(symtab).withrefnode:=p;
  356. obj:=obj.childof;
  357. inc(levelcount);
  358. end;
  359. symtab.next:=symtablestack;
  360. symtablestack:=withsymtable;
  361. end;
  362. recorddef : begin
  363. symtab:=trecorddef(p.resulttype.def).symtable;
  364. levelcount:=1;
  365. withsymtable:=twithsymtable.create(trecorddef(p.resulttype.def),symtab.symsearch);
  366. if (p.nodetype=loadn) and
  367. (tloadnode(p).symtable=aktprocdef.localst) then
  368. twithsymtable(withsymtable).direct_with:=true;
  369. twithsymtable(withsymtable).withrefnode:=p;
  370. withsymtable.next:=symtablestack;
  371. symtablestack:=withsymtable;
  372. end;
  373. end;
  374. if token=_COMMA then
  375. begin
  376. consume(_COMMA);
  377. right:=_with_statement{$ifdef FPCPROCVAR}(){$endif};
  378. end
  379. else
  380. begin
  381. consume(_DO);
  382. if token<>_SEMICOLON then
  383. right:=statement
  384. else
  385. right:=cerrornode.create;
  386. end;
  387. for i:=1 to levelcount do
  388. symtablestack:=symtablestack.next;
  389. _with_statement:=cwithnode.create(twithsymtable(withsymtable),p,right,levelcount);
  390. end
  391. else
  392. begin
  393. Message(parser_e_false_with_expr);
  394. { try to recover from error }
  395. if token=_COMMA then
  396. begin
  397. consume(_COMMA);
  398. hp:=_with_statement{$ifdef FPCPROCVAR}(){$endif};
  399. if (hp=nil) then; { remove warning about unused }
  400. end
  401. else
  402. begin
  403. consume(_DO);
  404. { ignore all }
  405. if token<>_SEMICOLON then
  406. statement;
  407. end;
  408. _with_statement:=nil;
  409. end;
  410. end;
  411. function with_statement : tnode;
  412. begin
  413. consume(_WITH);
  414. with_statement:=_with_statement;
  415. end;
  416. function raise_statement : tnode;
  417. var
  418. p,pobj,paddr,pframe : tnode;
  419. begin
  420. pobj:=nil;
  421. paddr:=nil;
  422. pframe:=nil;
  423. consume(_RAISE);
  424. if not(token in [_SEMICOLON,_END]) then
  425. begin
  426. { object }
  427. pobj:=comp_expr(true);
  428. if try_to_consume(_AT) then
  429. begin
  430. paddr:=comp_expr(true);
  431. if try_to_consume(_COMMA) then
  432. pframe:=comp_expr(true);
  433. end;
  434. end
  435. else
  436. begin
  437. if (block_type<>bt_except) then
  438. Message(parser_e_no_reraise_possible);
  439. end;
  440. p:=craisenode.create(pobj,paddr,pframe);
  441. raise_statement:=p;
  442. end;
  443. function try_statement : tnode;
  444. var
  445. p_try_block,p_finally_block,first,last,
  446. p_default,p_specific,hp : tnode;
  447. ot : ttype;
  448. sym : tvarsym;
  449. old_block_type : tblock_type;
  450. exceptsymtable : tsymtable;
  451. objname,objrealname : stringid;
  452. srsym : tsym;
  453. srsymtable : tsymtable;
  454. oldaktexceptblock: integer;
  455. begin
  456. procinfo^.flags:=procinfo^.flags or pi_uses_exceptions;
  457. p_default:=nil;
  458. p_specific:=nil;
  459. { read statements to try }
  460. consume(_TRY);
  461. first:=nil;
  462. inc(exceptblockcounter);
  463. oldaktexceptblock := aktexceptblock;
  464. aktexceptblock := exceptblockcounter;
  465. inc(statement_level);
  466. while (token<>_FINALLY) and (token<>_EXCEPT) do
  467. begin
  468. if first=nil then
  469. begin
  470. last:=cstatementnode.create(nil,statement);
  471. first:=last;
  472. end
  473. else
  474. begin
  475. tstatementnode(last).left:=cstatementnode.create(nil,statement);
  476. last:=tstatementnode(last).left;
  477. end;
  478. if not try_to_consume(_SEMICOLON) then
  479. break;
  480. consume_emptystats;
  481. end;
  482. p_try_block:=cblocknode.create(first);
  483. if try_to_consume(_FINALLY) then
  484. begin
  485. inc(exceptblockcounter);
  486. aktexceptblock := exceptblockcounter;
  487. p_finally_block:=statements_til_end;
  488. try_statement:=ctryfinallynode.create(p_try_block,p_finally_block);
  489. dec(statement_level);
  490. end
  491. else
  492. begin
  493. consume(_EXCEPT);
  494. old_block_type:=block_type;
  495. block_type:=bt_except;
  496. inc(exceptblockcounter);
  497. aktexceptblock := exceptblockcounter;
  498. ot:=generrortype;
  499. p_specific:=nil;
  500. if (idtoken=_ON) then
  501. { catch specific exceptions }
  502. begin
  503. repeat
  504. consume(_ID);
  505. if token=_ID then
  506. begin
  507. objname:=pattern;
  508. objrealname:=orgpattern;
  509. { can't use consume_sym here, because we need already
  510. to check for the colon }
  511. searchsym(objname,srsym,srsymtable);
  512. consume(_ID);
  513. { is a explicit name for the exception given ? }
  514. if try_to_consume(_COLON) then
  515. begin
  516. consume_sym(srsym,srsymtable);
  517. if (srsym.typ=typesym) and
  518. is_class(ttypesym(srsym).restype.def) then
  519. begin
  520. ot:=ttypesym(srsym).restype;
  521. sym:=tvarsym.create(objrealname,ot);
  522. end
  523. else
  524. begin
  525. sym:=tvarsym.create(objrealname,generrortype);
  526. if (srsym.typ=typesym) then
  527. Message1(type_e_class_type_expected,ttypesym(srsym).restype.def.typename)
  528. else
  529. Message1(type_e_class_type_expected,ot.def.typename);
  530. end;
  531. exceptsymtable:=tstt_exceptsymtable.create;
  532. exceptsymtable.insert(sym);
  533. { insert the exception symtable stack }
  534. exceptsymtable.next:=symtablestack;
  535. symtablestack:=exceptsymtable;
  536. end
  537. else
  538. begin
  539. { check if type is valid, must be done here because
  540. with "e: Exception" the e is not necessary }
  541. if srsym=nil then
  542. begin
  543. identifier_not_found(objrealname);
  544. srsym:=generrorsym;
  545. end;
  546. { support unit.identifier }
  547. if srsym.typ=unitsym then
  548. begin
  549. consume(_POINT);
  550. srsym:=searchsymonlyin(tunitsym(srsym).unitsymtable,pattern);
  551. if srsym=nil then
  552. begin
  553. identifier_not_found(orgpattern);
  554. srsym:=generrorsym;
  555. end;
  556. consume(_ID);
  557. end;
  558. { check if type is valid, must be done here because
  559. with "e: Exception" the e is not necessary }
  560. if (srsym.typ=typesym) and
  561. is_class(ttypesym(srsym).restype.def) then
  562. ot:=ttypesym(srsym).restype
  563. else
  564. begin
  565. ot:=generrortype;
  566. if (srsym.typ=typesym) then
  567. Message1(type_e_class_type_expected,ttypesym(srsym).restype.def.typename)
  568. else
  569. Message1(type_e_class_type_expected,ot.def.typename);
  570. end;
  571. exceptsymtable:=nil;
  572. end;
  573. end
  574. else
  575. consume(_ID);
  576. consume(_DO);
  577. hp:=connode.create(nil,statement);
  578. if ot.def.deftype=errordef then
  579. begin
  580. hp.free;
  581. hp:=cerrornode.create;
  582. end;
  583. if p_specific=nil then
  584. begin
  585. last:=hp;
  586. p_specific:=last;
  587. end
  588. else
  589. begin
  590. tonnode(last).left:=hp;
  591. last:=tonnode(last).left;
  592. end;
  593. { set the informations }
  594. { only if the creation of the onnode was succesful, it's possible }
  595. { that last and hp are errornodes (JM) }
  596. if last.nodetype = onn then
  597. begin
  598. tonnode(last).excepttype:=tobjectdef(ot.def);
  599. tonnode(last).exceptsymtable:=exceptsymtable;
  600. end;
  601. { remove exception symtable }
  602. if assigned(exceptsymtable) then
  603. begin
  604. dellexlevel;
  605. if last.nodetype <> onn then
  606. exceptsymtable.free;
  607. end;
  608. if not try_to_consume(_SEMICOLON) then
  609. break;
  610. consume_emptystats;
  611. until (token=_END) or (token=_ELSE);
  612. if token=_ELSE then
  613. { catch the other exceptions }
  614. begin
  615. consume(_ELSE);
  616. p_default:=statements_til_end;
  617. end
  618. else
  619. consume(_END);
  620. end
  621. else
  622. { catch all exceptions }
  623. begin
  624. p_default:=statements_til_end;
  625. end;
  626. dec(statement_level);
  627. block_type:=old_block_type;
  628. try_statement:=ctryexceptnode.create(p_try_block,p_specific,p_default);
  629. end;
  630. aktexceptblock := oldaktexceptblock;
  631. end;
  632. function _asm_statement : tnode;
  633. var
  634. asmstat : tasmnode;
  635. Marker : tai;
  636. r,r2 : tregister;
  637. found : boolean;
  638. begin
  639. Inside_asm_statement:=true;
  640. case aktasmmode of
  641. asmmode_none : ; { just be there to allow to a compile without
  642. any assembler readers }
  643. {$ifdef i386}
  644. {$ifndef NoRA386Att}
  645. asmmode_i386_att:
  646. asmstat:=tasmnode(ra386att.assemble);
  647. {$endif NoRA386Att}
  648. {$ifndef NoRA386Int}
  649. asmmode_i386_intel:
  650. asmstat:=tasmnode(ra386int.assemble);
  651. {$endif NoRA386Int}
  652. {$else}
  653. asmmode_direct:
  654. begin
  655. if not target_asm.allowdirect then
  656. Message(parser_f_direct_assembler_not_allowed);
  657. if (aktprocdef.proccalloption=pocall_inline) then
  658. Begin
  659. Message1(parser_w_not_supported_for_inline,'direct asm');
  660. Message(parser_w_inlining_disabled);
  661. aktprocdef.proccalloption:=pocall_fpccall;
  662. End;
  663. asmstat:=tasmnode(radirect.assemble);
  664. end;
  665. asmmode_standard:
  666. asmstat:=tasmnode(rasm.assemble);
  667. {$endif}
  668. else
  669. Message(parser_f_assembler_reader_not_supported);
  670. end;
  671. { Read first the _ASM statement }
  672. consume(_ASM);
  673. { END is read }
  674. if try_to_consume(_LECKKLAMMER) then
  675. begin
  676. if token<>_RECKKLAMMER then
  677. repeat
  678. { it's possible to specify the modified registers }
  679. include(asmstat.flags,nf_object_preserved);
  680. found:=false;
  681. for r:=low(tregister) to high(tregister) do
  682. if pattern=upper(std_reg2str[r]) then
  683. begin
  684. if r = SELF_POINTER_REG then
  685. begin
  686. exclude(asmstat.flags,nf_object_preserved);
  687. end;
  688. include(rg.usedinproc,r);
  689. include(rg.usedbyproc,r);
  690. found:=true;
  691. break;
  692. end;
  693. if not(found) then
  694. consume(_RECKKLAMMER);
  695. consume(_CSTRING);
  696. if not try_to_consume(_COMMA) then
  697. break;
  698. until false;
  699. consume(_RECKKLAMMER);
  700. end
  701. else
  702. begin
  703. rg.usedbyproc := ALL_REGISTERS;
  704. rg.usedinproc := ALL_REGISTERS;
  705. end;
  706. { mark the start and the end of the assembler block
  707. this is needed for the optimizer }
  708. If Assigned(AsmStat.p_asm) Then
  709. Begin
  710. Marker := Tai_Marker.Create(AsmBlockStart);
  711. AsmStat.p_asm.Insert(Marker);
  712. Marker := Tai_Marker.Create(AsmBlockEnd);
  713. AsmStat.p_asm.Concat(Marker);
  714. End;
  715. Inside_asm_statement:=false;
  716. _asm_statement:=asmstat;
  717. end;
  718. function statement : tnode;
  719. var
  720. p : tnode;
  721. code : tnode;
  722. filepos : tfileposinfo;
  723. srsym : tsym;
  724. srsymtable : tsymtable;
  725. s : stringid;
  726. begin
  727. filepos:=akttokenpos;
  728. case token of
  729. _GOTO :
  730. begin
  731. if not(cs_support_goto in aktmoduleswitches)then
  732. Message(sym_e_goto_and_label_not_supported);
  733. consume(_GOTO);
  734. if (token<>_INTCONST) and (token<>_ID) then
  735. begin
  736. Message(sym_e_label_not_found);
  737. code:=cerrornode.create;
  738. end
  739. else
  740. begin
  741. if token=_ID then
  742. consume_sym(srsym,srsymtable)
  743. else
  744. begin
  745. searchsym(pattern,srsym,srsymtable);
  746. if srsym=nil then
  747. begin
  748. identifier_not_found(pattern);
  749. srsym:=generrorsym;
  750. srsymtable:=nil;
  751. end;
  752. consume(token);
  753. end;
  754. if srsym.typ<>labelsym then
  755. begin
  756. Message(sym_e_id_is_no_label_id);
  757. code:=cerrornode.create;
  758. end
  759. else
  760. begin
  761. code:=cgotonode.create(tlabelsym(srsym));
  762. tgotonode(code).labsym:=tlabelsym(srsym);
  763. { set flag that this label is used }
  764. tlabelsym(srsym).used:=true;
  765. end;
  766. end;
  767. end;
  768. _BEGIN :
  769. code:=statement_block(_BEGIN);
  770. _IF :
  771. code:=if_statement;
  772. _CASE :
  773. code:=case_statement;
  774. _REPEAT :
  775. code:=repeat_statement;
  776. _WHILE :
  777. code:=while_statement;
  778. _FOR :
  779. code:=for_statement;
  780. _WITH :
  781. code:=with_statement;
  782. _TRY :
  783. code:=try_statement;
  784. _RAISE :
  785. code:=raise_statement;
  786. { semicolons,else until and end are ignored }
  787. _SEMICOLON,
  788. _ELSE,
  789. _UNTIL,
  790. _END:
  791. code:=cnothingnode.create;
  792. _FAIL :
  793. begin
  794. if (aktprocdef.proctypeoption<>potype_constructor) then
  795. Message(parser_e_fail_only_in_constructor);
  796. consume(_FAIL);
  797. code:=cfailnode.create;
  798. end;
  799. _ASM :
  800. code:=_asm_statement;
  801. _EOF :
  802. Message(scan_f_end_of_file);
  803. else
  804. begin
  805. p:=expr;
  806. { When a colon follows a intconst then transform it into a label }
  807. if try_to_consume(_COLON) then
  808. begin
  809. s:=tostr(tordconstnode(p).value);
  810. p.free;
  811. searchsym(s,srsym,srsymtable);
  812. if assigned(srsym) then
  813. begin
  814. if tlabelsym(srsym).defined then
  815. Message(sym_e_label_already_defined);
  816. tlabelsym(srsym).defined:=true;
  817. p:=clabelnode.create(tlabelsym(srsym),nil);
  818. end
  819. else
  820. begin
  821. identifier_not_found(s);
  822. p:=cnothingnode.create;
  823. end;
  824. end;
  825. if p.nodetype=labeln then
  826. begin
  827. { the pointer to the following instruction }
  828. { isn't a very clean way }
  829. tlabelnode(p).left:=statement{$ifdef FPCPROCVAR}(){$endif};
  830. { be sure to have left also resulttypepass }
  831. resulttypepass(tlabelnode(p).left);
  832. end;
  833. { blockn support because a read/write is changed into a blocknode }
  834. { with a separate statement for each read/write operation (JM) }
  835. { the same is true for val() if the third parameter is not 32 bit }
  836. if not(p.nodetype in [nothingn,calln,assignn,breakn,inlinen,
  837. continuen,labeln,blockn,exitn]) then
  838. Message(cg_e_illegal_expression);
  839. { specify that we don't use the value returned by the call }
  840. { Question : can this be also improtant
  841. for inlinen ??
  842. it is used for :
  843. - dispose of temp stack space
  844. - dispose on FPU stack }
  845. if p.nodetype=calln then
  846. exclude(p.flags,nf_return_value_used);
  847. code:=p;
  848. end;
  849. end;
  850. if assigned(code) then
  851. code.set_tree_filepos(filepos);
  852. statement:=code;
  853. end;
  854. function statement_block(starttoken : ttoken) : tnode;
  855. var
  856. first,last : tnode;
  857. filepos : tfileposinfo;
  858. begin
  859. first:=nil;
  860. filepos:=akttokenpos;
  861. consume(starttoken);
  862. inc(statement_level);
  863. while not(token in [_END,_FINALIZATION]) do
  864. begin
  865. if first=nil then
  866. begin
  867. last:=cstatementnode.create(nil,statement);
  868. first:=last;
  869. end
  870. else
  871. begin
  872. tstatementnode(last).left:=cstatementnode.create(nil,statement);
  873. last:=tstatementnode(last).left;
  874. end;
  875. if (token in [_END,_FINALIZATION]) then
  876. break
  877. else
  878. begin
  879. { if no semicolon, then error and go on }
  880. if token<>_SEMICOLON then
  881. begin
  882. consume(_SEMICOLON);
  883. consume_all_until(_SEMICOLON);
  884. end;
  885. consume(_SEMICOLON);
  886. end;
  887. consume_emptystats;
  888. end;
  889. { don't consume the finalization token, it is consumed when
  890. reading the finalization block, but allow it only after
  891. an initalization ! }
  892. if (starttoken<>_INITIALIZATION) or (token<>_FINALIZATION) then
  893. consume(_END);
  894. dec(statement_level);
  895. last:=cblocknode.create(first);
  896. last.set_tree_filepos(filepos);
  897. statement_block:=last;
  898. end;
  899. function assembler_block : tnode;
  900. {# Optimize the assembler block by removing all references
  901. which are via the frame pointer by replacing them with
  902. references via the stack pointer.
  903. This is only available to certain cpu targets where
  904. the frame pointer saving must be done explicitly.
  905. }
  906. procedure OptimizeFramePointer(p:tasmnode);
  907. var
  908. hp : tai;
  909. parafixup,
  910. i : longint;
  911. begin
  912. { replace framepointer with stackpointer }
  913. procinfo^.framepointer:=STACK_POINTER_REG;
  914. { set the right value for parameters }
  915. dec(aktprocdef.parast.address_fixup,pointer_size);
  916. dec(procinfo^.para_offset,pointer_size);
  917. { replace all references to parameters in the instructions,
  918. the parameters can be identified by the parafixup option
  919. that is set. For normal user coded [ebp+4] this field is not
  920. set }
  921. parafixup:=aktprocdef.parast.address_fixup;
  922. hp:=tai(p.p_asm.first);
  923. while assigned(hp) do
  924. begin
  925. if hp.typ=ait_instruction then
  926. begin
  927. { fixup the references }
  928. for i:=1 to taicpu(hp).ops do
  929. begin
  930. with taicpu(hp).oper[i-1] do
  931. if typ=top_ref then
  932. begin
  933. case ref^.options of
  934. ref_parafixup :
  935. begin
  936. ref^.offsetfixup:=parafixup;
  937. ref^.base:=STACK_POINTER_REG;
  938. end;
  939. end;
  940. end;
  941. end;
  942. end;
  943. hp:=tai(hp.next);
  944. end;
  945. end;
  946. {$ifdef CHECKFORPUSH}
  947. function UsesPush(p:tasmnode):boolean;
  948. var
  949. hp : tai;
  950. begin
  951. hp:=tai(p.p_asm.first);
  952. while assigned(hp) do
  953. begin
  954. if (hp.typ=ait_instruction) and
  955. (taicpu(hp).opcode=A_PUSH) then
  956. begin
  957. UsesPush:=true;
  958. exit;
  959. end;
  960. hp:=tai(hp.next);
  961. end;
  962. UsesPush:=false;
  963. end;
  964. {$endif CHECKFORPUSH}
  965. var
  966. p : tnode;
  967. haslocals,hasparas : boolean;
  968. begin
  969. { retrieve info about locals and paras before a result
  970. is inserted in the symtable }
  971. haslocals:=(aktprocdef.localst.datasize>0);
  972. hasparas:=(aktprocdef.parast.datasize>0);
  973. { temporary space is set, while the BEGIN of the procedure }
  974. if symtablestack.symtabletype=localsymtable then
  975. procinfo^.firsttemp_offset := -symtablestack.datasize
  976. else
  977. procinfo^.firsttemp_offset := 0;
  978. { assembler code does not allocate }
  979. { space for the return value }
  980. if not is_void(aktprocdef.rettype.def) then
  981. begin
  982. aktprocdef.funcretsym:=tfuncretsym.create(aktprocsym.name,aktprocdef.rettype);
  983. { insert in local symtable }
  984. { but with another name, so that recursive calls are possible }
  985. symtablestack.insert(aktprocdef.funcretsym);
  986. symtablestack.rename(aktprocdef.funcretsym.name,'$result');
  987. { update the symtablesize back to 0 if there were no locals }
  988. if not haslocals then
  989. symtablestack.datasize:=0;
  990. { set the used flag for the return }
  991. if paramanager.ret_in_acc(aktprocdef.rettype.def) then
  992. include(rg.usedinproc,accumulator);
  993. end;
  994. { force the asm statement }
  995. if token<>_ASM then
  996. consume(_ASM);
  997. procinfo^.Flags := procinfo^.Flags Or pi_is_assembler;
  998. p:=_asm_statement;
  999. { set the framepointer to esp for assembler functions when the
  1000. following conditions are met:
  1001. - if the are no local variables
  1002. - no reference to the result variable (refcount<=1)
  1003. - result is not stored as parameter
  1004. - target processor has optional frame pointer save
  1005. (vm, i386, vm only currently)
  1006. }
  1007. if (po_assembler in aktprocdef.procoptions) and
  1008. (not haslocals) and
  1009. (not hasparas) and
  1010. (aktprocdef.owner.symtabletype<>objectsymtable) and
  1011. (not assigned(aktprocdef.funcretsym) or
  1012. (tfuncretsym(aktprocdef.funcretsym).refcount<=1)) and
  1013. not(paramanager.ret_in_param(aktprocdef.rettype.def)) and
  1014. (target_cpu in [cpu_i386,cpu_m68k,cpu_vm])
  1015. {$ifdef CHECKFORPUSH}
  1016. and not(UsesPush(tasmnode(p)))
  1017. {$endif CHECKFORPUSH}
  1018. then
  1019. OptimizeFramePointer(tasmnode(p));
  1020. { Flag the result as assigned when it is returned in the
  1021. accumulator or on the fpu stack }
  1022. if assigned(aktprocdef.funcretsym) and
  1023. (is_fpu(aktprocdef.rettype.def) or
  1024. paramanager.ret_in_acc(aktprocdef.rettype.def)) then
  1025. tfuncretsym(aktprocdef.funcretsym).funcretstate:=vs_assigned;
  1026. { because the END is already read we need to get the
  1027. last_endtoken_filepos here (PFV) }
  1028. last_endtoken_filepos:=akttokenpos;
  1029. assembler_block:=p;
  1030. end;
  1031. end.
  1032. {
  1033. $Log$
  1034. Revision 1.68 2002-08-10 14:46:30 carl
  1035. + moved target_cpu_string to cpuinfo
  1036. * renamed asmmode enum.
  1037. * assembler reader has now less ifdef's
  1038. * move from nppcmem.pas -> ncgmem.pas vec. node.
  1039. Revision 1.67 2002/08/09 19:11:44 carl
  1040. + reading of used registers in assembler routines is now
  1041. cpu-independent
  1042. Revision 1.66 2002/08/06 20:55:22 florian
  1043. * first part of ppc calling conventions fix
  1044. Revision 1.65 2002/07/28 20:45:22 florian
  1045. + added direct assembler reader for PowerPC
  1046. Revision 1.64 2002/07/20 11:57:56 florian
  1047. * types.pas renamed to defbase.pas because D6 contains a types
  1048. unit so this would conflicts if D6 programms are compiled
  1049. + Willamette/SSE2 instructions to assembler added
  1050. Revision 1.63 2002/07/19 11:41:36 daniel
  1051. * State tracker work
  1052. * The whilen and repeatn are now completely unified into whilerepeatn. This
  1053. allows the state tracker to change while nodes automatically into
  1054. repeat nodes.
  1055. * Resulttypepass improvements to the notn. 'not not a' is optimized away and
  1056. 'not(a>b)' is optimized into 'a<=b'.
  1057. * Resulttypepass improvements to the whilerepeatn. 'while not a' is optimized
  1058. by removing the notn and later switchting the true and falselabels. The
  1059. same is done with 'repeat until not a'.
  1060. Revision 1.62 2002/07/16 15:34:20 florian
  1061. * exit is now a syssym instead of a keyword
  1062. Revision 1.61 2002/07/11 14:41:28 florian
  1063. * start of the new generic parameter handling
  1064. Revision 1.60 2002/07/04 20:43:01 florian
  1065. * first x86-64 patches
  1066. Revision 1.59 2002/07/01 18:46:25 peter
  1067. * internal linker
  1068. * reorganized aasm layer
  1069. Revision 1.58 2002/05/18 13:34:13 peter
  1070. * readded missing revisions
  1071. Revision 1.57 2002/05/16 19:46:44 carl
  1072. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  1073. + try to fix temp allocation (still in ifdef)
  1074. + generic constructor calls
  1075. + start of tassembler / tmodulebase class cleanup
  1076. Revision 1.55 2002/05/06 19:56:42 carl
  1077. + added more patches from Mazen for SPARC port
  1078. Revision 1.54 2002/04/21 19:02:05 peter
  1079. * removed newn and disposen nodes, the code is now directly
  1080. inlined from pexpr
  1081. * -an option that will write the secondpass nodes to the .s file, this
  1082. requires EXTDEBUG define to actually write the info
  1083. * fixed various internal errors and crashes due recent code changes
  1084. Revision 1.53 2002/04/20 21:32:24 carl
  1085. + generic FPC_CHECKPOINTER
  1086. + first parameter offset in stack now portable
  1087. * rename some constants
  1088. + move some cpu stuff to other units
  1089. - remove unused constents
  1090. * fix stacksize for some targets
  1091. * fix generic size problems which depend now on EXTEND_SIZE constant
  1092. Revision 1.52 2002/04/16 16:11:17 peter
  1093. * using inherited; without a parent having the same function
  1094. will do nothing like delphi
  1095. Revision 1.51 2002/04/15 19:01:28 carl
  1096. + target_info.size_of_pointer -> pointer_Size
  1097. Revision 1.50 2002/04/14 16:53:54 carl
  1098. + asm statement uses ALL_REGISTERS
  1099. Revision 1.49 2002/03/31 20:26:36 jonas
  1100. + a_loadfpu_* and a_loadmm_* methods in tcg
  1101. * register allocation is now handled by a class and is mostly processor
  1102. independent (+rgobj.pas and i386/rgcpu.pas)
  1103. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  1104. * some small improvements and fixes to the optimizer
  1105. * some register allocation fixes
  1106. * some fpuvaroffset fixes in the unary minus node
  1107. * push/popusedregisters is now called rg.save/restoreusedregisters and
  1108. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  1109. also better optimizable)
  1110. * fixed and optimized register saving/restoring for new/dispose nodes
  1111. * LOC_FPU locations now also require their "register" field to be set to
  1112. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  1113. - list field removed of the tnode class because it's not used currently
  1114. and can cause hard-to-find bugs
  1115. Revision 1.48 2002/03/11 19:10:28 peter
  1116. * Regenerated with updated fpcmake
  1117. Revision 1.47 2002/03/04 17:54:59 peter
  1118. * allow oridinal labels again
  1119. Revision 1.46 2002/01/29 21:32:03 peter
  1120. * allow accessing locals in other lexlevel when the current assembler
  1121. routine doesn't have locals.
  1122. Revision 1.45 2002/01/24 18:25:49 peter
  1123. * implicit result variable generation for assembler routines
  1124. * removed m_tp modeswitch, use m_tp7 or not(m_fpc) instead
  1125. }