FreeBASIC  0.91.0
symb-var.bas
Go to the documentation of this file.
1 '' symbol table module for variables (scalars and arrays)
2 ''
3 '' chng: sep/2004 written [v1ctor]
4 '' jan/2005 updated to use real linked-lists [v1ctor]
5 
6 
7 #include once "fb.bi"
8 #include once "fbint.bi"
9 #include once "parser.bi"
10 #include once "hash.bi"
11 #include once "list.bi"
12 #include once "ast.bi"
13 
14 declare sub hCreateArrayDescriptorType( )
15 declare function hCreateDescType _
16  ( _
17  byval symtb as FBSYMBOLTB ptr, _
18  byval dims as integer, _
19  byval id as zstring ptr, _
20  byval dtype as integer, _
21  byval subtype as FBSYMBOL ptr, _
22  byval attrib as integer _
23  ) as FBSYMBOL ptr
24 
26  listInit( @symb.dimlist, FB_INITDIMNODES, len( FBVARDIM ), LIST_FLAGS_NOCLEAR )
27 
28  '' assuming it's safe to create UDT symbols here, the array
29  '' dimension type must be allocated at module-level or it
30  '' would be removed when going out scope
32 end sub
33 
34 sub symbVarEnd( )
35  listEnd( @symb.dimlist )
36 end sub
37 
38 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
39 '' add
40 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
41 
43  static as FBARRAYDIM dTB(0)
44  dim as FBSYMBOL ptr fld = any
45 
46  '' type FBARRAYDIM
47  symb.fbarraydim = symbStructBegin( NULL, NULL, "__FB_ARRAYDIMTB$", NULL, FALSE, 0, NULL, 0 )
48 
49  '' elements as integer
50  symbAddField( symb.fbarraydim, "elements", 0, dTB(), _
51  FB_DATATYPE_INTEGER, NULL, 0, 0 )
52 
53  '' lbound as integer
54  symbAddField( symb.fbarraydim, "lbound", 0, dTB(), _
55  FB_DATATYPE_INTEGER, NULL, 0, 0 )
56 
57  '' ubound as integer
58  symbAddField( symb.fbarraydim, "ubound", 0, dTB(), _
59  FB_DATATYPE_INTEGER, NULL, 0, 0 )
60 
61  '' end type
62  symbStructEnd( symb.fbarraydim )
63 
64  '' type FBARRAY
65  '' ...
66  '' end type
67  symb.fbarray = hCreateDescType( NULL, -1, "__FB_ARRAYDESC$", FB_DATATYPE_VOID, NULL, 0 )
68 
69  ''
70  '' Store some field offsets into globals for easy access
71  ''
72 
73  '' FBARRAY
74  fld = symbUdtGetFirstField( symb.fbarray ) '' data
75  symb.fbarray_data = symbGetOfs( fld )
76  fld = symbUdtGetNextField( fld ) '' ptr
77  fld = symbUdtGetNextField( fld ) '' size
78  fld = symbUdtGetNextField( fld ) '' element_len
79  fld = symbUdtGetNextField( fld ) '' dimensions
80  fld = symbUdtGetNextField( fld ) '' dimTB
81  symb.fbarray_dimtb = symbGetOfs( fld )
82 
83  '' FBVARDIM
84  fld = symbUdtGetFirstField( symb.fbarraydim ) '' elements
85  fld = symbUdtGetNextField( fld ) '' lbound
86  symb.fbarraydim_lbound = symbGetOfs( fld )
87  fld = symbUdtGetNextField( fld ) '' ubound
88  symb.fbarraydim_ubound = symbGetOfs( fld )
89 end sub
90 
91 function hCreateDescType _
92  ( _
93  byval symtb as FBSYMBOLTB ptr, _
94  byval dims as integer, _
95  byval id as zstring ptr, _
96  byval dtype as integer, _
97  byval subtype as FBSYMBOL ptr, _
98  byval attrib as integer _
99  ) as FBSYMBOL ptr
100 
101  static as FBARRAYDIM dTB(0)
102  dim as FBSYMBOL ptr sym = any
103 
104  sym = symbStructBegin( symtb, NULL, id, NULL, FALSE, 0, NULL, attrib )
105 
106  '' data as any ptr
107  symbAddField( sym, "data", 0, dTB(), _
108  typeAddrOf( dtype ), subtype, 0, 0 )
109 
110  '' ptr as any ptr
111  symbAddField( sym, "ptr", 0, dTB(), _
112  typeAddrOf( dtype ), subtype, 0, 0 )
113 
114  '' size as integer
115  symbAddField( sym, "size", 0, dTB(), _
116  FB_DATATYPE_INTEGER, NULL, 0, 0 )
117 
118  '' element_len as integer
119  symbAddField( sym, "element_len", 0, dTB(), _
120  FB_DATATYPE_INTEGER, NULL, 0, 0 )
121 
122  '' dimensions as integer
123  symbAddField( sym, "dimensions", 0, dTB(), _
124  FB_DATATYPE_INTEGER, NULL, 0, 0 )
125 
126  '' If the dimension count is unknown, reserve room for the max amount
127  if( dims = -1 ) then
128  dims = FB_MAXARRAYDIMS
129  end if
130 
131  '' dimTB(0 to dims-1) as FBARRAYDIM
132  dTB(0).lower = 0
133  dTB(0).upper = dims-1
134 
135  symbAddField( sym, "dimTB", 1, dTB(), FB_DATATYPE_STRUCT, _
136  symb.fbarraydim, 0, 0 )
137 
138  symbStructEnd( sym )
139 
140  function = sym
141 end function
142 
143 '':::::
144 function symbAddArrayDesc _
145  ( _
146  byval array as FBSYMBOL ptr, _
147  byval dimensions as integer _
148  ) as FBSYMBOL ptr
149 
150  dim as zstring ptr id = any, id_alias = any
151  dim as FBSYMBOL ptr desc = any, desctype = any
152  dim as FB_SYMBATTRIB attrib = any
153  dim as FBSYMBOLTB ptr symtb = any
154  dim as integer isdynamic = any, ispubext = any, stats = any
155 
156  function = NULL
157 
158  '' don't add if it's a jump table
159  if( (env.clopt.backend = FB_BACKEND_GAS) and symbGetIsJumpTb( array ) ) then
160  exit function
161  end if
162 
163  id_alias = NULL
164  stats = 0
165 
166  '' field?
167  if( symbIsField( array ) ) then
168  static as string tmp
169  tmp = *symbUniqueId( )
170  id = strptr( tmp )
171  '' Only store an alias if in BASIC mangling
172  if( array->mangling <> FB_MANGLING_BASIC ) then
173  id_alias = id
174  end if
175 
176  attrib = FB_SYMBATTRIB_LOCAL
177  stats = FB_SYMBSTATS_IMPLICIT
178 
179  '' can't be ever static, the address has to be always
180  '' calculated at runtime
181 
182  '' var_..
183  else
184  isdynamic = symbIsDynamic( array )
185  ispubext = (array->attrib and (FB_SYMBATTRIB_PUBLIC or FB_SYMBATTRIB_EXTERN)) <> 0
186 
187  '' common or dynamic? Use the array's name/alias for the
188  '' descriptor, allowing it to be a from other modules if
189  '' Extern, and making debugging nicer.
190  if( symbIsCommon( array ) or isdynamic ) then
191  id = array->id.name
192  id_alias = array->id.alias
193  '' Preserve FB_SYMBSTATS_HASALIAS stat too
194  stats = array->stats and FB_SYMBSTATS_HASALIAS
195 
196  '' otherwise, create a temporary name for the descriptor,
197  '' as it will be used privately only, and must co-exist with
198  '' the static array symbol.
199  else
200  static as string tmp
201  tmp = *symbUniqueId( )
202  id = strptr( tmp )
203  '' Only store an alias if in BASIC mangling
204  if( array->mangling <> FB_MANGLING_BASIC ) then
205  id_alias = id
206  end if
207  stats = FB_SYMBSTATS_IMPLICIT
208  end if
209 
210  attrib = array->attrib and (FB_SYMBATTRIB_SHARED or _
211  FB_SYMBATTRIB_COMMON or _
212  FB_SYMBATTRIB_STATIC or _
213  FB_SYMBATTRIB_EXTERN or _
214  FB_SYMBATTRIB_PUBLIC or _
215  FB_SYMBATTRIB_LOCAL)
216 
217  '' not dynamic?
218  if( isdynamic = FALSE ) then
219  '' extern? always emit the descriptor (if accessed),
220  '' because the original one won't be accessible (or may don't
221  '' exist, if it's a "C" extern array)
222  if( symbIsExtern( array ) ) then
223  attrib and= not FB_SYMBATTRIB_EXTERN
224  end if
225 
226  '' if not-dynamic, the descriptor can't be ever public
227  attrib and= not FB_SYMBATTRIB_PUBLIC
228  end if
229  end if
230 
231  attrib or= FB_SYMBATTRIB_DESCRIPTOR
232 
233  '' field?
234  if( symbIsField( array ) ) then
235  '' if at mod-level, it can't be static, alloc on main()'s stack
236  if( parser.scope = FB_MAINSCOPE ) then
237  symtb = @symbGetProcSymbTb( parser.currproc )
238 
239  '' otherwise, let newSymbol() set it, we could be inside an
240  '' scope block (ie: a var initializer)
241  else
242  symtb = NULL
243  end if
244 
245  '' use the same symb tb as the array
246  else
247  symtb = array->symtb
248  end if
249 
250  '' Create descriptor UDT in same symtb, and preserving the
251  '' FB_SYMBATTRIB_LOCAL too if the descriptor has it.
252  desctype = hCreateDescType( symtb, dimensions, symbUniqueId( ), _
253  symbGetType( array ), symbGetSubType( array ), _
254  attrib and FB_SYMBATTRIB_LOCAL )
255 
256  desc = symbNewSymbol( FB_SYMBOPT_PRESERVECASE, NULL, symtb, NULL, _
257  FB_SYMBCLASS_VAR, id, id_alias, _
258  FB_DATATYPE_STRUCT, desctype, attrib )
259  if( desc = NULL ) then
260  exit function
261  end if
262 
263  desc->lgt = symbGetLen( desctype )
264  desc->ofs = 0
265 
266  desc->stats = stats or (array->stats and (FB_SYMBSTATS_VARALLOCATED or FB_SYMBSTATS_ACCESSED))
267 
268  desc->var_.initree = NULL
269  desc->var_.array.dims = 0
270  desc->var_.array.dimhead = NULL
271  desc->var_.array.dimtail = NULL
272  desc->var_.array.dif = 0
273  desc->var_.array.elms = 1
274  desc->var_.array.desc = NULL
275  desc->var_.array.has_ellipsis = FALSE
276  desc->var_.desc.array = array '' back link
277  desc->var_.stmtnum = parser.stmt.cnt
278  desc->var_.align = 0 '' default alignment
279  desc->var_.data.prev = NULL
280 
281  function = desc
282 end function
283 
284 sub symbAddArrayDim _
285  ( _
286  byval s as FBSYMBOL ptr, _
287  byval lower as longint, _
288  byval upper as longint _
289  )
290 
291  dim as FBVARDIM ptr d = any, n = any
292 
293  d = listNewNode( @symb.dimlist )
294 
295  d->lower = lower
296  d->upper = upper
297 
298  n = s->var_.array.dimtail
299  if( n <> NULL ) then
300  n->next = d
301  else
302  s->var_.array.dimhead = d
303  end if
304 
305  d->next = NULL
306  s->var_.array.dimtail = d
307 
308 end sub
309 
310 '':::::
311 sub symbSetArrayDimTb _
312  ( _
313  byval s as FBSYMBOL ptr, _
314  byval dimensions as integer, _
315  dTB() as FBARRAYDIM _
316  )
317 
318  dim as integer i = any
319  dim as FBVARDIM ptr d = any
320  dim as integer do_build = TRUE
321 
322  if( dimensions > 0 ) then
323  s->var_.array.dif = symbCalcArrayDiff( dimensions, dTB(), s->lgt )
324 
325  if( (s->var_.array.dimhead = NULL) or _
326  (symbGetArrayDimensions( s ) <> dimensions) ) then
327 
328  symbDelVarDims( s )
329 
330  for i = 0 to dimensions-1
331  symbAddArrayDim( s, dTB(i).lower, dTB(i).upper )
332 
333  '' If any dimension size is unknown yet (ellipsis), hold off on the actual build
334  '' until called later when it's known.
335  if( dTB(i).upper = FB_ARRAYDIM_UNKNOWN ) then do_build = FALSE
336  next
337  else
338  d = s->var_.array.dimhead
339  for i = 0 to dimensions-1
340  d->lower = dTB(i).lower
341  d->upper = dTB(i).upper
342  '' If any dimension size is unknown yet (ellipsis), hold off on the actual build
343  '' until called later when it's known.
344  if( d->upper = FB_ARRAYDIM_UNKNOWN ) then do_build = FALSE
345  d = d->next
346  next
347  end if
348 
349  s->var_.array.elms = symbCalcArrayElements( s )
350  else
351  s->var_.array.dif = 0
352  s->var_.array.elms = 1
353  end if
354 
355  s->var_.array.dims = dimensions
356 
357  '' dims can be -1 with COMMON arrays..
358  if( dimensions <> 0 ) then
359  if( do_build ) then
360  if( s->var_.array.desc = NULL ) then
361  s->var_.array.desc = symbAddArrayDesc( s, dimensions )
362  s->var_.array.desc->var_.initree = _
363  astBuildArrayDescIniTree( s->var_.array.desc, s, NULL )
364  end if
365  end if
366  else
367  s->var_.array.desc = NULL
368  end if
369 
370 end sub
371 
372 function symbAddVar _
373  ( _
374  byval id as const zstring ptr, _
375  byval id_alias as const zstring ptr, _
376  byval dtype as integer, _
377  byval subtype as FBSYMBOL ptr, _
378  byval lgt as longint, _
379  byval dimensions as integer, _
380  dTB() as FBARRAYDIM, _
381  byval attrib as integer, _
382  byval options as FB_SYMBOPT _
383  ) as FBSYMBOL ptr
384 
385  dim as FBSYMBOL ptr s = any
386  dim as FBSYMBOLTB ptr symtb = any
387  dim as FBHASHTB ptr hashtb = any
388  dim as integer isglobal = any, stats = any
389 
390  function = NULL
391 
392  ''
393  isglobal = (attrib and (FB_SYMBATTRIB_PUBLIC or _
394  FB_SYMBATTRIB_EXTERN or _
395  FB_SYMBATTRIB_SHARED or _
396  FB_SYMBATTRIB_COMMON)) <> 0
397 
398  ''
399  if( lgt <= 0 ) then
400  lgt = symbCalcLen( dtype, subtype )
401  end if
402 
403  '' no explict alias?
404  if( id_alias = NULL ) then
405  '' only preserve a case-sensitive version if in BASIC mangling
406  if( parser.mangling <> FB_MANGLING_BASIC ) then
407  id_alias = id
408  end if
409  stats = 0
410 
411  else
412  stats = FB_SYMBSTATS_HASALIAS
413  end if
414 
415  '' local? add to local symb & hash tbs
416  if( isglobal = FALSE ) then
417  attrib or= FB_SYMBATTRIB_LOCAL
418 
419  '' QB quirk: implicit variables are moved to the function scope..
420  if( (options and FB_SYMBOPT_UNSCOPE) = 0 ) then
421  symtb = symb.symtb
422  else
423  symtb = @symbGetProcSymbTb( parser.currproc )
424  end if
425 
426  hashtb = symb.hashtb
427 
428  '' can't add local static vars to global list because
429  '' symbDelSymbolTb() will miss them when flushing the
430  '' proc/scope block, and also because the GDB info
431 
432  '' global..
433  else
434  symtb = @symbGetGlobalTb( )
435  hashtb = @symbGetGlobalHashTb( )
436 
437  '' inside a namespace?
438  if( symbIsGlobalNamespc( ) = FALSE ) then
439  '' respect namespaces?
440  if( (options and FB_SYMBOPT_MOVETOGLOB) = 0 ) then
441  symtb = @symbGetCompSymbTb( symbGetCurrentNamespc( ) )
442  hashtb = @symbGetCompHashTb( symbGetCurrentNamespc( ) )
443  end if
444  end if
445  end if
446 
447  s = symbNewSymbol( options or FB_SYMBOPT_DOHASH, NULL, symtb, hashtb, _
448  FB_SYMBCLASS_VAR, id, id_alias, dtype, subtype, attrib )
449  if( s = NULL ) then
450  exit function
451  end if
452 
453  s->stats or= stats
454  s->lgt = lgt
455  s->ofs = 0
456  '' array fields
457  s->var_.array.dimhead = NULL
458  s->var_.array.dimtail = NULL
459  s->var_.array.desc = NULL
460  if( dimensions <> 0 ) then
461  symbSetArrayDimTb( s, dimensions, dTB() )
462  else
463  s->var_.array.dims = 0
464  s->var_.array.dif = 0
465  s->var_.array.elms = 1
466  end if
467  s->var_.array.has_ellipsis = FALSE
468  s->var_.desc.array = NULL
469  s->var_.initree = NULL
470  s->var_.align = 0 '' default alignment
471  s->var_.stmtnum = parser.stmt.cnt
472  s->var_.data.prev = NULL
473 
474  '' QB quirk: see above
475  if( (options and FB_SYMBOPT_UNSCOPE) <> 0 ) then
476  s->var_.stmtnum = parser.currproc->proc.ext->stmtnum + 1
477 
478  '' move to global?
479  elseif( (options and FB_SYMBOPT_MOVETOGLOB) <> 0 ) then
480  s->scope = FB_MAINSCOPE
481  end if
482 
483  function = s
484 end function
485 
486 '' For implicit variables that should live only in the current statement
487 '' - Will be marked with FB_SYMBATTRIB_TEMP, so it will not be destroyed
488 '' at scope breaks, but instead via the AST's dtor list and astAdd()
489 '' - Using a unique id, to avoid conflicts with the user's code
490 '' - As a positive side-effect, creating the var will always succeed
491 '' - FB_SYMBOPT_UNSCOPE is allowed, probably to ensure that temp vars used in
492 '' the user's var initializers will be unscoped just like the user's vars and
493 '' their initializers
494 '' - Temp vars should never be made STATIC automatically, e.g. due to
495 '' symbGetProcStaticLocals(), because they are hidden to the user, and making
496 '' them STATIC could cause hidden bugs with recursion or multi-threading.
497 function symbAddTempVar _
498  ( _
499  byval dtype as integer, _
500  byval subtype as FBSYMBOL ptr _
501  ) as FBSYMBOL ptr
502 
503  static as FBARRAYDIM dTB(0)
504  dim as FB_SYMBOPT options = FB_SYMBOPT_NONE
505 
506  '' Cannot create temp z/wstrings this way, since the length is unknown
507  assert( typeGetDtAndPtrOnly( dtype ) <> FB_DATATYPE_CHAR )
508  assert( typeGetDtAndPtrOnly( dtype ) <> FB_DATATYPE_WCHAR )
509 
510  if( fbLangOptIsSet( FB_LANG_OPT_SCOPE ) = FALSE ) then
511  options or= FB_SYMBOPT_UNSCOPE
512  end if
513 
514  var sym = symbAddVar( symbUniqueId( ), NULL, dtype, subtype, 0, 0, _
515  dTB(), FB_SYMBATTRIB_TEMP, options )
516  symbSetIsImplicit( sym )
517 
518  function = sym
519 end function
520 
521 '' For implicit variables that should live in the current scope, longer than
522 '' just the current statement.
523 '' - not marked with FB_SYMBATTRIB_TEMP, so the var will be destroyed properly
524 '' at scope breaks in the current scope, and at the end of the current scope
525 '' - just like a user-defined variable, just with an auto-generated name
526 '' - ditto regarding symbGetProcStaticLocals()
527 function symbAddImplicitVar _
528  ( _
529  byval dtype as integer, _
530  byval subtype as FBSYMBOL ptr, _
531  byval options as integer _
532  ) as FBSYMBOL ptr
533 
534  static as FBARRAYDIM dTB(0)
535 
536  '' Cannot create temp z/wstrings this way, since the length is unknown
537  assert( typeGetDtAndPtrOnly( dtype ) <> FB_DATATYPE_CHAR )
538  assert( typeGetDtAndPtrOnly( dtype ) <> FB_DATATYPE_WCHAR )
539 
540  var sym = symbAddVar( symbUniqueId( ), NULL, dtype, subtype, 0, 0, _
541  dTB(), 0, options )
542  symbSetIsImplicit( sym )
543 
544  function = sym
545 end function
546 
547 function symbAddAndAllocateTempVar( byval dtype as integer ) as FBSYMBOL ptr
548  dim as FBSYMBOL ptr s = any
549 
550  s = symbAddTempVar( dtype )
551 
552  assert( env.clopt.backend = FB_BACKEND_GAS )
553 
554  irProcAllocLocal( parser.currproc, s )
555 
556  function = s
557 end function
558 
559 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
560 '' misc
561 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
562 
563 '':::::
564 function symbCalcArrayDiff _
565  ( _
566  byval dimensions as integer, _
567  dTB() as FBARRAYDIM, _
568  byval lgt as longint _
569  ) as longint
570 
571  dim as integer d = any
572  dim as longint diff = any, elms = any
573 
574  if( dimensions <= 0 ) then
575  return 0
576  end if
577 
578  diff = 0
579  for d = 0 to (dimensions-1)-1
580  elms = (dTB(d+1).upper - dTB(d+1).lower) + 1
581  diff = (diff+dTB(d).lower) * elms
582  next
583 
584  diff += dTB(dimensions-1).lower
585 
586  diff *= lgt
587 
588  function = -diff
589 end function
590 
591 function symbCalcArrayElements _
592  ( _
593  byval s as FBSYMBOL ptr, _
594  byval n as FBVARDIM ptr = NULL _
595  ) as longint
596 
597  dim as longint e = any, d = any
598 
599  if( n = NULL ) then
600  n = s->var_.array.dimhead
601  end if
602 
603  e = 1
604  do while( n <> NULL )
605  d = (n->upper - n->lower) + 1
606  e = e * d
607  n = n->next
608  loop
609 
610  function = e
611 end function
612 
613 function symbCalcArrayElements _
614  ( _
615  byval dimensions as integer, _
616  dTB() as FBARRAYDIM _
617  ) as longint
618 
619  dim as longint e = any, d = any
620 
621  e = 1
622  for i as integer = 0 to dimensions-1
623  d = (dTB(i).upper - dTB(i).lower) + 1
624  e = e * d
625  next
626 
627  function = e
628 end function
629 
630 function symbCheckArraySize _
631  ( _
632  byval dimensions as integer, _
633  dTB() as FBARRAYDIM, _
634  byval lgt as longint, _
635  byval is_on_stack as integer, _
636  byval allow_ellipsis as integer _
637  ) as integer
638 
639  dim as ulongint allelements = any
640  dim as ulongint elements = any
641  dim as integer found_too_big = any
642 
643  found_too_big = FALSE
644  allelements = 1
645 
646  for i as integer = 0 to dimensions-1
647  '' ellipsis upper bound?
648  if( allow_ellipsis and (dTB(i).upper = FB_ARRAYDIM_UNKNOWN) ) then
649  '' Each dimension using ellipsis will have at least 1 element,
650  '' this is what can be assumed for now. (The check will need
651  '' to be repeated later when the real size is known)
652  elements = 1
653  else
654  '' elements for this array dimension
655  elements = (dTB(i).upper - dTB(i).lower) + 1
656  end if
657 
658  '' Too many elements in this dimension?
659  if( elements > &h7FFFFFFFu ) then
660  found_too_big = TRUE
661  exit for
662  end if
663 
664  allelements *= elements
665 
666  '' Too many elements overall after adding this dimension?
667  if( allelements > &h7FFFFFFFull ) then
668  found_too_big = TRUE
669  exit for
670  end if
671  next
672 
673  if( found_too_big = FALSE ) then
674  '' Apply data type size
675  allelements *= lgt
676  if( allelements > &h7FFFFFFFull ) then
677  found_too_big = TRUE
678  end if
679  end if
680 
681  if( found_too_big ) then
682  function = FALSE
683  else
684  if( is_on_stack and (allelements > culngint( env.clopt.stacksize )) ) then
685  errReportWarn( FB_WARNINGMSG_HUGEARRAYONSTACK )
686  end if
687  function = TRUE
688  end if
689 
690 end function
691 
692 function symbGetVarHasCtor( byval s as FBSYMBOL ptr ) as integer
693  '' shared, static, param or temp?
694  if( (s->attrib and (FB_SYMBATTRIB_SHARED or _
695  FB_SYMBATTRIB_STATIC or _
696  FB_SYMBATTRIB_COMMON or _
697  FB_SYMBATTRIB_PARAMBYDESC or _
698  FB_SYMBATTRIB_PARAMBYVAL or _
699  FB_SYMBATTRIB_PARAMBYREF or _
700  FB_SYMBATTRIB_TEMP or _
701  FB_SYMBATTRIB_FUNCRESULT)) <> 0 ) then
702  return FALSE
703  end if
704 
705  select case( symbGetType( s ) )
706  '' var-len string?
707  case FB_DATATYPE_STRING
708  return TRUE
709 
710  '' wchar ptr marked as "dynamic wstring"?
711  case typeAddrOf( FB_DATATYPE_WCHAR )
712  if( symbGetIsWstring( s ) ) then
713  return TRUE
714  end if
715 
716  end select
717 
718  '' array? dims can be -1 with "DIM foo()" arrays..
719  if( symbGetArrayDimensions( s ) <> 0 ) then
720  '' (note: it doesn't matter if it's dynamic array or not, local
721  '' non-dynamic array allocations will have to fill
722  '' the descriptor, so arrays can't be accessed before that)
723  return TRUE
724  end if
725 
726  '' UDT var with ctor?
727  function = symbHasCtor( s )
728 end function
729 
730 function symbGetVarHasDtor( byval s as FBSYMBOL ptr ) as integer
731  '' shared, static, param or temporary?
732  if( (s->attrib and (FB_SYMBATTRIB_SHARED or _
733  FB_SYMBATTRIB_STATIC or _
734  FB_SYMBATTRIB_COMMON or _
735  FB_SYMBATTRIB_PARAMBYDESC or _
736  FB_SYMBATTRIB_PARAMBYVAL or _
737  FB_SYMBATTRIB_PARAMBYREF or _
738  FB_SYMBATTRIB_TEMP or _
739  FB_SYMBATTRIB_FUNCRESULT)) <> 0 ) then
740  return FALSE
741  end if
742 
743  select case( symbGetType( s ) )
744  '' var-len string?
745  case FB_DATATYPE_STRING
746  return TRUE
747 
748  '' wchar ptr marked as "dynamic wstring"?
749  case typeAddrOf( FB_DATATYPE_WCHAR )
750  if( symbGetIsWstring(s) ) then
751  return TRUE
752  end if
753 
754  end select
755 
756  '' array? dims can be -1 with "DIM foo()" arrays..
757  if( symbGetArrayDimensions( s ) <> 0 ) then
758  '' dynamic?
759  if( symbIsDynamic( s ) ) then
760  return TRUE
761  end if
762  end if
763 
764  '' UDT var with dtor?
765  function = symbHasDtor( s )
766 end function
767 
768 function symbCloneVar( byval sym as FBSYMBOL ptr ) as FBSYMBOL ptr
769  static as FBARRAYDIM dTB(0 to FB_MAXARRAYDIMS-1)
770  dim as FBVARDIM ptr d = any
771  dim as integer dimensions = any
772 
773  '' assuming only temp vars or temp array descs will be cloned
774  if( symbIsDescriptor( sym ) ) then
775  function = symbAddArrayDesc( sym->var_.desc.array, _
776  symbGetArrayDimensions( sym->var_.desc.array ) )
777  '' no need to dup desc.initree, it was flushed in newARG() and
778  '' should be fixed up with the new symbol in TypeIniFlush()
779  elseif( symbIsTemp( sym ) ) then
780  function = symbAddTempVar( symbGetType( sym ), symbGetSubType( sym ) )
781  else
782  '' Fill the dTB() with the array's dimensions, if any
783  dimensions = symbGetArrayDimensions( sym )
784  d = symbGetArrayFirstDim( sym )
785  for i as integer = 0 to dimensions-1
786  dTB(i).lower = d->lower
787  dTB(i).upper = d->upper
788  d = d->next
789  next
790 
791  function = symbAddVar( symbGetName( sym ), NULL, _
792  symbGetType( sym ), symbGetSubType( sym ), 0, _
793  dimensions, dTB(), symbGetAttrib( sym ), 0 )
794  end if
795 end function
796 
797 function symbVarCheckAccess( byval sym as FBSYMBOL ptr ) as integer
798  '' inside a proc?
799  if( fbIsModLevel( ) = FALSE ) then
800  '' local?
801  if( symbIsLocal( sym ) ) then
802  '' not a main()'s local?
803  if( symbGetScope( sym ) = FB_MAINSCOPE ) then
804  return FALSE
805  end if
806  '' not shared?
807  elseif( symbIsShared( sym ) = FALSE ) then
808  return FALSE
809  end if
810  end if
811 
812  function = TRUE
813 end function
814 
815 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
816 '' del
817 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
818 
819 sub symbDelVarDims( byval s as FBSYMBOL ptr )
820  dim as FBVARDIM ptr n = any, nxt = any
821 
822  n = s->var_.array.dimhead
823  do while( n <> NULL )
824  nxt = n->next
825 
826  listDelNode( @symb.dimlist, n )
827 
828  n = nxt
829  loop
830 
831  s->var_.array.dimhead = NULL
832  s->var_.array.dimtail = NULL
833  s->var_.array.dims = 0
834 end sub
835 
836 sub symbDelVar( byval s as FBSYMBOL ptr, byval is_tbdel as integer )
837  if( symbGetArrayDimensions( s ) > 0 ) then
838  symbDelVarDims( s )
839  if( is_tbdel = FALSE ) then
840  '' del the array descriptor, recursively
841  if( s->var_.array.desc ) then
842  symbDelSymbol( s->var_.array.desc, FALSE )
843  end if
844  end if
845  end if
846 
847  if( symbGetIsLiteral( s ) ) then
848  s->attrib and= not FB_SYMBATTRIB_LITERAL
849 
850  '' not a wchar literal?
851  if( s->typ <> FB_DATATYPE_WCHAR ) then
852  if( s->var_.littext <> NULL ) then
853  ZstrFree( s->var_.littext )
854  end if
855  else
856  if( s->var_.littextw <> NULL ) then
857  WstrFree( s->var_.littextw )
858  end if
859  end if
860 
861  ''
862  elseif( symbGetIsInitialized( s ) ) then
863  s->stats and= not FB_SYMBSTATS_INITIALIZED
864  '' Note: astEnd() will already free the initree
865  end if
866 
867  ''
868  symbFreeSymbol( s )
869 end sub
870