FreeBASIC  0.91.0
parser-decl-var.bas
Go to the documentation of this file.
1 '' variable declarations (DIM, REDIM, COMMON, EXTERN or STATIC)
2 ''
3 '' chng: sep/2004 written [v1ctor]
4 
5 
6 #include once "fb.bi"
7 #include once "fbint.bi"
8 #include once "parser.bi"
9 #include once "rtl.bi"
10 #include once "ast.bi"
11 
13  ( _
14  byval dtype as integer, _
15  byval subtype as FBSYMBOL ptr _
16  )
17 
18  if( typeGetDtAndPtrOnly( dtype ) = FB_DATATYPE_STRUCT ) then
19  if( symbCompGetAbstractCount( subtype ) > 0 ) then
20  errReport( FB_ERRMSG_OBJECTOFABSTRACTCLASS )
21  end if
22  end if
23 
24 end sub
25 
26 sub hSymbolType _
27  ( _
28  byref dtype as integer, _
29  byref subtype as FBSYMBOL ptr, _
30  byref lgt as longint _
31  )
32 
33  '' parse the symbol type (INTEGER, STRING, etc...)
34  if( cSymbolType( dtype, subtype, lgt ) = FALSE ) then
35  errReport( FB_ERRMSG_EXPECTEDIDENTIFIER )
36  '' error recovery: fake a type
37  dtype = FB_DATATYPE_INTEGER
38  subtype = NULL
39  lgt = typeGetSize( dtype )
40  end if
41 
42  '' ANY?
43  if( dtype = FB_DATATYPE_VOID ) then
44  errReport( FB_ERRMSG_INVALIDDATATYPES )
45  '' error recovery: fake a type
46  dtype = typeAddrOf( dtype )
47  subtype = NULL
48  lgt = typeGetSize( dtype )
49  end if
50 
51 end sub
52 
53 function hCheckScope() as integer
54  if( parser.scope > FB_MAINSCOPE ) then
55  if( fbIsModLevel( ) = FALSE ) then
56  errReport( FB_ERRMSG_ILLEGALINSIDEASUB )
57  else
58  errReport( FB_ERRMSG_ILLEGALINSIDEASCOPE )
59  end if
60  function = FALSE
61  else
62  function = TRUE
63  end if
64 end function
65 
66 '':::::
67 ''VariableDecl = (REDIM PRESERVE?|DIM|COMMON) SHARED? SymbolDef
68 '' | EXTERN IMPORT? SymbolDef ALIAS STR_LIT
69 '' | STATIC SymbolDef .
70 ''
71 function cVariableDecl( byval attrib as FB_SYMBATTRIB ) as integer
72  dim as integer dopreserve = any, tk = any
73 
74 #macro hCheckPrivPubAttrib( attrib )
75  if( (attrib and (FB_SYMBATTRIB_PUBLIC or FB_SYMBATTRIB_PRIVATE)) <> 0 ) then
76  errReport( FB_ERRMSG_PRIVORPUBTTRIBNOTALLOWED )
77  attrib and= not FB_SYMBATTRIB_PUBLIC or FB_SYMBATTRIB_PRIVATE
78  end if
79 #endmacro
80 
81  dopreserve = FALSE
82 
83  tk = lexGetToken( )
84 
85  select case as const tk
86  '' REDIM
87  case FB_TK_REDIM
88  '' REDIM generates code, check if allowed
89  if( cCompStmtIsAllowed( FB_CMPSTMT_MASK_CODE ) = FALSE ) then
90  hSkipStmt( )
91  return TRUE
92  end if
93 
94  hCheckPrivPubAttrib( attrib )
95 
96  lexSkipToken( )
97  attrib or= FB_SYMBATTRIB_DYNAMIC
98 
99  '' PRESERVE?
100  if( hMatch( FB_TK_PRESERVE ) ) then
101  dopreserve = TRUE
102  end if
103 
104  '' COMMON
105  case FB_TK_COMMON
106  '' can't use COMMON inside a proc or inside a scope block
107  if( hCheckScope( ) = FALSE ) then
108  '' error recovery: don't share it
109  attrib = FB_SYMBATTRIB_STATIC or FB_SYMBATTRIB_DYNAMIC
110  else
111  attrib or= FB_SYMBATTRIB_COMMON or _
112  FB_SYMBATTRIB_STATIC or _
113  FB_SYMBATTRIB_DYNAMIC '' this will be removed, if it's not a array
114  end if
115 
116  hCheckPrivPubAttrib( attrib )
117 
118  lexSkipToken( )
119 
120  '' EXTERN
121  case FB_TK_EXTERN
122  if( attrib = FB_SYMBATTRIB_NONE ) then
123  '' ambiguity with EXTERN "mangling spec"
124  if( lexGetLookAheadClass( 1 ) = FB_TKCLASS_STRLITERAL ) then
125  return FALSE
126  end if
127  end if
128 
129  '' can't use EXTERN inside a proc
130  if( hCheckScope( ) = FALSE ) then
131  '' error recovery: don't make it extern
132  attrib = FB_SYMBATTRIB_STATIC
133  else
134  attrib or= FB_SYMBATTRIB_EXTERN or _
135  FB_SYMBATTRIB_SHARED or _
136  FB_SYMBATTRIB_STATIC
137  end if
138 
139  hCheckPrivPubAttrib( attrib )
140 
141  lexSkipToken( )
142 
143  '' STATIC
144  case FB_TK_STATIC
145  if( cCompStmtIsAllowed( FB_CMPSTMT_MASK_DECL or FB_CMPSTMT_MASK_CODE ) = FALSE ) then
146  hSkipStmt( )
147  return TRUE
148  end if
149 
150  lexSkipToken( )
151 
152  attrib or= FB_SYMBATTRIB_STATIC
153 
154  '' VAR?
155  if( lexGetToken( ) = FB_TK_VAR ) then
156  cAutoVarDecl( attrib )
157  return TRUE
158  end if
159 
160  case else
161  if( cCompStmtIsAllowed( FB_CMPSTMT_MASK_DECL or FB_CMPSTMT_MASK_CODE ) = FALSE ) then
162  hSkipStmt( )
163  return TRUE
164  end if
165 
166  lexSkipToken( )
167 
168  end select
169 
170  '' OPTION DYNAMIC enabled?
171  if( env.opt.dynamic ) then
172  attrib or= FB_SYMBATTRIB_DYNAMIC
173  end if
174 
175  if( (attrib and FB_SYMBATTRIB_EXTERN) = 0 ) then
176  '' SHARED?
177  if( lexGetToken( ) = FB_TK_SHARED ) then
178  '' can't use SHARED inside a proc
179  if( hCheckScope( ) = FALSE ) then
180  '' error recovery: don't make it shared
181  attrib or= FB_SYMBATTRIB_STATIC
182  else
183  attrib or= FB_SYMBATTRIB_SHARED or _
184  FB_SYMBATTRIB_STATIC
185  end if
186  lexSkipToken( )
187  end if
188  else
189  '' IMPORT?
190  if( lexGetToken( ) = FB_TK_IMPORT ) then
191  lexSkipToken( )
192 
193  '' only if target is Windows
194  select case env.clopt.target
195  case FB_COMPTARGET_WIN32, FB_COMPTARGET_CYGWIN
196  attrib or= FB_SYMBATTRIB_IMPORT
197  end select
198  end if
199  end if
200 
201  if( symbGetProcStaticLocals( parser.currproc ) ) then
202  attrib or= FB_SYMBATTRIB_STATIC
203  end if
204 
205  cVarDecl( attrib, dopreserve, tk, FALSE )
206  function = TRUE
207 end function
208 
209 '':::::
210 function hIsConst _
211  ( _
212  byval dimensions as integer, _
213  exprTB() as ASTNODE ptr _
214  ) as integer
215 
216  for i as integer = 0 to dimensions-1
217  if( astIsCONST( exprTB(i, 0) ) = FALSE ) then
218  return FALSE
219  elseif( exprTB(i, 1) = NULL ) then
220  '' do nothing, allow NULL expression here for ellipsis
221  elseif( astIsCONST( exprTB(i, 1) ) = FALSE ) then
222  return FALSE
223  end if
224  next
225 
226  function = TRUE
227 
228 end function
229 
230 '':::::
231 sub hVarExtToPub _
232  ( _
233  byval sym as FBSYMBOL ptr, _
234  byval attrib as FB_SYMBATTRIB _
235  )
236 
237  '' Remove EXTERN (or it won't be emitted), add PUBLIC (and SHARED
238  '' for safety), and preserve visibility attributes.
239  symbSetAttrib( sym, (symbGetAttrib( sym ) and (not FB_SYMBATTRIB_EXTERN)) or _
240  FB_SYMBATTRIB_PUBLIC or FB_SYMBATTRIB_SHARED )
241 
242  '' array? update the descriptor attributes too
243  if( symbGetArrayDimensions( sym ) <> 0 ) then
244  dim as FBSYMBOL ptr desc = symbGetArrayDescriptor( sym )
245 
246  attrib = (symbGetAttrib( desc ) and (not FB_SYMBATTRIB_EXTERN)) or _
247  FB_SYMBATTRIB_SHARED
248 
249  '' not dynamic? descriptor can't be public
250  if( symbIsDynamic( sym ) = FALSE ) then
251  attrib and= not FB_SYMBATTRIB_PUBLIC
252  else
253  attrib or= FB_SYMBATTRIB_PUBLIC
254  end if
255 
256  symbSetAttrib( desc, attrib )
257 
258  '' Add an initializer to the descriptor, now that we know this
259  '' EXTERN will be allocated in this module, and the EXTERN
260  '' attribute was removed
261  symbGetTypeIniTree( desc ) = astBuildArrayDescIniTree( desc, sym, NULL )
262  end if
263 
264 end sub
265 
267  ( _
268  byval sym as FBSYMBOL ptr, _
269  byval id as zstring ptr, _
270  byval dimensions as integer, _
271  dTB() as FBARRAYDIM _
272  )
273 
274  dim as FBVARDIM ptr d = any
275  dim as integer i = any
276 
277  '' Not an array?
278  if( symbGetArrayDimensions( sym ) = 0 ) then
279  exit sub
280  end if
281 
282  '' Different dimension count?
283  if( dimensions <> symbGetArrayDimensions( sym ) ) then
284  errReportEx( FB_ERRMSG_WRONGDIMENSIONS, *id )
285  exit sub
286  end if
287 
288  '' Same lbound/ubound for each dimension?
289  d = symbGetArrayFirstDim( sym )
290  i = 0
291  while( d )
292 
293  if( ((d->lower <> dTB(i).lower) or _
294  (d->upper <> dTB(i).upper) ) and _
295  (dTB(i).upper <> FB_ARRAYDIM_UNKNOWN) ) then
296  errReportEx( FB_ERRMSG_BOUNDSDIFFERFROMEXTERN, *id )
297  exit sub
298  end if
299 
300  d = d->next
301  i += 1
302  wend
303 
304 end sub
305 
306 function hDeclExternVar _
307  ( _
308  byval sym as FBSYMBOL ptr, _
309  byval id as zstring ptr, _
310  byval dtype as integer, _
311  byval subtype as FBSYMBOL ptr, _
312  byval attrib as integer, _
313  byval addsuffix as integer, _
314  byval dimensions as integer, _
315  dTB() as FBARRAYDIM _
316  ) as FBSYMBOL ptr
317 
318  function = NULL
319 
320  if( sym = NULL ) then
321  exit function
322  end if
323 
324  '' not extern?
325  if( symbIsExtern( sym ) = FALSE ) then
326  exit function
327  end if
328 
329  '' check type
330  if( (dtype <> symbGetFullType( sym )) or _
331  (subtype <> symbGetSubType( sym )) ) then
332  errReportEx( FB_ERRMSG_TYPEMISMATCH, *id )
333  end if
334 
335  dim as integer setattrib = TRUE
336 
337  '' dynamic?
338  if( symbIsDynamic( sym ) ) then
339  if( (attrib and FB_SYMBATTRIB_DYNAMIC) = 0 ) then
340  errReportEx( FB_ERRMSG_EXPECTEDDYNAMICARRAY, *id )
341  end if
342 
343  '' static..
344  else
345  if( (attrib and FB_SYMBATTRIB_DYNAMIC) <> 0 ) then
346  errReportEx( FB_ERRMSG_EXPECTEDDYNAMICARRAY, *id )
347  end if
348 
349  '' no extern static as local
350  if( hCheckScope( ) = FALSE ) then
351  '' error recovery: don't make it shared
352  setattrib = FALSE
353  end if
354  end if
355 
356  hCheckExternArrayDimensions( sym, id, dimensions, dTB() )
357 
358  '' dup extern?
359  if( (attrib and FB_SYMBATTRIB_EXTERN) <> 0 ) then
360  return sym
361  end if
362 
363  '' set type
364  if( setattrib ) then
365  hVarExtToPub( sym, attrib )
366  end if
367 
368  function = sym
369 end function
370 
371 '':::::
372 function hDeclStaticVar _
373  ( _
374  byval sym as FBSYMBOL ptr, _
375  byval id as zstring ptr, _
376  byval idalias as zstring ptr, _
377  byval dtype as integer, _
378  byval subtype as FBSYMBOL ptr, _
379  byval lgt as longint, _
380  byval addsuffix as integer, _
381  byval attrib as integer, _
382  byval dimensions as integer, _
383  dTB() as FBARRAYDIM _
384  ) as FBSYMBOL ptr
385 
386  '' any var already defined?
387  dim as integer is_extern = any
388  if( sym <> NULL ) then
389  is_extern = symbIsExtern( sym )
390  else
391  is_extern = FALSE
392  end if
393 
394  '' new (or dup) var?
395  if( is_extern = FALSE ) then
396  dim as FB_SYMBOPT options = FB_SYMBOPT_NONE
397 
398  if( addsuffix ) then
399  attrib or= FB_SYMBATTRIB_SUFFIXED
400  end if
401 
402  if( fbLangOptIsSet( FB_LANG_OPT_SCOPE ) = FALSE ) then
403  options or= FB_SYMBOPT_UNSCOPE
404  end if
405 
406  sym = symbAddVar( id, idalias, dtype, subtype, lgt, _
407  dimensions, dTB(), attrib, options )
408 
409  '' already declared extern..
410  else
411  sym = hDeclExternVar( sym, id, dtype, subtype, attrib, _
412  addsuffix, dimensions, dTB() )
413  end if
414 
415  if( sym = NULL ) then
416  errReportEx( FB_ERRMSG_DUPDEFINITION, id )
417  '' no error recovery: already parsed
418  end if
419 
420  function = sym
421 
422 end function
423 
424 function hDeclDynArray _
425  ( _
426  byval sym as FBSYMBOL ptr, _
427  byval id as zstring ptr, _
428  byval idalias as zstring ptr, _
429  byval dtype as integer, _
430  byval subtype as FBSYMBOL ptr, _
431  byval is_typeless as integer, _
432  byval lgt as longint, _
433  byval addsuffix as integer, _
434  byval attrib as integer, _
435  byval dimensions as integer, _
436  byval token as integer _
437  ) as FBSYMBOL ptr
438 
439  static as FBARRAYDIM dTB(0 to FB_MAXARRAYDIMS-1) '' always 0
440 
441  function = NULL
442 
443  if( dimensions <> -1 ) then
444  '' DIM'g dynamic arrays gens code, check if allowed
445  if( cCompStmtIsAllowed( FB_CMPSTMT_MASK_CODE ) = FALSE ) then
446  hSkipStmt( )
447  exit function
448  end if
449  end if
450 
451  '' any variable already defined?
452  if( sym <> NULL ) then
453  '' array in a udt?
454  if( symbIsField( sym ) ) then
455  errReportEx( FB_ERRMSG_CANTREDIMARRAYFIELDS, *id )
456  exit function
457  end if
458 
459  '' typeless REDIM's?
460  if( is_typeless ) then
461  dtype = symbGetType( sym )
462  subtype = symbGetSubtype( sym )
463  lgt = symbGetLen( sym )
464  end if
465  end if
466 
467  '' new var?
468  if( sym = NULL ) then
469  dim as FB_SYMBOPT options = FB_SYMBOPT_NONE
470 
471  if( addsuffix ) then
472  attrib or= FB_SYMBATTRIB_SUFFIXED
473  end if
474 
475  if( fbLangOptIsSet( FB_LANG_OPT_SCOPE ) = FALSE ) then
476  options or= FB_SYMBOPT_UNSCOPE
477  end if
478 
479  sym = symbAddVar( id, idalias, dtype, subtype, lgt, _
480  dimensions, dTB(), attrib, options )
481 
482  '' check reallocation..
483  else
484  '' not dynamic?
485  if( symbGetIsDynamic( sym ) = FALSE ) then
486  '' could be an external..
487  sym = hDeclExternVar( sym, id, dtype, subtype, attrib, addsuffix, _
488  dimensions, dTB() )
489  else
490  '' var already exists; dup checks
491 
492  '' EXTERNal?
493  if( symbIsExtern( sym ) ) then
494  '' another EXTERN? (declared twice)
495  if( (attrib and FB_SYMBATTRIB_EXTERN) <> 0 ) then
496  sym = NULL
497  else
498  '' define it...
499  hVarExtToPub( sym, attrib )
500  end if
501  '' [re]dim ()?
502  elseif( dimensions = -1 ) then
503  sym = NULL
504 
505  '' dim foo(variable)? (without a preceeding COMMON)
506  elseif( (token <> FB_TK_REDIM) and (symbIsCommon( sym ) = FALSE) ) then
507  sym = NULL
508  end if
509  end if
510  end if
511 
512  if( sym = NULL ) then
513  errReportEx( FB_ERRMSG_DUPDEFINITION, *id )
514  '' no error recovery, caller will take care of that
515  exit function
516  end if
517 
518  '' don't allow const dynamic arrays...
519  '' they can't be assigned even if resized...
520  if( typeIsConst( symbGetFullType( sym ) ) ) then
521  errReport( FB_ERRMSG_DYNAMICARRAYSCANTBECONST )
522  end if
523 
524  attrib = symbGetAttrib( sym )
525 
526  '' external? don't do any checks..
527  if( (attrib and FB_SYMBATTRIB_EXTERN) <> 0 ) then
528  return sym
529  end if
530 
531  if( (dtype <> symbGetFullType( sym )) or _
532  (subtype <> symbGetSubType( sym )) ) then
533  errReportEx( FB_ERRMSG_DUPDEFINITION, *id )
534  '' no error recovery, caller will take care of that
535  exit function
536  end if
537 
538  '' Check dimensions, unless it's a bydesc param or a COMMON array,
539  '' then we don't know the dimensions at compile-time.
540  if( (attrib and (FB_SYMBATTRIB_PARAMBYDESC or FB_SYMBATTRIB_COMMON)) = 0 ) then
541  if( symbGetArrayDimensions( sym ) > 0 ) then
542  if( dimensions <> symbGetArrayDimensions( sym ) ) then
543  errReportEx( FB_ERRMSG_WRONGDIMENSIONS, *id )
544  '' no error recovery, ditto
545  exit function
546  end if
547  end if
548  end if
549 
550  '' if COMMON, check for max dimensions used
551  if( (attrib and FB_SYMBATTRIB_COMMON) <> 0 ) then
552  if( dimensions > symbGetArrayDimensions( sym ) ) then
553  symbSetArrayDimensions( sym, dimensions )
554  end if
555  '' or if dims = -1 (cause of "DIM|REDIM array()")
556  elseif( symbGetArrayDimensions( sym ) = -1 ) then
557  symbSetArrayDimensions( sym, dimensions )
558  end if
559 
560  function = sym
561 end function
562 
563 '':::::
564 function hGetId _
565  ( _
566  byval parent as FBSYMBOL ptr, _
567  byval id as zstring ptr, _
568  byref suffix as integer, _
569  byval options as FB_IDOPT _
570  ) as FBSYMCHAIN ptr
571 
572  dim as FBSYMCHAIN ptr chain_ = any
573 
574  '' no parent? read as-is
575  if( parent = NULL ) then
576  chain_ = lexGetSymChain( )
577  else
579  lexGetText( ), _
580  FALSE, _
581  (options and FB_IDOPT_ISDECL) = 0 )
582  end if
583 
584  '' ID
585  select case as const lexGetClass( )
586  case FB_TKCLASS_IDENTIFIER
587  if( fbLangOptIsSet( FB_LANG_OPT_PERIODS ) ) then
588  '' if inside a namespace, symbols can't contain periods (.)'s
589  if( symbIsGlobalNamespc( ) = FALSE ) then
590  if( lexGetPeriodPos( ) > 0 ) then
591  errReport( FB_ERRMSG_CANTINCLUDEPERIODS )
592  end if
593  end if
594  end if
595 
596  *id = *lexGetText( )
597  suffix = lexGetType( )
598 
599  case FB_TKCLASS_QUIRKWD
600  if( env.clopt.lang <> FB_LANG_QB ) then
601  '' only if inside a ns and if not local
602  if( (parent = NULL) or (parser.scope > FB_MAINSCOPE) ) then
603  errReport( FB_ERRMSG_DUPDEFINITION )
604  '' error recovery: fake an id
605  *id = *symbUniqueLabel( )
606  suffix = FB_DATATYPE_INVALID
607  else
608  *id = *lexGetText( )
609  suffix = lexGetType( )
610  end if
611 
612  '' QB mode..
613  else
614  *id = *lexGetText( )
615  suffix = lexGetType( )
616  end if
617 
618  case FB_TKCLASS_KEYWORD, FB_TKCLASS_OPERATOR
619  if( env.clopt.lang <> FB_LANG_QB ) then
620  errReport( FB_ERRMSG_DUPDEFINITION )
621  '' error recovery: fake an id
622  *id = *symbUniqueLabel( )
623  suffix = FB_DATATYPE_INVALID
624 
625  '' QB mode..
626  else
627  *id = *lexGetText( )
628  suffix = lexGetType( )
629 
630  '' must have a suffix if it is a keyword
631  if( suffix = FB_DATATYPE_INVALID ) then
632  errReport( FB_ERRMSG_DUPDEFINITION )
633  '' error recovery: fake an id
634  *id = *symbUniqueLabel( )
635  suffix = FB_DATATYPE_INVALID
636  end if
637  end if
638 
639  case else
640  errReport( FB_ERRMSG_EXPECTEDIDENTIFIER )
641  '' error recovery: fake an id
642  *id = *symbUniqueLabel( )
643  suffix = FB_DATATYPE_INVALID
644  end select
645 
646  hCheckSuffix( suffix )
647 
648  lexSkipToken( )
649 
650  function = chain_
651 
652 end function
653 
654 function hLookupVar _
655  ( _
656  byval chain_ as FBSYMCHAIN ptr, _
657  byval dtype as integer, _
658  byval is_typeless as integer, _
659  byval has_suffix as integer _
660  ) as FBSYMBOL ptr
661 
662  dim as FBSYMBOL ptr sym = any
663 
664  if( chain_ = NULL ) then
665  exit function
666  end if
667 
668  if( is_typeless ) then
669  if( fbLangOptIsSet( FB_LANG_OPT_DEFTYPE ) ) then
670  sym = symbFindVarByDefType( chain_, dtype )
671  else
672  sym = symbFindByClass( chain_, FB_SYMBCLASS_VAR )
673  end if
674  elseif( has_suffix ) then
675  sym = symbFindVarBySuffix( chain_, dtype )
676  else
677  sym = symbFindVarByType( chain_, dtype )
678  end if
679 
680  function = sym
681 end function
682 
683 function hLookupVarAndCheckParent _
684  ( _
685  byval parent as FBSYMBOL ptr, _
686  byval chain_ as FBSYMCHAIN ptr, _
687  byval dtype as integer, _
688  byval is_typeless as integer, _
689  byval has_suffix as integer, _
690  byval is_decl as integer _
691  ) as FBSYMBOL ptr
692 
693  dim as FBSYMBOL ptr sym = any
694 
695  sym = hLookupVar( chain_, dtype, is_typeless, has_suffix )
696 
697  '' Namespace prefix explicitly given?
698  if( parent ) then
699  if( sym ) then
700  '' "DIM Parent.foo" is only allowed if there was an
701  '' "EXTERN foo" in the Parent namespace, or if it's a
702  '' "REDIM Parent.foo" redimming an array declared in
703  '' the Parent namespace.
704  '' No EXTERN, or different parent, and not REDIM?
705  if( ((symbIsExtern( sym ) = FALSE) or _
706  (symbGetNamespace( sym ) <> parent)) and _
707  is_decl ) then
708  errReport( FB_ERRMSG_DECLOUTSIDECLASS )
709  end if
710  else
711  '' Symbol not found in the specified parent namespace
712  errReport( FB_ERRMSG_DECLOUTSIDENAMESPC, TRUE )
713  end if
714  else
715  '' The looked up symbol may be an existing var. If it's from
716  '' another namespace, then we ignore it, so that this new
717  '' declaration declares a new var in the current namespace,
718  '' i.e. a duplicate. However if it's from the current namespace
719  '' already, then we cannot allow declaring a second variable
720  '' with that name. Unless this is a REDIM, of course.
721  if( sym ) then
722  if( (symbGetNamespace( sym ) <> symbGetCurrentNamespc( )) and _
723  is_decl ) then
724  sym = NULL
725  end if
726  end if
727  end if
728 
729  function = sym
730 end function
731 
732 sub hMakeArrayDimTB _
733  ( _
734  byval dimensions as integer, _
735  exprTB() as ASTNODE ptr, _
736  dTB() as FBARRAYDIM _
737  )
738 
739  if( dimensions = -1 ) then
740  exit sub
741  end if
742 
743  for i as integer = 0 to dimensions-1
744  dim as ASTNODE ptr expr = any
745 
746  '' lower bound
747  dTB(i).lower = astConstFlushToInt( exprTB(i, 0) )
748 
749  '' upper bound
750  expr = exprTB(i, 1)
751  if( expr = NULL ) then
752  '' if a null expr is found, that means it was an ellipsis for the
753  '' upper bound, so we set a special upper value, and CONTINUE in
754  '' order to skip the check
755  dTB(i).upper = FB_ARRAYDIM_UNKNOWN
756  continue for
757  else
758  dTB(i).upper = astConstFlushToInt( expr )
759  end if
760 
761  '' Besides the upper < lower case, also complain about FB_ARRAYDIM_UNKNOWN being
762  '' specified, otherwise we'd think ellipsis was given...
763  if( (dTB(i).upper < dTB(i).lower) or (dTB(i).upper = FB_ARRAYDIM_UNKNOWN) ) then
764  errReport( FB_ERRMSG_INVALIDSUBSCRIPT )
765  end if
766  next
767 
768 end sub
769 
770 '':::::
771 function hVarInitDefault _
772  ( _
773  byval sym as FBSYMBOL ptr, _
774  byval is_decl as integer, _
775  byval has_defctor as integer _
776  ) as ASTNODE ptr
777 
778  function = NULL
779 
780  if( sym = NULL ) then
781  exit function
782  end if
783 
784  '' No default initialization for EXTERNs
785  '' (they're initialized when defined by corresponding DIM)
786  if( symbIsExtern( sym ) ) then
787  exit function
788  end if
789 
790  '' If it's marked as CONST we require it to have an initializer,
791  '' because that's the only way for the coder to set the value.
792  if( typeIsConst( symbGetFullType( sym ) ) ) then
793  errReport( FB_ERRMSG_AUTONEEDSINITIALIZER )
794  '' error recovery: fake an expr
795  return astNewCONSTi( 0 )
796  end if
797 
798  '' Has default constructor?
799  if( has_defctor ) then
800  '' not already declared nor dynamic array?
801  if( (not is_decl) and ((symbGetAttrib( sym ) and (FB_SYMBATTRIB_DYNAMIC or FB_SYMBATTRIB_COMMON)) = 0) ) then
802  '' Check visibility
803  if( symbCheckAccess( symbGetCompDefCtor( symbGetSubtype( sym ) ) ) = FALSE ) then
804  errReport( FB_ERRMSG_NOACCESSTODEFAULTCTOR )
805  end if
806  function = astBuildTypeIniCtorList( sym )
807  end if
808  else
809  '' Complain about lack of default ctor if there are others
810  if( symbHasCtor( sym ) ) then
811  errReport( FB_ERRMSG_NODEFAULTCTORDEFINED )
812  end if
813  end if
814 
815 end function
816 
817 function hHasEllipsis _
818  ( _
819  byval sym as FBSYMBOL ptr _
820  ) as integer
821 
822  function = FALSE
823 
824  if( sym <> NULL ) then
825  if symbIsArray( sym ) then
826  if sym->var_.array.has_ellipsis then
827  function = TRUE
828  end if
829  end if
830  end if
831 
832 end function
833 
834 '':::::
835 function hVarInit _
836  ( _
837  byval sym as FBSYMBOL ptr, _
838  byval isdecl as integer _
839  ) as ASTNODE ptr
840 
841  dim as integer attrib = any, ignoreattribs = any
842  dim as ASTNODE ptr initree = any
843 
844  function = NULL
845 
846  if( sym <> NULL ) then
847  attrib = symbGetAttrib( sym )
848  else
849  attrib = 0
850  end if
851 
852  '' already declared, extern or common?
853  if( isdecl or _
854  ((attrib and (FB_SYMBATTRIB_EXTERN or FB_SYMBATTRIB_COMMON)) <> 0) ) then
855  errReport( FB_ERRMSG_CANNOTINITEXTERNORCOMMON )
856  '' error recovery: skip
857  hSkipUntil( FB_TK_EOL )
858  exit function
859  end if
860 
861  if( fbLangOptIsSet( FB_LANG_OPT_INITIALIZER ) = FALSE ) then
862  errReportNotAllowed( FB_LANG_OPT_INITIALIZER )
863  '' error recovery: skip
864  hSkipUntil( FB_TK_EOL )
865  exit function
866  end if
867 
868  '' '=' | '=>'
869  lexSkipToken( )
870 
871  if( sym = NULL ) then
872  '' error recovery: skip until next ','
873  hSkipUntil( CHAR_COMMA )
874  exit function
875  end if
876 
877  '' ANY?
878  if( lexGetToken( ) = FB_TK_ANY ) then
879 
880  '' don't allow arrays with ellipsis denoting unknown size at this time
881  if hHasEllipsis( sym ) = TRUE then
882  errReport( FB_ERRMSG_CANTUSEANYINITELLIPSIS )
883  exit function
884  end if
885 
886  '' don't allow var-len strings
887  if( symbGetType( sym ) = FB_DATATYPE_STRING ) then
888  errReport( FB_ERRMSG_INVALIDDATATYPES )
889  else
890  symbSetDontInit( sym )
891  end if
892 
893  '' ...or const-qualified vars
894  if( typeIsConst( symbGetFullType( sym ) ) ) then
895  errReport( FB_ERRMSG_AUTONEEDSINITIALIZER )
896  '' error recovery: fake an expr
897  return astNewCONSTi( 0 )
898  end if
899 
900  lexSkipToken( )
901  exit function
902  end if
903 
904  initree = cInitializer( sym, FB_INIOPT_ISINI )
905  if( initree = NULL ) then
906  '' fake an expression
907  initree = astNewCONSTi( 0 )
908  end if
909 
910  '' static or shared?
911  if( (symbGetAttrib( sym ) and (FB_SYMBATTRIB_STATIC or FB_SYMBATTRIB_SHARED)) <> 0 ) then
912  ''
913  '' In general, STATIC/SHARED var initializers must be constants,
914  '' that includes OFFSETs (address of other global symbols),
915  '' because they're emitted into .data/.bss sections, so no code
916  '' (that needs to be executed) can be allowed.
917  ''
918  '' (Currently) the only exception are vars with constructors:
919  '' - the constructor must be called with certain parameters
920  '' - so code is executed, and the initializer can aswell allow
921  '' more than just constants
922  '' - temp vars are ok, because they will be duplicated as
923  '' needed by the TYPEINI scope handling
924  '' - local non-static vars cannot be allowed, since they're
925  '' from a different scope
926  ''
927  '' SHARED var initializers must not reference local STATICs,
928  '' because those symbols will be deleted by the time the global
929  '' is emitted. This can only happen with STATICs from the
930  '' implicit main() because those from inside procedures aren't
931  '' visible to SHARED declarations at the toplevel.
932  ''
933  '' The other way round (STATIC non-SHARED initializer using a
934  '' non-STATIC SHARED) is ok though; it will be "forward
935  '' referenced" in the .asm output, because STATICs are emitted
936  '' before globals, but it works.
937  ''
938  '' Even constant initializers can reference other global vars,
939  '' in form of OFFSETs (address-of), because of this the
940  '' astTypeIniUsesLocals() check must run in both constant and
941  '' non-constant initializer cases.
942  ''
943 
944  '' Check for constant initializer?
945  '' (doing this check first, it results in a nicer error message)
946  if( symbHasCtor( sym ) = FALSE ) then
947  if( astTypeIniIsConst( initree ) = FALSE ) then
948  errReport( FB_ERRMSG_EXPECTEDCONST )
949  '' error recovery: discard the tree
950  astDelTree( initree )
951  symbGetStats( sym ) and= not FB_SYMBSTATS_INITIALIZED
952  exit function
953  end if
954  end if
955 
956  '' Ensure the initializer doesn't reference any vars it mustn't
957 
958  '' Allow temp vars and temp array descriptors
959  ignoreattribs = FB_SYMBATTRIB_TEMP or FB_SYMBATTRIB_DESCRIPTOR
960 
961  '' Allow only non-SHARED STATICs to reference STATICs
962  if( symbIsShared( sym ) = FALSE ) then
963  ignoreattribs or= FB_SYMBATTRIB_STATIC
964  end if
965 
966  if( astTypeIniUsesLocals( initree, ignoreattribs ) ) then
967  errReport( FB_ERRMSG_INVALIDREFERENCETOLOCAL )
968  '' error recovery: discard the tree
969  astDelTree( initree )
970  symbGetStats( sym ) and= not FB_SYMBSTATS_INITIALIZED
971  exit function
972  end if
973  end if
974 
975  function = initree
976 end function
977 
978 '':::::
979 function hFlushDecl _
980  ( _
981  byval var_decl as ASTNODE ptr _
982  ) as ASTNODE ptr
983 
984  '' respect scopes?
985  if( fbLangOptIsSet( FB_LANG_OPT_SCOPE ) ) then
986  function = var_decl
987 
988  '' move to function scope..
989  else
990  '' note: addUnscoped() won't flush the dtor list
991  astAddUnscoped( var_decl )
992  function = NULL
993  end if
994 
995 end function
996 
997 function hWrapInStaticFlag( byval code as ASTNODE ptr ) as ASTNODE ptr
998  dim as ASTNODE ptr t = any
999  dim as FBARRAYDIM dTB(0) = any
1000  dim as FBSYMBOL ptr flag = any, label = any
1001 
1002  '' static flag as integer
1003  flag = symbAddVar( symbUniqueLabel( ), NULL, FB_DATATYPE_INTEGER, NULL, 0, _
1004  0, dTB(), FB_SYMBATTRIB_STATIC )
1005  symbSetIsImplicit( flag )
1006  t = astNewDECL( flag, TRUE )
1007 
1008  '' if flag = 0 then
1009  label = symbAddLabel( NULL )
1010  t = astNewLINK( t, _
1011  astBuildBranch( _
1012  astNewBOP( AST_OP_EQ, astNewVAR( flag ), astNewCONSTi( 0 ) ), _
1013  label, FALSE ) )
1014 
1015  '' flag = 1
1016  t = astNewLINK( t, astBuildVarAssign( flag, 1 ) )
1017 
1018  '' <code>
1019  t = astNewLINK( t, code )
1020 
1021  '' end if
1022  function = astNewLINK( t, astNewLABEL( label ) )
1023 end function
1024 
1025 function hCallStaticCtor _
1026  ( _
1027  byval sym as FBSYMBOL ptr, _
1028  byval var_decl as ASTNODE ptr, _
1029  byval initree as ASTNODE ptr, _
1030  byval has_dtor as integer _
1031  ) as ASTNODE ptr
1032 
1033  dim as ASTNODE ptr t = any, initcode = any
1034  dim as FBSYMBOL ptr proc = any
1035 
1036  t = hFlushDecl( var_decl )
1037  initcode = NULL
1038 
1039  if( initree ) then
1040  '' static var's initializer
1041  initcode = astTypeIniFlush( initree, sym, AST_INIOPT_ISINI )
1042  end if
1043 
1044  if( has_dtor ) then
1045  '' Register an atexit() handler to call the static var's dtor
1046  '' at program exit.
1047  '' atexit( @static_proc )
1048  proc = astProcAddStaticInstance( sym )
1049  initcode = astNewLINK( initcode, rtlAtExit( astBuildProcAddrof( proc ) ) )
1050  end if
1051 
1052  '' Any initialization code for a static var must be wrapped with a
1053  '' static flag, to ensure it'll be only executed once, not everytime the
1054  '' parent procedure is called.
1055  if( initcode ) then
1056  t = astNewLINK( t, hWrapInStaticFlag( initcode ) )
1057  end if
1058 
1059  function = t
1060 end function
1061 
1062 '':::::
1063 function hCallGlobalCtor _
1064  ( _
1065  byval sym as FBSYMBOL ptr, _
1066  byval var_decl as ASTNODE ptr, _
1067  byval initree as ASTNODE ptr, _
1068  byval has_dtor as integer _
1069  ) as ASTNODE ptr
1070 
1071  var_decl = hFlushDecl( var_decl )
1072 
1073  if( (initree = NULL) and (has_dtor = FALSE) ) then
1074  return var_decl
1075  end if
1076 
1077  astProcAddGlobalInstance( sym, initree, has_dtor )
1078 
1079  '' No temp dtors should be left registered after the TYPEINI build-up
1080  assert( astDtorListIsEmpty( ) )
1081 
1082  '' cannot call astAdd() before deleting the dtor list or it
1083  '' would be flushed
1084  function = var_decl
1085 
1086 end function
1087 
1088 '':::::
1089 function hFlushInitializer _
1090  ( _
1091  byval sym as FBSYMBOL ptr, _
1092  byval var_decl as ASTNODE ptr, _
1093  byval initree as ASTNODE ptr, _
1094  byval has_dtor as integer _
1095  ) as ASTNODE ptr
1096 
1097  '' object?
1098  if( has_dtor ) then
1099  '' check visibility
1100  if( symbCheckAccess( symbGetCompDtor( symbGetSubtype( sym ) ) ) = FALSE ) then
1101  errReport( FB_ERRMSG_NOACCESSTODTOR )
1102  end if
1103  end if
1104 
1105  '' no initializer?
1106  if( initree = NULL ) then
1107  '' static or shared?
1108  if( (symbGetAttrib( sym ) and (FB_SYMBATTRIB_STATIC or _
1109  FB_SYMBATTRIB_SHARED or _
1110  FB_SYMBATTRIB_COMMON)) <> 0 ) then
1111  '' object?
1112  if( has_dtor ) then
1113  '' local?
1114  if( symbIsLocal( sym ) ) then
1115  var_decl = hCallStaticCtor( sym, var_decl, NULL, TRUE )
1116 
1117  '' global..
1118  else
1119  var_decl = hCallGlobalCtor( sym, var_decl, NULL, TRUE )
1120  end if
1121  end if
1122  end if
1123 
1124  return var_decl
1125  end if
1126 
1127  '' not static or shared?
1128  if( (symbGetAttrib( sym ) and (FB_SYMBATTRIB_STATIC or _
1129  FB_SYMBATTRIB_SHARED or _
1130  FB_SYMBATTRIB_COMMON)) = 0 ) then
1131 
1132  var_decl = hFlushDecl( var_decl )
1133 
1134  return astNewLINK( var_decl, _
1135  astTypeIniFlush( initree, sym, AST_INIOPT_ISINI ) )
1136  end if
1137 
1138  '' not an object?
1139  if( symbHasCtor( sym ) = FALSE ) then
1140  '' let emit flush it..
1141  symbSetTypeIniTree( sym, initree )
1142 
1143  '' no dtor?
1144  if( has_dtor = FALSE ) then
1145  return hFlushDecl( var_decl )
1146  end if
1147 
1148  '' must be added to the dtor list..
1149  initree = NULL
1150  else
1151  '' Don't let the backend emit the initializer for this global/static
1152  symbGetStats( sym ) and= not FB_SYMBSTATS_INITIALIZED
1153  end if
1154 
1155  '' local?
1156  if( symbIsLocal( sym ) ) then
1157  '' the only possibility is static, SHARED can't be
1158  '' used in -lang fb..
1159  function = hCallStaticCtor( sym, var_decl, initree, has_dtor )
1160 
1161  '' global.. add to the list, to be emitted later
1162  else
1163  function = hCallGlobalCtor( sym, var_decl, initree, has_dtor )
1164  end if
1165 
1166 end function
1167 
1168 '':::::
1169 ''VarDecl = ID ('(' ArrayDecl? ')')? (AS SymbolType)? ('=' VarInitializer)?
1170 '' (',' SymbolDef)* .
1171 ''
1172 function cVarDecl _
1173  ( _
1174  byval attrib as integer, _
1175  byval dopreserve as integer, _
1176  byval token as integer, _
1177  byval is_fordecl as integer _
1178  ) as FBSYMBOL ptr
1179 
1180  static as zstring * FB_MAXNAMELEN+1 id
1181  static as ASTNODE ptr exprTB(0 to FB_MAXARRAYDIMS-1, 0 to 1)
1182  static as FBARRAYDIM dTB(0 to FB_MAXARRAYDIMS-1)
1183  dim as FBSYMBOL ptr sym, subtype = any
1184  dim as ASTNODE ptr initree = any, redimcall = any
1185  dim as integer addsuffix = any, is_multdecl = any
1186  dim as integer is_typeless = any, is_decl = any, check_exprtb = any
1187  dim as integer dtype = any
1188  dim as longint lgt = any
1189  dim as integer dimensions = any, suffix = any
1190  dim as zstring ptr palias = any
1191  dim as ASTNODE ptr assign_initree = any
1192  dim as integer doassign = any
1193  dim as integer has_ellipsis = FALSE
1194  dim as FB_IDOPT options = any
1195 
1196  function = NULL
1197 
1198  '' inside a namespace but outside a proc?
1199  if( symbIsGlobalNamespc( ) = FALSE ) then
1200  if( fbIsModLevel( ) ) then
1201  '' variables will be always shared..
1202  attrib or= FB_SYMBATTRIB_SHARED or FB_SYMBATTRIB_STATIC
1203  end if
1204  end if
1205 
1206  '' (AS SymbolType)?
1207  is_multdecl = FALSE
1208  if( lexGetToken( ) = FB_TK_AS ) then
1209  lexSkipToken( )
1210 
1211  '' parse the symbol type (INTEGER, STRING, etc...)
1212  hSymbolType( dtype, subtype, lgt )
1213 
1214  '' Disallow creating objects of abstract classes
1215  hComplainIfAbstractClass( dtype, subtype )
1216 
1217  addsuffix = FALSE
1218  is_multdecl = TRUE
1219  end if
1220 
1221  options = FB_IDOPT_DEFAULT or FB_IDOPT_ALLOWSTRUCT or FB_IDOPT_ISVAR
1222 
1223  '' It's a declaration unless it's a REDIM (REDIMs are code,
1224  '' not declarations), except when it's SHARED, because a REDIM SHARED
1225  '' is always a declaration and never a code REDIM.
1226  if( (token <> FB_TK_REDIM) or ((attrib and FB_SYMBATTRIB_SHARED) <> 0) ) then
1227  options or= FB_IDOPT_ISDECL
1228  end if
1229 
1230  do
1231  dim as FBSYMBOL ptr parent = cParentId( options )
1232  dim as FBSYMCHAIN ptr chain_ = hGetId( parent, @id, suffix, options )
1233 
1234  is_typeless = FALSE
1235 
1236  if( is_multdecl = FALSE ) then
1237  dtype = suffix
1238  subtype = NULL
1239  lgt = 0
1240  addsuffix = TRUE
1241  else
1242  '' the user did 'DIM AS _____', and then
1243  '' specified a suffix on a symbol, e.g.
1244  ''
1245  '' DIM AS INTEGER x, y$
1246  if( suffix <> FB_DATATYPE_INVALID ) then
1247  errReportEx( FB_ERRMSG_SYNTAXERROR, @id )
1248  '' error recovery: the symbol gets the
1249  '' type specified 'AS'
1250  suffix = FB_DATATYPE_INVALID
1251  end if
1252  end if
1253 
1254  '' ('(' ArrayDecl? ')')?
1255  dimensions = 0
1256  check_exprtb = FALSE
1257  if( (lexGetToken( ) = CHAR_LPRNT) and (is_fordecl = FALSE) ) then
1258  lexSkipToken( )
1259 
1260  '' '()'
1261  if( lexGetToken( ) = CHAR_RPRNT ) then
1262  '' fake it
1263  dimensions = -1
1264  attrib or= FB_SYMBATTRIB_DYNAMIC
1265 
1266  '' '(' ArrayDecl ')'
1267  else
1268  '' COMMON? No subscripts allowed
1269  if( attrib and FB_SYMBATTRIB_COMMON ) then
1270  errReport( FB_ERRMSG_SYNTAXERROR )
1271  '' error recovery: skip until next ')'
1272  hSkipUntil( CHAR_RPRNT )
1273  else
1274  cArrayDecl( dimensions, exprTB() )
1275 
1276  check_exprtb = TRUE
1277 
1278  '' If there were any ellipsises in the
1279  '' array decl then we mark the symbol before initializing
1280  for i as integer = 0 to dimensions - 1
1281  if( exprTB(i,1) = NULL ) then
1282  has_ellipsis = TRUE
1283  end if
1284  next
1285  end if
1286  end if
1287 
1288  '' ')'
1289  if( lexGetToken( ) <> CHAR_RPRNT ) then
1290  errReport( FB_ERRMSG_EXPECTEDRPRNT )
1291  else
1292  lexSkipToken( )
1293  end if
1294 
1295  '' Scalar, no array subscripts
1296  else
1297  '' With REDIM it must have array subscripts though
1298  if( token = FB_TK_REDIM ) then
1299  errReportEx( FB_ERRMSG_EXPECTEDARRAY, @id )
1300  end if
1301 
1302  '' (could have been added due to OPTION DYNAMIC,
1303  '' but if it's not an array, then it can't be DYNAMIC)
1304  attrib and= not FB_SYMBATTRIB_DYNAMIC
1305  end if
1306 
1307  palias = NULL
1308  if( (attrib and (FB_SYMBATTRIB_PUBLIC or FB_SYMBATTRIB_EXTERN)) <> 0 ) then
1309  '' [ALIAS "id"]
1310  palias = cAliasAttribute()
1311  end if
1312 
1313  if( is_multdecl = FALSE ) then
1314  '' (AS SymbolType)?
1315  if( lexGetToken( ) = FB_TK_AS ) then
1316  if( dtype <> FB_DATATYPE_INVALID ) then
1317  errReport( FB_ERRMSG_SYNTAXERROR )
1318  dtype = FB_DATATYPE_INVALID
1319  end if
1320 
1321  lexSkipToken( )
1322 
1323  '' parse the symbol type (INTEGER, STRING, etc...)
1324  hSymbolType( dtype, subtype, lgt )
1325 
1326  '' Disallow creating objects of abstract classes
1327  hComplainIfAbstractClass( dtype, subtype )
1328 
1329  addsuffix = FALSE
1330 
1331  '' no explicit type..
1332  else
1333  if( fbLangOptIsSet( FB_LANG_OPT_DEFTYPE ) = FALSE ) then
1334  '' it's not an error if REDIM'g an already declared array
1335  if( (chain_ = NULL) or (token <> FB_TK_REDIM) ) then
1336  errReportNotAllowed( FB_LANG_OPT_DEFTYPE, FB_ERRMSG_DEFTYPEONLYVALIDINLANG )
1337  '' error recovery: fake a type
1338  dtype = FB_DATATYPE_INTEGER
1339  end if
1340  end if
1341 
1342  if( dtype = FB_DATATYPE_INVALID ) then
1343  is_typeless = TRUE
1344  dtype = symbGetDefType( id )
1345  end if
1346 
1347  lgt = symbCalcLen( dtype, subtype )
1348  end if
1349  end if
1350 
1351  sym = hLookupVarAndCheckParent( parent, chain_, dtype, is_typeless, _
1352  (suffix <> FB_DATATYPE_INVALID), _
1353  ((options and FB_IDOPT_ISDECL) <> 0) )
1354 
1355  if( dimensions > 0 ) then
1356  '' QB quirk: when the symbol was defined already by a preceeding COMMON
1357  '' statement, then a DIM will work the same way as a REDIM
1358  if( token = FB_TK_DIM ) then
1359  if( (attrib and FB_SYMBATTRIB_DYNAMIC) = 0 ) then
1360  if( sym <> NULL ) then
1361  if( symbIsCommon( sym ) ) then
1362  if( symbGetArrayDimensions( sym ) <> 0 ) then
1363  attrib or= FB_SYMBATTRIB_DYNAMIC
1364  end if
1365  end if
1366  end if
1367  end if
1368  end if
1369 
1370  if( check_exprtb ) then
1371  '' if subscripts are constants, convert exprTB to dimTB
1372  if( hIsConst( dimensions, exprTB() ) ) then
1373  '' only if not explicitly dynamic (ie: not REDIM, COMMON)
1374  if( (attrib and FB_SYMBATTRIB_DYNAMIC) = 0 ) then
1375  hMakeArrayDimTB( dimensions, exprTB(), dTB() )
1376  end if
1377  else
1378  '' Non-constant array bounds, must be dynamic
1379  attrib or= FB_SYMBATTRIB_DYNAMIC
1380  end if
1381  end if
1382 
1383  '' "array too big/huge array on stack" check
1384  if( (attrib and FB_SYMBATTRIB_DYNAMIC) = 0 ) then
1385  if( symbCheckArraySize( dimensions, dTB(), lgt, _
1386  ((attrib and (FB_SYMBATTRIB_SHARED or FB_SYMBATTRIB_STATIC)) = 0), _
1387  has_ellipsis ) = FALSE ) then
1388  errReport( FB_ERRMSG_ARRAYTOOBIG )
1389  '' error recovery: use small array
1390  dimensions = 1
1391  dTB(0).lower = 0
1392  dTB(0).upper = 0
1393  end if
1394  end if
1395  elseif( dimensions = 0 ) then
1396  '' "huge variable on stack" check
1397  if( ((attrib and (FB_SYMBATTRIB_SHARED or FB_SYMBATTRIB_STATIC)) = 0) and _
1398  (lgt > env.clopt.stacksize) ) then
1399  errReportWarn( FB_WARNINGMSG_HUGEVARONSTACK )
1400  end if
1401  end if
1402 
1403  '' don't allow COMMON object instances
1404  if( (attrib and FB_SYMBATTRIB_COMMON) <> 0 ) then
1405  if( typeHasCtor( dtype, subtype ) or typeHasDtor( dtype, subtype ) ) then
1406  errReport( FB_ERRMSG_COMMONCANTBEOBJINST, TRUE )
1407  end if
1408  end if
1409 
1410  if( attrib and FB_SYMBATTRIB_DYNAMIC ) then
1411  sym = hDeclDynArray( sym, id, palias, dtype, subtype, is_typeless, _
1412  lgt, addsuffix, attrib, dimensions, token )
1413  else
1414  sym = hDeclStaticVar( sym, id, palias, _
1415  dtype, subtype, _
1416  lgt, addsuffix, attrib, _
1417  dimensions, dTB() )
1418  end if
1419 
1420  dim as integer has_defctor = FALSE, has_dtor = FALSE
1421 
1422  if( sym <> NULL ) then
1423  is_decl = symbGetIsDeclared( sym )
1424  has_defctor = symbHasDefCtor( sym )
1425  has_dtor = symbHasDtor( sym )
1426  if( has_ellipsis ) then
1427  sym->var_.array.has_ellipsis = TRUE
1428  end if
1429  else
1430  is_decl = FALSE
1431  end if
1432 
1433  '' check for an initializer
1434  if( is_fordecl = FALSE ) then
1435 
1436  '' assume no assignment
1437  doassign = FALSE
1438  assign_initree = NULL
1439 
1440  '' '=' | '=>' ?
1441  if( hIsAssignToken( ) ) then
1442  initree = hVarInit( sym, is_decl )
1443 
1444  if( ( initree <> NULL ) and ( fbLangOptIsSet( FB_LANG_OPT_SCOPE ) = FALSE ) ) then
1445  '' local?
1446  if( (symbGetAttrib( sym ) and (FB_SYMBATTRIB_STATIC or _
1447  FB_SYMBATTRIB_SHARED or _
1448  FB_SYMBATTRIB_COMMON)) = 0 ) then
1449  doassign = TRUE
1450 
1451  ''
1452  '' The variable will be unscoped, i.e. it needs a default initree
1453  '' for the implicit declaration at procedure level, plus the assignment
1454  '' with the initializer in the nested scope where it was defined.
1455  ''
1456  '' scope
1457  '' dim as integer i = 5
1458  '' end scope
1459  ''
1460  '' becomes:
1461  ''
1462  '' dim as integer i
1463  '' scope
1464  '' i = 5
1465  '' end scope
1466  ''
1467  assign_initree = initree
1468  initree = hVarInitDefault( sym, is_decl, has_defctor )
1469  end if
1470  end if
1471  else
1472  '' default initialization
1473  if( hHasEllipsis( sym ) ) then
1474  errReport( FB_ERRMSG_MUSTHAVEINITWITHELLIPSIS )
1475  hSkipStmt( )
1476  exit function
1477  end if
1478 
1479  initree = hVarInitDefault( sym, is_decl, has_defctor )
1480  end if
1481  else
1482  initree = NULL
1483  assign_initree = NULL
1484  doassign = FALSE
1485  end if
1486 
1487  '' add to AST
1488  if( sym <> NULL ) then
1489 
1490  dim as FBSYMBOL ptr desc = NULL
1491  dim as ASTNODE ptr var_decl = NULL
1492 
1493  '' not declared already?
1494  if( is_decl = FALSE ) then
1495  '' Don't init if it's a temp FOR var, it will
1496  '' have the start condition put into it.
1497  var_decl = astNewDECL( sym, _
1498  ((initree = NULL) and (not is_fordecl)) )
1499 
1500  '' add the descriptor too, if any
1501  desc = symbGetArrayDescriptor( sym )
1502  if( desc <> NULL ) then
1503  var_decl = astNewLINK( var_decl, astNewDECL( desc, (symbGetTypeIniTree( desc ) = NULL) ) )
1504  end if
1505  end if
1506 
1507  '' handle arrays (must be done after adding the decl node)
1508 
1509  '' do nothing if it's EXTERN
1510  if( token <> FB_TK_EXTERN ) then
1511 
1512  '' array?
1513  if( ((attrib and FB_SYMBATTRIB_DYNAMIC) <> 0) or (dimensions > 0) ) then
1514  '' not declared yet?
1515  if( is_decl = FALSE ) then
1516  '' local?
1517  if( (symbGetAttrib( sym ) and (FB_SYMBATTRIB_STATIC or _
1518  FB_SYMBATTRIB_SHARED or _
1519  FB_SYMBATTRIB_COMMON)) = 0 ) then
1520 
1521  '' flush the decl node, safe to do here as it's a non-static
1522  '' local var (and because the decl must be flushed first)
1523  var_decl = hFlushDecl( var_decl )
1524 
1525  '' bydesc array params have no descriptor
1526  if( desc <> NULL ) then
1527  var_decl = astNewLINK( var_decl, astTypeIniFlush( symbGetTypeIniTree( desc ), desc, AST_INIOPT_ISINI ) )
1528  symbSetTypeIniTree( desc, NULL )
1529  end if
1530 
1531  if( fbLangOptIsSet( FB_LANG_OPT_SCOPE ) ) then
1532  astAdd( var_decl )
1533  else
1534  astAddUnscoped( var_decl )
1535  end if
1536  var_decl = NULL
1537  end if
1538  end if
1539  end if
1540 
1541  '' all set as declared
1542  symbSetIsDeclared( sym )
1543 
1544  '' not declared already?
1545  if( is_decl = FALSE ) then
1546  if( fbLangOptIsSet( FB_LANG_OPT_SCOPE ) ) then
1547  '' flush the init tree (must be done after adding the decl node)
1548  astAdd( hFlushInitializer( sym, var_decl, initree, has_dtor ) )
1549  '' unscoped
1550  else
1551  '' flush the init tree (must be done after adding the decl node)
1552  astAddUnscoped( hFlushInitializer( sym, var_decl, initree, has_dtor ) )
1553 
1554  '' initializer as assignment?
1555  if( doassign ) then
1556  dim as ASTNODE ptr assign_vardecl = any
1557 
1558  '' clear it before it's initialized?
1559  if( symbGetVarHasDtor( sym ) ) then
1560  astAdd( astBuildVarDtorCall( sym, TRUE ) )
1561  end if
1562 
1563  assign_vardecl = astNewDECL( sym, (assign_initree = NULL) )
1564  assign_vardecl = hFlushDecl( assign_vardecl )
1565 
1566  '' use the initializer as an assignment
1567  astAdd( astNewLINK( assign_vardecl, _
1568  astTypeIniFlush( assign_initree, _
1569  sym, _
1570  AST_INIOPT_ISINI ) ) )
1571  end if
1572  end if
1573  end if
1574 
1575  '' Dynamic array? If the dimensions are known, redim it.
1576  if( ((attrib and FB_SYMBATTRIB_DYNAMIC) <> 0) and (dimensions > 0) ) then
1577  redimcall = rtlArrayRedim( sym, symbGetLen( sym ), dimensions, exprTB(), _
1578  dopreserve, symbGetDontInit( sym ) = FALSE )
1579 
1580  '' If this is a local STATIC (not SHARED/COMMON) array declaration (and not
1581  '' a typeless REDIM), then the redim call should be executed only once, not
1582  '' during every call to the parent procedure.
1583  if( symbIsStatic( sym ) and symbIsLocal( sym ) and _
1584  ((symbGetAttrib( sym ) and (FB_SYMBATTRIB_SHARED or FB_SYMBATTRIB_COMMON)) = 0) and _
1585  (not is_decl) ) then
1586  redimcall = hWrapInStaticFlag( redimcall )
1587  end if
1588 
1589  astAdd( redimcall )
1590  redimcall = NULL
1591  end if
1592  end if
1593  end if
1594 
1595  ''
1596  if( is_fordecl ) then
1597  return sym
1598  end if
1599 
1600  '' (',' SymbolDef)*
1601  if( lexGetToken( ) <> CHAR_COMMA ) then
1602  exit do
1603  end if
1604 
1605  lexSkipToken( )
1606  loop
1607 end function
1608 
1609 '' look for ... followed by ')', ',' or TO
1610 function hMatchEllipsis( ) as integer
1611  function = FALSE
1612 
1613  if( lexGetToken( ) = CHAR_DOT ) then
1614  if( lexGetLookAhead( 1 ) = CHAR_DOT ) then
1615  if( lexGetLookAhead( 2 ) = CHAR_DOT ) then
1616  select case lexGetLookAhead( 3 )
1617  case CHAR_COMMA, CHAR_RPRNT, FB_TK_TO
1618  function = TRUE
1619  ' Skip the dots
1620  lexSkipToken( )
1621  lexSkipToken( )
1622  lexSkipToken( )
1623  end select
1624  end if
1625  end if
1626  end if
1627 end function
1628 
1629 '':::::
1630 ''ArrayDecl = '(' Expression (TO Expression)?
1631 '' (',' Expression (TO Expression)?)*
1632 '' ')' .
1633 ''
1634 function cStaticArrayDecl _
1635  ( _
1636  byref dimensions as integer, _
1637  dTB() as FBARRAYDIM, _
1638  byval checkprnts as integer, _
1639  byval allow_ellipsis as integer _
1640  ) as integer
1641 
1642  dim as integer i = any
1643 
1644  function = FALSE
1645 
1646  dimensions = 0
1647 
1648  if( checkprnts ) then
1649  '' '('
1650  if( lexGetToken() <> CHAR_LPRNT ) then
1651  exit function
1652  end if
1653 
1654  lexSkipToken( )
1655  end if
1656 
1657  i = 0
1658  do
1659  dim as integer dimension_has_ellipsis = FALSE
1660 
1661  '' First value - lower bound or upper bound
1662  if( iif( allow_ellipsis, hMatchEllipsis( ), FALSE ) ) then
1663  dimension_has_ellipsis = TRUE
1664  '' This is for the case of '( ... )' with the lower bound being
1665  '' automatically chosen based on OPTION BASE. It will be given
1666  '' to dTB(i).upper below.
1667  dTB(i).lower = FB_ARRAYDIM_UNKNOWN
1668  else
1669  '' Expression (integer constant)
1670  dTB(i).lower = cConstIntExpr( cExpression( ), env.opt.base )
1671  end if
1672 
1673  '' TO
1674  if( lexGetToken( ) = FB_TK_TO ) then
1675  lexSkipToken( )
1676 
1677  if( dimension_has_ellipsis ) then
1678  errReport( FB_ERRMSG_CANTUSEELLIPSISASLOWERBOUND )
1679  dTB(i).lower = 0
1680  end if
1681 
1682  '' Second value - upper bound
1683  if( iif( allow_ellipsis, hMatchEllipsis( ), FALSE ) ) then
1684  dimension_has_ellipsis = TRUE
1685  dTB(i).upper = FB_ARRAYDIM_UNKNOWN
1686  else
1687  '' Expression (integer constant)
1688  dTB(i).upper = cConstIntExpr( cExpression( ), dTB(i).lower )
1689  end if
1690  else
1691  '' First value was upper bound, not lower, use default for lower
1692  dTB(i).upper = dTB(i).lower
1693  dTB(i).lower = env.opt.base
1694  end if
1695 
1696  '' Don't check when we have ellipsis, as upper will be set to FB_ARRAYDIM_UNKNOWN
1697  if( dimension_has_ellipsis = FALSE ) then
1698  '' Besides the upper < lower case, also complain about FB_ARRAYDIM_UNKNOWN being
1699  '' specified, otherwise we'd think ellipsis was given...
1700  if( (dTB(i).upper < dTB(i).lower) or (dTB(i).upper = FB_ARRAYDIM_UNKNOWN) ) then
1701  errReport( FB_ERRMSG_INVALIDSUBSCRIPT )
1702  end if
1703  end if
1704 
1705  dimensions += 1
1706  i += 1
1707 
1708  '' separator
1709  if( lexGetToken( ) <> CHAR_COMMA ) then
1710  exit do
1711  end if
1712 
1713  lexSkipToken( )
1714 
1715  if( i >= FB_MAXARRAYDIMS ) then
1716  errReport( FB_ERRMSG_TOOMANYDIMENSIONS )
1717  '' error recovery: skip to next ')'
1718  hSkipUntil( CHAR_RPRNT )
1719  exit do
1720  end if
1721  loop
1722 
1723  if( checkprnts ) then
1724  '' ')'
1725  if( lexGetToken( ) <> CHAR_RPRNT ) then
1726  errReport( FB_ERRMSG_EXPECTEDRPRNT )
1727  else
1728  lexSkipToken( )
1729  end if
1730  end if
1731 
1732  function = TRUE
1733 
1734 end function
1735 
1736 function hIntExpr( byval defaultexpr as ASTNODE ptr ) as ASTNODE ptr
1737  dim as ASTNODE ptr expr = any, intexpr = any
1738 
1739  expr = cExpression( )
1740 
1741  if( expr ) then
1742  '' expression must be integral (no strings, etc.)
1743  intexpr = astNewCONV( FB_DATATYPE_INTEGER, NULL, expr )
1744  if( intexpr ) then
1745  expr = intexpr
1746  else
1747  errReport( FB_ERRMSG_INVALIDDATATYPES, TRUE )
1748  astDelTree( expr )
1749  expr = NULL
1750  end if
1751  else
1752  errReport( FB_ERRMSG_EXPECTEDEXPRESSION )
1753  '' error recovery: fake an expr
1754  if( lexGetToken( ) <> FB_TK_TO ) then
1755  hSkipUntil( CHAR_COMMA )
1756  end if
1757  end if
1758 
1759  if( expr = NULL ) then
1760  if( defaultexpr ) then
1761  expr = astCloneTree( defaultexpr )
1762  else
1763  expr = astNewCONSTi( env.opt.base )
1764  end if
1765  end if
1766 
1767  function = expr
1768 end function
1769 
1770 '':::::
1771 ''ArrayDecl = '(' Expression (TO Expression)?
1772 '' (',' Expression (TO Expression)?)*
1773 '' ')' .
1774 ''
1775 sub cArrayDecl( byref dimensions as integer, exprTB() as ASTNODE ptr )
1776  dim as integer i = any
1777 
1778  dimensions = 0
1779 
1780  i = 0
1781  do
1782  dim as integer dimension_has_ellipsis = FALSE
1783 
1784  if( hMatchEllipsis( ) ) then
1785  dimension_has_ellipsis = TRUE
1786  exprTB(i,0) = NULL
1787  else
1788  '' Expression
1789  exprTB(i,0) = hIntExpr( NULL )
1790  end if
1791 
1792  '' TO
1793  if( lexGetToken( ) = FB_TK_TO ) then
1794  lexSkipToken( )
1795 
1796  if( dimension_has_ellipsis ) then
1797  errReport( FB_ERRMSG_CANTUSEELLIPSISASLOWERBOUND )
1798  exprTB(i,0) = astNewCONSTi( 0 )
1799  end if
1800 
1801  if( hMatchEllipsis( ) ) then
1802  dimension_has_ellipsis = TRUE
1803  exprTB(i,1) = NULL
1804  else
1805  '' Expression
1806  exprTB(i,1) = hIntExpr( exprTB(i,0) )
1807  end if
1808  else
1809  exprTB(i,1) = exprTB(i,0)
1810  exprTB(i,0) = astNewCONSTi( env.opt.base )
1811  end if
1812 
1813  dimensions += 1
1814  i += 1
1815 
1816  '' separator
1817  if( lexGetToken( ) <> CHAR_COMMA ) then
1818  exit do
1819  end if
1820 
1821  lexSkipToken( )
1822 
1823  if( i >= FB_MAXARRAYDIMS ) then
1824  errReport( FB_ERRMSG_TOOMANYDIMENSIONS )
1825  '' error recovery: skip to next ')'
1826  hSkipUntil( CHAR_RPRNT )
1827  exit do
1828  end if
1829  loop
1830 end sub
1831 
1832 '':::::
1833 ''AutoVarDecl = VAR SHARED? SymbolDef '=' VarInitializer
1834 '' (',' SymbolDef)* .
1835 sub cAutoVarDecl(byval attrib as FB_SYMBATTRIB)
1836  static as FBARRAYDIM dTB(0 to FB_MAXARRAYDIMS-1) '' needed for hDeclStaticVar()
1837  static as zstring * FB_MAXNAMELEN+1 id
1838  dim as FBSYMBOL ptr parent = any, sym = any
1839 
1840  '' allowed?
1841  if( fbLangOptIsSet( FB_LANG_OPT_AUTOVAR ) = FALSE ) then
1842  errReportNotAllowed( FB_LANG_OPT_AUTOVAR, FB_ERRMSG_AUTOVARONLYVALIDINLANG )
1843  '' error recovery: skip stmt
1844  hSkipStmt( )
1845  return
1846  end if
1847 
1848  if( cCompStmtIsAllowed( FB_CMPSTMT_MASK_DECL or FB_CMPSTMT_MASK_CODE ) = FALSE ) then
1849  hSkipStmt( )
1850  exit sub
1851  end if
1852 
1853  '' VAR
1854  lexSkipToken( )
1855 
1856  '' SHARED?
1857  if( lexGetToken( ) = FB_TK_SHARED ) then
1858  '' can't use SHARED inside a proc
1859  if( hCheckScope( ) = FALSE ) then
1860  '' error recovery: don't make it shared
1861  attrib or= FB_SYMBATTRIB_STATIC
1862  else
1863  attrib or= FB_SYMBATTRIB_SHARED or FB_SYMBATTRIB_STATIC
1864  end if
1865  lexSkipToken( )
1866  end if
1867 
1868  '' this proc static?
1869  if( symbGetProcStaticLocals( parser.currproc ) ) then
1870  attrib or= FB_SYMBATTRIB_STATIC
1871  end if
1872 
1873  '' inside a namespace but outside a proc?
1874  if( symbIsGlobalNamespc( ) = FALSE ) then
1875  if( fbIsModLevel( ) ) then
1876  '' variables will be always shared..
1877  attrib or= FB_SYMBATTRIB_SHARED or FB_SYMBATTRIB_STATIC
1878  end if
1879  end if
1880 
1881  do
1882  '' id.id? if not, NULL
1883  parent = cParentId( FB_IDOPT_DEFAULT or FB_IDOPT_ISDECL or _
1884  FB_IDOPT_ALLOWSTRUCT or FB_IDOPT_ISVAR )
1885 
1886  '' get id
1887  dim as integer suffix = any
1888  dim as FBSYMCHAIN ptr chain_ = hGetId( parent, @id, suffix, 0 )
1889 
1890  if( suffix <> FB_DATATYPE_INVALID ) then
1891  errReportEx( FB_ERRMSG_SYNTAXERROR, @id )
1892  end if
1893 
1894  '' array? rejected.
1895  if( lexGetToken( ) = CHAR_LPRNT ) then
1896  errReport( FB_ERRMSG_TYPEMISMATCH )
1897  '' error recovery: skip until next ')'
1898  hSkipUntil( CHAR_RPRNT, TRUE )
1899  end if
1900 
1901  sym = hLookupVarAndCheckParent( parent, chain_, FB_DATATYPE_INVALID, _
1902  TRUE, FALSE, TRUE )
1903 
1904  '' '=' | '=>' ?
1905  if( cAssignToken( ) = FALSE ) then
1906  errReport( FB_ERRMSG_EXPECTEDEQ )
1907  end if
1908 
1909  '' parse expression
1910  dim as ASTNODE ptr expr = cExpression( )
1911  if( expr = NULL ) then
1912  errReport( FB_ERRMSG_AUTONEEDSINITIALIZER )
1913  '' error recovery: fake an expr
1914  expr = astNewCONSTi( 0 )
1915  end if
1916 
1917  dim as integer dtype = astGetFullType( expr )
1918  dim as FBSYMBOL ptr subtype = astGetSubType( expr )
1919 
1920  '' check for special types
1921  dim as integer has_ctor = any, has_dtor = any
1922 
1923  has_ctor = typeHasCtor( dtype, subtype )
1924  has_dtor = typeHasDtor( dtype, subtype )
1925 
1926  select case as const typeGetDtAndPtrOnly( dtype )
1927  '' wstrings not allowed...
1928  case FB_DATATYPE_WCHAR
1929  errReport( FB_ERRMSG_INVALIDDATATYPES, TRUE )
1930  '' error recovery: create a fake expression
1931  astDelTree( expr )
1932  expr = astNewCONSTi( 0 )
1933  dtype = FB_DATATYPE_INTEGER
1934  subtype = NULL
1935 
1936  '' zstring... convert to string
1937  case FB_DATATYPE_CHAR, FB_DATATYPE_FIXSTR
1938  dtype = FB_DATATYPE_STRING
1939 
1940  '' if it's a function pointer and not a fun ptr prototype, create one
1941  case typeAddrOf( FB_DATATYPE_FUNCTION )
1942  if( symbGetIsFuncPtr( subtype ) = FALSE ) then
1943  subtype = symbAddProcPtrFromFunction( subtype )
1944  end if
1945 
1946  end select
1947 
1948  '' add var after parsing the expression, or the the var itself could be used
1949  sym = hDeclStaticVar( sym, id, NULL, _
1950  dtype, subtype, _
1951  symbCalcLen( dtype, subtype ), FALSE, attrib, _
1952  0, dTB() )
1953 
1954  if( sym <> NULL ) then
1955 
1956  '' build a ini-tree
1957  dim as ASTNODE ptr initree = any
1958 
1959  initree = astTypeIniBegin( astGetFullType( expr ), subtype, symbIsLocal( sym ) )
1960 
1961  '' not an object?
1962  if( has_ctor = FALSE ) then
1963  astTypeIniAddAssign( initree, expr, sym )
1964 
1965  '' handle constructors..
1966  else
1967  dim as integer is_ctorcall = any
1968  expr = astBuildImplicitCtorCallEx( sym, expr, cBydescArrayArgParens( expr ), is_ctorcall )
1969 
1970  if( expr <> NULL ) then
1971  if( is_ctorcall ) then
1972  astTypeIniAddCtorCall( initree, sym, expr )
1973  else
1974  '' no proper ctor, try an assign
1975  astTypeIniAddAssign( initree, expr, sym )
1976  end if
1977  end if
1978  end if
1979 
1980  if( (symbGetAttrib( sym ) and (FB_SYMBATTRIB_STATIC or _
1981  FB_SYMBATTRIB_SHARED)) <> 0 ) then
1982  '' only if it's not an object, static or global instances are allowed
1983  if( has_ctor = FALSE ) then
1984  if( astTypeIniIsConst( initree ) = FALSE ) then
1985  '' error recovery: discard the tree
1986  astDelTree( expr )
1987  expr = astNewCONSTz( dtype, subtype )
1988  dtype = FB_DATATYPE_INTEGER
1989  subtype = NULL
1990  has_dtor = FALSE
1991  end if
1992  end if
1993  end if
1994 
1995  astTypeIniEnd( initree, TRUE )
1996 
1997  ''
1998  symbSetIsInitialized( sym )
1999 
2000  '' add to AST
2001  dim as ASTNODE ptr var_decl = astNewDECL( sym, FALSE )
2002 
2003  '' set as declared
2004  symbSetIsDeclared( sym )
2005 
2006  '' flush the init tree (must be done after adding the decl node)
2007  astAdd( hFlushInitializer( sym, var_decl, initree, has_dtor ) )
2008 
2009  end if
2010 
2011  '' (',' SymbolDef)*
2012  if( lexGetToken( ) <> CHAR_COMMA ) then
2013  exit do
2014  end if
2015 
2016  lexSkipToken( )
2017  loop
2018 end sub
2019