FreeBASIC  0.91.0
ast-misc.bas
Go to the documentation of this file.
1 '' misc AST function
2 ''
3 '' chng: sep/2004 written [v1ctor]
4 
5 #include once "fb.bi"
6 #include once "fbint.bi"
7 #include once "list.bi"
8 #include once "ir.bi"
9 #include once "rtl.bi"
10 #include once "ast.bi"
11 #include once "hlp.bi"
12 
13 declare sub astReplaceSymbolOnCALL _
14  ( _
15  byval n as ASTNODE ptr, _
16  byval old_sym as FBSYMBOL ptr, _
17  byval new_sym as FBSYMBOL ptr _
18  )
19 
21  listInit( @ast.dtorlist, 64, len( AST_DTORLIST_ITEM ), LIST_FLAGS_NOCLEAR )
22  with( ast.dtorlistscopes )
23  .cookies = NULL
24  .count = 0
25  .room = 0
26  end with
27  ast.dtorlistcookies = 0
28  ast.flushdtorlist = TRUE
29 end sub
30 
31 sub astMiscEnd( )
32  with( ast.dtorlistscopes )
33  assert( .count = 0 )
34  deallocate( .cookies )
35  end with
36  listEnd( @ast.dtorlist )
37 end sub
38 
39 '':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
40 '' tree scanning
41 '':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
42 
43 ''::::
44 function astIsTreeEqual _
45  ( _
46  byval l as ASTNODE ptr, _
47  byval r as ASTNODE ptr _
48  ) as integer
49 
50  function = FALSE
51 
52  if( (l = NULL) or (r = NULL) ) then
53  if( l = r ) then
54  function = TRUE
55  end if
56  exit function
57  end if
58 
59  if( l->class <> r->class ) then
60  exit function
61  end if
62 
63  if( astGetFullType( l ) <> astGetFullType( r ) ) then
64  exit function
65  end if
66 
67  if( l->subtype <> r->subtype ) then
68  exit function
69  end if
70 
71  select case as const l->class
72  case AST_NODECLASS_VAR
73  if( l->sym <> r->sym ) then
74  exit function
75  end if
76 
77  if( l->var_.ofs <> r->var_.ofs ) then
78  exit function
79  end if
80 
81  case AST_NODECLASS_FIELD
82  if( l->sym <> r->sym ) then
83  exit function
84  end if
85 
86  case AST_NODECLASS_CONST
87  select case( typeGetClass( l->dtype ) )
88  case FB_DATACLASS_FPOINT
89  if( l->val.f <> r->val.f ) then
90  exit function
91  end if
92 
93  case FB_DATACLASS_INTEGER
94  if( l->val.i <> r->val.i ) then
95  exit function
96  end if
97 
98  end select
99 
100  case AST_NODECLASS_DEREF
101  if( l->ptr.ofs <> r->ptr.ofs ) then
102  exit function
103  end if
104 
105  case AST_NODECLASS_IDX
106  if( l->idx.ofs <> r->idx.ofs ) then
107  exit function
108  end if
109 
110  if( l->idx.mult <> r->idx.mult ) then
111  exit function
112  end if
113 
114  case AST_NODECLASS_BOP
115  if( l->op.op <> r->op.op ) then
116  exit function
117  end if
118 
119  if( l->op.options <> r->op.options ) then
120  exit function
121  end if
122 
123  if( l->op.ex <> r->op.ex ) then
124  exit function
125  end if
126 
127  case AST_NODECLASS_UOP
128  if( l->op.op <> r->op.op ) then
129  exit function
130  end if
131 
132  if( l->op.options <> r->op.options ) then
133  exit function
134  end if
135 
136  case AST_NODECLASS_ADDROF
137  if( l->sym <> r->sym ) then
138  exit function
139  end if
140 
141  if( l->op.op <> r->op.op ) then
142  exit function
143  end if
144 
145  case AST_NODECLASS_OFFSET
146  if( l->sym <> r->sym ) then
147  exit function
148  end if
149 
150  if( l->ofs.ofs <> r->ofs.ofs ) then
151  exit function
152  end if
153 
154  case AST_NODECLASS_CONV
155  '' do nothing, the l child will be checked below
156 
157  case AST_NODECLASS_CALL, AST_NODECLASS_BRANCH, _
158  AST_NODECLASS_LOAD, AST_NODECLASS_ASSIGN, _
159  AST_NODECLASS_LINK
160  '' unpredictable nodes
161  exit function
162 
163  end select
164 
165  '' check childs
166  if( astIsTreeEqual( l->l, r->l ) = FALSE ) then
167  exit function
168  end if
169 
170  if( astIsTreeEqual( l->r, r->r ) = FALSE ) then
171  exit function
172  end if
173 
174  ''
175  function = TRUE
176 
177 end function
178 
179 ''
180 '' Check whether two parameter initializers are the same (for comparing
181 '' initializer expressions from prototype and body). This is basically the same
182 '' as astIsTreeEqual(), except it allows CALLs and such aswell as temp vars,
183 '' because for a param initializer those things can be treated equal.
184 ''
185 '' For example, two calls f(1) and f(1) are equal as far as param initializers
186 '' are concerned, but astIsTreeEqual() wouldn't treat them as equal, so we need
187 '' a custom function.
188 ''
189 '' Also, two expressions such as iif(a,b,c) and iif(a,b,c) are equal for param
190 '' initializers. The two iif()'s will use separate temp vars, causing
191 '' astIsTreeEqual() to treat them as different, but that doesn't matter for
192 '' param initializers where the expression and the temp vars it uses will be
193 '' duplicated & inserted into the call scopes.
194 ''
195 '' Temp labels stored in BOP's or LOOP's ASTNODE.op.ex field should be treated
196 '' equal too (e.g. used by iif()).
197 ''
198 function astIsEqualParamInit _
199  ( _
200  byval l as ASTNODE ptr, _
201  byval r as ASTNODE ptr _
202  ) as integer
203 
204  function = FALSE
205 
206  if( (l = NULL) or (r = NULL) ) then
207  if( l = r ) then
208  function = TRUE
209  end if
210  exit function
211  end if
212 
213  if( l->class <> r->class ) then
214  exit function
215  end if
216 
217  if( l->dtype <> r->dtype ) then
218  exit function
219  end if
220 
221  if( l->subtype <> r->subtype ) then
222  '' If it's a function pointer, the subtype may point to different proc
223  '' symbols, but if they have the same signature they should still be
224  '' treated equal here.
225  if( typeGetDtOnly( l->dtype ) = FB_DATATYPE_FUNCTION ) then
226  if( symbIsEqual( l->subtype, r->subtype ) = FALSE ) then
227  exit function
228  end if
229  else
230  exit function
231  end if
232  end if
233 
234  select case as const( l->class )
235  case AST_NODECLASS_LINK
236  if( l->link.ret_left <> r->link.ret_left ) then
237  exit function
238  end if
239 
240  case AST_NODECLASS_VAR
241  '' VARs must access the same symbol, unless they're accessing
242  '' temp vars. Those will be duplicated anyways when the param
243  '' initializer is inserted in a call.
244  if( l->sym <> r->sym ) then
245  if( symbIsTemp( l->sym ) = FALSE ) then
246  exit function
247  end if
248  if( symbIsTemp( r->sym ) = FALSE ) then
249  exit function
250  end if
251  end if
252 
253  if( l->var_.ofs <> r->var_.ofs ) then
254  exit function
255  end if
256 
257  case AST_NODECLASS_FIELD
258  if( l->sym <> r->sym ) then
259  if( symbIsTemp( l->sym ) = FALSE ) then
260  exit function
261  end if
262  if( symbIsTemp( r->sym ) = FALSE ) then
263  exit function
264  end if
265  end if
266 
267  case AST_NODECLASS_CONST
268  if( typeGetClass( l->dtype ) = FB_DATACLASS_FPOINT ) then
269  if( l->val.f <> r->val.f ) then
270  exit function
271  end if
272  else
273  assert( typeGetClass( l->dtype ) = FB_DATACLASS_INTEGER )
274  if( l->val.i <> r->val.i ) then
275  exit function
276  end if
277  end if
278 
279  case AST_NODECLASS_DEREF
280  if( l->ptr.ofs <> r->ptr.ofs ) then
281  exit function
282  end if
283 
284  case AST_NODECLASS_IDX
285  if( l->idx.ofs <> r->idx.ofs ) then
286  exit function
287  end if
288 
289  if( l->idx.mult <> r->idx.mult ) then
290  exit function
291  end if
292 
293  case AST_NODECLASS_BOP, AST_NODECLASS_UOP
294  if( l->op.op <> r->op.op ) then
295  exit function
296  end if
297 
298  if( l->op.options <> r->op.options ) then
299  exit function
300  end if
301 
302  case AST_NODECLASS_ADDROF
303  if( l->sym <> r->sym ) then
304  if( symbIsTemp( l->sym ) = FALSE ) then
305  exit function
306  end if
307  if( symbIsTemp( r->sym ) = FALSE ) then
308  exit function
309  end if
310  end if
311 
312  if( l->op.op <> r->op.op ) then
313  exit function
314  end if
315 
316  case AST_NODECLASS_OFFSET
317  if( l->sym <> r->sym ) then
318  if( symbIsTemp( l->sym ) = FALSE ) then
319  exit function
320  end if
321  if( symbIsTemp( r->sym ) = FALSE ) then
322  exit function
323  end if
324  end if
325 
326  if( l->ofs.ofs <> r->ofs.ofs ) then
327  exit function
328  end if
329 
330  case AST_NODECLASS_CALL
331  if( l->sym <> r->sym ) then
332  exit function
333  end if
334  end select
335 
336  if( astIsEqualParamInit( l->l, r->l ) = FALSE ) then
337  exit function
338  end if
339 
340  if( astIsEqualParamInit( l->r, r->r ) = FALSE ) then
341  exit function
342  end if
343 
344  function = TRUE
345 end function
346 
347 '':::::
348 function astIsClassOnTree _
349  ( _
350  byval class_ as integer, _
351  byval n as ASTNODE ptr _
352  ) as ASTNODE ptr
353 
354  dim as ASTNODE ptr m = any
355 
356  ''
357  if( n = NULL ) then
358  return NULL
359  end if
360 
361  if( n->class = class_ ) then
362  return n
363  end if
364 
365  '' walk
366  m = astIsClassOnTree( class_, n->l )
367  if( m <> NULL ) then
368  return m
369  end if
370 
371  m = astIsClassOnTree( class_, n->r )
372  if( m <> NULL ) then
373  return m
374  end if
375 
376  function = NULL
377 
378 end function
379 
380 ''::::
381 function astIsSymbolOnTree _
382  ( _
383  byval sym as FBSYMBOL ptr, _
384  byval n as ASTNODE ptr _
385  ) as integer
386 
387  dim as FBSYMBOL ptr s = any
388 
389  if( n = NULL ) then
390  return FALSE
391  end if
392 
393  select case as const n->class
394  case AST_NODECLASS_VAR, AST_NODECLASS_IDX, AST_NODECLASS_FIELD, _
395  AST_NODECLASS_ADDROF, AST_NODECLASS_OFFSET
396 
397  s = astGetSymbol( n )
398  '' same symbol?
399  if( s = sym ) then
400  return TRUE
401  end if
402 
403  '' passed by ref or by desc? can't do any assumption..
404  if( s <> NULL ) then
405  if (symbIsParamBydescOrByref(s)) then
406  return TRUE
407  end if
408  end if
409 
410  '' pointer? could be pointing to source symbol too..
411  case AST_NODECLASS_DEREF
412  return TRUE
413  end select
414 
415  '' walk
416  if( n->l <> NULL ) then
417  if( astIsSymbolOnTree( sym, n->l ) ) then
418  return TRUE
419  end if
420  end if
421 
422  if( n->r <> NULL ) then
423  if( astIsSymbolOnTree( sym, n->r ) ) then
424  return TRUE
425  end if
426  end if
427 
428  function = FALSE
429 
430 end function
431 
432 '':::::
434  ( _
435  byval n as ASTNODE ptr, _
436  byval old_sym as FBSYMBOL ptr, _
437  byval new_sym as FBSYMBOL ptr _
438  )
439 
440  if( n = NULL ) then
441  return
442  end if
443 
444  if( n->sym = old_sym ) then
445  n->sym = new_sym
446  end if
447 
448  '' assuming no other complex node will be on the
449  '' tree (TypeIniTree's won't have blocks, breaks, etc)
450 
451  select case as const n->class
452  case AST_NODECLASS_BOP, AST_NODECLASS_UOP, _
453  AST_NODECLASS_BRANCH, AST_NODECLASS_LOOP
454  if( n->op.ex = old_sym ) then
455  n->op.ex = new_sym
456  end if
457 
458  case AST_NODECLASS_IIF
459  if( n->iif.falselabel = old_sym ) then
460  n->iif.falselabel = new_sym
461  end if
462 
463  case AST_NODECLASS_CALL
464  '' too complex, let a helper function replace the symbols
465  astReplaceSymbolOnCALL( n, old_sym, new_sym )
466 
467  end select
468 
469  '' walk
470  if( n->l <> NULL ) then
471  astReplaceSymbolOnTree( n->l, old_sym, new_sym )
472  end if
473 
474  if( n->r <> NULL ) then
475  astReplaceSymbolOnTree( n->r, old_sym, new_sym )
476  end if
477 
478 end sub
479 
480 sub astReplaceFwdref _
481  ( _
482  byval n as ASTNODE ptr, _
483  byval oldsubtype as FBSYMBOL ptr, _
484  byval newdtype as integer, _
485  byval newsubtype as FBSYMBOL ptr _
486  )
487 
488  if( (typeGetDtOnly( n->dtype ) = FB_DATATYPE_FWDREF) and _
489  (n->subtype = oldsubtype) ) then
490  n->dtype = typeMerge( n->dtype, newdtype )
491  n->subtype = newsubtype
492  end if
493 
494  if( n->l ) then
495  astReplaceFwdref( n->l, oldsubtype, newdtype, newsubtype )
496  end if
497  if( n->r ) then
498  astReplaceFwdref( n->r, oldsubtype, newdtype, newsubtype )
499  end if
500 
501 end sub
502 
503 '':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
504 '' const helpers
505 '':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
506 
507 function astIsConstant( byval expr as ASTNODE ptr ) as integer
508  '' Checks whether an expression is a CONST node (number literals,
509  '' numeric constants), an access to a constant symbol (string literals
510  '' and string constants are accessed through VAR nodes), or whether it
511  '' has CONST on its data type.
512 
513  if( expr->sym ) then
514  if( symbIsConstant( expr->sym ) ) then
515  return TRUE
516  end if
517  end if
518 
519  return (astIsCONST( expr ) or typeIsConst( astGetFullType( expr ) ))
520 end function
521 
522 '':::::
523 function astGetStrLitSymbol _
524  ( _
525  byval n as ASTNODE ptr _
526  ) as FBSYMBOL ptr
527 
528  dim as FBSYMBOL ptr s = any
529 
530  function = NULL
531 
532  if( astIsVAR( n ) ) then
533  s = astGetSymbol( n )
534  if( s <> NULL ) then
535  if( symbGetIsLiteral( s ) ) then
536  function = s
537  end if
538  end if
539  end if
540 
541 end function
542 
543 '':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
544 '' checks
545 '':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
546 
547 sub astCheckConst _
548  ( _
549  byval dtype as integer, _
550  byval n as ASTNODE ptr _
551  )
552 
553  dim as integer result = any
554  dim as double dval = any
555  dim as single sval = any
556  dim as longint lval = any
557 
558  result = TRUE
559 
560  ''
561  '' We don't want to show overflow warnings for conversions where only
562  '' the sign differs, such as integer <-> uinteger, because in that case
563  '' there is no data/precision loss. Technically speaking there can be
564  '' overflows in such a conversion, but it's trivial to convert back
565  '' and nothing is lost. It would probably be rather annoying to have
566  '' warnings about it in many cases, such as:
567  '' dim a as uinteger = -1
568  '' dim b as uinteger = 1 shl 31
569  ''
570 
571  select case as const( typeGetDtAndPtrOnly( dtype ) )
572  ''case FB_DATATYPE_DOUBLE
573  '' DOUBLE can hold all the other dtype's values;
574  '' perhaps not with 100% precision (e.g. huge ULONGINTs will
575  '' lose some least-significant digits), but the DOUBLE doesn't
576  '' overflow to INF (the same can be seen with SINGLEs, but at
577  '' least those can be overflown with really huge DOUBLEs).
578  '' Thus, no checks are needed for DOUBLE.
579 
580  case FB_DATATYPE_SINGLE
581  '' anything to SINGLE: show warning when out of SINGLE limits
582  '' min = 1.401298e-45
583  '' max = 3.402823e+38
584 
585  dval = astConstGetAsDouble( n )
586 
587  select case abs( dval )
588  case 0.0, 2e-45 to 3e+38 '' definitely no overflow: comfortably within SINGLE bounds
589  result = TRUE
590  case else '' might overflow - slower/more thorough test
591 
592  sval = csng( dval )
593 
594  #define IS_INFINITY_OR_ZERO(x) ( (x) + (x) = (x) )
595  '' if sval is infinity or 0, then dval must also have been otherwise there was an overflow/underflow
596  if IS_INFINITY_OR_ZERO( sval ) then
597  result = IS_INFINITY_OR_ZERO( dval )
598  else
599  result = TRUE
600  end if
601  end select
602 
603  case FB_DATATYPE_BITFIELD
604  '' !!!WRITEME!!! use ->subtype's
605 
606  case else
607  select case as const( typeGetSizeType( dtype ) )
608  case FB_SIZETYPE_INT8, FB_SIZETYPE_UINT8
609  lval = astConstGetAsInt64( n )
610  result = ((lval >= -128) and (lval <= 255))
611 
612  case FB_SIZETYPE_INT16, FB_SIZETYPE_UINT16
613  lval = astConstGetAsInt64( n )
614  result = ((lval >= -32768) and (lval <= 65535))
615 
616  case FB_SIZETYPE_INT32, FB_SIZETYPE_UINT32
617  lval = astConstGetAsInt64( n )
618  result = ((lval >= -2147483648ll) and (lval <= 4294967295ll))
619 
620  case FB_SIZETYPE_INT64, FB_SIZETYPE_UINT64
621  '' longints can hold most other type's values, except floats
622  '' float?
623  if( typeGetClass( n->dtype ) = FB_DATACLASS_FPOINT ) then
624  dval = astConstGetAsDouble( n )
625  result = ((dval >= -9223372036854775808ull) and _
626  (dval <= 18446744073709551615ull))
627  end if
628  end select
629 
630  end select
631 
632  if( (result = FALSE) and ast.warn_convoverflow ) then
633  errReportWarn( FB_WARNINGMSG_CONVOVERFLOW )
634  end if
635 end sub
636 
637 '':::::
638 function astPtrCheck _
639  ( _
640  byval pdtype as integer, _
641  byval psubtype as FBSYMBOL ptr, _
642  byval expr as ASTNODE ptr, _
643  byval strictcheck as integer _
644  ) as integer
645 
646  dim as integer edtype = any
647 
648  function = FALSE
649 
650  edtype = astGetFullType( expr )
651 
652  '' expr not a pointer?
653  if( typeIsPtr( edtype ) = FALSE ) then
654  '' Only ok if it's a 0 constant
655  if( astIsCONST( expr ) ) then
656  if( typeGetClass( edtype ) = FB_DATACLASS_INTEGER ) then
657  function = astConstEqZero( expr )
658  end if
659  end if
660  exit function
661  end if
662 
663  '' different constant masks?
664  if( strictcheck ) then
665  if( typeGetPtrConstMask( edtype ) <> _
666  typeGetPtrConstMask( pdtype ) ) then
667  exit function
668  end if
669  end if
670 
671  '' different types?
672  if( typeGetDtAndPtrOnly( pdtype ) <> typeGetDtAndPtrOnly( edtype ) ) then
673 
674  '' remove the pointers
675  dim as integer pdtype_np = any, edtype_np = any
676  pdtype_np = typeGetDtOnly( pdtype )
677  edtype_np = typeGetDtOnly( edtype )
678 
679  '' 1st) is one of them an ANY PTR?
680  if( pdtype_np = FB_DATATYPE_VOID ) then
681  return TRUE
682  elseif( edtype_np = FB_DATATYPE_VOID ) then
683  return TRUE
684  end if
685 
686  '' 2nd) same level of indirection?
687  if( typeGetPtrCnt( pdtype ) <> typeGetPtrCnt( edtype ) ) then
688  exit function
689  end if
690 
691  '' 4th) same size and class?
692  if( (pdtype_np <= FB_DATATYPE_DOUBLE) and _
693  (edtype_np <= FB_DATATYPE_DOUBLE) ) then
694  if( typeGetSize( pdtype_np ) = typeGetSize( edtype_np ) ) then
695  if( typeGetClass( pdtype_np ) = typeGetClass( edtype_np ) ) then
696  return TRUE
697  end if
698  end if
699  end if
700 
701  exit function
702  end if
703 
704  '' check sub types
705  function = symbIsEqual( astGetSubType( expr ), psubtype )
706 
707 end function
708 
709 '':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
710 '' node type update
711 '':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
712 
713 function astUpdStrConcat( byval n as ASTNODE ptr ) as ASTNODE ptr
714  dim as ASTNODE ptr l = any, r = any
715 
716  function = n
717 
718  if( n = NULL ) then
719  exit function
720  end if
721 
722  select case as const astGetDataType( n )
723  case FB_DATATYPE_STRING, FB_DATATYPE_FIXSTR, _
724  FB_DATATYPE_WCHAR
725 
726  case else
727  exit function
728  end select
729 
730  '' walk
731  l = n->l
732  if( l <> NULL ) then
733  n->l = astUpdStrConcat( l )
734  end if
735 
736  r = n->r
737  if( r <> NULL ) then
738  n->r = astUpdStrConcat( r )
739  end if
740 
741  '' convert "string + string" to "StrConcat( string, string )"
742  if( n->class = AST_NODECLASS_BOP ) then
743  if( n->op.op = AST_OP_ADD ) then
744  l = n->l
745  r = n->r
746  dim as integer ldtype = astGetDataType( l ), rdtype = astGetDataType( r )
747  if( astGetDataType( n ) <> FB_DATATYPE_WCHAR ) then
748  function = rtlStrConcat( l, ldtype, r, rdtype )
749  else
750  function = rtlWstrConcat( l, ldtype, r, rdtype )
751  end if
752  astDelNode( n )
753  end if
754  end if
755 
756 end function
757 
758 '' Turn a comparison expression (or anything that can be compared = 0)
759 '' into a (conditional) branch
760 function astBuildBranch _
761  ( _
762  byval expr as ASTNODE ptr, _
763  byval label as FBSYMBOL ptr, _
764  byval is_inverse as integer, _
765  byval is_iif as integer _
766  ) as ASTNODE ptr
767 
768  dim as ASTNODE ptr n = any, parentlink = any, m = any
769  dim as integer dtype = any, call_dtors = any
770  dim as FBSYMBOL ptr temp = any
771 
772  if( expr = NULL ) then
773  return NULL
774  end if
775 
776  '' Optimize here already to ensure the toplevel BOP is final and can be
777  '' relied upon for x86 flag assumptions below
778  expr = astOptimizeTree( expr )
779 
780  dtype = astGetDataType( expr )
781 
782  '' string? invalid..
783  if( typeGetClass( dtype ) = FB_DATACLASS_STRING ) then
784  return NULL
785  end if
786 
787  '' CHAR and WCHAR literals are also from the INTEGER class
788  select case as const dtype
789  case FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR
790  '' don't allow, unless it's a deref pointer
791  if( astIsDEREF( expr ) = FALSE ) then
792  return NULL
793  end if
794 
795  '' UDT or CLASS?
796  case FB_DATATYPE_STRUCT ', FB_DATATYPE_CLASS
797  dim as FB_ERRMSG err_num = any
798  dim as FBSYMBOL ptr ovlProc = any
799 
800  '' check for a scalar overload..
801  ovlProc = symbFindCastOvlProc( FB_DATATYPE_VOID, NULL, expr, @err_num )
802  if( ovlProc = NULL ) then
803  '' no? try pointers...
804  ovlProc = symbFindCastOvlProc( typeAddrOf( FB_DATATYPE_VOID ), NULL, expr, @err_num )
805  if( ovlProc = NULL ) then
806  ovlProc = symbGetCompOpOvlHead( expr->subtype, AST_OP_CAST )
807  if( ovlProc = NULL ) then
808  if( expr->subtype ) then
809  errReport( FB_ERRMSG_NOMATCHINGPROC, _
810  TRUE, _
811  " """ & *symbGetName( expr->subtype ) & ".cast()""" )
812  return NULL
813  end if
814  end if
815 
816  errReport( FB_ERRMSG_NOMATCHINGPROC, TRUE )
817  return NULL
818  end if
819  end if
820 
821  '' build cast call
822  expr = astBuildCall( ovlProc, expr )
823  dtype = astGetDataType( expr )
824 
825  end select
826 
827  '' If the condition expression uses temp vars, we may have to call their
828  '' dtors before branching (or instead insert the dtor calls at the two
829  '' possible code blocks reached after the conditional branch).
830  ''
831  '' For iif(), it's better to call the temp var dtors later, because
832  '' we're still in the middle of an expression. A manual call to
833  '' astDtorListFlush() may accidentally emit dtor calls for temp vars
834  '' outside the iif(), e.g. in a statement like:
835  '' foo = returnUdt( ).field + iif( returnUdt.field = 0, 1, 2 )
836  ''
837  '' If it's a statement though (IF blocks, WHILE/UNTIL loops), we must
838  '' call the temp var dtors manually (instead of letting astAdd() do it)
839  '' in front of the branch, or else astAdd() would insert them behind
840  '' the branch, where they would be unreachable dead code.
841  ''
842  '' This only affects astBuildBranch() calls that may use a condition
843  '' expression with temp vars, and are not immediately astAdd()'ed,
844  '' but LINKed together with something instead.
845 
846  '' Update any remaining TYPEINIs in the condition expression, in case
847  '' they result in temp vars with dtors, otherwise astAdd() later would
848  '' do that, causing the dtor calls to appear at the end of the
849  '' statement (i.e. as dead code behind the branch...)
850  expr = astTypeIniUpdate( expr )
851 
852  call_dtors = not (is_iif or astDTorListIsEmpty( ))
853 
854  if( call_dtors = FALSE ) then
855  '' Skip LINK nodes, if any
856  n = expr
857  parentlink = NULL
858  while( n->class = AST_NODECLASS_LINK )
859  parentlink = n
860  if( n->link.ret_left ) then
861  n = n->l
862  else
863  n = n->r
864  end if
865  wend
866 
867  select case( n->class )
868  case AST_NODECLASS_CONST
869  '' Note: a CONST expression will never use temp vars.
870  '' Although the AST may have dtors registered from other parts
871  '' of the expression if it's an iif(), iif() will (currently)
872  '' optimize out itself when the condition is CONST, so this
873  '' case never happens.
874  assert( is_iif = FALSE )
875  assert( call_dtors = FALSE )
876 
877  '' If the condition is...
878  '' a) false (or true but inverted), emit a simple jump to jump
879  '' over the IF block.
880  '' b) true (or false but inverted), don't emit a jump at all,
881  '' but fall trough to the IF block.
882  if( astConstEqZero( n ) <> is_inverse ) then
883  m = astNewBRANCH( AST_OP_JMP, label, NULL )
884  else
885  m = astNewNOP( )
886  end if
887 
888  astDelNode( n )
889  n = m
890 
891  case AST_NODECLASS_BOP
892 
893  '' relational operator?
894  select case as const( n->op.op )
895  case AST_OP_EQ, AST_OP_NE, AST_OP_GT, _
896  AST_OP_LT, AST_OP_GE, AST_OP_LE
897 
898  '' Not possible if dtors have to be called,
899  '' since they must be emitted in between the
900  '' expression and the branch...
901  assert( call_dtors = FALSE )
902 
903  '' Directly update this BOP to do the branch itself
904  n->op.ex = label
905  if( is_inverse = FALSE ) then
906  n->op.op = astGetInverseLogOp( n->op.op )
907  end if
908 
909  '' BOP that sets x86 flags?
910  case AST_OP_ADD, AST_OP_SUB, AST_OP_SHL, AST_OP_SHR, _
911  AST_OP_AND, AST_OP_OR, AST_OP_XOR, AST_OP_IMP
912  ''AST_OP_EQV -- NOT doesn't set any flags, so EQV can't be optimized (x86 assumption)
913 
914  '' Can't optimize if dtors have be called, they'd trash the flags
915  assert( call_dtors = FALSE )
916 
917  dim as integer doopt = any
918 
919  if( typeGetClass( dtype ) = FB_DATACLASS_INTEGER ) then
920  doopt = irGetOption( IR_OPT_CPUBOPFLAGS )
921  if( doopt ) then
922  select case as const dtype
923  case FB_DATATYPE_LONGINT, FB_DATATYPE_ULONGINT
924  '' can't be done with longints either, as flag is set twice
925  doopt = irGetOption( IR_OPT_64BITCPUREGS )
926  end select
927  end if
928  else
929  doopt = irGetOption( IR_OPT_FPUBOPFLAGS )
930  end if
931 
932  if( doopt ) then
933  '' Check against zero (= FALSE), relying on the flags set by the BOP;
934  '' so it must not be removed by later astAdd() optimizations.
935  n = astNewBRANCH( iif( is_inverse, AST_OP_JNE, AST_OP_JEQ ), label, n )
936  else
937  n = NULL
938  end if
939 
940  case else
941  n = NULL
942  end select
943 
944  case else
945  n = NULL
946  end select
947 
948  '' An optimization was done?
949  if( n ) then
950  '' Update the parent LINK node, if any
951  if( parentlink ) then
952  if( parentlink->link.ret_left ) then
953  parentlink->l = n
954  else
955  parentlink->r = n
956  end if
957  else
958  '' Otherwise the whole expression was replaced
959  expr = n
960  end if
961 
962  return expr
963  end if
964  else
965  n = NULL
966  end if
967 
968  '' No optimization could be done, check expression against zero
969 
970  '' Remap zstring/wstring types, we don't want the temp var to be a
971  '' string, or the comparison against zero to be a string comparison...
972  select case( dtype )
973  case FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR
974  dtype = typeRemap( dtype, expr->subtype )
975  end select
976 
977  if( call_dtors ) then
978  '' 1. assign the condition to a temp var
979  temp = symbAddTempVar( dtype, expr->subtype )
980  n = astBuildVarAssign( temp, expr )
981 
982  '' 2. call dtors
983  n = astNewLINK( n, astDtorListFlush( ) )
984 
985  '' 3. branch if tempvar = zero
986  expr = astNewVAR( temp )
987  end if
988 
989  '' Check expression against zero (= FALSE)
990  n = astNewLINK( n, _
991  astNewBOP( iif( is_inverse, AST_OP_NE, AST_OP_EQ ), _
992  expr, astNewCONSTz( dtype, expr->subtype ), _
993  label, AST_OPOPT_NONE ) )
994 
995  function = n
996 end function
997 
998 '':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
999 '' temp destructors handling
1000 '':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
1001 
1002 function hHasDtor( byval sym as FBSYMBOL ptr ) as integer
1003  assert( symbIsVar( sym ) )
1004 
1005  '' Everything with a destructor (classes)
1006  function = symbHasDtor( sym )
1007 
1008  '' But also dynamic [w]strings
1009  select case( symbGetType( sym ) )
1010  case FB_DATATYPE_STRING
1011  function = TRUE
1012 
1013  case typeAddrOf( FB_DATATYPE_WCHAR )
1014  if( symbGetIsWstring( sym ) ) then
1015  function = TRUE
1016  end if
1017 
1018  end select
1019 end function
1020 
1021 #if __FB_DEBUG__
1023  dim as AST_DTORLIST_ITEM ptr i = any
1024 
1025  print "-------------- dtorlist: ------------------"
1026  i = listGetTail( @ast.dtorlist )
1027  while( i )
1028  print " ";symbDump( i->sym );" cookie: ";i->cookie;" refcount: ";i->refcount;" has dtor? ";hHasDtor( i->sym )
1029  i = listGetPrev( i )
1030  wend
1031 end sub
1032 #endif
1033 
1034 sub astDtorListAdd( byval sym as FBSYMBOL ptr )
1035  dim as AST_DTORLIST_ITEM ptr n = any
1036 
1037  if( hHasDtor( sym ) = FALSE ) then
1038  exit sub
1039  end if
1040 
1041  n = listNewNode( @ast.dtorlist )
1042  n->sym = sym
1043 
1044  with( ast.dtorlistscopes )
1045  '' If inside a dtorlist scope, mark the new entry
1046  '' with the scope's cookie
1047  if( .count > 0 ) then
1048  n->cookie = .cookies[.count-1]
1049  else
1050  n->cookie = 0
1051  end if
1052  end with
1053 
1054  n->refcount = 0
1055 end sub
1056 
1057 sub astDtorListAddRef( byval sym as FBSYMBOL ptr )
1058  dim as AST_DTORLIST_ITEM ptr i = any
1059 
1060  if( hHasDtor( sym ) = FALSE ) then
1061  exit sub
1062  end if
1063 
1064  '' Find the entry for this symbol (if any still exists)
1065  '' and increase its refcount
1066  i = listGetTail( @ast.dtorlist )
1067  while( i )
1068  if( i->sym = sym ) then
1069  i->refcount += 1
1070  exit while
1071  end if
1072 
1073  i = listGetPrev( i )
1074  wend
1075 end sub
1076 
1077 sub astDtorListRemoveRef( byval sym as FBSYMBOL ptr )
1078  dim as AST_DTORLIST_ITEM ptr i = any
1079 
1080  if( hHasDtor( sym ) = FALSE ) then
1081  exit sub
1082  end if
1083 
1084  '' Find the entry for this symbol (if any still exists)
1085  '' and decrease its refcount
1086  i = listGetTail( @ast.dtorlist )
1087  while( i )
1088  if( i->sym = sym ) then
1089  assert( i->refcount > 0 )
1090  i->refcount -= 1
1091 
1092  if( i->refcount <= 0 ) then
1093  listDelNode( @ast.dtorlist, i )
1094  end if
1095 
1096  exit while
1097  end if
1098 
1099  i = listGetPrev( i )
1100  wend
1101 end sub
1102 
1103 function astDtorListFlush( byval cookie as integer ) as ASTNODE ptr
1104  dim as AST_DTORLIST_ITEM ptr n = any, p = any
1105  dim as ASTNODE ptr t = any
1106 
1107  '' call the dtors in the reverse order
1108  t = NULL
1109  n = listGetTail( @ast.dtorlist )
1110  while( n )
1111  p = listGetPrev( n )
1112 
1113  '' astDtorListFlush() shouldn't be called without cookie
1114  '' while there still are entries registered with cookies,
1115  '' they probably should have been flushed first.
1116  assert( iif( cookie = 0, n->cookie = 0, TRUE ) )
1117 
1118  '' Only call dtors for the given cookie number
1119  if( n->cookie = cookie ) then
1120  t = astNewLINK( t, astBuildVarDtorCall( n->sym ) )
1121  listDelNode( @ast.dtorlist, n )
1122  end if
1123 
1124  n = p
1125  wend
1126 
1127  if( cookie = 0 ) then
1128  ast.dtorlistcookies = 0 '' Can aswell be reset
1129  end if
1130 
1131  function = t
1132 end function
1133 
1134 sub astDtorListDel( byval sym as FBSYMBOL ptr )
1135  dim as AST_DTORLIST_ITEM ptr n = any
1136 
1137  if( hHasDtor( sym ) = FALSE ) then
1138  exit sub
1139  end if
1140 
1141  n = listGetTail( @ast.dtorlist )
1142  while( n )
1143  if( n->sym = sym ) then
1144  listDelNode( @ast.dtorlist, n )
1145  exit while
1146  end if
1147  n = listGetPrev( n )
1148  wend
1149 end sub
1150 
1151 '' Opens a new dtorlist "scope", the newly allocated cookie number will be used
1152 '' to mark all dtorlist entries added by astDtorListAdd()'s while in this scope.
1153 '' If a "cookie" is given then that will be used to mark new entries, instead of
1154 '' allocating a new cookie.
1155 sub astDtorListScopeBegin( byval cookie as integer )
1156  if( cookie = 0 ) then
1157  '' Allocate new cookie
1158  ast.dtorlistcookies += 1
1159  cookie = ast.dtorlistcookies
1160  end if
1161 
1162  '' Add new scope with that cookie
1163  with( ast.dtorlistscopes )
1164  '' No more room? Enlarge the array
1165  if( .count = .room ) then
1166  .room += 8
1167  .cookies = xreallocate( .cookies, sizeof( *.cookies ) * .room )
1168  end if
1169  .cookies[.count] = cookie
1170  .count += 1
1171  end with
1172 end sub
1173 
1174 '' Closes the scope and returns its cookie number so it can be passed through
1175 '' to the following astNewIIF()
1176 function astDtorListScopeEnd( ) as integer
1177  '' Pop entry from the scopes stack
1178  with( ast.dtorlistscopes )
1179  assert( .count > 0 )
1180  function = .cookies[.count-1]
1181  .count -= 1
1182  end with
1183 end function
1184 
1185 sub astDtorListUnscope( byval cookie as integer )
1186  dim as AST_DTORLIST_ITEM ptr i = any
1187 
1188  '' call the dtors in the reverse order
1189  i = listGetTail( @ast.dtorlist )
1190  while( i )
1191  if( i->cookie = cookie ) then
1192  i->cookie = 0
1193  end if
1194  i = listGetPrev( i )
1195  wend
1196 end sub
1197 
1198 '':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
1199 '' hacks
1200 '':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
1201 
1202 '':::::
1203 sub astSetType _
1204  ( _
1205  byval n as ASTNODE ptr, _
1206  byval dtype as integer, _
1207  byval subtype as FBSYMBOL ptr _
1208  )
1209 
1210 #if __FB_DEBUG__
1211  if( astIsTYPEINI( n ) ) then
1212  '' TYPEINI types shouldn't be changed by optimizations,
1213  '' it would cause astTypeIniUpdate() to use the wrong type
1214  '' for the temp var.
1215  '' (astSetType() can still be called, e.g. from astNewDEREF(),
1216  '' just the type shouldn't be changed)
1217  assert( typeGetDtAndPtrOnly( n->dtype ) = typeGetDtAndPtrOnly( dtype ) )
1218  assert( n->subtype = subtype )
1219  end if
1220 #endif
1221 
1222  astGetFullType( n ) = dtype
1223  n->subtype = subtype
1224 
1225  select case n->class
1226  case AST_NODECLASS_LINK
1227  if( n->link.ret_left ) then
1228  astSetType( n->l, dtype, subtype )
1229  else
1230  astSetType( n->r, dtype, subtype )
1231  end if
1232 
1233  case AST_NODECLASS_FIELD
1234  astSetType( n->l, dtype, subtype )
1235 
1236  case AST_NODECLASS_CALLCTOR
1237  '' Propagate type change up to the temp VAR access, since that's
1238  '' what will be returned by astLoadCALLCTOR().
1239  astSetType( n->r, dtype, subtype )
1240 
1241  '' This happens with field accesses on a CALLCTOR expression
1242  '' such as (UDT( )).field. The access to offset 0 of the temp
1243  '' UDT var is optimized out, causing the CALLCTOR expression to
1244  '' be changed over to the field's dtype for a "direct" access.
1245 
1246  case AST_NODECLASS_IIF
1247  astSetType( n->l, dtype, subtype )
1248 
1249  end select
1250 
1251 end sub
1252 
1253 function astSizeOf( byval n as ASTNODE ptr ) as longint
1254  function = symbCalcLen( n->dtype, n->subtype )
1255 
1256  '' If it's a STRING * N, we must get the real length from the
1257  '' associated symbol, since the N isn't encoded in the dtype/subtype.
1258  select case( typeGetDtAndPtrOnly( n->dtype ) )
1259  case FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR, FB_DATATYPE_FIXSTR
1260  if( n->sym ) then
1261  function = symbGetLen( n->sym )
1262  end if
1263  end select
1264 end function
1265 
1266 function hSymbIsOnLocalStack( byval sym as FBSYMBOL ptr ) as integer
1267  function = symbIsLocal( sym ) and (not symbIsStatic( sym ))
1268 end function
1269 
1270 function astIsAccessToLocal( byval expr as ASTNODE ptr ) as integer
1271  function = FALSE
1272 
1273  select case( astGetClass( expr ) )
1274  case AST_NODECLASS_VAR
1275  '' Disallow local var accesses
1276  '' Note: accesses to byref params are automatically allowed,
1277  '' because they have DEREFs at the top, not VARs.
1278  function = hSymbIsOnLocalStack( expr->sym )
1279 
1280  case AST_NODECLASS_IDX
1281  '' Disallow local array accesses, unless it's a bydesc param
1282  '' (accesses to them also have an IDX at the top)
1283  if( symbIsParamBydesc( expr->sym ) = FALSE ) then
1284  function = hSymbIsOnLocalStack( expr->sym )
1285  end if
1286 
1287  case AST_NODECLASS_CALL
1288  '' No CALLs can be allowed - either their result
1289  '' is in registers or in a local temp var.
1290  '' Note: functions returning BYREF are ok, because they have
1291  '' DEREFs at the top, not CALLs.
1292  function = TRUE
1293 
1294  case AST_NODECLASS_FIELD
1295  if( astIsDEREF( expr->l ) ) then
1296  if( astIsBOP( expr->l->l, AST_OP_ADD ) ) then
1297  if( astGetClass( expr->l->l->l ) = AST_NODECLASS_ADDROF ) then
1298  '' will be a VAR/FIELD again
1299  function = astIsAccessToLocal( expr->l->l->l->l )
1300  end if
1301  end if
1302  end if
1303 
1304  end select
1305 
1306 end function
1307