FreeBASIC  0.91.0
parser-decl-symb-init.bas
Go to the documentation of this file.
1 '' symbol initializers
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 "ast.bi"
10 #include once "ir.bi"
11 #include once "symb.bi"
12 
14  sym as FBSYMBOL ptr
15  dim_ as FBVARDIM ptr
16  dimcnt as integer
17  tree as ASTNODE ptr
19  init_expr as ASTNODE ptr
20 end type
21 
22 declare function hUDTInit _
23  ( _
24  byref ctx as FB_INITCTX _
25  ) as integer
26 
27 '':::::
28 function hDoAssign _
29  ( _
30  byref ctx as FB_INITCTX, _
31  byval expr as ASTNODE ptr, _
32  byval no_fake as integer = FALSE _
33  ) as integer
34 
35  dim as integer dtype = any
36  dim as FBSYMBOL ptr subtype = any
37 
38  dtype = symbGetFullType( ctx.sym )
39  subtype = symbGetSubtype( ctx.sym )
40 
41  if( (ctx.options and FB_INIOPT_DODEREF) <> 0 ) then
42  dtype = typeDeref( dtype )
43  end if
44 
45  if( astCheckASSIGNToType( dtype, subtype, expr ) = FALSE ) then
46  '' check if it's a cast
47  expr = astNewCONV( dtype, subtype, expr )
48  if( expr = NULL ) then
49  '' hand it back...
50  '' (used with UDTs; if an UDT var is given in an UDT initializer,
51  '' but the assignment to the UDT's first field fails here,
52  '' then it will be assigned to the UDT itself instead)
53  if( no_fake ) then
54  exit function
55  end if
56 
57  errReport( FB_ERRMSG_INVALIDDATATYPES, TRUE )
58  '' error recovery: create a fake expression
59  astDelTree( expr )
60  expr = astNewCONSTz( dtype, subtype )
61  end if
62  end if
63 
65 
66  function = TRUE
67 end function
68 
69 '':::::
70 function hElmInit _
71  ( _
72  byref ctx as FB_INITCTX, _
73  byval no_fake as integer = FALSE _
74  ) as integer
75 
76  dim as ASTNODE ptr expr = any
77  dim as FBSYMBOL ptr oldsym = any
78  dim as integer old_dtype = any
79 
80  function = FALSE
81 
82  '' set the context symbol to allow taking the address of overloaded
83  '' procs and also to allow anonymous UDT's
84  oldsym = parser.ctxsym
85  old_dtype = parser.ctx_dtype
86  parser.ctxsym = symbGetSubType( ctx.sym )
87  parser.ctx_dtype = symbGetType( ctx.sym )
88 
89  '' parse expression
90  expr = cExpression( )
91 
92  '' invalid expression
93  if( expr = NULL ) then
94  errReport( FB_ERRMSG_EXPECTEDEXPRESSION )
95  '' error recovery: skip until ',' and create a fake expression
96  hSkipUntil( CHAR_COMMA )
97 
98  '' generate an expression matching the symbol's type
99  dim as integer dtype = symbGetType( ctx.sym )
100  if( (ctx.options and FB_INIOPT_DODEREF) <> 0 ) then
101  dtype = typeDeref( dtype )
102  end if
103  expr = astNewCONSTz( dtype, symbGetSubtype( ctx.sym ) )
104  end if
105 
106  '' to hand it back if necessary
107  ctx.init_expr = expr
108 
109  '' restore context if needed
110  parser.ctxsym = oldsym
111  parser.ctx_dtype = old_dtype
112 
113  function = hDoAssign( ctx, expr, no_fake )
114 
115 end function
116 
117 function hArrayInit _
118  ( _
119  byref ctx as FB_INITCTX, _
120  byval no_fake as integer = FALSE _
121  ) as integer
122 
123  dim as integer dimensions = any, elm_cnt = any
124  dim as longint elements = any
125  dim as integer isarray = any, dtype = any
126  dim as FBVARDIM ptr old_dim = any
127  dim as FBSYMBOL ptr subtype = any
128  static as FBARRAYDIM dTB(0 to FB_MAXARRAYDIMS - 1)
129 
130  function = FALSE
131 
132  '' We're accessing FBSYMBOL.var_.* fields below,
133  '' so it must be a VAR or FIELD
134  assert( symbIsVar( ctx.sym ) or symbIsField( ctx.sym ) )
135 
136  ''
137  '' Nested "{ a, b, c }" array initializer parser
138  ''
139  '' For arrays with well-known boundaries only matching initializers
140  '' are allowed:
141  ''
142  '' array(0 to 3) = { 1, 1, 1, 1 }
143  '' array(0 to 1, 0 to 1) = { { 1, 1 }, { 2, 2 } }
144  '' array(1 to 3, 0 to 1) = { { 1, 1 }, { 2, 2 }, { 3, 3 } }
145  ''
146  '' For arrays declared using "..." ellipsis as the upper bound of
147  '' some dimension(s), the array initializer determines the upper bound,
148  '' and the array symbol is updated accordingly:
149  ''
150  '' array(0 to ...) = { 1, 1 } = array(0 to 1)
151  '' array(5 to ...) = { 1, 1, 1, 1 } = array(5 to 8)
152  ''
153  '' array(0 to ..., 0 to 0) = { { 1 }, { 2 }, { 3 } } =
154  '' array(0 to 2, 0 to 0)
155  ''
156  '' array(0 to ..., 0 to ...) = { { 1, 1 } ...... =
157  '' array(0 to ..., 0 to 1) = { { 1, 1 }, { 2, 2 } } =
158  '' array(0 to 1, 0 to 1)
159  ''
160  '' The parsing starts with the first (outer-most) dimension,
161  '' and recursively descends into the next (inner) dimension.
162  '' The first '}' seen is that of the first group of elements in the
163  '' inner-most dimension, corresponding to the last dimension listed in
164  '' the array declaration and the dTB(). Thus, the dimension's sizes are
165  '' filled in "backwards" - inner-most first, outer-most last.
166  ''
167 
168  dimensions = symbGetArrayDimensions( ctx.sym )
169  old_dim = ctx.dim_
170 
171  '' '{'?
172  isarray = FALSE
173  if( lexGetToken( ) = CHAR_LBRACE ) then
174  lexSkipToken( )
175 
176  ctx.dimcnt += 1
177 
179 
180  '' too many dimensions?
181  if( ctx.dimcnt > dimensions ) then
182  errReport( iif( dimensions > 0, _
183  FB_ERRMSG_TOOMANYEXPRESSIONS, _
184  FB_ERRMSG_EXPECTEDARRAY ) )
185  '' error recovery: skip until next '}'
186  hSkipUntil( CHAR_RBRACE, TRUE )
187  ctx.dim_ = NULL
188  else
189  '' first dim?
190  if( ctx.dim_ = NULL ) then
191  ctx.dim_ = symbGetArrayFirstDim( ctx.sym )
192 
193  '' next..
194  else
195  ctx.dim_ = ctx.dim_->next
196  end if
197 
198  isarray = TRUE
199  end if
200  else
201  '' not the last dimension?
202  if( ctx.dimcnt < dimensions ) then
203  errReport( FB_ERRMSG_EXPECTEDLBRACE )
204  ctx.dimcnt += 1
205  if( ctx.dim_ = NULL ) then
206  ctx.dim_ = symbGetArrayFirstDim( ctx.sym )
207  else
208  ctx.dim_ = ctx.dim_->next
209  end if
210  end if
211  end if
212 
213  if( ctx.dim_ <> NULL ) then
214  dTB(ctx.dimcnt - 1).lower = ctx.dim_->lower
215  dTB(ctx.dimcnt - 1).upper = ctx.dim_->upper
216  '' Ellipsis?
217  if( ctx.dim_->upper = FB_ARRAYDIM_UNKNOWN ) then
218  elements = -1
219  else
220  elements = (ctx.dim_->upper - ctx.dim_->lower) + 1
221  end if
222  else
223  elements = 1
224  end if
225 
226  ''
227  dtype = symbGetType( ctx.sym )
228  subtype = symbGetSubtype( ctx.sym )
229  if( (ctx.options and FB_INIOPT_DODEREF) <> 0 ) then
230  dtype = typeDeref( dtype )
231  end if
232 
233  '' for each array element..
234  elm_cnt = 0
235  do
236  '' not the last dimension?
237  if( ctx.dimcnt < dimensions ) then
238  if( hArrayInit( ctx ) = FALSE ) then
239  exit function
240  end if
241  else
242  select case as const dtype
243  case FB_DATATYPE_STRUCT ', FB_DATATYPE_CLASS
244  if( hUDTInit( ctx ) = FALSE ) then
245  exit function
246  end if
247 
248  case else
249  if( hElmInit( ctx, no_fake ) = FALSE ) then
250  exit function
251  end if
252  end select
253  end if
254 
255  elm_cnt += 1
256  if( elements = -1 ) then
257  '' ellipsis elements...
258  if( lexGetToken( ) <> CHAR_COMMA ) then
259  '' Fill in this dimension's upper bound
260  elements = elm_cnt
261  ctx.dim_->upper = ctx.dim_->lower + elm_cnt - 1
262  dTB(ctx.dimcnt - 1).upper = ctx.dim_->upper
263 
264  '' "array too big" check
265  '' Note: the dTB() was initialized by now by the recursive parsing,
266  '' but there can still be ellipsis upper bounds if some of the other
267  '' dimensions used them, because their respective initializers haven't
268  '' been fully parsed yet, unless this is the outer-most dimension.
269  if( symbCheckArraySize( dimensions, dTB(), ctx.sym->lgt, _
270  ((ctx.sym->attrib and (FB_SYMBATTRIB_SHARED or FB_SYMBATTRIB_STATIC)) = 0), _
271  (ctx.dimcnt > 1) ) = FALSE ) then
272  errReport( FB_ERRMSG_ARRAYTOOBIG )
273  '' error recovery: set this dimension to 1 element
274  dTB(ctx.dimcnt - 1).lower = 0
275  dTB(ctx.dimcnt - 1).upper = 0
276  end if
277 
278  symbSetArrayDimTb( ctx.sym, dimensions, dTB() )
279  exit do
280  end if
281  else
282  if( elm_cnt >= elements ) then
283  exit do
284  end if
285  end if
286 
287  '' ','
288  if( hMatch( CHAR_COMMA ) = FALSE ) then
289  exit do
290  end if
291  loop
292 
293  '' Any array elements not initialized by this '{...}'?
294  '' Then default-initialize/zero them. With multi-dimensional arrays,
295  '' this may happen "in the middle" of the array.
296  elements -= elm_cnt
297  if( elements > 0 ) then
298  '' not the last dimension?
299  if( ctx.dim_->next ) then
300  elements *= symbCalcArrayElements( ctx.sym, ctx.dim_->next )
301  end if
302 
303  dim as FBSYMBOL ptr ctor = NULL
304  if( (ctx.options and FB_INIOPT_ISOBJ) <> 0 ) then
305  ctor = symbGetCompDefCtor( subtype )
306  if( ctor = NULL ) then
307  errReport( FB_ERRMSG_NODEFAULTCTORDEFINED )
308  else
309  '' check visibility
310  if( symbCheckAccess( ctor ) = FALSE ) then
311  errReport( FB_ERRMSG_NOACCESSTODEFAULTCTOR )
312  end if
313  end if
314  end if
315 
316  if( ctor <> NULL ) then
317  astTypeIniAddCtorList( ctx.tree, ctx.sym, elements )
318  else
319  dim as longint pad_lgt = any
320  '' calc len.. handle fixed-len strings
321  select case as const dtype
322  case FB_DATATYPE_FIXSTR, FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR
323  pad_lgt = symbGetLen( ctx.sym )
324  case else
325  pad_lgt = symbCalcLen( dtype, subtype )
326  end select
327 
328  pad_lgt *= elements
329 
330  astTypeIniAddPad( ctx.tree, pad_lgt )
331  astTypeIniGetOfs( ctx.tree ) += pad_lgt
332  end if
333  end if
334 
335  if( isarray ) then
337 
338  '' '}'
339  if( lexGetToken( ) <> CHAR_RBRACE ) then
340  errReport( FB_ERRMSG_EXPECTEDRBRACE )
341  '' error recovery: skip until next '}'
342  hSkipUntil( CHAR_RBRACE, TRUE )
343  else
344  lexSkipToken( )
345  end if
346 
347  ctx.dim_ = old_dim
348  ctx.dimcnt -= 1
349  end if
350 
351  function = TRUE
352 
353 end function
354 
355 '':::::
356 function hUDTInit _
357  ( _
358  byref ctx as FB_INITCTX _
359  ) as integer
360 
361  static as integer rec_cnt
362 
363  dim as integer elm_cnt = any, dtype = any
364  dim as longint lgt = any, baseofs = any, pad_lgt = any
365  dim as FBSYMBOL ptr fld = any, first = any, subtype = any
366  dim as FBSYMBOL ptr oldsubtype = any
367  dim as integer olddtype = any
368  dim as FB_INITCTX old_ctx = any
369 
370  function = FALSE
371 
372  rec_cnt += 1
373 
374  dtype = symbGetType( ctx.sym )
375  subtype = symbGetSubtype( ctx.sym )
376  if( (ctx.options and FB_INIOPT_DODEREF) <> 0 ) then
377  dtype = typeDeref( dtype )
378  end if
379 
380  '' ctor?
381  if( (ctx.options and FB_INIOPT_ISOBJ) <> 0 ) then
382  dim as ASTNODE ptr expr = any
383 
384  '' Set the context data type, to allow anonymous type()'s to
385  '' work for UDTs with constructors here
386  oldsubtype = parser.ctxsym
387  olddtype = parser.ctx_dtype
388  parser.ctx_dtype = dtype
389  parser.ctxsym = subtype
390 
391  '' Expression
392  expr = cExpression( )
393 
394  '' Restore context data type
395  parser.ctx_dtype = olddtype
396  parser.ctxsym = oldsubtype
397 
398  if( expr = NULL ) then
399  errReport( FB_ERRMSG_EXPECTEDEXPRESSION )
400  '' error recovery: fake an expr
401  expr = astNewCONSTi( 0 )
402  end if
403 
404  '' When initializing a BYREF parameter, an expression of the
405  '' same type should be used as-is instead of causing a copy
406  '' constructor call + temp var to be used, because that would
407  '' destroy the BYREF semantics. For any other expression it's
408  '' ok to cause implicit constructor calls though, because it
409  '' couldn't be passed BYREF anyways.
410  if( symbGetClass( ctx.sym ) = FB_SYMBCLASS_PARAM ) then
411  if( symbGetParamMode( ctx.sym ) = FB_PARAMMODE_BYREF ) then
412  if( (astGetDataType( expr ) = dtype) and _
413  (astGetSubtype( expr ) = subtype) ) then
414  rec_cnt -= 1
415  return hDoAssign( ctx, expr )
416  end if
417  end if
418  end if
419 
420  dim as integer is_ctorcall = any
421  expr = astBuildImplicitCtorCallEx( ctx.sym, expr, cBydescArrayArgParens( expr ), is_ctorcall )
422  if( expr = NULL ) then
423  rec_cnt -= 1
424  exit function
425  end if
426 
427  if( is_ctorcall ) then
428  rec_cnt -= 1
429  return astTypeIniAddCtorCall( ctx.tree, ctx.sym, expr ) <> NULL
430  else
431  '' try to assign it (do a shallow copy)
432  rec_cnt -= 1
433  return hDoAssign( ctx, expr )
434  end if
435  end if
436 
437  dim as integer parenth = TRUE, comma = FALSE
438 
439  '' '('
440  if( lexGetToken( ) <> CHAR_LPRNT ) then
441  if( rec_cnt <= 1 ) then
442  rec_cnt -= 1
443  return hElmInit( ctx )
444  end if
445 
446  '' ','? Leave one for the parent func (see below)
447  comma = (lexGetLookAhead(1) = CHAR_COMMA)
448  parenth = FALSE
449  else
451  end if
452 
453  if( parenth ) then
454  lexSkipToken( )
455  end if
456 
457  first = symbUdtGetFirstField( subtype )
458  fld = first
459 
460  lgt = 0
461  baseofs = astTypeIniGetOfs( ctx.tree )
462 
463  '' save parent
464  old_ctx = ctx
465 
466  ctx.options and= not FB_INIOPT_DODEREF
467  ctx.dim_ = NULL
468  ctx.dimcnt = 0
469 
470  '' for each initializable UDT field...
471  '' (for unions, only the first field can be initialized)
472  do
473  if( fld = NULL ) then
474  errReport( FB_ERRMSG_TOOMANYEXPRESSIONS )
475  '' error recovery: jump out
476  exit do
477  end if
478 
479  if( lgt > 0 ) then
480  '' Padding between fields (due to structure layout)
481  '' (this also clears uninited parts of unions)
482  pad_lgt = fld->ofs - lgt
483  if( pad_lgt > 0 ) then
484  astTypeIniAddPad( ctx.tree, pad_lgt )
485  lgt += pad_lgt
486  end if
487  end if
488 
489  astTypeIniGetOfs( ctx.tree ) = baseofs + fld->ofs
490 
491  if( symbCheckAccess( fld ) = FALSE ) then
492  errReport( FB_ERRMSG_ILLEGALMEMBERACCESS )
493  end if
494  ctx.sym = fld
495 
496  '' has ctor?
497  ctx.options and= not FB_INIOPT_ISOBJ
498  if( symbHasCtor( fld ) ) then
499  ctx.options or= FB_INIOPT_ISOBJ
500  end if
501 
502  '' element assignment failed?
503  if( hArrayInit( ctx, TRUE ) = FALSE ) then
504  '' not first or nothing passed back?
505  if( (fld <> first) or (ctx.init_expr = NULL) ) then
506  errReport( FB_ERRMSG_INVALIDDATATYPES, TRUE )
507  rec_cnt -= 1
508  exit function
509  end if
510 
511  '' try to assign the expression to the parent
512  dim as integer is_ctorcall = any
513  dim as ASTNODE ptr expr = ctx.init_expr
514 
515  ctx = old_ctx
516 
517  expr = astBuildImplicitCtorCallEx( ctx.sym, expr, INVALID, is_ctorcall )
518  if( expr = NULL ) then
519  rec_cnt -= 1
520  exit function
521  end if
522 
523  '' ')'
524  if( parenth ) then
525  if( lexGetToken( ) <> CHAR_RPRNT ) then
526  errReport( FB_ERRMSG_EXPECTEDRPRNT )
527  '' error recovery: skip until next ')'
528  hSkipUntil( CHAR_RPRNT, TRUE )
529  end if
530  lexSkipToken( )
531  end if
532 
533  rec_cnt -= 1
534 
535  if( is_ctorcall ) then
536  return astTypeIniAddCtorCall( ctx.tree, ctx.sym, expr ) <> NULL
537  else
538  '' try to assign it (do a shallow copy)
539  return hDoAssign( ctx, expr )
540  end if
541  end if
542 
543  lgt += symbGetLen( fld ) * symbGetArrayElements( fld )
544 
545  '' next
546  fld = symbUdtGetNextInitableField( fld )
547 
548  '' if we're not top level,
549  if( rec_cnt > 1 ) then
550  '' if there's a comma at the end, we have to leave it for
551  '' the parent UDT initializer, to signal that we completed
552  '' initializing this UDT, and the next field should be assigned.
553  if( comma ) then
554  if( fld = NULL ) then
555  exit do
556  end if
557  end if
558  end if
559 
560  '' ','
561  if( hMatch( CHAR_COMMA ) = FALSE ) then
562  exit do
563  end if
564  loop
565 
566  '' ')'
567  if( parenth ) then
568  if( lexGetToken( ) <> CHAR_RPRNT ) then
569  errReport( FB_ERRMSG_EXPECTEDRPRNT )
570  '' error recovery: skip until next ')'
571  hSkipUntil( CHAR_RPRNT, TRUE )
572  else
573  lexSkipToken( )
575  end if
576  end if
577 
578  '' restore parent
579  ctx = old_ctx
580 
581  '' Padding at the end of the UDT -- this zeroes tail padding bytes,
582  '' and also any uninited fields and/or uninited parts of unions.
583  dim as longint sym_len = symbCalcLen( dtype, subtype )
584  pad_lgt = sym_len - lgt
585  if( pad_lgt > 0 ) then
586  astTypeIniAddPad( ctx.tree, pad_lgt )
587  end if
588  astTypeIniGetOfs( ctx.tree ) = baseofs + sym_len
589 
590  rec_cnt -= 1
591 
592  function = TRUE
593 end function
594 
595 '':::::
596 function cInitializer _
597  ( _
598  byval sym as FBSYMBOL ptr, _
599  byval options as FB_INIOPT _
600  ) as ASTNODE ptr
601 
602  dim as integer is_local = any, dtype = any, ok = any
603  dim as FBSYMBOL ptr subtype = any
604  dim as FB_INITCTX ctx = any
605 
606  function = NULL
607 
608  if( symbIsVar( sym ) ) then
609  '' cannot initialize dynamic vars
610  if( symbGetIsDynamic( sym ) ) then
611  errReport( FB_ERRMSG_CANTINITDYNAMICARRAYS, TRUE )
612  exit function
613  end if
614 
615  '' common?? impossible but..
616  if( symbIsCommon( sym ) ) then
617  errReport( FB_ERRMSG_CANTINITDYNAMICARRAYS, TRUE )
618  exit function
619  end if
620 
621  is_local = symbIsLocal( sym )
622 
623  '' param, struct/class field or anon-udt
624  else
625  is_local = FALSE
626  end if
627 
628  dtype = symbGetType( sym )
629  subtype = symbGetSubtype( sym )
630  if( (options and FB_INIOPT_DODEREF) <> 0 ) then
631  dtype = typeDeref( dtype )
632  end if
633 
634  ''
636  ctx.sym = sym
637  ctx.dim_ = NULL
638  ctx.dimcnt = 0
639  ctx.init_expr = NULL
640 
641  ctx.tree = astTypeIniBegin( symbGetFullType( sym ), subtype, is_local, symbGetOfs( sym ) )
642 
643  '' has ctor?
644  if( typeHasCtor( dtype, subtype ) ) then
645  ctx.options or= FB_INIOPT_ISOBJ
646  end if
647 
648  '' If it can be an array, start with hArrayInit()
649  if( symbIsVar( ctx.sym ) or symbIsField( ctx.sym ) ) then
650  ok = hArrayInit( ctx )
651  else
652  '' Everything else (e.g. params)
653  if( dtype = FB_DATATYPE_STRUCT ) then
654  ok = hUDTInit( ctx )
655  else
656  ok = hElmInit( ctx )
657  end if
658  end if
659 
660  astTypeIniEnd( ctx.tree, (options and FB_INIOPT_ISINI) <> 0 )
661 
662  if( symbIsVar( ctx.sym ) ) then
663  symbSetIsInitialized( ctx.sym )
664  end if
665 
666  function = iif( ok, ctx.tree, NULL )
667 end function
668