FreeBASIC  0.91.0
parser-assignment.bas
Go to the documentation of this file.
1 '' assignments (including LET) or function-pointer calls (foo()) 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 '':::::
13 
14  listInit( @parser.stmt.let.list, 16, len( FB_LETSTMT_NODE ) )
15 
16 end sub
17 
18 '':::::
20 
21  listEnd( @parser.stmt.let.list )
22 
23 end sub
24 
25 function hIsAssignToken( ) as integer
26  select case( lexGetToken( ) )
27  case FB_TK_ASSIGN, FB_TK_DBLEQ
28  function = TRUE
29  case else
30  function = FALSE
31  end select
32 end function
33 
34 function cAssignToken( ) as integer
35  if( hIsAssignToken( ) ) then
36  lexSkipToken( )
37  function = TRUE
38  else
39  function = FALSE
40  end if
41 end function
42 
43 function cOperator( byval is_overload as integer ) as integer
44  dim as integer op = any, tk = any
45 
46  function = INVALID
47  op = INVALID
48 
49  tk = lexGetToken( )
50  select case as const( tk )
51  case FB_TK_AND : op = AST_OP_AND
52  case FB_TK_OR : op = AST_OP_OR
53  case FB_TK_ANDALSO : op = AST_OP_ANDALSO
54  case FB_TK_ORELSE : op = AST_OP_ORELSE
55  case FB_TK_XOR : op = AST_OP_XOR
56  case FB_TK_EQV : op = AST_OP_EQV
57  case FB_TK_IMP : op = AST_OP_IMP
58  case FB_TK_SHL : op = AST_OP_SHL
59  case FB_TK_SHR : op = AST_OP_SHR
60  case FB_TK_MOD : op = AST_OP_MOD
61  case CHAR_PLUS : op = AST_OP_ADD
62  case CHAR_MINUS : op = AST_OP_SUB
63  case CHAR_RSLASH : op = AST_OP_INTDIV
64  case CHAR_TIMES : op = AST_OP_MUL
65  case CHAR_SLASH : op = AST_OP_DIV
66  case CHAR_CART : op = AST_OP_POW
67  case CHAR_AMP : op = AST_OP_CONCAT
68  case FB_TK_EQ, FB_TK_GT, FB_TK_LT, FB_TK_NE, FB_TK_LE, FB_TK_GE, _
69  FB_TK_LET, FB_TK_NOT, FB_TK_CAST, _
70  FB_TK_ABS, FB_TK_SGN, FB_TK_FIX, FB_TK_FRAC, _
71  FB_TK_INT, FB_TK_EXP, FB_TK_LOG, FB_TK_SIN, _
72  FB_TK_ASIN, FB_TK_COS, FB_TK_ACOS, FB_TK_TAN, _
73  FB_TK_ATN, _
74  FB_TK_ADDROFCHAR, FB_TK_FIELDDEREF, CHAR_LBRACKET, _
75  FB_TK_NEW, FB_TK_DELETE, _
76  FB_TK_FOR, FB_TK_STEP, FB_TK_NEXT
77 
78  if( is_overload = FALSE ) then
79  exit function
80  end if
81 
82  lexSkipToken( )
83 
84  select case as const( tk )
85  case FB_TK_EQ : op = AST_OP_EQ
86  case FB_TK_GT : op = AST_OP_GT
87  case FB_TK_LT : op = AST_OP_LT
88  case FB_TK_NE : op = AST_OP_NE
89  case FB_TK_LE : op = AST_OP_LE
90  case FB_TK_GE : op = AST_OP_GE
91  case FB_TK_LET : op = AST_OP_ASSIGN
92  case FB_TK_NOT : op = AST_OP_NOT
93  case FB_TK_CAST : op = AST_OP_CAST
94  case FB_TK_ABS : op = AST_OP_ABS
95  case FB_TK_SGN : op = AST_OP_SGN
96  case FB_TK_FIX : op = AST_OP_FIX
97  case FB_TK_FRAC : op = AST_OP_FRAC
98  case FB_TK_INT : op = AST_OP_FLOOR
99  case FB_TK_EXP : op = AST_OP_EXP
100  case FB_TK_LOG : op = AST_OP_LOG
101  case FB_TK_SIN : op = AST_OP_SIN
102  case FB_TK_ASIN : op = AST_OP_ASIN
103  case FB_TK_COS : op = AST_OP_COS
104  case FB_TK_ACOS : op = AST_OP_ACOS
105  case FB_TK_TAN : op = AST_OP_TAN
106  case FB_TK_ATN : op = AST_OP_ATAN
107  case FB_TK_ADDROFCHAR : op = AST_OP_ADDROF
108  case FB_TK_FIELDDEREF : op = AST_OP_FLDDEREF
109  case CHAR_LBRACKET '' '['
110  '' ']'
111  if( hMatch( CHAR_RBRACKET ) = FALSE ) then
112  errReport( FB_ERRMSG_EXPECTEDRBRACKET )
113  end if
114 
115  op = AST_OP_PTRINDEX
116 
117  case FB_TK_NEW, FB_TK_DELETE
118  dim as integer is_new = (tk = FB_TK_NEW)
119 
120  '' '['?
121  if( hMatch( CHAR_LBRACKET ) ) then
122  '' ']'
123  if( hMatch( CHAR_RBRACKET ) = FALSE ) then
124  errReport( FB_ERRMSG_EXPECTEDRBRACKET )
125  end if
126 
127  op = iif( is_new, AST_OP_NEW_VEC_SELF, AST_OP_DEL_VEC_SELF )
128  else
129  op = iif( is_new, AST_OP_NEW_SELF, AST_OP_DEL_SELF )
130  end if
131 
132  case FB_TK_FOR : op = AST_OP_FOR
133  case FB_TK_STEP : op = AST_OP_STEP
134  case FB_TK_NEXT : op = AST_OP_NEXT
135  case else
136  assert( FALSE )
137  end select
138 
139  return op
140  case else
141  exit function
142  end select
143 
144  lexSkipToken( )
145 
146  if( is_overload = FALSE ) then
147  return op
148  end if
149 
150  '' '='?
151  if( cAssignToken( ) ) then
152  '' get the self version
153  op = astGetOpSelfVer( op )
154  end if
155 
156  function = op
157 end function
158 
159 sub cAssignment( byval l as ASTNODE ptr )
160  if( astIsConstant( l ) ) then
161  errReport( FB_ERRMSG_CONSTANTCANTBECHANGED, TRUE )
162  end if
163 
164  '' '='?
165  dim as integer op = INVALID
166  if( hIsAssignToken( ) = FALSE ) then
167  '' BOP?
168  op = cOperator( FALSE )
169 
170  '' '='?
171  if( hIsAssignToken( ) = FALSE ) then
172  errReport( FB_ERRMSG_EXPECTEDEQ )
173  '' error recovery: skip stmt
174  hSkipStmt( )
175  return
176  end if
177 
178  '' get the self version
179  op = astGetOpSelfVer( op )
180  end if
181 
182  '' '='
183  lexSkipToken( )
184 
185  '' set the context symbol to allow taking the address of overloaded
186  '' procs and also to allow anonymous UDT's
187  parser.ctxsym = astGetSubType( l )
188  parser.ctx_dtype = astGetDataType( l )
189 
190  '' Expression
191  dim as ASTNODE ptr r = cExpression( )
192  if( r = NULL ) then
193  errReport( FB_ERRMSG_EXPECTEDEXPRESSION )
194  '' error recovery: skip until next stmt
195  hSkipStmt( )
196  return
197  end if
198 
199  parser.ctxsym = NULL
200  parser.ctx_dtype = FB_DATATYPE_INVALID
201 
202  '' BOP?
203  if( op <> INVALID ) then
204  '' l op= r
205  l = astNewSelfBOP( op, l, r, NULL, AST_OPOPT_LPTRARITH )
206  if (l) then
207  astAdd(l)
208  else
209  errReport( FB_ERRMSG_TYPEMISMATCH, TRUE )
210  end if
211  else
212  '' l = r
213  l = astNewASSIGN( l, r )
214  if (l) then
215  astAdd(l)
216  else
217  errReport( FB_ERRMSG_ILLEGALASSIGNMENT, TRUE )
218  end if
219  end if
220 end sub
221 
222 '':::::
223 function cAssignmentOrPtrCallEx _
224  ( _
225  byval expr as ASTNODE ptr _
226  ) as integer
227 
228  function = FALSE
229 
230  if( cCompStmtIsAllowed( FB_CMPSTMT_MASK_CODE ) = FALSE ) then
231  hSkipStmt( )
232  exit function
233  end if
234 
235  '' calling a SUB ptr?
236  if( expr = NULL ) then
237  return TRUE
238  end if
239 
240  '' skip any casting if they won't do any conversion
241  dim as ASTNODE ptr t = expr
242  if( astIsCAST( expr ) ) then
243  if( astGetCASTDoConv( expr ) = FALSE ) then
244  t = astGetLeft( expr )
245  end if
246  end if
247 
248  '' ordinary assignment?
249  if( astIsCALL( t ) = FALSE ) then
250  cAssignment( expr )
251  return TRUE
252  end if
253 
254  '' calling a function ptr..
255 
256  '' can the result be skipped?
257  if( typeGetClass( astGetDataType( t ) ) <> FB_DATACLASS_INTEGER ) then
258  errReport( FB_ERRMSG_VARIABLEREQUIRED )
259  '' error recovery: skip call
260  astDelTree( expr )
261  return TRUE
262 
263  '' CHAR and WCHAR literals are also from the INTEGER class
264  else
265  select case astGetDataType( t )
266  case FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR
267  errReport( FB_ERRMSG_VARIABLEREQUIRED )
268  '' error recovery: skip call
269  astDelTree( expr )
270  return TRUE
271  end select
272  end if
273 
274  '' flush the call
275  if( expr <> NULL ) then
276  astAdd( expr )
277  end if
278 
279  function = TRUE
280 
281 end function
282 
283 '':::::
284 function hCard2Ord _
285  ( _
286  byval num as integer _
287  ) as const zstring ptr
288 
289  select case num
290  case 1
291  return @"1st"
292  case 2
293  return @"2nd"
294  case 3
295  return @"3rd"
296  case else
297  static as string tmp
298  tmp = str( num ) + "th"
299  return strptr( tmp )
300  end select
301 
302 end function
303 
304 sub hReportLetError(byval errnum as integer, byval elmnum as integer)
305  errReportEx( errnum, "at the " + *hCard2Ord( elmnum ) + " element of LET()" )
306 end sub
307 
308 '':::::
309 function hAssignFromField _
310  ( _
311  byval fld as FBSYMBOL ptr, _
312  byval lhs as ASTNODE ptr, _
313  byval rhs as FBSYMBOL ptr, _
314  byval num as integer _
315  ) as ASTNODE ptr
316 
317  '' data member?
318  if( symbIsField( fld ) = FALSE ) then
319  hReportLetError( FB_ERRMSG_NOTADATAMEMBER, num )
320  '' error recovery
321  astDelTree( lhs )
322  return astNewNOP( )
323  end if
324 
325  '' check visibility
326  if( symbCheckAccess( fld ) = FALSE ) then
327  hReportLetError( FB_ERRMSG_ILLEGALMEMBERACCESS, num )
328  '' error recovery
329  astDelTree( lhs )
330  return astNewNOP()
331  end if
332 
333  if( symbGetArrayDimensions( fld ) <> 0 ) then
334  hReportLetError( FB_ERRMSG_ARRAYSNOTALLOWED, num )
335  '' error recovery
336  astDelTree( lhs )
337  return astNewNOP()
338  end if
339 
340  '' build field access
341  dim as ASTNODE ptr expr = any
342  expr = astNewVAR( rhs )
343  expr = astNewBOP( AST_OP_ADD, expr, astNewCONSTi( symbGetOfs( fld ) ) )
344  expr = astNewDEREF( expr, symbGetFullType( fld ), symbGetSubType( fld ) )
345  expr = astNewFIELD( expr, fld )
346 
347  expr = astNewASSIGN( lhs, expr )
348  if( expr = NULL ) then
349  hReportLetError( FB_ERRMSG_ILLEGALASSIGNMENT, num )
350  '' error recovery
351  return astNewNOP()
352  end if
353 
354  function = expr
355 
356 end function
357 
358 '':::::
359 ''Assignment = LET? Variable BOP? '=' Expression
360 '' | Variable{function ptr} '(' ProcParamList ')' .
361 ''
362 function cAssignmentOrPtrCall _
363  ( _
364  _
365  ) as integer
366 
367  dim as integer ismult = FALSE
368  dim as ASTNODE ptr expr = any
369  dim as FBSYMBOL ptr fld = any
370 
371  function = FALSE
372 
373  '' not LET?
374  if( lexGetToken( ) <> FB_TK_LET ) then
375  '' Variable
376  expr = cVarOrDeref( )
377  if( expr = NULL ) then
378  exit function
379  end if
380 
381  return cAssignmentOrPtrCallEx( expr )
382  end if
383 
384  '' LET..
385  if( fbLangOptIsSet( FB_LANG_OPT_LET ) = FALSE ) then
386  if( lexGetLookAhead( 1 ) <> CHAR_LPRNT ) then
387  errReportNotAllowed( FB_LANG_OPT_LET )
388  else
389  ismult = TRUE
390  lexSkipToken( )
391  end if
392  end if
393 
394  if( cCompStmtIsAllowed( FB_CMPSTMT_MASK_CODE ) = FALSE ) then
395  hSkipStmt( )
396  exit function
397  end if
398 
399  lexSkipToken( )
400 
401  '' single?
402  if( ismult = FALSE ) then
403  expr = cVarOrDeref( )
404  if( expr = NULL ) then
405  errReport( FB_ERRMSG_EXPECTEDIDENTIFIER )
406  '' error recovery: skip stmt
407  hSkipStmt( )
408  else
409  cAssignment( expr )
410  end if
411  return TRUE
412  end if
413 
414  '' multiple..
415  dim as integer exprcnt = 0
416 
417  do
418  '' null expressions are allowed ('let(foo, , bar)')
419  dim as FB_LETSTMT_NODE ptr node = listNewNode( @parser.stmt.let.list )
420 
421  node->expr = cVarOrDeref( )
422  if( node->expr <> NULL ) then
423  '' const?
424  if( astIsConstant( node->expr ) ) then
425  errReport( FB_ERRMSG_CONSTANTCANTBECHANGED, TRUE )
426  end if
427 
428  exprcnt += 1
429  end if
430 
431  '' ','?
432  if( lexGetToken( ) <> CHAR_COMMA ) then
433  exit do
434  end if
435 
436  lexSkipToken( )
437  loop
438 
439  if( exprcnt = 0 ) then
440  errReport( FB_ERRMSG_EXPECTEDIDENTIFIER )
441  end if
442 
443  '' ')'?
444  if( lexGetToken( ) <> CHAR_RPRNT ) then
445  errReport( FB_ERRMSG_EXPECTEDRPRNT )
446  '' error recovery: skip until next ')'
447  hSkipUntil( CHAR_RPRNT )
448  else
449  lexSkipToken( )
450  end if
451 
452  '' '='?
453  if( cAssignToken( ) = FALSE ) then
454  errReport( FB_ERRMSG_EXPECTEDEQ )
455  '' error recovery: skip stmt
456  hSkipStmt( )
457  expr = NULL
458  else
459  '' Expression?
460  expr = cExpression( )
461  if( expr = NULL ) then
462  errReport( FB_ERRMSG_EXPECTEDEXPRESSION )
463  '' error recovery: skip until next stmt
464  hSkipStmt( )
465  end if
466  end if
467 
468  if( expr <> NULL ) then
469  select case astGetDataType( expr )
470  case FB_DATATYPE_STRUCT
471  if( symbGetUDTIsUnion( astGetSubtype( expr ) ) or _
472  symbGetUDTHasAnonUnion( astGetSubtype( expr ) ) ) then
473  errReport( FB_ERRMSG_UNIONSNOTALLOWED )
474  '' error recovery:
475  astDelTree( expr )
476  expr = NULL
477  end if
478 
479  ''case FB_DATATYPE_CLASS
480 
481  case else
482  errReport( FB_ERRMSG_INVALIDDATATYPES )
483  '' error recovery:
484  astDelTree( expr )
485  expr = NULL
486  end select
487  end if
488 
489  if( expr = NULL ) then
490  do
491  dim as FB_LETSTMT_NODE ptr node = listGetHead( @parser.stmt.let.list )
492  if( node = NULL ) then
493  exit do
494  end if
495 
496  listDelNode( @parser.stmt.let.list, node )
497  loop
498 
499  exit function
500  end if
501 
502  '' proc call?
503  if( astIsCALL( expr ) ) then
504  expr = astBuildCallResultUdt( expr )
505  end if
506 
507  dim as FBSYMBOL ptr tmp = NULL
508  dim as ASTNODE ptr tree = NULL
509 
510  if( exprcnt > 0 ) then
511  tmp = symbAddTempVar( typeAddrOf( astGetFulltype( expr ) ), astGetSubtype( expr ) )
512  '' tmp = @expr
513  tree = astBuildVarAssign( tmp, astNewADDROF( expr ) )
514  end if
515 
516  fld = symbUdtGetFirstField( astGetSubtype( expr ) )
517  exprcnt = 0
518  do
519  dim as FB_LETSTMT_NODE ptr node = listGetHead( @parser.stmt.let.list )
520  if( node = NULL ) then
521  exit do
522  end if
523 
524  '' EOL?
525  if( fld = NULL ) then
526  errReport( FB_ERRMSG_TOOMANYELEMENTS )
527  else
528  exprcnt += 1
529 
530  if( node->expr <> NULL ) then
531  expr = hAssignFromField( fld, node->expr, tmp, exprcnt )
532  if( expr = NULL ) then
533  exit function
534  end if
535 
536  tree = astNewLINK( tree, expr )
537  end if
538 
539  fld = symbUdtGetNextField( fld )
540  end if
541 
542  listDelNode( @parser.stmt.let.list, node )
543  loop
544 
545  '' must add the tree at once because the temporary results
546  '' that may need to be destroyed
547  astAdd( tree )
548 
549  function = TRUE
550 end function
551