FreeBASIC  0.91.0
parser-expr-atom.bas
Go to the documentation of this file.
1 '' atomic and parentheses expression 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 
11 declare function hBaseMemberAccess _
12  ( _
13  _
14  ) as ASTNODE ptr
15 
16 
17 '':::::
18 function cEqInParensOnlyExpr _
19  ( _
20  _
21  ) as ASTNODE ptr
22 
23  dim as ASTNODE ptr expr = any
24 
25  dim as integer eqinparensonly = fbGetEqInParensOnly( )
26  fbSetEqInParensOnly( TRUE )
27 
28  expr = cExpression( )
29 
30  fbSetEqInParensOnly( eqinparensonly )
31 
32  return expr
33 
34 end function
35 
36 '':::::
37 function cGtInParensOnlyExpr _
38  ( _
39  _
40  ) as ASTNODE ptr
41 
42  dim as ASTNODE ptr expr = any
43 
44  dim as integer gtinparensonly = fbGetGtInParensOnly( )
45  fbSetGtInParensOnly( TRUE )
46 
47  expr = cExpression( )
48 
49  fbSetGtInParensOnly( gtinparensonly )
50 
51  return expr
52 
53 end function
54 
55 '':::::
56 ''ParentExpression= '(' Expression ')' .
57 ''
58 function cParentExpression _
59  ( _
60  _
61  ) as ASTNODE ptr
62 
63  dim as ASTNODE ptr parexpr = any
64  dim as integer eqinparensonly = any, gtinparensonly = any
65 
66  '' '('
67  if( lexGetToken( ) <> CHAR_LPRNT ) then
68  return NULL
69  end if
70 
71  lexSkipToken( )
72 
73  '' ++parent cnt
74  parser.prntcnt += 1
75 
76  dim as integer is_opt = fbGetPrntOptional( )
77  fbSetPrntOptional( FALSE )
78 
79 
80  eqinparensonly = fbGetEqInParensOnly( )
81  gtinparensonly = fbGetGtInParensOnly( )
82  fbSetEqInParensOnly( FALSE )
83  fbSetGtInParensOnly( FALSE )
84 
85  parexpr = cExpression( )
86 
87  fbSetEqInParensOnly( eqinparensonly )
88  fbSetGtInParensOnly( gtinparensonly )
89 
90  if( parexpr = NULL ) then
91  '' calling a SUB? it could be a BYVAL or nothing due the optional ()'s
92  if( is_opt ) then
93  return NULL
94  end if
95 
96  errReport( FB_ERRMSG_EXPECTEDEXPRESSION )
97  '' error recovery: skip until next ')', fake an expr
98  hSkipUntil( CHAR_RPRNT, TRUE )
99  return astNewCONSTi( 0 )
100  end if
101 
102  '' ')'
103  if( lexGetToken( ) = CHAR_RPRNT ) then
104  lexSkipToken( )
105  '' --parent cnt
106  parser.prntcnt -= 1
107 
108  else
109  '' not calling a SUB or parent cnt = 0?
110  if( (is_opt = FALSE) or (parser.prntcnt = 0) ) then
111  errReport( FB_ERRMSG_EXPECTEDRPRNT )
112  '' error recovery: skip until next ')'
113  hSkipUntil( CHAR_RPRNT, TRUE )
114  end if
115  end if
116 
117  function = parexpr
118 
119 end function
120 
121 '':::::
122 function hFindId_QB _
123  ( _
124  byval base_parent as FBSYMBOL ptr, _
125  byval chain_ as FBSYMCHAIN ptr _
126  ) as ASTNODE ptr
127 
128  dim as zstring ptr id = lexGetText( )
129  dim as integer suffix = lexGetType( )
130  dim as integer defdtype = symbGetDefType( id )
131 
132  do
133  dim as FBSYMBOL ptr sym = chain_->sym
134  dim as FBSYMBOL ptr var_sym = NULL
135 
136  '' no suffix?
137  if( suffix = FB_DATATYPE_INVALID ) then
138 
139  do
140  dim as integer is_match = TRUE
141  '' is the original symbol suffixed?
142  if( symbIsSuffixed( sym ) ) then
143  '' if it's a VAR, lookup the default type (last DEF###) in
144  '' the case symbol could not be found..
145  if( symbGetClass( sym ) = FB_SYMBCLASS_VAR ) then
146  if( defdtype = FB_DATATYPE_STRING ) then
147  select case as const symbGetType( sym )
148  case FB_DATATYPE_STRING, FB_DATATYPE_FIXSTR, FB_DATATYPE_CHAR
149 
150  case else
151  is_match = FALSE
152  end select
153  else
154  is_match = (symbGetType( sym ) = defdtype)
155  end if
156  end if
157  end if
158 
159  if( is_match ) then
160  select case as const symbGetClass( sym )
161  case FB_SYMBCLASS_CONST
162  return cConstant( sym )
163 
164  case FB_SYMBCLASS_PROC
165  '' if it's a RTL func, the suffix is obligatory
166  if( symbGetIsRTL( sym ) ) then
167  is_match = (symbIsSuffixed( sym ) = FALSE)
168  end if
169 
170  if( is_match ) then
171  return cFunctionEx( base_parent, sym )
172  end if
173 
174  case FB_SYMBCLASS_VAR
175  if( var_sym = NULL ) then
176  if( symbVarCheckAccess( sym ) ) then
177  var_sym = sym
178  end if
179  end if
180 
181  case FB_SYMBCLASS_KEYWORD
182  '' only if not suffixed
183  if( symbIsSuffixed( sym ) = FALSE ) then
184  return cQuirkFunction( sym )
185  end if
186 
187  end select
188  end if
189 
190  sym = sym->hash.next
191  loop while( sym <> NULL )
192 
193  '' suffix..
194  else
195  do
196  dim as integer is_match = any
197  if( suffix = FB_DATATYPE_STRING ) then
198  select case as const symbGetType( sym )
199  case FB_DATATYPE_STRING, FB_DATATYPE_FIXSTR, FB_DATATYPE_CHAR
200  is_match = TRUE
201  case else
202  is_match = FALSE
203  end select
204 
205  else
206  is_match = (symbGetType( sym ) = suffix)
207 
208  end if
209 
210  if( is_match ) then
211  select case as const symbGetClass( sym )
212  case FB_SYMBCLASS_CONST
213  return cConstant( sym )
214 
215  case FB_SYMBCLASS_PROC
216  return cFunctionEx( base_parent, sym )
217 
218  case FB_SYMBCLASS_VAR
219  if( var_sym = NULL ) then
220  if( symbVarCheckAccess( sym ) ) then
221  var_sym = sym
222  end if
223  end if
224 
225  case FB_SYMBCLASS_KEYWORD
226  return cQuirkFunction( sym )
227 
228  end select
229 
230  else
231 
232  '' Special case for INPUT$()
233  if( symbGetClass( sym ) = FB_SYMBCLASS_KEYWORD ) then
234  if( sym->key.id = FB_TK_INPUT ) then
235 
236  if( suffix = FB_DATATYPE_STRING ) then
237  return cQuirkFunction( sym )
238  end if
239 
240  end if
241 
242  end if
243 
244  end if
245 
246  sym = sym->hash.next
247  loop while( sym <> NULL )
248  end if
249 
250  '' vars have the less priority than keywords and rtl procs
251  if( var_sym <> NULL ) then
252  return cVariableEx( var_sym, fbGetCheckArray( ) )
253  end if
254 
255  chain_ = symbChainGetNext( chain_ )
256  loop while( chain_ <> NULL )
257 
258  function = NULL
259 
260 end function
261 
262 '':::::
263 function hFindId _
264  ( _
265  byval base_parent as FBSYMBOL ptr, _
266  byval chain_ as FBSYMCHAIN ptr, _
267  byval options as FB_PARSEROPT = 0 _
268  ) as ASTNODE ptr
269 
270  '' QB mode?
271  if( env.clopt.lang = FB_LANG_QB ) then
272  return hFindId_QB( base_parent, chain_ )
273  end if
274 
275  do
276  dim as FBSYMBOL ptr sym = chain_->sym
277  do
278  select case as const symbGetClass( sym )
279  case FB_SYMBCLASS_CONST
280  return cConstant( sym )
281 
282  case FB_SYMBCLASS_PROC
283  return cFunctionEx( base_parent, sym, options )
284 
285  case FB_SYMBCLASS_VAR
286  return cVariableEx( chain_, fbGetCheckArray( ) )
287 
288  case FB_SYMBCLASS_FIELD
289  return cImplicitDataMember( base_parent, chain_, fbGetCheckArray( ), options )
290 
291  '' quirk-keyword?
292  case FB_SYMBCLASS_KEYWORD
293  '' BASE?
294  if( lexGetToken() = FB_TK_BASE ) then
295  return hBaseMemberAccess( )
296  else
297  return cQuirkFunction( sym )
298  end if
299 
300  case FB_SYMBCLASS_STRUCT, FB_SYMBCLASS_CLASS
301  if( symbGetCompCtorHead( sym ) ) then
302  '' skip ID, ctorCall() is also used by type<>(...)
303  lexSkipToken( )
304  return cCtorCall( sym )
305  end if
306 
307  case FB_SYMBCLASS_TYPEDEF
308  '' typedef of a TYPE/CLASS?
309  if( symbHasCtor( sym ) ) then
310  '' skip ID, ctorCall() is also used by type<>(...)
311  lexSkipToken( )
312  return cCtorCall( symbGetSubtype( sym ) )
313  end if
314 
315  end select
316 
317  sym = sym->hash.next
318  loop while( sym <> NULL )
319 
320  chain_ = symbChainGetNext( chain_ )
321  loop while( chain_ <> NULL )
322 
323  function = NULL
324 
325 end function
326 
327 '':::::
328 '' BaseMemberAccess = (BASE '.')+ ID
329 ''
330 ''
331 function hBaseMemberAccess _
332  ( _
333  _
334  ) as ASTNODE ptr
335 
336  var proc = parser.currproc
337 
338  '' not inside a method?
339  if( symbIsMethod( proc ) = FALSE ) then
340  errReport( FB_ERRMSG_ILLEGALOUTSIDEAMETHOD )
341  '' error recovery: skip stmt, return
342  hSkipStmt( )
343  return astNewCONSTi( 0 )
344  end if
345 
346  var parent = symbGetNamespace( proc )
347 
348  '' is class derived?
349  var base_ = parent->udt.base
350 
351  do
352  if( base_ = NULL ) then
353  errReport( FB_ERRMSG_CLASSNOTDERIVED )
354  '' error recovery: skip stmt, return
355  hSkipStmt( )
356  return astNewCONSTi( 0 )
357  end if
358 
359  '' skip BASE
360  lexSkipToken( LEXCHECK_NOPERIOD )
361 
362  '' skip '.'
363  lexSkipToken()
364 
365  '' (BASE '.')?
366  if( lexGetToken() <> FB_TK_BASE ) then
367  exit do
368  end if
369 
370  '' '.'
371  if( lexGetLookAhead( 1 ) <> CHAR_DOT ) then
372  errReport( FB_ERRMSG_EXPECTEDPERIOD )
373  '' error recovery: skip stmt, return
374  hSkipStmt( )
375  return astNewCONSTi( 0 )
376  end if
377 
378  base_ = symbGetSubtype( base_ )->udt.base
379  loop
380 
381  dim as FBSYMCHAIN chain_ = (base_, NULL, FALSE)
382  function = hFindId( symbGetSubtype( base_ ), @chain_, FB_PARSEROPT_EXPLICITBASE )
383 end function
384 
385 function hCheckId _
386  ( _
387  byval base_parent as FBSYMBOL ptr, _
388  byval chain_ as FBSYMCHAIN ptr _
389  ) as ASTNODE ptr
390 
391  dim as ASTNODE ptr expr = any
392 
393  '' declared id?
394  if( chain_ <> NULL ) then
395  expr = hFindId( base_parent, chain_ )
396  if( expr ) then
397  return expr
398  end if
399  end if
400 
401  '' Undeclared identifiers in PP expressions are upper-cased and then
402  '' turned into string literals, allowing them to be compared
403  if( fbGetIsPP( ) ) then
404  expr = astNewCONSTstr( ucase( *lexGetText( ) ) )
405  lexSkipToken( )
406  return expr
407  end if
408 
409  '' try to alloc an implicit variable..
410  if( env.clopt.lang <> FB_LANG_QB ) then
411  if( lexGetClass( ) <> FB_TKCLASS_IDENTIFIER ) then
412  return NULL
413  end if
414  end if
415 
416  if( fbLangOptIsSet( FB_LANG_OPT_IMPLICIT = FALSE ) ) then
417  errReportNotAllowed( FB_LANG_OPT_IMPLICIT, _
418  FB_ERRMSG_IMPLICITVARSONLYVALIDINLANG )
419  return NULL
420  end if
421 
422  return cVariableEx( cast( FBSYMCHAIN ptr, NULL ), fbGetCheckArray( ) )
423 end function
424 
425 '' Atom = Constant | Function | QuirkFunction | Variable | Literal .
426 function cAtom _
427  ( _
428  byval base_parent as FBSYMBOL ptr, _
429  byval chain_ as FBSYMCHAIN ptr _
430  ) as ASTNODE ptr
431 
432  dim as integer tk_class = any
433 
434  if( chain_ = NULL ) then
435  tk_class = lexGetClass( )
436  else
437  tk_class = FB_TKCLASS_IDENTIFIER
438  end if
439 
440  select case as const tk_class
441  case FB_TKCLASS_IDENTIFIER, FB_TKCLASS_QUIRKWD, FB_TKCLASS_KEYWORD
442  if( chain_ = NULL ) then
443  chain_ = cIdentifier( base_parent, FB_IDOPT_DEFAULT or FB_IDOPT_ALLOWSTRUCT )
444  end if
445 
446  return hCheckId( base_parent, chain_ )
447 
448  case FB_TKCLASS_OPERATOR
449  '' QB quirks..
450  if( env.clopt.lang = FB_LANG_QB ) then
451  return hCheckId( base_parent, lexGetSymChain( ) )
452  end if
453 
454  case FB_TKCLASS_NUMLITERAL
455  return cNumLiteral( )
456 
457  case FB_TKCLASS_STRLITERAL
458  return cStrLiteral( )
459 
460  case FB_TKCLASS_DELIMITER
461  '' '.'?
462  if( lexGetToken( ) <> CHAR_DOT ) then
463  return FALSE
464  end if
465 
466  '' inside a WITH block?
467  if( parser.stmt.with.sym <> NULL ) then
468  '' not '..'?
469  if( lexGetLookAhead( 1, LEXCHECK_NOPERIOD ) <> CHAR_DOT ) then
470  return cWithVariable( fbGetCheckArray( ) )
471  end if
472  end if
473 
474  '' global namespace access..
475  chain_ = cIdentifier( base_parent, FB_IDOPT_DEFAULT or FB_IDOPT_ALLOWSTRUCT )
476  if( chain_ <> NULL ) then
477  return hFindId( base_parent, chain_ )
478  end if
479 
480  end select
481 
482  function = NULL
483 end function
484