FreeBASIC  0.91.0
parser-expr-variable.bas
Go to the documentation of this file.
1 '' variable parsing (scalars, arrays, fields and anything between)
2 ''
3 '' chng: sep/2004 written [v1ctor]
4 '' oct/2004 arrays on fields [v1c]
5 
6 
7 #include once "fb.bi"
8 #include once "fbint.bi"
9 #include once "parser.bi"
10 #include once "ast.bi"
11 
12 function hIndexExpr( ) as ASTNODE ptr
13  dim as ASTNODE ptr expr = any
14  dim as integer check_array = any
15 
16  check_array = fbGetCheckArray( )
17  fbSetCheckArray( TRUE )
18  expr = cExpression( )
19  fbSetCheckArray( check_array )
20  if( expr = NULL ) then
21  errReport( FB_ERRMSG_EXPECTEDEXPRESSION )
22  '' error recovery: faken an expr
23  expr = astNewCONSTi( 0 )
24  end if
25 
26  function = expr
27 end function
28 
29 function hCheckIntegerIndex( byval expr as ASTNODE ptr ) as ASTNODE ptr
30  '' if index isn't an integer, convert
31  select case( typeGet( astGetDataType( expr ) ) )
32  case FB_DATATYPE_INTEGER
33 
34  case FB_DATATYPE_POINTER
35  '' Disallow pointers explicitly, because they can be converted
36  '' to integer fine, but we don't want to allow pointers as indices.
37  errReport( FB_ERRMSG_INVALIDARRAYINDEX, TRUE )
38  '' error recovery: fake an expr
39  expr = astNewCONSTi( 0 )
40 
41  case else
42  expr = astNewCONV( FB_DATATYPE_INTEGER, NULL, expr )
43  if( expr = NULL ) then
44  errReport( FB_ERRMSG_INVALIDARRAYINDEX, TRUE )
45  '' error recovery: fake an expr
46  expr = astNewCONSTi( 0 )
47  end if
48  end select
49 
50  function = expr
51 end function
52 
53 function hStaticArrayBoundChk _
54  ( _
55  byval dimexpr as ASTNODE ptr, _
56  byval d as FBVARDIM ptr _
57  ) as ASTNODE ptr
58 
59  dimexpr = astBuildBOUNDCHK( dimexpr, astNewCONSTi( d->lower ), astNewCONSTi( d->upper ) )
60  if( dimexpr = NULL ) then
61  errReport( FB_ERRMSG_ARRAYOUTOFBOUNDS )
62  '' error recovery: fake an expr
63  dimexpr = astNewCONSTi( d->lower )
64  end if
65 
66  function = dimexpr
67 end function
68 
69 '':::::
70 ''FieldArray = '(' Expression (',' Expression)* ')' .
71 ''
72 function hFieldArray _
73  ( _
74  byval sym as FBSYMBOL ptr, _
75  byval idxexpr as ASTNODE ptr _
76  ) as ASTNODE ptr
77 
78  dim as integer maxdims = any, dims = any
79  dim as longint diff = any
80  dim as ASTNODE ptr expr = any, dimexpr = any
81  dim as FBVARDIM ptr d = any
82 
83  function = NULL
84 
85  ''
86  maxdims = symbGetArrayDimensions( sym )
87  dims = 0
88  d = symbGetArrayFirstDim( sym )
89  expr = NULL
90  do
91  dims += 1
92  if( dims > maxdims ) then
93  errReport( FB_ERRMSG_WRONGDIMENSIONS )
94  '' error recovery: fake an expr
95  return astNewCONSTi( 0 )
96  end if
97 
98  '' Expression
99  dimexpr = hCheckIntegerIndex( hIndexExpr( ) )
100 
101  '' bounds checking
102  if( env.clopt.extraerrchk ) then
103  dimexpr = hStaticArrayBoundChk( dimexpr, d )
104  end if
105 
106  ''
107  if( expr = NULL ) then
108  expr = dimexpr
109  else
110  expr = astNewBOP( AST_OP_ADD, expr, dimexpr )
111  end if
112 
113  '' separator
114  if( lexGetToken( ) <> FB_TK_DECLSEPCHAR ) then
115  exit do
116  end if
117 
118  lexSkipToken( )
119 
120  '' next
121  d = d->next
122  if( d = NULL ) then
123  errReport( FB_ERRMSG_WRONGDIMENSIONS )
124  exit do
125  end if
126 
127  expr = astNewBOP( AST_OP_MUL, expr, astNewCONSTi( (d->upper - d->lower)+1 ) )
128  loop
129 
130  ''
131  if( dims < maxdims ) then
132  errReport( FB_ERRMSG_WRONGDIMENSIONS )
133  end if
134 
135  '' times length
136  expr = astNewBOP( AST_OP_MUL, expr, astNewCONSTi( symbGetLen( sym ) ) )
137 
138  '' plus difference
139  diff = symbGetArrayDiff( sym )
140  if( diff <> 0 ) then
141  expr = astNewBOP( AST_OP_ADD, expr, astNewCONSTi( diff ) )
142  end if
143 
144  '' plus initial expression
145  if( idxexpr <> NULL ) then
146  function = astNewBOP( AST_OP_ADD, idxexpr, expr )
147  else
148  function = expr
149  end if
150 
151 end function
152 
153 '':::::
154 function hUdtDataMember _
155  ( _
156  byval fld as FBSYMBOL ptr, _
157  byval checkarray as integer _
158  ) as ASTNODE ptr
159 
160  dim as ASTNODE ptr expr = any
161 
162  expr = astNewCONSTi( symbGetOfs( fld ) )
163 
164  '' '('?
165  if( lexGetToken( ) = CHAR_LPRNT ) then
166 
167  '' if field isn't an array, it can be function field, exit
168  if( symbGetArrayDimensions( fld ) = 0 ) then
169  return expr
170  end if
171 
172  '' '('')'?
173  if( lexGetLookAhead( 1 ) = CHAR_RPRNT ) then
174  return expr
175  end if
176 
177  lexSkipToken( )
178 
179  expr = hFieldArray( fld, expr )
180  if( expr = NULL ) then
181  return NULL
182  end if
183 
184  '' ')'
185  if( lexGetToken( ) <> CHAR_RPRNT ) then
186  errReport( FB_ERRMSG_EXPECTEDRPRNT )
187  '' error recovery: skip until next ')'
188  hSkipUntil( CHAR_RPRNT, TRUE )
189  else
190  lexSkipToken( )
191  end if
192 
193  else
194  '' array and no index?
195  if( symbGetArrayDimensions( fld ) <> 0 ) then
196  if( checkarray ) then
197  errReport( FB_ERRMSG_EXPECTEDINDEX )
198  '' error recovery: no need to fake an expr, field arrays
199  '' are never dynamic (for now)
200 
201  '' non-indexed array..
202  else
203  '' don't let the offset expr be NULL
204  if( expr = NULL ) then
205  expr = astNewCONSTi( 0 )
206  end if
207 
208  expr = astNewNIDXARRAY( expr )
209  end if
210  end if
211  end if
212 
213  function = expr
214 
215 end function
216 
217 '':::::
218 '' MemberId = ID ArrayIdx?
219 ''
220 function hMemberId( byval parent as FBSYMBOL ptr ) as FBSYMBOL ptr
221  dim as FBSYMBOL ptr res = any
222 
223  if( parent = NULL ) then
224  errReport( FB_ERRMSG_EXPECTEDUDT, TRUE )
225  '' no error recovery: caller will take care
226  return NULL
227  end if
228 
229  '' ID?
230  select case as const lexGetClass( )
231  case FB_TKCLASS_IDENTIFIER, FB_TKCLASS_KEYWORD, FB_TKCLASS_QUIRKWD
232 
233  case else
234  errReport( FB_ERRMSG_EXPECTEDIDENTIFIER )
235  '' no error recovery: caller will take care
236  return NULL
237  end select
238 
239  res = NULL
240 
241  select case( lexGetToken( ) )
242  case FB_TK_CONSTRUCTOR
243  res = symbGetCompCtorHead( parent )
244  case FB_TK_DESTRUCTOR
245  res = symbGetCompDtor( parent )
246  end select
247 
248  if( res ) then
249  return res
250  end if
251 
252  dim as FBSYMCHAIN ptr chain_ = symbLookupCompField( parent, lexGetText( ) )
253  if( chain_ = NULL ) then
254  errReportUndef( FB_ERRMSG_ELEMENTNOTDEFINED, lexGetText( ) )
255  '' no error recovery: caller will take care
256  lexSkipToken( )
257  return NULL
258  end if
259 
260  '' since methods don't start a new hash, params and local
261  '' symbol dups will also be found
262  do
263  dim as FBSYMBOL ptr sym = chain_->sym
264  do
265  if( symbGetScope( sym ) = symbGetScope( parent ) ) then
266  select case as const symbGetClass( sym )
267  '' field or static members?
268  case FB_SYMBCLASS_FIELD, FB_SYMBCLASS_VAR, _
269  FB_SYMBCLASS_CONST, FB_SYMBCLASS_ENUM
270  '' check visibility
271  if( symbCheckAccess( sym ) = FALSE ) then
272  errReport( FB_ERRMSG_ILLEGALMEMBERACCESS )
273  end if
274 
275  '' method?
276  case FB_SYMBCLASS_PROC
277 
278  case else
279  errReportEx( FB_ERRMSG_INTERNAL, __FUNCTION__ )
280  return NULL
281  end select
282 
283  return sym
284  end if
285 
286  sym = sym->hash.next
287  loop while( sym <> NULL )
288 
289  chain_ = chain_->next
290  loop while( chain_ <> NULL )
291 
292  '' nothing found..
293  errReportUndef( FB_ERRMSG_ELEMENTNOTDEFINED, lexGetText( ) )
294  '' no error recovery: caller will take care
295  lexSkipToken( )
296 
297  function = NULL
298 
299 end function
300 
301 '':::::
302 '' UdtMember = MemberId ('.' MemberId)*
303 ''
304 function cUdtMember _
305  ( _
306  byval dtype as integer, _
307  byval subtype as FBSYMBOL ptr, _
308  byval varexpr as ASTNODE ptr, _
309  byval check_array as integer, _
310  byval options as FB_PARSEROPT _
311  ) as ASTNODE ptr
312 
313  '' note: assuming a pointer is being passed to this function
314  dim as integer is_ptr = TRUE, mask = typeGetConstMask( dtype )
315 
316  do
317  dim as FBSYMBOL ptr fld = hMemberId( subtype )
318  if( fld = NULL ) then
319  return NULL
320  end if
321 
322  select case as const symbGetClass( fld )
323  '' const? (enum elmts too), exit
324  case FB_SYMBCLASS_CONST
325  lexSkipToken( )
326 
327  astDeltree( varexpr )
328  return astBuildConst( fld )
329 
330  '' enum?
331  case FB_SYMBCLASS_ENUM
332  lexSkipToken( )
333 
334  astDeltree( varexpr )
335  varexpr = NULL
336 
337  '' '.'?
338  if( lexGetToken( ) <> CHAR_DOT ) then
339  return NULL
340  end if
341 
342  '' field?
343  case FB_SYMBCLASS_FIELD
344  lexSkipToken( )
345 
346  '' make sure the field inherits the parent's constant mask
347  dtype = symbGetFullType( fld ) or mask
348  subtype = symbGetSubType( fld )
349 
350  dim as ASTNODE ptr fldexpr = hUdtDataMember( fld, check_array )
351  if( fldexpr = NULL ) then
352  exit do
353  end if
354 
355  '' ugly hack to deal with arrays w/o indexes
356  dim as integer is_nidxarray = FALSE
357  if( astIsNIDXARRAY( fldexpr ) ) then
358  dim as ASTNODE ptr tmpexpr = astGetLeft( fldexpr )
359  astDelNode( fldexpr )
360  fldexpr = tmpexpr
361  is_nidxarray = TRUE
362  end if
363 
364  '' convert foo.bar to cast( typeof( foo ), (cast( byte ptr, @foo ) + offsetof( foo, bar ) ) )->bar
365  if( is_ptr = FALSE ) then
366  varexpr = astNewADDROF( varexpr )
367  end if
368 
369  varexpr = astNewBOP( AST_OP_ADD, varexpr, fldexpr )
370 
371  varexpr = astNewDEREF( varexpr, dtype, subtype )
372 
373  varexpr = astNewFIELD( varexpr, fld )
374 
375  if( is_nidxarray ) then
376  return astNewNIDXARRAY( varexpr )
377  end if
378 
379  select case typeGet( dtype )
380  case FB_DATATYPE_STRUCT ', FB_DATATYPE_CLASS
381  '' '.'?
382  if( lexGetToken( ) <> CHAR_DOT ) then
383  return varexpr
384  end if
385 
386  case else
387  return varexpr
388  end select
389 
390  is_ptr = FALSE
391 
392  '' static var?
393  case FB_SYMBCLASS_VAR
394  astDelTree( varexpr )
395  varexpr = cVariableEx( fld, check_array )
396 
397  '' make sure the field inherits the parent's constant mask
398  dtype = symbGetFullType( fld ) or mask
399  subtype = symbGetSubType( fld )
400 
401  select case typeGet( dtype )
402  case FB_DATATYPE_STRUCT ', FB_DATATYPE_CLASS
403  if( lexGetToken( ) <> CHAR_DOT ) then
404  return varexpr
405  end if
406 
407  case else
408  return varexpr
409  end select
410 
411  is_ptr = FALSE
412 
413  '' method?
414  case FB_SYMBCLASS_PROC
415  if( is_ptr ) then
416  varexpr = astNewDEREF( varexpr, dtype, subtype )
417  end if
418 
419  return cMethodCall( fld, varexpr, options )
420 
421  case else
422  errReportEx( FB_ERRMSG_INTERNAL, __FUNCTION__ )
423  return NULL
424  end select
425 
426  lexSkipToken( LEXCHECK_NOPERIOD )
427  loop
428 
429  function = varexpr
430 
431 end function
432 
433 '':::::
434 function cMemberAccess _
435  ( _
436  byval dtype as integer, _
437  byval subtype as FBSYMBOL ptr, _
438  byval expr as ASTNODE ptr _
439  ) as ASTNODE ptr
440 
441  '' proc call?
442  if( astIsCALL( expr ) ) then
443  expr = astBuildCallResultUdt( expr )
444  end if
445 
446  '' build: cast( udt ptr, (cast( byte ptr, @udt) + fldexpr))->field
447  function = cUdtMember( dtype, subtype, astNewADDROF( expr ), TRUE )
448 
449 end function
450 
451 '':::::
452 function hStrIndexing _
453  ( _
454  byval dtype as integer, _
455  byval varexpr as ASTNODE ptr, _
456  byval idxexpr as ASTNODE ptr _
457  ) as ASTNODE ptr
458 
459  '' string concatenation is delayed because optimizations..
460  varexpr = astUpdStrConcat( varexpr )
461 
462  '' function deref?
463  if( astIsCALL( varexpr ) ) then
464  '' not allowed, STRING and WCHAR results are temporary
465  errReport( FB_ERRMSG_SYNTAXERROR, TRUE )
466  end if
467 
468  if( typeGet( dtype ) = FB_DATATYPE_STRING ) then
469  '' deref
470  varexpr = astBuildStrPtr( varexpr )
471  else
472  '' address of
473  varexpr = astNewADDROF( varexpr )
474  end if
475 
476  '' add index
477  if( typeGet( dtype ) = FB_DATATYPE_WCHAR ) then
478  '' times sizeof( wchar ) if it's wstring
479  idxexpr = astNewBOP( AST_OP_MUL, idxexpr, _
480  astNewCONSTi( typeGetSize( FB_DATATYPE_WCHAR ) ) )
481  end if
482 
483  '' null pointer checking
484  if( env.clopt.extraerrchk ) then
485  varexpr = astBuildPTRCHK( varexpr )
486  end if
487 
488  varexpr = astNewBOP( AST_OP_ADD, varexpr, idxexpr )
489 
490  '' wstring?
491  if( typeGet( dtype ) = FB_DATATYPE_WCHAR ) then
492  dtype = typeJoin( dtype, env.target.wchar )
493  else
494  dtype = typeJoin( dtype, FB_DATATYPE_UBYTE )
495  end if
496 
497  '' make a pointer
498  function = astNewDEREF( varexpr, dtype, NULL )
499 
500 end function
501 
502 '':::::
503 ''MemberDeref = (('->' DREF* | '[' Expression ']' '.'?) UdtMember)* .
504 ''
505 function cMemberDeref _
506  ( _
507  byval dtype as integer, _
508  byval subtype as FBSYMBOL ptr, _
509  byval varexpr as ASTNODE ptr, _
510  byval check_array as integer _
511  ) as ASTNODE ptr
512 
513  dim as integer derefcnt = any, is_field = any
514  dim as longint lgt = any
515  dim as ASTNODE ptr idxexpr = any
516 
517  function = NULL
518 
519  do
520  idxexpr = NULL
521  derefcnt = 0
522 
523  select case lexGetToken( )
524  '' ('->' DREF* UdtMember)*
525  case FB_TK_FIELDDEREF
526  is_field = TRUE
527 
528  dim as integer is_ovl = FALSE
529  if( typeIsPtr( dtype ) = FALSE ) then
530  '' check op overloading
531  if( symb.globOpOvlTb(AST_OP_FLDDEREF).head = NULL ) then
532  errReport( FB_ERRMSG_EXPECTEDPOINTER, TRUE )
533  exit do
534  end if
535 
536  dim as FBSYMBOL ptr proc = any
537  dim as FB_ERRMSG err_num = any
538 
539  proc = symbFindUopOvlProc( AST_OP_FLDDEREF, varexpr, @err_num )
540  if( proc <> NULL ) then
541  '' build a proc call
542  varexpr = astBuildCall( proc, varexpr )
543  if( varexpr = NULL ) then
544  exit function
545  end if
546 
547  lexSkipToken( LEXCHECK_NOPERIOD )
548 
549  varexpr = cMemberAccess( astGetFullType( varexpr ), _
550  astGetSubType( varexpr ), _
551  varexpr )
552  if( varexpr = NULL ) then
553  exit function
554  end if
555 
556  dtype = astGetFullType( varexpr )
557  subtype = astGetSubType( varexpr )
558  is_ovl = TRUE
559 
560  else
561  errReport( FB_ERRMSG_EXPECTEDPOINTER, TRUE )
562  exit do
563  end if
564 
565  else
566  lexSkipToken( LEXCHECK_NOPERIOD )
567  dtype = typeDeref( dtype )
568  end if
569 
570  '' DREF*
571  do while( lexGetToken( ) = FB_TK_DEREFCHAR )
572  lexSkipToken( LEXCHECK_NOPERIOD )
573  derefcnt += 1
574  loop
575 
576  if( is_ovl ) then
577  goto check_deref
578  end if
579 
580  '' '['
581  case CHAR_LBRACKET
582  lexSkipToken( )
583 
584  '' Expression
585  idxexpr = hIndexExpr( )
586 
587  '' ']'
588  if( lexGetToken( ) <> CHAR_RBRACKET ) then
589  errReport( FB_ERRMSG_SYNTAXERROR )
590  '' error recovery: skip until next ']'
591  hSkipUntil( CHAR_RBRACKET, TRUE )
592  else
593  lexSkipToken( )
594  end if
595 
596 
597  '' string, fixstr, w|zstring?
598  select case( typeGetDtAndPtrOnly( dtype ) )
599  case FB_DATATYPE_STRING, FB_DATATYPE_FIXSTR, _
600  FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR
601  idxexpr = hCheckIntegerIndex( idxexpr )
602  varexpr = hStrIndexing( dtype, varexpr, idxexpr )
603  exit do
604 
605  case FB_DATATYPE_STRUCT
606  '' [] overloaded for UDT?
607  dim as FB_ERRMSG err_num = any
608  var proc = symbFindSelfBopOvlProc( AST_OP_PTRINDEX, varexpr, idxexpr, @err_num )
609  if( proc ) then
610  varexpr = astBuildCall( proc, varexpr, idxexpr )
611  else
612  if( err_num = FB_ERRMSG_OK ) then
613  errReport( FB_ERRMSG_EXPECTEDPOINTER, TRUE )
614  end if
615  end if
616 
617  exit do
618 
619  case else
620  if( typeIsPtr( dtype ) = FALSE ) then
621  errReport( FB_ERRMSG_EXPECTEDPOINTER, TRUE )
622  exit do
623  end if
624 
625  '' If [] isn't overloaded, then the index must be an INTEGER
626  idxexpr = hCheckIntegerIndex( idxexpr )
627  end select
628 
629  '' times length
630  lgt = symbCalcLen( typeDeref( dtype ), subtype )
631 
632  if( lgt = 0 ) then
633  errReport( FB_ERRMSG_INCOMPLETETYPE, TRUE )
634  '' error recovery: fake a type
635  dtype = typeAddrOf( FB_DATATYPE_BYTE )
636  subtype = NULL
637  lgt = 1
638  end if
639 
640  idxexpr = astNewBOP( AST_OP_MUL, idxexpr, astNewCONSTi( lgt ) )
641  dtype = typeDeref( dtype )
642 
643  '' '.'?
644  is_field = (lexGetToken( ) = CHAR_DOT)
645  if( is_field ) then
646  lexSkipToken( LEXCHECK_NOPERIOD )
647  end if
648 
649  '' exit..
650  case else
651  exit do
652 
653  end select
654 
655  select case as const typeGet( dtype )
656  '' incomplete type?
657  case FB_DATATYPE_VOID, FB_DATATYPE_FWDREF
658  errReport( FB_ERRMSG_INCOMPLETETYPE, TRUE )
659  '' error recovery: fake a type
660  dtype = typeAddrOf( FB_DATATYPE_BYTE )
661  subtype = NULL
662 
663  case FB_DATATYPE_STRUCT ', FB_DATATYPE_CLASS
664 
665  case else
666  if( is_field ) then
667  errReport( FB_ERRMSG_INVALIDDATATYPES, TRUE )
668  exit do
669  end if
670 
671  end select
672 
673  '' null pointer checking
674  if( env.clopt.extraerrchk ) then
675  varexpr = astBuildPTRCHK( varexpr )
676  end if
677 
678  ''
679  if( idxexpr <> NULL ) then
680  varexpr = astNewBOP( AST_OP_ADD, varexpr, idxexpr )
681  end if
682 
683  if( is_field ) then
684  varexpr = cUdtMember( dtype, subtype, varexpr, check_array )
685  if( varexpr = NULL ) then
686  exit function
687  end if
688 
689  '' non-indexed array?
690  if( astIsNIDXARRAY( varexpr ) ) then
691  if( derefcnt > 0 ) then
692  errReport( FB_ERRMSG_EXPECTEDPOINTER, TRUE )
693  end if
694 
695  exit do
696  end if
697 
698  dtype = astGetFullType( varexpr )
699  subtype = astGetSubType( varexpr )
700 
701  else
702  varexpr = astNewDEREF( varexpr, dtype, subtype )
703  end if
704 
705 check_deref:
706  if( derefcnt > 0 ) then
707  varexpr = astBuildMultiDeref( derefcnt, varexpr, dtype, subtype )
708  if( varexpr = NULL ) then
709  exit function
710  end if
711 
712  dtype = astGetFullType( varexpr )
713  subtype = astGetSubType( varexpr )
714  end if
715  loop
716 
717  function = varexpr
718 
719 end function
720 
721 '':::::
722 ''FuncPtrOrDeref = FuncPtr '(' Args? ')'
723 '' | MemberDeref .
724 ''
725 function cFuncPtrOrMemberDeref _
726  ( _
727  byval dtype as integer, _
728  byval subtype as FBSYMBOL ptr, _
729  byval expr as ASTNODE ptr, _
730  byval isfuncptr as integer, _
731  byval checkarray as integer _
732  ) as ASTNODE ptr
733 
734  function = NULL
735 
736  ''
737  if( isfuncptr = FALSE ) then
738  '' MemberDeref?
739  expr = cMemberDeref( dtype, subtype, expr, checkarray )
740  if( expr = NULL ) then
741  exit function
742  end if
743 
744  dtype = astGetDataType( expr )
745  subtype = astGetSubType( expr )
746 
747  '' check for functions called through pointers
748  if( lexGetToken( ) = CHAR_LPRNT ) then
749  if( dtype = typeAddrOf( FB_DATATYPE_FUNCTION ) ) then
750  isfuncptr = TRUE
751  end if
752  end if
753  end if
754 
755  '' function pointer dref? call it
756  if( isfuncptr = FALSE ) then
757  return expr
758  end if
759 
760  '' null pointer checking
761  if( env.clopt.extraerrchk ) then
762  expr = astBuildPTRCHK( expr )
763  end if
764 
765  '' function?
766  if( symbGetType( subtype ) <> FB_DATATYPE_VOID ) then
767  expr = cFunctionCall( NULL, subtype, expr )
768  if( expr = NULL ) then
769  exit function
770  end if
771 
772  '' sub..
773  else
774  if( fbGetIsExpression( ) = FALSE ) then
775  expr = cProcCall( NULL, subtype, expr )
776  else
777  errReport( FB_ERRMSG_SYNTAXERROR )
778  '' error recovery: fake an expr
779  expr = astNewCONSTi( 0 )
780  end if
781  end if
782 
783  function = expr
784 
785 end function
786 
787 function hDynArrayBoundChk _
788  ( _
789  byval expr as ASTNODE ptr, _
790  byval desc as FBSYMBOL ptr, _
791  byval idx as integer _
792  ) as ASTNODE ptr
793 
794  dim as longint dimoffset = any
795 
796  dimoffset = symb.fbarray_dimtb + (idx * symbGetLen( symb.fbarraydim ))
797 
798  function = astBuildBOUNDCHK( expr, _
799  astNewVAR( desc, dimoffset + symb.fbarraydim_lbound, FB_DATATYPE_INTEGER ), _
800  astNewVAR( desc, dimoffset + symb.fbarraydim_ubound, FB_DATATYPE_INTEGER ) )
801 
802 end function
803 
804 '':::::
805 ''DynArrayIdx = '(' Expression (',' Expression)* ')' .
806 ''
807 function cDynArrayIdx( byval sym as FBSYMBOL ptr ) as ASTNODE ptr
808  dim as integer i = any, dims = any, maxdims = any
809  dim as ASTNODE ptr expr = any, dimexpr = any
810  dim as FBSYMBOL ptr desc = any
811 
812  desc = symbGetArrayDescriptor( sym )
813  dims = 0
814 
815  if( symbIsCommon( sym ) = FALSE ) then
816  maxdims = symbGetArrayDimensions( sym )
817  else
818  maxdims = INVALID
819  end if
820 
821  ''
822  i = 0
823  expr = NULL
824  do
825  dims += 1
826 
827  '' check dimensions, if not common
828  if( maxdims <> -1 ) then
829  if( dims > maxdims ) then
830  errReport( FB_ERRMSG_WRONGDIMENSIONS )
831  return NULL
832  end if
833  end if
834 
835  '' Expression
836  dimexpr = hCheckIntegerIndex( hIndexExpr( ) )
837 
838  '' bounds checking
839  if( env.clopt.extraerrchk ) then
840  dimexpr = hDynArrayBoundChk( dimexpr, desc, i )
841  if( dimexpr = NULL ) then
842  return NULL
843  end if
844  end if
845 
846  if( expr = NULL ) then
847  expr = dimexpr
848  else
849  expr = astNewBOP( AST_OP_ADD, expr, dimexpr )
850  end if
851 
852  '' separator
853  if( lexGetToken( ) <> FB_TK_DECLSEPCHAR ) then
854  exit do
855  else
856  lexSkipToken( )
857  end if
858 
859  i += 1
860 
861  '' times desc(i).elements
862  expr = astNewBOP( AST_OP_MUL, expr, _
863  astNewVAR( desc, symb.fbarray_dimtb + (i * symbGetLen( symb.fbarraydim )), _
864  FB_DATATYPE_INTEGER ) )
865  loop
866 
867  '' times length
868  expr = astNewBOP( AST_OP_MUL, expr, astNewCONSTi( symbGetLen( sym ) ) )
869 
870  '' check dimensions, if not common
871  if( maxdims <> -1 ) then
872  if( dims < maxdims ) then
873  errReport( FB_ERRMSG_WRONGDIMENSIONS )
874  end if
875  end if
876 
877  '' plus desc.data (= ptr + diff)
878  function = astNewBOP( AST_OP_ADD, expr, _
879  astNewVAR( desc, symb.fbarray_data, FB_DATATYPE_INTEGER ) )
880 end function
881 
882 function hArgArrayBoundChk _
883  ( _
884  byval expr as ASTNODE ptr, _
885  byval desc as FBSYMBOL ptr, _
886  byval idx as integer _
887  ) as ASTNODE ptr
888 
889  dim as longint dimoffset = any
890 
891  dimoffset = symb.fbarray_dimtb + (idx * symbGetLen( symb.fbarraydim ))
892 
893  function = astBuildBOUNDCHK( expr, _
894  astNewDEREF( astNewVAR( desc, 0, FB_DATATYPE_INTEGER ), _
895  FB_DATATYPE_INTEGER, NULL, _
896  dimoffset + symb.fbarraydim_lbound ), _
897  astNewDEREF( astNewVAR( desc, 0, FB_DATATYPE_INTEGER ), _
898  FB_DATATYPE_INTEGER, NULL, _
899  dimoffset + symb.fbarraydim_ubound ) )
900 
901 
902 end function
903 
904 '':::::
905 ''ArgArrayIdx = '(' Expression (',' Expression)* ')' .
906 ''
907 function cArgArrayIdx( byval sym as FBSYMBOL ptr ) as ASTNODE ptr
908  dim as ASTNODE ptr expr = any, dimexpr = any
909  dim as integer i = any
910 
911  ''
912  i = 0
913  expr = NULL
914  do
915  '' Expression
916  dimexpr = hCheckIntegerIndex( hIndexExpr( ) )
917 
918  '' bounds checking
919  if( env.clopt.extraerrchk ) then
920  dimexpr = hArgArrayBoundChk( dimexpr, sym, i )
921  if( dimexpr = NULL ) then
922  return NULL
923  end if
924  end if
925 
926  if( expr = NULL ) then
927  expr = dimexpr
928  else
929  expr = astNewBOP( AST_OP_ADD, expr, dimexpr )
930  end if
931 
932  '' separator
933  if( lexGetToken( ) <> FB_TK_DECLSEPCHAR ) then
934  exit do
935  else
936  lexSkipToken( )
937  end if
938 
939  i += 1
940 
941  '' it's a descriptor pointer, dereference (only with DAG this will be optimized)
942 
943  '' times desc[i].elements
944  expr = astNewBOP( AST_OP_MUL, expr, _
945  astNewDEREF( astNewVAR( sym, 0, FB_DATATYPE_INTEGER ), _
946  FB_DATATYPE_INTEGER, NULL, _
947  symb.fbarray_dimtb + (i * symbGetLen( symb.fbarraydim )) ) )
948  loop
949 
950  '' times length
951  expr = astNewBOP( AST_OP_MUL, expr, astNewCONSTi( symbGetLen( sym ) ) )
952 
953  '' plus desc->data (= ptr + diff)
954  function = astNewBOP( AST_OP_ADD, expr, _
955  astNewDEREF( astNewVAR( sym, 0, FB_DATATYPE_INTEGER ), _
956  FB_DATATYPE_INTEGER, NULL, symb.fbarray_data ) )
957 end function
958 
959 '':::::
960 ''ArrayIdx = '(' Expression (',' Expression)* ')' .
961 ''
962 function cArrayIdx( byval sym as FBSYMBOL ptr ) as ASTNODE ptr
963  dim as FBVARDIM ptr d = any
964  dim as integer dtype = any, dims = any, maxdims = any
965  dim as ASTNODE ptr expr = any, dimexpr = any, varexpr = any
966 
967  '' argument passed by descriptor?
968  if( symbIsParamByDesc( sym ) ) then
969  return cArgArrayIdx( sym )
970 
971  '' dynamic array? (will handle common's too)
972  elseif( symbGetIsDynamic( sym ) ) then
973  return cDynArrayIdx( sym )
974  end if
975 
976  ''
977  maxdims = symbGetArrayDimensions( sym )
978  dims = 0
979 
980  ''
981  d = symbGetArrayFirstDim( sym )
982  expr = NULL
983  do
984  dims += 1
985  if( dims > maxdims ) then
986  errReport( FB_ERRMSG_WRONGDIMENSIONS )
987  return NULL
988  end if
989 
990  '' Expression
991  dimexpr = hCheckIntegerIndex( hIndexExpr( ) )
992 
993  '' bounds checking
994  if( env.clopt.extraerrchk ) then
995  dimexpr = hStaticArrayBoundChk( dimexpr, d )
996  end if
997 
998  ''
999  if( expr = NULL ) then
1000  expr = dimexpr
1001  else
1002  expr = astNewBOP( AST_OP_ADD, expr, dimexpr )
1003  end if
1004 
1005  '' separator
1006  if( lexGetToken( ) <> FB_TK_DECLSEPCHAR ) then
1007  exit do
1008  else
1009  lexSkipToken( )
1010  end if
1011 
1012  '' next
1013  d = d->next
1014  if( d = NULL ) then
1015  errReport( FB_ERRMSG_WRONGDIMENSIONS )
1016  exit do
1017  end if
1018 
1019  expr = astNewBOP( AST_OP_MUL, expr, astNewCONSTi( (d->upper - d->lower) + 1 ) )
1020  loop
1021 
1022  ''
1023  if( dims < maxdims ) then
1024  errReport( FB_ERRMSG_WRONGDIMENSIONS )
1025  end if
1026 
1027  '' times length (this will be optimized if len < 10 and there are
1028  '' no arrays on following fields)
1029  function = astNewBOP( AST_OP_MUL, expr, astNewCONSTi( symbGetLen( sym ) ) )
1030 end function
1031 
1032 '':::::
1033 function hVarAddUndecl _
1034  ( _
1035  byval id as zstring ptr, _
1036  byval dtype as integer _
1037  ) as FBSYMBOL ptr
1038 
1039  dim as FBSYMBOL ptr s = any
1040  dim as FBARRAYDIM dTB(0) = any
1041  dim as integer attrib = any, options = any
1042  dim as ASTNODE ptr var_ = any
1043 
1044  function = NULL
1045 
1046  if( symbGetProcStaticLocals( parser.currproc ) ) then
1047  attrib = FB_SYMBATTRIB_STATIC
1048  else
1049  attrib = 0
1050 
1051  '' inside a namespace but outside a proc?
1052  if( symbIsGlobalNamespc( ) = FALSE ) then
1053  if( fbIsModLevel( ) ) then
1054  if( (attrib and (FB_SYMBATTRIB_SHARED or _
1055  FB_SYMBATTRIB_COMMON or _
1056  FB_SYMBATTRIB_PUBLIC or _
1057  FB_SYMBATTRIB_EXTERN)) = 0 ) then
1058  '' they are never allocated on stack..
1059  attrib or= FB_SYMBATTRIB_STATIC
1060  end if
1061  end if
1062  end if
1063 
1064  end if
1065 
1066  '' no suffix?
1067  if( dtype = FB_DATATYPE_INVALID ) then
1068  dtype = symbGetDefType( id )
1069  else
1070  attrib or= FB_SYMBATTRIB_SUFFIXED
1071  end if
1072 
1073  options = 0
1074 
1075  '' respect scopes?
1076  if( fbLangOptIsSet( FB_LANG_OPT_SCOPE ) ) then
1077  '' deprecated quirk: not inside an explicit SCOPE .. END SCOPE block?
1078  if( fbGetIsScope( ) = FALSE ) then
1079  options or= FB_SYMBOPT_UNSCOPE
1080  end if
1081 
1082  '' no scopes..
1083  else
1084  options or= FB_SYMBOPT_UNSCOPE
1085  end if
1086 
1087  s = symbAddVar( id, NULL, dtype, NULL, 0, 0, dTB(), attrib, options )
1088  if( s = NULL ) then
1089  errReportEx( FB_ERRMSG_DUPDEFINITION, id )
1090  '' error recovery: fake an id
1091  s = symbAddVar( symbUniqueLabel( ), NULL, dtype, NULL, 0, 0, dTB(), attrib )
1092  else
1093  var_ = astNewDECL( s, TRUE )
1094 
1095  '' move to function scope?
1096  if( (options and FB_SYMBOPT_UNSCOPE) <> 0 ) then
1097  astAddUnscoped( var_ )
1098  '' respect the scope..
1099  else
1100  astAdd( var_ )
1101  end if
1102  end if
1103 
1104  function = s
1105 end function
1106 
1107 function hMakeArrayIdx( byval sym as FBSYMBOL ptr ) as ASTNODE ptr
1108  '' argument passed by descriptor?
1109  if( symbIsParamByDesc( sym ) ) then
1110  '' return descriptor->data
1111  return astNewDEREF( astNewVAR( sym, 0, FB_DATATYPE_INTEGER ), _
1112  FB_DATATYPE_INTEGER, NULL, symb.fbarray_data )
1113  end if
1114 
1115  '' dynamic array? (this will handle common's too)
1116  if( symbGetIsDynamic( sym ) ) then
1117  '' return descriptor.data
1118  return astNewVAR( symbGetArrayDescriptor( sym ), _
1119  symb.fbarray_data, FB_DATATYPE_INTEGER )
1120  end if
1121 
1122  '' static array, return lbound( array )
1123  function = astNewCONSTi( symbGetArrayFirstDim( sym )->lower )
1124 end function
1125 
1126 '':::::
1127 ''Variable = ID ArrayIdx? UdtMember? FuncPtrOrMemberDeref? .
1128 ''
1129 function cVariableEx overload _
1130  ( _
1131  byval sym as FBSYMBOL ptr, _
1132  byval check_array as integer _
1133  ) as ASTNODE ptr
1134 
1135  dim as integer dtype = any
1136  dim as FBSYMBOL ptr subtype = any
1137  dim as ASTNODE ptr varexpr = any, idxexpr = any
1138  dim as integer is_byref = any, is_funcptr = any, is_array = any
1139 
1140  function = NULL
1141 
1142  '' check visibility
1143  if( symbCheckAccess( sym ) = FALSE ) then
1144  errReport( FB_ERRMSG_ILLEGALMEMBERACCESS )
1145  end if
1146 
1147  '' ID
1148  lexSkipToken( )
1149 
1150  dtype = symbGetFullType( sym )
1151  subtype = symbGetSubtype( sym )
1152 
1153  is_byref = symbIsParamByRef( sym ) or symbIsImport( sym )
1154  is_array = symbIsArray( sym )
1155  is_funcptr = FALSE
1156 
1157  varexpr = NULL
1158  idxexpr = NULL
1159 
1160  dim as integer check_fields = TRUE, is_nidxarray = FALSE
1161 
1162  '' check for '('')', it's not an array, just passing by desc
1163  if( lexGetToken( ) = CHAR_LPRNT ) then
1164  if( lexGetLookAhead( 1 ) <> CHAR_RPRNT ) then
1165 
1166  '' ArrayIdx?
1167  if( is_array ) then
1168  '' '('
1169  lexSkipToken( )
1170 
1171  idxexpr = cArrayIdx( sym )
1172 
1173  '' ')'
1174  if( hMatch( CHAR_RPRNT ) = FALSE ) then
1175  errReport( FB_ERRMSG_EXPECTEDRPRNT )
1176  '' error recovery: skip until next ')'
1177  hSkipUntil( CHAR_RPRNT, TRUE )
1178  end if
1179  else
1180  '' check if calling functions through pointers
1181  is_funcptr = (typeGetDtAndPtrOnly( dtype ) = typeAddrOf( FB_DATATYPE_FUNCTION ))
1182 
1183  '' using (...) with scalars?
1184  if( (is_array = FALSE) and (is_funcptr = FALSE) ) then
1185  errReport( FB_ERRMSG_ARRAYNOTALLOCATED, TRUE )
1186  '' error recovery: skip the index
1187  lexSkipToken( )
1188  hSkipUntil( CHAR_RPRNT, TRUE )
1189  end if
1190  end if
1191  else
1192  '' array? could be a func ptr call too..
1193  if( is_array ) then
1194  check_fields = FALSE
1195  end if
1196  end if
1197 
1198  else
1199  '' array and no index?
1200  if( is_array ) then
1201  if( check_array ) then
1202  errReport( FB_ERRMSG_EXPECTEDINDEX, TRUE )
1203  '' error recovery: fake an index
1204  idxexpr = hMakeArrayIdx( sym )
1205  else
1206  check_fields = FALSE
1207  is_nidxarray = TRUE
1208  end if
1209  end if
1210  end if
1211 
1212  '' AST will handle descriptor pointers
1213  if( is_byref ) then
1214  '' byref or import? by now it's a pointer var, the real type will be set bellow
1215  varexpr = astNewVAR( sym, 0, typeAddrOf( dtype ), subtype )
1216  else
1217  varexpr = astNewVAR( sym, 0, dtype, subtype )
1218  end if
1219 
1220  '' array or index?
1221  if( idxexpr <> NULL ) then
1222  '' byref or import's are already pointers
1223  if( is_byref ) then
1224  varexpr = astNewBOP( AST_OP_ADD, varexpr, idxexpr )
1225  else
1226  varexpr = astNewIDX( varexpr, idxexpr, dtype, subtype )
1227  end if
1228  end if
1229 
1230  '' check arguments passed by reference (implicity pointer's)
1231  if( is_byref ) then
1232  varexpr = astNewDEREF( varexpr, dtype, subtype )
1233  end if
1234 
1235  ''
1236  if( is_funcptr = FALSE ) then
1237  if( check_fields ) then
1238  '' ('.' UdtMember)?
1239  if( lexGetToken( ) = CHAR_DOT ) then
1240 
1241  select case typeGet( dtype )
1242  case FB_DATATYPE_STRUCT ', FB_DATATYPE_CLASS
1243 
1244  case else
1245  errReport( FB_ERRMSG_EXPECTEDUDT, TRUE )
1246  hSkipStmt( )
1247  return varexpr
1248  end select
1249 
1250  lexSkipToken( LEXCHECK_NOPERIOD )
1251 
1252  varexpr = cUdtMember( dtype, _
1253  subtype, _
1254  astNewADDROF( varexpr ), _
1255  check_array )
1256  if( varexpr = NULL ) then
1257  exit function
1258  end if
1259 
1260  '' non-indexed array?
1261  if( astIsNIDXARRAY( varexpr ) ) then
1262  return varexpr
1263  end if
1264 
1265  dtype = astGetDataType( varexpr )
1266  subtype = astGetSubType( varexpr )
1267 
1268  '' check if calling functions through pointers
1269  if( lexGetToken( ) = CHAR_LPRNT ) then
1270  is_funcptr = (dtype = typeAddrOf( FB_DATATYPE_FUNCTION ))
1271  end if
1272 
1273  end if
1274  end if
1275  end if
1276 
1277  if( check_fields ) then
1278  '' FuncPtrOrMemberDeref?
1279  varexpr = cFuncPtrOrMemberDeref( dtype, _
1280  subtype, _
1281  varexpr, _
1282  is_funcptr, _
1283  check_array )
1284 
1285  else
1286  if( is_nidxarray ) then
1287  varexpr = astNewNIDXARRAY( varexpr )
1288  end if
1289  end if
1290 
1291  function = varexpr
1292 
1293 end function
1294 
1295 '':::::
1296 ''Variable = ID .
1297 ''
1298 function cVariableEx _
1299  ( _
1300  byval chain_ as FBSYMCHAIN ptr, _
1301  byval check_array as integer _
1302  ) as ASTNODE ptr
1303 
1304  dim as zstring ptr id = any
1305  dim as integer suffix = any
1306  dim as FBSYMBOL ptr sym = any
1307 
1308  id = lexGetText( )
1309  suffix = lexGetType( )
1310 
1311  if( env.clopt.lang = FB_LANG_QB ) then
1312  '' keyword with no suffix? Then it can't be a variable
1313  if( lexGetClass( ) = FB_TKCLASS_KEYWORD ) then
1314  if( suffix = FB_DATATYPE_INVALID ) then
1315  return NULL
1316  end if
1317  end if
1318  end if
1319 
1320  if( fbLangOptIsSet( FB_LANG_OPT_SUFFIX ) ) then
1321  '' no suffix? lookup the default type (last DEF###) in the
1322  '' case symbol could not be found..
1323  if( suffix = FB_DATATYPE_INVALID ) then
1325  else
1326  sym = symbFindVarBySuffix( chain_, suffix )
1327  end if
1328 
1329  else
1330  if( suffix <> FB_DATATYPE_INVALID ) then
1331  errReportNotAllowed( FB_LANG_OPT_SUFFIX, FB_ERRMSG_SUFFIXONLYVALIDINLANG )
1332  end if
1333 
1334  sym = symbFindByClass( chain_, FB_SYMBCLASS_VAR )
1335  end if
1336 
1337  if( sym = NULL ) then
1338  if( env.opt.explicit ) then
1339  errReportUndef( FB_ERRMSG_VARIABLENOTDECLARED, id )
1340  end if
1341 
1342  '' don't allow explicit namespaces
1343  if( chain_ <> NULL ) then
1344  if( fbLangOptIsSet( FB_LANG_OPT_SUFFIX ) ) then
1345  '' variable?
1346  sym = symbFindByClass( chain_, FB_SYMBCLASS_VAR )
1347  if( sym <> NULL ) then
1348  '' from a different namespace?
1349  if( symbGetNamespace( sym ) <> symbGetCurrentNamespc( ) ) then
1350  errReport( FB_ERRMSG_DECLOUTSIDENAMESPC )
1351  end if
1352  end if
1353  end if
1354  end if
1355 
1356  '' add undeclared variable
1357  sym = hVarAddUndecl( id, suffix )
1358  if( sym = NULL ) then
1359  return NULL
1360  end if
1361 
1362  '' show warning if inside an expression (ie: var was never set)
1363  if( fbGetIsExpression( ) ) then
1364  if( fbLangOptIsSet( FB_LANG_OPT_SCOPE ) ) then
1365  if( env.opt.explicit = FALSE ) then
1366  errReportWarn( FB_WARNINGMSG_IMPLICITALLOCATION, id )
1367  end if
1368  end if
1369  end if
1370 
1371  end if
1372 
1373  function = cVariableEx( sym, check_array )
1374 
1375 end function
1376 
1377 function hImpField _
1378  ( _
1379  byval this_ as FBSYMBOL ptr, _
1380  byval dtype as integer, _
1381  byval subtype as FBSYMBOL ptr, _
1382  byval check_array as integer, _
1383  byval is_ptr as integer, _
1384  byval options as FB_PARSEROPT _
1385  ) as ASTNODE ptr
1386 
1387  dim as ASTNODE ptr varexpr = any
1388 
1389  if( is_ptr ) then
1390  varexpr = astNewVAR( this_, , typeAddrOf( dtype ), subtype )
1391  else
1392  varexpr = astNewADDROF( astNewVAR( this_, , dtype, subtype ) )
1393  end if
1394 
1395  varexpr = cUdtMember( dtype, subtype, varexpr, check_array, options )
1396 
1397  if( varexpr = NULL ) then
1398  return NULL
1399  end if
1400 
1401  '' non-indexed array?
1402  if( astIsNIDXARRAY( varexpr ) ) then
1403  return varexpr
1404  end if
1405 
1406  dtype = astGetFullType( varexpr )
1407  subtype = astGetSubType( varexpr )
1408 
1409  '' check if calling functions through pointers
1410  dim as integer is_funcptr = FALSE
1411  if( lexGetToken( ) = CHAR_LPRNT ) then
1412  is_funcptr = (typeGetDtAndPtrOnly( dtype ) = typeAddrOf( FB_DATATYPE_FUNCTION ))
1413  end if
1414 
1415  '' FuncPtrOrMemberDeref?
1416  function = cFuncPtrOrMemberDeref( dtype, _
1417  subtype, _
1418  varexpr, _
1419  is_funcptr, _
1420  check_array )
1421 end function
1422 
1423 '' WithVariable = '.' UdtMember FuncPtrOrMemberDeref? .
1424 function cWithVariable( byval check_array as integer ) as ASTNODE ptr
1425  dim as FBSYMBOL ptr sym = any
1426  dim as integer dtype = any
1427 
1428  '' '.'
1429  lexSkipToken( LEXCHECK_NOPERIOD )
1430 
1431  sym = parser.stmt.with.sym
1432  dtype = symbGetFullType( sym )
1433  if( parser.stmt.with.is_ptr ) then
1434  dtype = typeDeref( dtype )
1435  end if
1436 
1437  function = hImpField( sym, dtype, symbGetSubtype( sym ), check_array, _
1438  parser.stmt.with.is_ptr, 0 )
1439 end function
1440 
1441 '':::::
1442 ''Variable = '.'? ID ArrayIdx? UdtMember? FuncPtrOrMemberDeref? .
1443 ''
1444 function cVariable _
1445  ( _
1446  byval chain_ as FBSYMCHAIN ptr, _
1447  byval check_array as integer _
1448  ) as ASTNODE ptr
1449 
1450  '' ID
1451  select case lexGetClass( )
1452  case FB_TKCLASS_IDENTIFIER, FB_TKCLASS_QUIRKWD
1453  return cVariableEx( chain_, check_array )
1454 
1455  case else
1456  if( parser.stmt.with.sym = NULL ) then
1457  return NULL
1458  end if
1459 
1460  '' '.'?
1461  if( lexGetToken( ) <> CHAR_DOT ) then
1462  return NULL
1463  end if
1464 
1465  return cWithVariable( check_array )
1466  end select
1467 
1468 end function
1469 
1470 '':::::
1471 ''ImplicitDataMember = UdtMember? FuncPtrOrMemberDeref? .
1472 ''
1473 function cImplicitDataMember _
1474  ( _
1475  byval base_parent as FBSYMBOL ptr, _
1476  byval chain_ as FBSYMCHAIN ptr, _
1477  byval check_array as integer, _
1478  byval options as FB_PARSEROPT _
1479  ) as ASTNODE ptr
1480 
1481  dim as FBSYMBOL ptr this_ = NULL
1482 
1483  dim as FBSYMBOL ptr param = symbGetProcHeadParam( parser.currproc )
1484  if( symbIsMethod( parser.currproc ) and (param <> NULL) ) then
1485  this_ = symbGetParamVar( param )
1486  end if
1487 
1488  if( this_ = NULL ) then
1489  errReport( FB_ERRMSG_STATICMEMBERHASNOINSTANCEPTR )
1490  return NULL
1491  end if
1492 
1493  if( base_parent = NULL ) then
1494  base_parent = symbGetSubtype( this_ )
1495  End If
1496 
1497  function = hImpField( this_, symbGetFullType( this_ ), base_parent, _
1498  check_array, TRUE, options )
1499 
1500 end function
1501 
1502 '' cVarOrDeref = Deref | PtrTypeCasting | AddrOf | Variable
1503 function cVarOrDeref _
1504  ( _
1505  byval options as FB_VAREXPROPT _
1506  ) as ASTNODE ptr
1507 
1508  dim as integer last_isexpr = any, check_array = any
1509 
1510  if( options and FB_VAREXPROPT_ISEXPR ) then
1511  last_isexpr = fbGetIsExpression( )
1512  fbSetIsExpression( TRUE )
1513  end if
1514  check_array = fbGetCheckArray( )
1515  fbSetCheckArray( ((options and FB_VAREXPROPT_NOARRAYCHECK) = 0) )
1516 
1517  dim as ASTNODE ptr expr = cHighestPrecExpr( NULL, NULL )
1518 
1519  fbSetCheckArray( check_array )
1520  if( options and FB_VAREXPROPT_ISEXPR ) then
1521  fbSetIsExpression( last_isexpr )
1522  end if
1523 
1524  if( expr <> NULL ) then
1525  '' skip any casting if they won't do any conversion
1526  dim as ASTNODE ptr t = expr
1527  if( astIsCAST( expr ) ) then
1528  if( astGetCASTDoConv( expr ) = FALSE ) then
1529  t = astGetLeft( expr )
1530  end if
1531  end if
1532 
1533  dim as integer complain = TRUE
1534 
1535  select case as const astGetClass( t )
1536  case AST_NODECLASS_VAR, AST_NODECLASS_IDX, _
1537  AST_NODECLASS_FIELD, AST_NODECLASS_DEREF
1538  complain = FALSE
1539 
1540  case AST_NODECLASS_CALL, AST_NODECLASS_NIDXARRAY
1541  complain = ((options and FB_VAREXPROPT_ISASSIGN) <> 0)
1542 
1543  case AST_NODECLASS_ADDROF, AST_NODECLASS_OFFSET
1544  complain = ((options and FB_VAREXPROPT_ALLOWADDROF) = 0)
1545 
1546  case AST_NODECLASS_BOP
1547  '' allow addresses?
1548  if( options and FB_VAREXPROPT_ALLOWADDROF ) then
1549  '' not a pointer? (@foo[bar] will be converted to foo + bar)
1550  complain = not typeIsPtr( astGetDataType( expr ) )
1551  end if
1552  end select
1553 
1554  if( complain ) then
1555  errReport( FB_ERRMSG_INVALIDDATATYPES )
1556  astDelTree( expr )
1557  expr = NULL
1558  '' no error recovery: caller will take care
1559  end if
1560  end if
1561 
1562  function = expr
1563 
1564 end function
1565