nset.pas 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009
  1. {
  2. Copyright (c) 2000-2002 by Florian Klaempfl
  3. Type checking and register allocation for set/case nodes
  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 nset;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. cclasses,constexp,
  22. node,globtype,globals,
  23. aasmbase,aasmtai,aasmdata,ncon,symtype;
  24. type
  25. TLabelType = (ltOrdinal, ltConstString);
  26. pcaselabel = ^tcaselabel;
  27. tcaselabel = record
  28. { unique blockid }
  29. blockid : longint;
  30. { left and right tree node }
  31. less,
  32. greater : pcaselabel;
  33. { range type }
  34. case label_type : TLabelType of
  35. ltOrdinal:
  36. (
  37. _low,
  38. _high : TConstExprInt;
  39. );
  40. ltConstString:
  41. (
  42. _low_str,
  43. _high_str : tstringconstnode;
  44. );
  45. end;
  46. pcaseblock = ^tcaseblock;
  47. tcaseblock = record
  48. { label (only used in pass_generate_code) }
  49. blocklabel : tasmlabel;
  50. { instructions }
  51. statement : tnode;
  52. end;
  53. tsetelementnode = class(tbinarynode)
  54. constructor create(l,r : tnode);virtual;
  55. function pass_typecheck:tnode;override;
  56. function pass_1 : tnode;override;
  57. end;
  58. tsetelementnodeclass = class of tsetelementnode;
  59. tinnode = class(tbinopnode)
  60. constructor create(l,r : tnode);virtual;reintroduce;
  61. function pass_typecheck:tnode;override;
  62. function simplify:tnode;override;
  63. function pass_1 : tnode;override;
  64. end;
  65. tinnodeclass = class of tinnode;
  66. trangenode = class(tbinarynode)
  67. constructor create(l,r : tnode);virtual;
  68. function pass_typecheck:tnode;override;
  69. function pass_1 : tnode;override;
  70. end;
  71. trangenodeclass = class of trangenode;
  72. tcasenode = class(tunarynode)
  73. labels : pcaselabel;
  74. blocks : TFPList;
  75. elseblock : tnode;
  76. constructor create(l:tnode);virtual;
  77. destructor destroy;override;
  78. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  79. procedure ppuwrite(ppufile:tcompilerppufile);override;
  80. procedure buildderefimpl;override;
  81. procedure derefimpl;override;
  82. function dogetcopy : tnode;override;
  83. procedure insertintolist(l : tnodelist);override;
  84. function pass_typecheck:tnode;override;
  85. function pass_1 : tnode;override;
  86. function docompare(p: tnode): boolean; override;
  87. procedure addlabel(blockid:longint;l,h : TConstExprInt); overload;
  88. procedure addlabel(blockid:longint;l,h : tstringconstnode); overload;
  89. procedure addblock(blockid:longint;instr:tnode);
  90. procedure addelseblock(instr:tnode);
  91. end;
  92. tcasenodeclass = class of tcasenode;
  93. var
  94. csetelementnode : tsetelementnodeclass;
  95. cinnode : tinnodeclass;
  96. crangenode : trangenodeclass;
  97. ccasenode : tcasenodeclass;
  98. { counts the labels }
  99. function case_count_labels(root : pcaselabel) : longint;
  100. { searches the highest label }
  101. function case_get_max(root : pcaselabel) : tconstexprint;
  102. { searches the lowest label }
  103. function case_get_min(root : pcaselabel) : tconstexprint;
  104. implementation
  105. uses
  106. systems,
  107. verbose,
  108. symconst,symdef,symsym,symtable,defutil,defcmp,
  109. htypechk,pass_1,
  110. nadd,nbas,ncnv,nld,nflw,cgobj,cgbase,
  111. widestr;
  112. {*****************************************************************************
  113. TSETELEMENTNODE
  114. *****************************************************************************}
  115. constructor tsetelementnode.create(l,r : tnode);
  116. begin
  117. inherited create(setelementn,l,r);
  118. end;
  119. function tsetelementnode.pass_typecheck:tnode;
  120. begin
  121. result:=nil;
  122. typecheckpass(left);
  123. if assigned(right) then
  124. typecheckpass(right);
  125. set_varstate(left,vs_read,[vsf_must_be_valid]);
  126. if codegenerror then
  127. exit;
  128. resultdef:=left.resultdef;
  129. end;
  130. function tsetelementnode.pass_1 : tnode;
  131. begin
  132. result:=nil;
  133. firstpass(left);
  134. if assigned(right) then
  135. firstpass(right);
  136. if codegenerror then
  137. exit;
  138. expectloc:=left.expectloc;
  139. end;
  140. {*****************************************************************************
  141. TINNODE
  142. *****************************************************************************}
  143. constructor tinnode.create(l,r : tnode);
  144. begin
  145. inherited create(inn,l,r);
  146. end;
  147. function tinnode.pass_typecheck:tnode;
  148. var
  149. t : tnode;
  150. pst : pconstset;
  151. function createsetconst(psd : tsetdef) : pconstset;
  152. var
  153. pcs : pconstset;
  154. pes : tenumsym;
  155. i : longint;
  156. begin
  157. new(pcs);
  158. case psd.elementdef.typ of
  159. enumdef :
  160. begin
  161. pes:=tenumsym(tenumdef(psd.elementdef).firstenum);
  162. while assigned(pes) do
  163. begin
  164. include(pcs^,pes.value);
  165. pes:=pes.nextenum;
  166. end;
  167. end;
  168. orddef :
  169. begin
  170. for i:=int64(torddef(psd.elementdef).low) to int64(torddef(psd.elementdef).high) do
  171. include(pcs^,i);
  172. end;
  173. end;
  174. createsetconst:=pcs;
  175. end;
  176. begin
  177. result:=nil;
  178. resultdef:=booltype;
  179. typecheckpass(right);
  180. set_varstate(right,vs_read,[vsf_must_be_valid]);
  181. if codegenerror then
  182. exit;
  183. { Convert array constructor first to set }
  184. if is_array_constructor(right.resultdef) then
  185. begin
  186. arrayconstructor_to_set(right);
  187. firstpass(right);
  188. if codegenerror then
  189. exit;
  190. end;
  191. if right.resultdef.typ<>setdef then
  192. CGMessage(sym_e_set_expected);
  193. if codegenerror then
  194. exit;
  195. if (right.nodetype=typen) then
  196. begin
  197. { we need to create a setconstn }
  198. pst:=createsetconst(tsetdef(ttypenode(right).resultdef));
  199. t:=csetconstnode.create(pst,ttypenode(right).resultdef);
  200. dispose(pst);
  201. right.free;
  202. right:=t;
  203. typecheckpass(right);
  204. end;
  205. typecheckpass(left);
  206. set_varstate(left,vs_read,[vsf_must_be_valid]);
  207. if codegenerror then
  208. exit;
  209. if not assigned(left.resultdef) then
  210. internalerror(20021126);
  211. if (m_tp7 in current_settings.modeswitches) then
  212. begin
  213. { insert a hint that a range check error might occur on non-byte
  214. elements with the in operator.
  215. }
  216. if (
  217. (left.resultdef.typ = orddef) and not
  218. (torddef(left.resultdef).ordtype in [s8bit,u8bit,uchar,pasbool,bool8bit])
  219. )
  220. or
  221. (
  222. (left.resultdef.typ = enumdef) and
  223. (tenumdef(left.resultdef).maxval > 255)
  224. )
  225. then
  226. CGMessage(type_h_in_range_check);
  227. { type conversion/check }
  228. if assigned(tsetdef(right.resultdef).elementdef) then
  229. inserttypeconv(left,tsetdef(right.resultdef).elementdef);
  230. end
  231. else if not is_ordinal(left.resultdef) or (left.resultdef.size > u32inttype.size) then
  232. begin
  233. CGMessage(type_h_in_range_check);
  234. if is_signed(left.resultdef) then
  235. inserttypeconv(left,s32inttype)
  236. else
  237. inserttypeconv(left,u32inttype);
  238. end
  239. else if assigned(tsetdef(right.resultdef).elementdef) and
  240. not(is_integer(tsetdef(right.resultdef).elementdef) and
  241. is_integer(left.resultdef)) then
  242. { Type conversion to check things like 'char in set_of_byte'. }
  243. { Can't use is_subequal because that will fail for }
  244. { 'widechar in set_of_char' }
  245. { Can't use the type conversion for integers because then }
  246. { "longint in set_of_byte" will give a range check error }
  247. { instead of false }
  248. inserttypeconv(left,tsetdef(right.resultdef).elementdef);
  249. { empty set then return false }
  250. if not assigned(tsetdef(right.resultdef).elementdef) or
  251. ((right.nodetype = setconstn) and
  252. (tnormalset(tsetconstnode(right).value_set^) = [])) then
  253. begin
  254. t:=cordconstnode.create(0,booltype,false);
  255. typecheckpass(t);
  256. result:=t;
  257. exit;
  258. end;
  259. result:=simplify;
  260. end;
  261. function tinnode.simplify:tnode;
  262. var
  263. t : tnode;
  264. begin
  265. result:=nil;
  266. { constant evaluation }
  267. if (left.nodetype=ordconstn) then
  268. begin
  269. if (right.nodetype=setconstn) then
  270. begin
  271. { tordconstnode.value is int64 -> signed -> the expression }
  272. { below will be converted to longint on 32 bit systems due }
  273. { to the rule above -> will give range check error if }
  274. { value > high(longint) if we don't take the signedness }
  275. { into account }
  276. if Tordconstnode(left).value.signed then
  277. t:=cordconstnode.create(byte(tordconstnode(left).value.svalue in Tsetconstnode(right).value_set^),
  278. booltype,true)
  279. else
  280. t:=cordconstnode.create(byte(tordconstnode(left).value.uvalue in Tsetconstnode(right).value_set^),
  281. booltype,true);
  282. typecheckpass(t);
  283. result:=t;
  284. exit;
  285. end
  286. else
  287. begin
  288. if (Tordconstnode(left).value<int64(tsetdef(right.resultdef).setbase)) or
  289. (Tordconstnode(left).value>int64(Tsetdef(right.resultdef).setmax)) then
  290. begin
  291. t:=cordconstnode.create(0, booltype, true);
  292. typecheckpass(t);
  293. result:=t;
  294. exit;
  295. end;
  296. end;
  297. end;
  298. end;
  299. function tinnode.pass_1 : tnode;
  300. begin
  301. result:=nil;
  302. expectloc:=LOC_REGISTER;
  303. firstpass(right);
  304. firstpass(left);
  305. if codegenerror then
  306. exit;
  307. end;
  308. {*****************************************************************************
  309. TRANGENODE
  310. *****************************************************************************}
  311. constructor trangenode.create(l,r : tnode);
  312. var
  313. value: string;
  314. begin
  315. { if right is char and left is string then }
  316. { right should be treated as one-symbol string }
  317. if is_conststringnode(l) and is_constcharnode(r) then
  318. begin
  319. value := char(tordconstnode(r).value.uvalue) + ''#0;
  320. r.free;
  321. r := cstringconstnode.createstr(value);
  322. do_typecheckpass(r);
  323. end;
  324. inherited create(rangen,l,r);
  325. end;
  326. function trangenode.pass_typecheck : tnode;
  327. begin
  328. result:=nil;
  329. typecheckpass(left);
  330. typecheckpass(right);
  331. set_varstate(left,vs_read,[vsf_must_be_valid]);
  332. set_varstate(right,vs_read,[vsf_must_be_valid]);
  333. if codegenerror then
  334. exit;
  335. { both types must be compatible }
  336. if compare_defs(left.resultdef,right.resultdef,left.nodetype)=te_incompatible then
  337. IncompatibleTypes(left.resultdef,right.resultdef);
  338. { Check if only when its a constant set }
  339. if (left.nodetype=ordconstn) and (right.nodetype=ordconstn) then
  340. begin
  341. { upper limit must be greater or equal than lower limit }
  342. if (tordconstnode(left).value>tordconstnode(right).value) and
  343. ((tordconstnode(left).value<0) or (tordconstnode(right).value>=0)) then
  344. CGMessage(parser_e_upper_lower_than_lower);
  345. end;
  346. resultdef:=left.resultdef;
  347. end;
  348. function trangenode.pass_1 : tnode;
  349. begin
  350. result:=nil;
  351. firstpass(left);
  352. firstpass(right);
  353. if codegenerror then
  354. exit;
  355. expectloc:=left.expectloc;
  356. end;
  357. {*****************************************************************************
  358. Case Helpers
  359. *****************************************************************************}
  360. function case_count_labels(root : pcaselabel) : longint;
  361. var
  362. _l : longint;
  363. procedure count(p : pcaselabel);
  364. begin
  365. inc(_l);
  366. if assigned(p^.less) then
  367. count(p^.less);
  368. if assigned(p^.greater) then
  369. count(p^.greater);
  370. end;
  371. begin
  372. _l:=0;
  373. count(root);
  374. case_count_labels:=_l;
  375. end;
  376. function case_get_max(root : pcaselabel) : tconstexprint;
  377. var
  378. hp : pcaselabel;
  379. begin
  380. hp:=root;
  381. while assigned(hp^.greater) do
  382. hp:=hp^.greater;
  383. case_get_max:=hp^._high;
  384. end;
  385. function case_get_min(root : pcaselabel) : tconstexprint;
  386. var
  387. hp : pcaselabel;
  388. begin
  389. hp:=root;
  390. while assigned(hp^.less) do
  391. hp:=hp^.less;
  392. case_get_min:=hp^._low;
  393. end;
  394. procedure deletecaselabels(p : pcaselabel);
  395. begin
  396. if assigned(p^.greater) then
  397. deletecaselabels(p^.greater);
  398. if assigned(p^.less) then
  399. deletecaselabels(p^.less);
  400. if (p^.label_type = ltConstString) then
  401. begin
  402. p^._low_str.Free;
  403. p^._high_str.Free;
  404. end;
  405. dispose(p);
  406. end;
  407. function copycaselabel(p : pcaselabel) : pcaselabel;
  408. var
  409. n : pcaselabel;
  410. begin
  411. new(n);
  412. n^:=p^;
  413. if (p^.label_type = ltConstString) then
  414. begin
  415. n^._low_str := tstringconstnode(p^._low_str.getcopy);
  416. n^._high_str := tstringconstnode(p^._high_str.getcopy);
  417. end;
  418. if assigned(p^.greater) then
  419. n^.greater:=copycaselabel(p^.greater);
  420. if assigned(p^.less) then
  421. n^.less:=copycaselabel(p^.less);
  422. copycaselabel:=n;
  423. end;
  424. procedure ppuwritecaselabel(ppufile:tcompilerppufile;p : pcaselabel);
  425. var
  426. b : byte;
  427. begin
  428. ppufile.putbyte(byte(p^.label_type = ltConstString));
  429. if (p^.label_type = ltConstString) then
  430. begin
  431. p^._low_str.ppuwrite(ppufile);
  432. p^._high_str.ppuwrite(ppufile);
  433. end
  434. else
  435. begin
  436. ppufile.putexprint(p^._low);
  437. ppufile.putexprint(p^._high);
  438. end;
  439. ppufile.putlongint(p^.blockid);
  440. b:=ord(assigned(p^.greater)) or (ord(assigned(p^.less)) shl 1);
  441. ppufile.putbyte(b);
  442. if assigned(p^.greater) then
  443. ppuwritecaselabel(ppufile,p^.greater);
  444. if assigned(p^.less) then
  445. ppuwritecaselabel(ppufile,p^.less);
  446. end;
  447. function ppuloadcaselabel(ppufile:tcompilerppufile):pcaselabel;
  448. var
  449. b : byte;
  450. p : pcaselabel;
  451. begin
  452. new(p);
  453. if boolean(ppufile.getbyte) then
  454. begin
  455. p^.label_type := ltConstString;
  456. p^._low_str := cstringconstnode.ppuload(stringconstn,ppufile);
  457. p^._high_str := cstringconstnode.ppuload(stringconstn,ppufile);
  458. end
  459. else
  460. begin
  461. p^.label_type := ltOrdinal;
  462. p^._low:=ppufile.getexprint;
  463. p^._high:=ppufile.getexprint;
  464. end;
  465. p^.blockid:=ppufile.getlongint;
  466. b:=ppufile.getbyte;
  467. if (b and 1)=1 then
  468. p^.greater:=ppuloadcaselabel(ppufile)
  469. else
  470. p^.greater:=nil;
  471. if (b and 2)=2 then
  472. p^.less:=ppuloadcaselabel(ppufile)
  473. else
  474. p^.less:=nil;
  475. ppuloadcaselabel:=p;
  476. end;
  477. {*****************************************************************************
  478. TCASENODE
  479. *****************************************************************************}
  480. constructor tcasenode.create(l:tnode);
  481. begin
  482. inherited create(casen,l);
  483. labels:=nil;
  484. blocks:=TFPList.create;
  485. elseblock:=nil;
  486. end;
  487. destructor tcasenode.destroy;
  488. var
  489. i : longint;
  490. hp : pcaseblock;
  491. begin
  492. elseblock.free;
  493. deletecaselabels(labels);
  494. for i:=0 to blocks.count-1 do
  495. begin
  496. pcaseblock(blocks[i])^.statement.free;
  497. hp:=pcaseblock(blocks[i]);
  498. dispose(hp);
  499. end;
  500. blocks.free;
  501. inherited destroy;
  502. end;
  503. constructor tcasenode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  504. var
  505. cnt,i : longint;
  506. begin
  507. inherited ppuload(t,ppufile);
  508. elseblock:=ppuloadnode(ppufile);
  509. cnt:=ppufile.getlongint();
  510. blocks:=TFPList.create;
  511. for i:=0 to cnt-1 do
  512. addblock(i,ppuloadnode(ppufile));
  513. labels:=ppuloadcaselabel(ppufile);
  514. end;
  515. procedure tcasenode.ppuwrite(ppufile:tcompilerppufile);
  516. var
  517. i : longint;
  518. begin
  519. inherited ppuwrite(ppufile);
  520. ppuwritenode(ppufile,elseblock);
  521. ppufile.putlongint(blocks.count);
  522. for i:=0 to blocks.count-1 do
  523. ppuwritenode(ppufile,pcaseblock(blocks[i])^.statement);
  524. ppuwritecaselabel(ppufile,labels);
  525. end;
  526. procedure tcasenode.buildderefimpl;
  527. var
  528. i : integer;
  529. begin
  530. inherited buildderefimpl;
  531. if assigned(elseblock) then
  532. elseblock.buildderefimpl;
  533. for i:=0 to blocks.count-1 do
  534. pcaseblock(blocks[i])^.statement.buildderefimpl;
  535. end;
  536. procedure tcasenode.derefimpl;
  537. var
  538. i : integer;
  539. begin
  540. inherited derefimpl;
  541. if assigned(elseblock) then
  542. elseblock.derefimpl;
  543. for i:=0 to blocks.count-1 do
  544. pcaseblock(blocks[i])^.statement.derefimpl;
  545. end;
  546. function tcasenode.pass_typecheck : tnode;
  547. begin
  548. result:=nil;
  549. resultdef:=voidtype;
  550. end;
  551. function tcasenode.pass_1 : tnode;
  552. var
  553. i : integer;
  554. node_thenblock,node_elseblock,if_node : tnode;
  555. tempcaseexpr : ttempcreatenode;
  556. if_block, init_block : tblocknode;
  557. stmt : tstatementnode;
  558. function makeifblock(const labtree : pcaselabel; prevconditblock : tnode): tnode;
  559. var
  560. condit : tnode;
  561. begin
  562. if assigned(labtree^.less) then
  563. result := makeifblock(labtree^.less, prevconditblock)
  564. else
  565. result := prevconditblock;
  566. condit := caddnode.create(equaln, left.getcopy, labtree^._low_str.getcopy);
  567. if (labtree^._low_str.fullcompare(labtree^._high_str)<>0) then
  568. begin
  569. condit.nodetype := gten;
  570. condit := caddnode.create(
  571. andn, condit, caddnode.create(
  572. lten, left.getcopy, labtree^._high_str.getcopy));
  573. end;
  574. result :=
  575. cifnode.create(
  576. condit, pcaseblock(blocks[labtree^.blockid])^.statement, result);
  577. pcaseblock(blocks[labtree^.blockid])^.statement := nil;
  578. if assigned(labtree^.greater) then
  579. result := makeifblock(labtree^.greater, result);
  580. typecheckpass(result);
  581. end;
  582. begin
  583. result:=nil;
  584. init_block:=nil;
  585. expectloc:=LOC_VOID;
  586. { evalutes the case expression }
  587. firstpass(left);
  588. set_varstate(left,vs_read,[vsf_must_be_valid]);
  589. if codegenerror then
  590. exit;
  591. { Load caseexpr into temp var if complex. }
  592. { No need to do this for ordinal, because }
  593. { in that case caseexpr is generated once }
  594. if (labels^.label_type = ltConstString) and (not valid_for_addr(left, false)) and
  595. (blocks.count > 0) then
  596. begin
  597. init_block := internalstatements(stmt);
  598. tempcaseexpr :=
  599. ctempcreatenode.create(
  600. left.resultdef, left.resultdef.size, tt_persistent, true);
  601. typecheckpass(tnode(tempcaseexpr));
  602. addstatement(stmt, tempcaseexpr);
  603. addstatement(
  604. stmt, cassignmentnode.create(
  605. ctemprefnode.create(tempcaseexpr), left));
  606. left := ctemprefnode.create(tempcaseexpr);
  607. typecheckpass(left);
  608. end;
  609. { first case }
  610. for i:=0 to blocks.count-1 do
  611. firstpass(pcaseblock(blocks[i])^.statement);
  612. { may be handle else tree }
  613. if assigned(elseblock) then
  614. begin
  615. firstpass(elseblock);
  616. { kill case? }
  617. if blocks.count=0 then
  618. begin
  619. result:=elseblock;
  620. elseblock:=nil;
  621. exit;
  622. end;
  623. end
  624. else
  625. if blocks.count=0 then
  626. begin
  627. result:=cnothingnode.create;
  628. exit;
  629. end;
  630. if (labels^.label_type = ltConstString) then
  631. begin
  632. if_node := makeifblock(labels, elseblock);
  633. if assigned(init_block) then
  634. begin
  635. firstpass(tnode(init_block));
  636. if_block := internalstatements(stmt);
  637. addstatement(stmt, init_block);
  638. addstatement(stmt, if_node);
  639. result := if_block;
  640. end
  641. else
  642. result := if_node;
  643. elseblock := nil;
  644. exit;
  645. end;
  646. if is_boolean(left.resultdef) then
  647. begin
  648. case blocks.count of
  649. 2:
  650. begin
  651. if boolean(qword(labels^._low))=false then
  652. begin
  653. node_thenblock:=pcaseblock(blocks[labels^.greater^.blockid])^.statement;
  654. node_elseblock:=pcaseblock(blocks[labels^.blockid])^.statement;
  655. pcaseblock(blocks[labels^.greater^.blockid])^.statement:=nil;
  656. end
  657. else
  658. begin
  659. node_thenblock:=pcaseblock(blocks[labels^.blockid])^.statement;
  660. node_elseblock:=pcaseblock(blocks[labels^.less^.blockid])^.statement;
  661. pcaseblock(blocks[labels^.less^.blockid])^.statement:=nil;
  662. end;
  663. pcaseblock(blocks[labels^.blockid])^.statement:=nil;
  664. end;
  665. 1:
  666. begin
  667. if labels^._low=labels^._high then
  668. begin
  669. if boolean(qword(labels^._low))=false then
  670. begin
  671. node_thenblock:=elseblock;
  672. node_elseblock:=pcaseblock(blocks[labels^.blockid])^.statement;
  673. end
  674. else
  675. begin
  676. node_thenblock:=pcaseblock(blocks[labels^.blockid])^.statement;
  677. node_elseblock:=elseblock;
  678. end;
  679. pcaseblock(blocks[labels^.blockid])^.statement:=nil;
  680. elseblock:=nil;
  681. end
  682. else
  683. begin
  684. result:=pcaseblock(blocks[labels^.blockid])^.statement;
  685. pcaseblock(blocks[labels^.blockid])^.statement:=nil;
  686. elseblock:=nil;
  687. exit;
  688. end;
  689. end;
  690. else
  691. internalerror(200805031);
  692. end;
  693. result:=cifnode.create(left,node_thenblock,node_elseblock);
  694. left:=nil;
  695. end;
  696. end;
  697. function tcasenode.dogetcopy : tnode;
  698. var
  699. n : tcasenode;
  700. i : longint;
  701. begin
  702. n:=tcasenode(inherited dogetcopy);
  703. if assigned(elseblock) then
  704. n.elseblock:=elseblock.dogetcopy
  705. else
  706. n.elseblock:=nil;
  707. if assigned(labels) then
  708. n.labels:=copycaselabel(labels)
  709. else
  710. n.labels:=nil;
  711. if assigned(blocks) then
  712. begin
  713. n.blocks:=TFPList.create;
  714. for i:=0 to blocks.count-1 do
  715. begin
  716. if not assigned(blocks[i]) then
  717. internalerror(200411302);
  718. n.addblock(i,pcaseblock(blocks[i])^.statement.dogetcopy);
  719. end;
  720. end
  721. else
  722. n.blocks:=nil;
  723. dogetcopy:=n;
  724. end;
  725. procedure tcasenode.insertintolist(l : tnodelist);
  726. begin
  727. end;
  728. function caselabelsequal(n1,n2: pcaselabel): boolean;
  729. begin
  730. result :=
  731. (not assigned(n1) and not assigned(n2)) or
  732. (assigned(n1) and assigned(n2) and
  733. (n1^._low = n2^._low) and
  734. (n1^._high = n2^._high) and
  735. { the rest of the fields don't matter for equality (JM) }
  736. caselabelsequal(n1^.less,n2^.less) and
  737. caselabelsequal(n1^.greater,n2^.greater))
  738. end;
  739. function caseblocksequal(b1,b2:TFPList): boolean;
  740. var
  741. i : longint;
  742. begin
  743. result:=false;
  744. if b1.count<>b2.count then
  745. exit;
  746. for i:=0 to b1.count-1 do
  747. begin
  748. if not pcaseblock(b1[i])^.statement.isequal(pcaseblock(b2[i])^.statement) then
  749. exit;
  750. end;
  751. result:=true;
  752. end;
  753. function tcasenode.docompare(p: tnode): boolean;
  754. begin
  755. result :=
  756. inherited docompare(p) and
  757. caselabelsequal(labels,tcasenode(p).labels) and
  758. caseblocksequal(blocks,tcasenode(p).blocks) and
  759. elseblock.isequal(tcasenode(p).elseblock);
  760. end;
  761. procedure tcasenode.addblock(blockid:longint;instr:tnode);
  762. var
  763. hcaseblock : pcaseblock;
  764. begin
  765. new(hcaseblock);
  766. fillchar(hcaseblock^,sizeof(hcaseblock^),0);
  767. hcaseblock^.statement:=instr;
  768. if blockid>=blocks.count then
  769. blocks.count:=blockid+1;
  770. blocks[blockid]:=hcaseblock;
  771. end;
  772. procedure tcasenode.addelseblock(instr:tnode);
  773. begin
  774. elseblock:=instr;
  775. end;
  776. procedure tcasenode.addlabel(blockid:longint;l,h : TConstExprInt);
  777. var
  778. hcaselabel : pcaselabel;
  779. function insertlabel(var p : pcaselabel):pcaselabel;
  780. begin
  781. if p=nil then
  782. begin
  783. p:=hcaselabel;
  784. result:=p;
  785. end
  786. else
  787. if (p^._low>hcaselabel^._low) and
  788. (p^._low>hcaselabel^._high) then
  789. begin
  790. if (hcaselabel^.blockid = p^.blockid) and
  791. (p^._low = hcaselabel^._high + 1) then
  792. begin
  793. p^._low := hcaselabel^._low;
  794. dispose(hcaselabel);
  795. result:=p;
  796. end
  797. else
  798. result:=insertlabel(p^.less)
  799. end
  800. else
  801. if (p^._high<hcaselabel^._low) and
  802. (p^._high<hcaselabel^._high) then
  803. begin
  804. if (hcaselabel^.blockid = p^.blockid) and
  805. (p^._high+1 = hcaselabel^._low) then
  806. begin
  807. p^._high := hcaselabel^._high;
  808. dispose(hcaselabel);
  809. result:=p;
  810. end
  811. else
  812. result:=insertlabel(p^.greater);
  813. end
  814. else
  815. begin
  816. dispose(hcaselabel);
  817. Message(parser_e_double_caselabel);
  818. end
  819. end;
  820. begin
  821. new(hcaselabel);
  822. fillchar(hcaselabel^,sizeof(tcaselabel),0);
  823. hcaselabel^.blockid:=blockid;
  824. hcaselabel^.label_type:=ltOrdinal;
  825. hcaselabel^._low:=l;
  826. hcaselabel^._high:=h;
  827. insertlabel(labels);
  828. end;
  829. procedure tcasenode.addlabel(blockid: longint; l, h: tstringconstnode);
  830. var
  831. hcaselabel : pcaselabel;
  832. function insertlabel(var p : pcaselabel) : pcaselabel;
  833. begin
  834. if not assigned(p) then
  835. begin
  836. p := hcaselabel;
  837. result := p;
  838. end
  839. else
  840. if (p^._low_str.fullcompare(hcaselabel^._high_str) > 0) then
  841. result := insertlabel(p^.less)
  842. else
  843. if (p^._high_str.fullcompare(hcaselabel^._low_str) < 0) then
  844. result := insertlabel(p^.greater)
  845. else
  846. begin
  847. hcaselabel^._low_str.free;
  848. hcaselabel^._high_str.free;
  849. dispose(hcaselabel);
  850. Message(parser_e_double_caselabel);
  851. end;
  852. end;
  853. begin
  854. new(hcaselabel);
  855. fillchar(hcaselabel^, sizeof(tcaselabel), 0);
  856. hcaselabel^.blockid := blockid;
  857. hcaselabel^.label_type := ltConstString;
  858. hcaselabel^._low_str := tstringconstnode(l.getcopy);
  859. hcaselabel^._high_str := tstringconstnode(h.getcopy);
  860. insertlabel(labels);
  861. end;
  862. begin
  863. csetelementnode:=tsetelementnode;
  864. cinnode:=tinnode;
  865. crangenode:=trangenode;
  866. ccasenode:=tcasenode;
  867. end.