FreeBASIC  0.91.0
parser-expr-unary.bas
Go to the documentation of this file.
1 '' unary operators (NOT, @, *, ...) parsing
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 "pp.bi"
11 
12 declare function hCast( byval options as AST_CONVOPT ) as ASTNODE ptr
13 
14 function hPPDefinedExpr( ) as ASTNODE ptr
15  dim as FBSYMBOL ptr base_parent = any
16  dim as integer is_defined = any
17 
18  '' DEFINED
19  lexSkipToken( LEXCHECK_NODEFINE )
20 
21  '' '('
22  if( lexGetToken( ) <> CHAR_LPRNT ) then
23  errReport( FB_ERRMSG_EXPECTEDLPRNT )
24  else
25  lexSkipToken( LEXCHECK_NODEFINE )
26  end if
27 
28  '' Identifier
29  is_defined = (cIdentifier( base_parent, FB_IDOPT_NONE ) <> NULL)
30  lexSkipToken( )
31 
32  '' ')'
33  if( hMatch( CHAR_RPRNT ) = FALSE ) then
34  errReport( FB_ERRMSG_EXPECTEDRPRNT )
35  '' error recovery: skip until ')'
36  hSkipUntil( CHAR_RPRNT, TRUE )
37  end if
38 
39  function = astNewCONSTi( is_defined )
40 end function
41 
42 '':::::
43 ''NegNotExpression= ('-'|'+'|) ExpExpression
44 '' | NOT RelExpression
45 '' | HighestPresExpr .
46 ''
47 function cNegNotExpression _
48  ( _
49  _
50  ) as ASTNODE ptr
51 
52  dim as ASTNODE ptr negexpr = any
53 
54  select case lexGetToken( )
55  '' '-'
56  case CHAR_MINUS
57  lexSkipToken( )
58 
59  '' ExpExpression
60  negexpr = cExpExpression( )
61  if( negexpr = NULL ) then
62  errReport( FB_ERRMSG_EXPECTEDEXPRESSION )
63  '' error recovery: fake a new node
64  negexpr = astNewCONSTi( 0 )
65  else
66  negexpr = astNewUOP( AST_OP_NEG, negexpr )
67  end if
68 
69  if( negexpr = NULL ) Then
70  errReport( FB_ERRMSG_TYPEMISMATCH )
71  '' error recovery: fake a new node
72  negexpr = astNewCONSTi( 0 )
73  end if
74 
75  return negexpr
76 
77  '' '+'
78  case CHAR_PLUS
79  lexSkipToken( )
80 
81  '' ExpExpression
82  negexpr = cExpExpression( )
83  if( negexpr = NULL ) then
84  errReport( FB_ERRMSG_EXPECTEDEXPRESSION )
85  '' error recovery: fake a new node
86  negexpr = astNewCONSTi( 0 )
87  else
88  negexpr = astNewUOP( AST_OP_PLUS, negexpr )
89  end if
90 
91  if( negexpr = NULL ) Then
92  errReport( FB_ERRMSG_TYPEMISMATCH )
93  '' error recovery: fake a new node
94  negexpr = astNewCONSTi( 0 )
95  end if
96 
97  return negexpr
98 
99  '' NOT
100  case FB_TK_NOT
101  lexSkipToken( )
102 
103  '' RelExpression
104  negexpr = cRelExpression( )
105  if( negexpr = NULL ) then
106  errReport( FB_ERRMSG_EXPECTEDEXPRESSION )
107  '' error recovery: fake a new node
108  negexpr = astNewCONSTi( 0 )
109  else
110  negexpr = astNewUOP( AST_OP_NOT, negexpr )
111  end if
112 
113  if( negexpr = NULL ) Then
114  errReport( FB_ERRMSG_TYPEMISMATCH )
115  '' error recovery: fake a new node
116  negexpr = astNewCONSTi( 0 )
117  end if
118 
119  return negexpr
120  end select
121 
122  function = cHighestPrecExpr( NULL, NULL )
123 
124 end function
125 
126 ''::::
127 function cStrIdxOrMemberDeref _
128  ( _
129  byval expr as ASTNODE ptr _
130  ) as ASTNODE ptr
131 
132  dim as FBSYMBOL ptr subtype = any
133  dim as integer dtype = any
134 
135  dtype = astGetFullType( expr )
136  subtype = astGetSubType( expr )
137 
138  select case as const typeGet( dtype )
139  '' zstring indexing?
140  case FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR, FB_DATATYPE_STRING, FB_DATATYPE_FIXSTR
141  '' '['?
142  if( lexGetToken( ) = CHAR_LBRACKET ) then
143  expr = cMemberDeref( dtype, subtype, expr, TRUE )
144  end if
145 
146  return expr
147 
148  '' udt '.' ?
149  case FB_DATATYPE_STRUCT ', FB_DATATYPE_CLASS
150  select case( lexGetToken( ) )
151  case CHAR_DOT
152  lexSkipToken( LEXCHECK_NOPERIOD )
153 
154  expr = cMemberAccess( dtype, subtype, expr )
155  if( expr = NULL ) then
156  return NULL
157  end if
158 
159  dtype = astGetFullType( expr )
160  subtype = astGetSubType( expr )
161 
162  '' '['?
163  case CHAR_LBRACKET
164  expr = cMemberDeref( dtype, subtype, expr, TRUE )
165  end select
166 
167  end select
168 
169  '' FuncPtrOrMemberDeref?
170  if( typeIsPtr( dtype ) ) then
171  dim as integer isfuncptr = FALSE, isfield = FALSE
172 
173  select case lexGetToken( )
174  '' function ptr '(' ?
175  case CHAR_LPRNT
176  isfuncptr = (typeGetDtAndPtrOnly( dtype ) = typeAddrOf( FB_DATATYPE_FUNCTION ))
177  isfield = isfuncptr
178 
179  '' ptr ('->' | '[') ?
180  case FB_TK_FIELDDEREF, CHAR_LBRACKET
181  isfield = TRUE
182  end select
183 
184  if( isfield ) then
185  expr = cFuncPtrOrMemberDeref( dtype, _
186  subtype, _
187  expr, _
188  isfuncptr, _
189  TRUE )
190  end if
191  end if
192 
193  function = expr
194 
195 end function
196 
197 ''::::
198 '' HighestPrecExpr= AddrOfExpression
199 '' | ( DerefExpr
200 '' | CastingExpr
201 '' | PtrTypeCastingExpr
202 '' | ParentExpression
203 '' ) FuncPtrOrMemberDeref?
204 '' | AnonType
205 '' | Atom .
206 ''
207 function cHighestPrecExpr _
208  ( _
209  byval base_parent as FBSYMBOL ptr, _
210  byval chain_ as FBSYMCHAIN ptr _
211  ) as ASTNODE ptr
212 
213  dim as ASTNODE ptr expr = any
214 
215  select case lexGetToken( )
216  '' AddrOfExpression
217  case FB_TK_ADDROFCHAR
218  return cAddrOfExpression( )
219 
220  '' DerefExpr
221  case FB_TK_DEREFCHAR
222  expr = cDerefExpression( )
223  if( expr = NULL ) then
224  return NULL
225  end if
226 
227  '' ParentExpression
228  case CHAR_LPRNT
229  dim as integer is_opt = fbGetPrntOptional( )
230 
231  expr = cParentExpression( )
232  if( expr = NULL ) then
233  return NULL
234  end if
235 
236  '' if parsing a SUB, don't call StrIdxOrMemberDeref() twice
237  if( is_opt ) then
238  return expr
239  end if
240 
241  case else
242 
243  select case as const lexGetToken( )
244  '' AddrOfExpression
245  case FB_TK_VARPTR, FB_TK_PROCPTR, FB_TK_SADD, FB_TK_STRPTR
246  return cAddrOfExpression( )
247 
248  '' CAST '(' DataType ',' Expression ')'
249  case FB_TK_CAST
250  '' CAST
251  lexSkipToken( )
252 
253  expr = hCast( 0 )
254  if( expr = NULL ) then
255  return NULL
256  end if
257 
258  '' CPTR '(' DataType ',' Expression{int|uint|ptr} ')'
259  case FB_TK_CPTR
260  '' CPTR
261  lexSkipToken( )
262 
263  expr = hCast( AST_CONVOPT_PTRONLY )
264  if( expr = NULL ) then
265  return NULL
266  end if
267 
268  '' OperatorNew
269  case FB_TK_NEW
270  expr = cOperatorNew( )
271  if( expr = NULL ) then
272  return NULL
273  end if
274 
275  '' Atom
276  case else
277  '' PP expression?
278  if( fbGetIsPP( ) ) then
279  select case( lexGetToken( ) )
280  '' TYPEOF '(' Expression ')'
281  case FB_TK_TYPEOF
282  return astNewCONSTstr( ppTypeOf( ) )
283 
284  '' DEFINED '(' Identifier ')'
285  case FB_TK_DEFINED
286  return hPPDefinedExpr( )
287 
288  end select
289  end if
290 
291  return cAtom( base_parent, chain_ )
292 
293  end select
294 
295  end select
296 
297  function = cStrIdxOrMemberDeref( expr )
298 end function
299 
300 '' '(' DataType ',' Expression ')'
301 function hCast( byval options as AST_CONVOPT ) as ASTNODE ptr
302  dim as integer dtype = any, errmsg = any
303  dim as FBSYMBOL ptr subtype = any
304  dim as ASTNODE ptr expr = any
305 
306  '' '('
307  if( lexGetToken( ) <> CHAR_LPRNT ) then
308  errReport( FB_ERRMSG_EXPECTEDLPRNT )
309  '' error recovery: skip until ')', fake a node
310  hSkipUntil( CHAR_RPRNT, TRUE )
311  return astNewCONSTi( 0 )
312  end if
313  lexSkipToken( )
314 
315  '' DataType
316  if( cSymbolType( dtype, subtype, 0 ) = FALSE ) then
317  errReport( FB_ERRMSG_SYNTAXERROR )
318  '' error recovery: skip until ',', create a fake type
319  hSkipUntil( CHAR_COMMA )
320 
321  if( options and AST_CONVOPT_PTRONLY ) then
322  dtype = typeAddrOf( FB_DATATYPE_VOID )
323  else
324  dtype = FB_DATATYPE_INTEGER
325  end if
326  subtype = NULL
327  end if
328 
329  '' check for invalid types
330  select case as const( typeGet( dtype ) )
331  case FB_DATATYPE_VOID, FB_DATATYPE_FIXSTR
332  errReport( FB_ERRMSG_INVALIDDATATYPES, TRUE )
333  '' error recovery: create a fake type
334  if( options and AST_CONVOPT_PTRONLY ) then
335  dtype = typeAddrOf( FB_DATATYPE_VOID )
336  else
337  dtype = FB_DATATYPE_INTEGER
338  end if
339  subtype = NULL
340 
341  case FB_DATATYPE_INTEGER, FB_DATATYPE_UINT, _
342  FB_DATATYPE_LONG, FB_DATATYPE_ULONG, _
343  FB_DATATYPE_LONGINT, FB_DATATYPE_ULONGINT, _
344  FB_DATATYPE_ENUM
345 
346  if( options and AST_CONVOPT_PTRONLY ) then
347  if( fbPdCheckIsSet( FB_PDCHECK_CASTTONONPTR ) ) then
348  errReportWarn( FB_WARNINGMSG_CASTTONONPTR )
349  end if
350  end if
351 
352  case FB_DATATYPE_POINTER
353  options or= AST_CONVOPT_PTRONLY
354 
355  case else
356  if( options and AST_CONVOPT_PTRONLY ) then
357  errReportWarn( FB_WARNINGMSG_CASTTONONPTR )
358  end if
359 
360  end select
361 
362  '' ','
363  if( lexGetToken( ) <> CHAR_COMMA ) then
364  errReport( FB_ERRMSG_EXPECTEDCOMMA )
365  else
366  lexSkipToken( )
367  end if
368 
369  '' Expression
370  expr = cExpression( )
371  if( expr = NULL ) then
372  errReport( FB_ERRMSG_EXPECTEDEXPRESSION )
373  '' error recovery: create a fake node
374  expr = astNewCONSTz( dtype, subtype )
375  end if
376 
377  options or= AST_CONVOPT_CHECKSTR
378  expr = astNewCONV( dtype, subtype, expr, options, @errmsg )
379  if( expr = NULL ) then
380  if( errmsg = FB_ERRMSG_OK ) then
381  if( options and AST_CONVOPT_PTRONLY ) then
382  errmsg = FB_ERRMSG_EXPECTEDPOINTER
383  else
384  errmsg = FB_ERRMSG_TYPEMISMATCH
385  end if
386  end if
387  errReport( errmsg, TRUE )
388 
389  '' error recovery: create a fake node
390  expr = astNewCONSTz( dtype, subtype )
391  end if
392 
393  '' ')'
394  if( lexGetToken( ) <> CHAR_RPRNT ) then
395  errReport( FB_ERRMSG_EXPECTEDRPRNT )
396  '' error recovery: skip until next ')'
397  hSkipUntil( CHAR_RPRNT, TRUE )
398  else
399  lexSkipToken( )
400  end if
401 
402  function = expr
403 end function
404 
405 '':::::
406 ''DerefExpression = DREF+ HighestPresExpr .
407 ''
408 function cDerefExpression( ) as ASTNODE ptr
409  dim as integer derefcnt = any
410  dim as ASTNODE ptr expr = any
411 
412  '' DREF?
413  if( lexGetToken( ) <> FB_TK_DEREFCHAR ) then
414  return NULL
415  end if
416 
417  '' DREF+
418  derefcnt = 0
419  do
420  lexSkipToken( )
421  derefcnt += 1
422  loop while( lexGetToken( ) = FB_TK_DEREFCHAR )
423 
424  '' HighestPresExpr
425  expr = cHighestPrecExpr( NULL, NULL )
426  if( expr = NULL ) then
427  errReport( FB_ERRMSG_EXPECTEDEXPRESSION )
428  '' error recovery: fake a node
429  return astNewCONSTi( 0 )
430  end if
431 
432  function = astBuildMultiDeref( derefcnt, expr, astGetFullType( expr ), astGetSubType( expr ) )
433 end function
434 
435 function hProcPtrBody _
436  ( _
437  byval base_parent as FBSYMBOL ptr, _
438  byval proc as FBSYMBOL ptr _
439  ) as ASTNODE ptr
440 
441  dim as FBSYMBOL ptr sym = any
442 
443  '' '('')'?
444  if( lexGetToken( ) = CHAR_LPRNT ) then
445  lexSkipToken( )
446  if( hMatch( CHAR_RPRNT ) = FALSE ) then
447  errReport( FB_ERRMSG_EXPECTEDRPRNT )
448  hSkipUntil( CHAR_RPRNT, TRUE )
449  end if
450  end if
451 
452  '' resolve overloaded procs
453  if( symbIsOverloaded( proc ) ) then
454  if( parser.ctxsym <> NULL ) then
455  if( symbIsProc( parser.ctxsym ) ) then
456  sym = symbFindOverloadProc( proc, parser.ctxsym )
457  if( sym <> NULL ) then
458  proc = sym
459  end if
460  end if
461  end if
462  end if
463 
464  '' taking the address of an method? pointer to methods not supported yet..
465  if( symbIsMethod( proc ) ) then
466  errReportEx( FB_ERRMSG_ACCESSTONONSTATICMEMBER, symbGetFullProcName( proc ) )
467  return astNewCONSTi( 0 )
468  end if
469 
470  if( symbCheckAccess( proc ) = FALSE ) then
471  errReportEx( FB_ERRMSG_ILLEGALMEMBERACCESS, symbGetFullProcName( proc ) )
472  end if
473 
474  '' call any necessary rtl callbacks...
475  dim as FBRTLCALLBACK callback = symbGetProcCallback( proc )
476  if( callback <> NULL ) then
477  callback( proc )
478  end if
479 
480  function = astBuildProcAddrof( proc )
481 end function
482 
483 function hVarPtrBody _
484  ( _
485  byval base_parent as FBSYMBOL ptr, _
486  byval chain_ as FBSYMCHAIN ptr _
487  ) as ASTNODE ptr
488 
489  dim as ASTNODE ptr expr = cHighestPrecExpr( base_parent, chain_ )
490  if( expr = NULL ) then
491  errReport( FB_ERRMSG_EXPECTEDIDENTIFIER )
492  '' error recovery: fake a node
493  return astNewCONSTi( 0 )
494  end if
495 
496  '' skip any casting if they won't do any conversion
497  dim as ASTNODE ptr t = expr
498  if( astIsCAST( expr ) ) then
499  if( astGetCASTDoConv( expr ) = FALSE ) then
500  t = astGetLeft( expr )
501  end if
502  end if
503 
504  select case as const astGetClass( t )
505  case AST_NODECLASS_VAR, AST_NODECLASS_IDX, AST_NODECLASS_DEREF, AST_NODECLASS_TYPEINI
506 
507  case AST_NODECLASS_FIELD
508  '' can't take address of bitfields..
509  if( astGetDataType( astGetLeft( t ) ) = FB_DATATYPE_BITFIELD ) then
510  errReport( FB_ERRMSG_INVALIDDATATYPES )
511  '' error recovery: fake a node
512  astDelTree( expr )
513  return astNewCONSTi( 0 )
514  end if
515 
516  case else
517  errReportEx( FB_ERRMSG_INVALIDDATATYPES, "for @ or VARPTR" )
518  '' error recovery: fake a node
519  astDelTree( expr )
520  return astNewCONSTi( 0 )
521  end select
522 
523  '' check op overloading
524  scope
525  dim as FBSYMBOL ptr proc = any
526  dim as FB_ERRMSG err_num = any
527 
528  proc = symbFindSelfUopOvlProc( AST_OP_ADDROF, expr, @err_num )
529  if( proc <> NULL ) then
530  '' build a proc call
531  expr = astBuildCall( proc, expr )
532  if( expr = NULL ) then
533  expr = astNewCONSTi( 0 )
534  end if
535  return expr
536  else
537  if( err_num <> FB_ERRMSG_OK ) then
538  return astNewCONSTi( 0 )
539  end if
540  end if
541  end scope
542 
543  function = astNewADDROF( expr )
544 end function
545 
546 '':::::
547 ''AddrOfExpression = VARPTR '(' HighPrecExpr ')'
548 '' | PROCPTR '(' Proc ('('')')? ')'
549 '' | '@' (Proc ('('')')? | HighPrecExpr)
550 '' | SADD|STRPTR '(' Variable{str}|Const{str}|Literal{str} ')' .
551 ''
552 function cAddrOfExpression( ) as ASTNODE ptr
553  dim as ASTNODE ptr expr = NULL
554 
555  '' '@' (Proc ('('')')? | Variable)
556  if( lexGetToken( ) = FB_TK_ADDROFCHAR ) then
557  lexSkipToken( )
558 
559  '' not inside a WITH block?
560  dim as integer check_id = TRUE
561  if( parser.stmt.with.sym <> NULL ) then
562  if( lexGetToken( ) = CHAR_DOT ) then
563  '' not a '..'?
564  check_id = (lexGetLookAhead( 1, LEXCHECK_NOPERIOD ) = CHAR_DOT)
565  end if
566  end if
567 
568  '' check if the address of function is being taken
569  dim as FBSYMCHAIN ptr chain_ = NULL
570  dim as FBSYMBOL ptr sym = NULL, base_parent = NULL
571 
572  if( check_id ) then
573  chain_ = cIdentifier( base_parent, FB_IDOPT_DEFAULT or FB_IDOPT_ALLOWSTRUCT )
574  sym = symbFindByClass( chain_, FB_SYMBCLASS_PROC )
575  end if
576 
577  '' proc?
578  if( sym <> NULL ) then
579  lexSkipToken( )
580  return hProcPtrBody( base_parent, sym )
581  '' anything else..
582  else
583  return hVarPtrBody( base_parent, chain_ )
584  end if
585  end if
586 
587  select case as const lexGetToken( )
588  '' VARPTR '(' Variable ')'
589  case FB_TK_VARPTR
590  lexSkipToken( )
591 
592  '' '('
593  if( hMatch( CHAR_LPRNT ) = FALSE ) then
594  errReport( FB_ERRMSG_EXPECTEDLPRNT )
595  '' error recovery: skip until ')' and fake a node
596  hSkipUntil( CHAR_RPRNT, TRUE )
597  return astNewCONSTi( 0 )
598  end if
599 
600  expr = hVarPtrBody( NULL, NULL )
601 
602  '' ')'
603  if( hMatch( CHAR_RPRNT ) = FALSE ) then
604  errReport( FB_ERRMSG_EXPECTEDRPRNT )
605  '' error recovery: skip until ')'
606  hSkipUntil( CHAR_RPRNT, TRUE )
607  end if
608 
609  '' PROCPTR '(' Proc ('('')')? ')'
610  case FB_TK_PROCPTR
611  lexSkipToken( )
612 
613  '' '('
614  if( hMatch( CHAR_LPRNT ) = FALSE ) then
615  errReport( FB_ERRMSG_EXPECTEDLPRNT )
616  '' error recovery: skip until ')' and fake a node
617  hSkipUntil( CHAR_RPRNT, TRUE )
618  return astNewCONSTi( 0 )
619  end if
620 
621  '' proc?
622  dim as FBSYMCHAIN ptr chain_ = any
623  dim as FBSYMBOL ptr sym = any, base_parent = any
624 
626  FB_IDOPT_DEFAULT or FB_IDOPT_ALLOWSTRUCT )
627  sym = symbFindByClass( chain_, FB_SYMBCLASS_PROC )
628  if( sym = NULL ) then
629  errReport( FB_ERRMSG_UNDEFINEDSYMBOL )
630  '' error recovery: skip until ')' and fake a node
631  hSkipUntil( CHAR_RPRNT, TRUE )
632  return astNewCONSTi( 0 )
633  else
634  lexSkipToken( )
635  end if
636 
637  expr = hProcPtrBody( base_parent, sym )
638 
639  '' ')'
640  if( hMatch( CHAR_RPRNT ) = FALSE ) then
641  errReport( FB_ERRMSG_EXPECTEDRPRNT )
642  '' error recovery: skip until ')'
643  hSkipUntil( CHAR_RPRNT, TRUE )
644  end if
645 
646  '' SADD|STRPTR '(' Variable{str} ')'
647  case FB_TK_SADD, FB_TK_STRPTR
648  lexSkipToken( )
649 
650  '' '('
651  if( hMatch( CHAR_LPRNT ) = FALSE ) then
652  errReport( FB_ERRMSG_EXPECTEDLPRNT )
653  '' error recovery: skip until ')' and fake a node
654  hSkipUntil( CHAR_RPRNT, TRUE )
655  return astNewCONSTi( 0 )
656  end if
657 
658  expr = cHighestPrecExpr( NULL, NULL )
659  if( expr = NULL ) then
660  errReport( FB_ERRMSG_INVALIDDATATYPES )
661  '' error recovery: skip until ')' and fake a node
662  hSkipUntil( CHAR_RPRNT, TRUE )
663  return astNewCONSTi( 0 )
664  end if
665 
666  dim as integer dtype = astGetDataType( expr )
667 
668  if( symbIsString( dtype ) = FALSE ) then
669  errReport( FB_ERRMSG_INVALIDDATATYPES )
670  '' error recovery: skip until ')' and fake a node
671  hSkipUntil( CHAR_RPRNT, TRUE )
672  astDelTree( expr )
673  return astNewCONSTi( 0 )
674  end if
675 
676  '' check for invalid classes (functions, etc)
677 
678  '' skip any casting if they won't do any conversion
679  dim as ASTNODE ptr t = expr
680  if( astIsCAST( expr ) ) then
681  if( astGetCASTDoConv( expr ) = FALSE ) then
682  t = astGetLeft( expr )
683  end if
684  end if
685 
686  select case as const astGetClass( t )
687  case AST_NODECLASS_VAR, AST_NODECLASS_IDX, _
688  AST_NODECLASS_DEREF, AST_NODECLASS_TYPEINI, _
689  AST_NODECLASS_FIELD
690 
691  case else
692  errReportEx( FB_ERRMSG_INVALIDDATATYPES, "for STRPTR" )
693  end select
694 
695  '' varlen? do: *cast( zstring ptr ptr, @expr )
696  if( dtype = FB_DATATYPE_STRING ) then
697  expr = astBuildStrPtr( expr )
698 
699  '' anything else: do cast( zstring ptr, @expr )
700  else
701  expr = astNewCONV( typeAddrOf( FB_DATATYPE_CHAR ), _
702  NULL, _
703  astNewADDROF( expr ) )
704  end if
705 
706  '' ')'
707  if( hMatch( CHAR_RPRNT ) = FALSE ) then
708  errReport( FB_ERRMSG_EXPECTEDRPRNT )
709  '' error recovery: skip until ')'
710  hSkipUntil( CHAR_RPRNT, TRUE )
711  end if
712 
713  end select
714 
715  if( expr ) then
716  '' Allow indexing on VARPTR()/STRPTR()/etc. directly, they look
717  '' like functions so this isn't ambigious, while for @ it would
718  '' mess up the operator precedence:
719  '' @expr[i] should be @(expr[i]), not (@expr)[i]
720  '' but for
721  '' varptr(expr)[i], that problem doesn't exist.
722  expr = cStrIdxOrMemberDeref( expr )
723  end if
724 
725  function = expr
726 end function
727