FreeBASIC  0.91.0
parser-decl-struct.bas
Go to the documentation of this file.
1 '' structures (TYPE or UNION) declarations
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 sub hTypeBody( byval s as FBSYMBOL ptr )
12 
13 declare sub hPatchByvalParamsToSelf _
14  ( _
15  byval parent as FBSYMBOL ptr _
16  )
17 
18 declare sub hPatchByvalResultToSelf _
19  ( _
20  byval parent as FBSYMBOL ptr _
21  )
22 
23 sub hBeginNesting( byval parent as FBSYMBOL ptr )
24  if( symbGetIsUnique( parent ) = FALSE ) then
25  '' must be unique
26  symbSetIsUnique( parent )
27 
28  '' start nesting
29  symbNestBegin( parent, FALSE )
30  end if
31 end sub
32 
33 ''
34 '' TypeProtoDecl =
35 '' DECLARE
36 '' (STATIC?
37 '' | CONST? (VIRTUAL|ABSTRACT)?)
38 '' (CONSTRUCTOR|DESTRUCTOR CtorHeader
39 '' | OPERATOR OperatorHeader
40 '' | PROPERTY PropertyHeader
41 '' | SUB|FUNCTION ProcHeader)
42 '' .
43 ''
44 sub hTypeProtoDecl _
45  ( _
46  byval parent as FBSYMBOL ptr, _
47  byval attrib as FB_SYMBATTRIB _
48  )
49 
50  dim as integer is_nested = any, tk = any
51 
52  '' anon?
53  if( symbGetUDTIsAnon( parent ) ) then
54  errReport( FB_ERRMSG_METHODINANONUDT )
55  '' error recovery: skip stmt
56  hSkipStmt( )
57  exit sub
58  end if
59 
60  '' methods not allowed?
61  if( fbLangOptIsSet( FB_LANG_OPT_CLASS ) = FALSE ) then
62  errReportNotAllowed( FB_LANG_OPT_CLASS )
63  end if
64 
66 
67  '' DECLARE
68  lexSkipToken( )
69 
70  cMethodAttributes( parent, attrib )
71 
72  tk = lexGetToken( )
73  select case( tk )
74  case FB_TK_CONSTRUCTOR
75  hDisallowStaticAttrib( attrib )
76  hDisallowVirtualCtor( attrib )
77  hDisallowConstCtorDtor( tk, attrib )
78  case FB_TK_DESTRUCTOR
79  hDisallowStaticAttrib( attrib )
80  hDisallowAbstractDtor( attrib )
81  hDisallowConstCtorDtor( tk, attrib )
82  case FB_TK_PROPERTY
83  hDisallowStaticAttrib( attrib )
84  end select
85 
86  select case( tk )
87  case FB_TK_SUB, FB_TK_FUNCTION, _
88  FB_TK_CONSTRUCTOR, FB_TK_DESTRUCTOR, _
89  FB_TK_OPERATOR, FB_TK_PROPERTY
90  lexSkipToken( )
91 
92  cProcHeader( attrib, is_nested, _
93  FB_PROCOPT_ISPROTO or FB_PROCOPT_HASPARENT, tk )
94 
95  case else
96  errReport( FB_ERRMSG_SYNTAXERROR )
97  '' error recovery: skip stmt
98  hSkipStmt( )
99  end select
100 end sub
101 
102 '' TypeEnumDecl = ENUM|CONST ...
103 sub hTypeEnumDecl _
104  ( _
105  byval parent as FBSYMBOL ptr, _
106  byval tk as integer, _
107  byval attrib as integer _
108  )
109 
110  '' anon?
111  if( symbGetUDTIsAnon( parent ) ) then
112  errReport( FB_ERRMSG_CONSTINANONUDT )
113  '' error recovery: skip stmt
114  hSkipStmt( )
115  exit sub
116  end if
117 
119 
120  if( tk = FB_TK_CONST ) then
121  cConstDecl( attrib )
122  else
123  cEnumDecl( attrib )
124  end if
125 end sub
126 
127 '':::::
128 sub hFieldInit( byval parent as FBSYMBOL ptr, byval sym as FBSYMBOL ptr )
129  dim as FBSYMBOL ptr defctor = any, subtype = any
130 
131  '' '=' | '=>' ?
132  if( hIsAssignToken( ) = FALSE ) then
133  '' No initializer
134 
135  '' Check ctors/dtors
136  if( sym ) then
137  if( symbGetType( sym ) = FB_DATATYPE_STRUCT ) then
138  subtype = symbGetSubtype( sym )
139 
140  '' Does it have any constructors? (Then we must call one to initialize this field)
141  if( symbGetCompCtorHead( subtype ) ) then
142  '' Does it have a default constructor?
143  defctor = symbGetCompDefCtor( subtype )
144  if( defctor ) then
145  '' Check whether we have access
146  if( symbCheckAccess( defctor ) = FALSE ) then
147  errReport( FB_ERRMSG_NOACCESSTODEFAULTCTOR )
148  end if
149  else
150  '' It has constructors, but no default one -- we cannot initialize it
151  errReport( FB_ERRMSG_NODEFAULTCTORDEFINED )
152  end if
153  end if
154 
155  '' Does it have a destructor?
156  defctor = symbGetCompDtor( subtype )
157  if( defctor ) then
158  '' Check whether we have access
159  if( symbCheckAccess( defctor ) = FALSE ) then
160  errReport( FB_ERRMSG_NOACCESSTODTOR )
161  end if
162  end if
163  end if
164  end if
165 
166  exit sub
167  end if
168 
169  if( fbLangOptIsSet( FB_LANG_OPT_INITIALIZER ) = FALSE ) then
170  errReportNotAllowed( FB_LANG_OPT_INITIALIZER )
171  '' error recovery: skip
172  hSkipUntil( FB_TK_EOL )
173  exit sub
174  end if
175 
176  if( sym <> NULL ) then
177  '' union or anon?
178  if( symbGetUDTIsUnionOrAnon( parent ) ) then
179  errReport( FB_ERRMSG_CTORINUNION )
180  '' error recovery: skip
181  hSkipUntil( FB_TK_EOL )
182  exit sub
183  end if
184  end if
185 
186  lexSkipToken( )
187 
188  if( sym = NULL ) then
189  '' error recovery: skip stmt
190  hSkipStmt( )
191  exit sub
192  end if
193 
194  '' Field initializers are only used in constructors (replacing the
195  '' implicit default initialization), so we make sure to add a default
196  '' constructor, if no constructor was specified.
197  symbSetUDTHasInitedField( parent )
198 
199  '' ANY?
200  if( lexGetToken( ) = FB_TK_ANY ) then
201  '' don't allow var-len strings
202  if( symbGetType( sym ) = FB_DATATYPE_STRING ) then
203  errReport( FB_ERRMSG_INVALIDDATATYPES )
204  else
205  symbSetDontInit( sym )
206  end if
207 
208  lexSkipToken( )
209  exit sub
210  end if
211 
213 
214  dim as ASTNODE ptr initree = cInitializer( sym, FB_INIOPT_ISINI )
215  if( initree ) then
216  '' Disallow references to local vars, except for temp vars/descriptors
217  if( astTypeIniUsesLocals( initree, FB_SYMBATTRIB_TEMP or FB_SYMBATTRIB_DESCRIPTOR ) ) then
218  errReport( FB_ERRMSG_INVALIDREFERENCETOLOCAL, TRUE )
219  '' error recovery
220  astDelTree( initree )
221  initree = NULL
222  end if
223  end if
224 
225  '' No temp dtors should be left registered after the TYPEINI build-up
226  assert( astDtorListIsEmpty( ) )
227 
228  '' Remove bitfields from the AST's bitfield counter - the field
229  '' initializer will never be astAdd()ed itself, only cloned.
230  astForgetBitfields( initree )
231 
232  if( initree ) then
233  symbSetTypeIniTree( sym, initree )
234  end if
235 end sub
236 
237 '':::::
238 ''TypeMultElementDecl = AS SymbolType ID (ArrayDecl | ':' NUMLIT)? ('=' Expression)?
239 '' (',' ID (ArrayDecl | ':' NUMLIT)? ('=' Expression)?)*
240 ''
242  ( _
243  byval parent as FBSYMBOL ptr, _
244  byval attrib as integer _
245  ) static
246 
247  static as zstring * FB_MAXNAMELEN+1 id
248  static as FBARRAYDIM dTB(0 to FB_MAXARRAYDIMS-1)
249  dim as FBSYMBOL ptr sym, subtype
250  dim as integer dims, dtype, bits
251  dim as longint lgt
252 
253  '' SymbolType
254  hSymbolType( dtype, subtype, lgt )
255 
256  '' Disallow creating objects of abstract classes
257  hComplainIfAbstractClass( dtype, subtype )
258 
259  do
260  '' allow keywords as field names
261  select case as const lexGetClass( )
262  case FB_TKCLASS_IDENTIFIER, FB_TKCLASS_KEYWORD, FB_TKCLASS_QUIRKWD
263  '' contains a period?
264  if( lexGetPeriodPos( ) > 0 ) then
265  errReport( FB_ERRMSG_CANTINCLUDEPERIODS )
266  end if
267 
268  '' but don't allow keywords if it's an object (because the implicit inst. ptr)
269  if( lexGetClass( ) = FB_TKCLASS_KEYWORD ) then
270  if( symbGetIsUnique( parent ) ) then
271  errReport( FB_ERRMSG_KEYWORDFIELDSNOTALLOWEDINCLASSES )
272  else
273  symbSetUDTHasKwdField( parent )
274  end if
275  end if
276 
277  id = *lexGetText( )
278  lexSkipToken( )
279 
280  case else
281  errReport( FB_ERRMSG_EXPECTEDIDENTIFIER )
282  '' error recovery: fake an id
283  id = *symbUniqueLabel( )
284  end select
285 
286  bits = 0
287 
288  '' ArrayDecl?
289  if( cStaticArrayDecl( dims, dTB(), , FALSE ) = FALSE ) then
290  '' ':' NUMLIT?
291  if( lexGetToken( ) = FB_TK_STMTSEP ) then
292  if( lexGetLookAheadClass( 1 ) = FB_TKCLASS_NUMLITERAL ) then
293  lexSkipToken( )
294  bits = valint( *lexGetText( ) )
295  lexSkipToken( )
296 
297  if( symbCheckBitField( parent, dtype, lgt, bits ) = FALSE ) then
298  errReport( FB_ERRMSG_INVALIDBITFIELD, TRUE )
299  '' error recovery: no bits
300  bits = 0
301  end if
302  end if
303  end if
304  end if
305 
306  '' array?
307  if( dims > 0 ) then
308  '' "array too big" check
309  if( symbCheckArraySize( dims, dTB(), lgt, FALSE, FALSE ) = FALSE ) then
310  errReport( FB_ERRMSG_ARRAYTOOBIG )
311  '' error recovery: use small array
312  dims = 1
313  dTB(0).lower = 0
314  dTB(0).upper = 0
315  end if
316  end if
317 
318  '' ref to self?
319  if( typeGet( dtype ) = FB_DATATYPE_STRUCT ) then
320  if( subtype = parent ) then
321  errReport( FB_ERRMSG_RECURSIVEUDT )
322  '' error recovery: fake type
323  dtype = FB_DATATYPE_INTEGER
324  subtype = NULL
325  lgt = 0
326  end if
327  end if
328 
329  ''
330  sym = symbAddField( parent, @id, _
331  dims, dTB(), _
332  dtype, subtype, _
333  lgt, bits )
334  if( sym = NULL ) then
335  errReportEx( FB_ERRMSG_DUPDEFINITION, id )
336  else
337  symbGetAttrib( sym ) or= attrib
338  hFieldInit( parent, sym )
339  end if
340 
341  '' ','?
342  if( lexGetToken( ) <> CHAR_COMMA ) then
343  exit do
344  end if
345 
346  lexSkipToken( )
347  loop
348 end sub
349 
350 '':::::
351 '' TypeElementDecl = ID (ArrayDecl| ':' NUMLIT)? AS SymbolType ('=' Expression)?
352 ''
353 sub hTypeElementDecl _
354  ( _
355  byval parent as FBSYMBOL ptr, _
356  byval attrib as integer _
357  ) static
358 
359  static as zstring * FB_MAXNAMELEN+1 id
360  static as FBARRAYDIM dTB(0 to FB_MAXARRAYDIMS-1)
361  dim as FBSYMBOL ptr sym, subtype
362  dim as integer dims, dtype, bits
363  dim as longint lgt
364 
365  '' allow keywords as field names
366  select case as const lexGetClass( )
367  case FB_TKCLASS_IDENTIFIER, FB_TKCLASS_KEYWORD, FB_TKCLASS_QUIRKWD
368 
369  '' ID
370  id = *lexGetText( )
371 
372  if( lexGetType( ) <> FB_DATATYPE_INVALID ) then
373  errReport( FB_ERRMSG_SYNTAXERROR )
374  end if
375 
376  '' contains a period?
377  if( lexGetPeriodPos( ) > 0 ) then
378  errReport( FB_ERRMSG_CANTINCLUDEPERIODS )
379  end if
380 
381  '' but don't allow keywords if it's an object (because the implicit inst. ptr)
382  if( lexGetClass( ) = FB_TKCLASS_KEYWORD ) then
383  if( symbGetIsUnique( parent ) ) then
384  errReport( FB_ERRMSG_KEYWORDFIELDSNOTALLOWEDINCLASSES )
385  else
386  symbSetUDTHasKwdField( parent )
387  end if
388  end if
389 
390  lexSkipToken( )
391 
392  case else
393  errReport( FB_ERRMSG_EXPECTEDIDENTIFIER )
394  '' error recovery: fake an id
395  id = *symbUniqueLabel( )
396  dtype = FB_DATATYPE_INVALID
397  end select
398 
399  subtype = NULL
400  bits = 0
401 
402  '' ArrayDecl?
403  if( cStaticArrayDecl( dims, dTB(), , FALSE ) = FALSE ) then
404  '' ':' NUMLIT?
405  if( lexGetToken( ) = FB_TK_STMTSEP ) then
406  if( lexGetLookAheadClass( 1 ) = FB_TKCLASS_NUMLITERAL ) then
407  lexSkipToken( )
408  bits = valint( *lexGetText( ) )
409  lexSkipToken( )
410  if( bits <= 0 ) then
411  errReport( FB_ERRMSG_SYNTAXERROR, TRUE )
412  '' error recovery: no bits
413  bits = 0
414  end if
415  end if
416  end if
417  end if
418 
419  '' AS
420  if( lexGetToken( ) <> FB_TK_AS ) then
421  errReport( FB_ERRMSG_SYNTAXERROR )
422  else
423  lexSkipToken( )
424  end if
425 
426  '' SymbolType
427  hSymbolType( dtype, subtype, lgt )
428 
429  '' Disallow creating objects of abstract classes
430  hComplainIfAbstractClass( dtype, subtype )
431 
432  '' array?
433  if( dims > 0 ) then
434  '' "array too big" check
435  if( symbCheckArraySize( dims, dTB(), lgt, FALSE, FALSE ) = FALSE ) then
436  errReport( FB_ERRMSG_ARRAYTOOBIG )
437  '' error recovery: use small array
438  dims = 1
439  dTB(0).lower = 0
440  dTB(0).upper = 0
441  end if
442  end if
443 
444  ''
445  if( bits <> 0 ) then
446  if( symbCheckBitField( parent, dtype, lgt, bits ) = FALSE ) then
447  errReport( FB_ERRMSG_INVALIDBITFIELD, TRUE )
448  '' error recovery: no bits
449  bits = 0
450  end if
451  end if
452 
453  '' ref to self?
454  if( dtype = FB_DATATYPE_STRUCT ) then
455  if( subtype = parent ) then
456  errReport( FB_ERRMSG_RECURSIVEUDT )
457  '' error recovery: fake type
458  dtype = FB_DATATYPE_INTEGER
459  subtype = NULL
460  lgt = 0
461  end if
462  end if
463 
464  ''
465  sym = symbAddField( parent, @id, _
466  dims, dTB(), _
467  dtype, subtype, _
468  lgt, bits )
469 
470  if( sym = NULL ) then
471  errReportEx( FB_ERRMSG_DUPDEFINITION, id )
472  '' error recovery: pretend the field was added
473  return
474  end if
475  sym->attrib or= attrib
476 
477  '' initializer
478  hFieldInit( parent, sym )
479 end sub
480 
481 sub hTypeStaticVarDecl _
482  ( _
483  byval parent as FBSYMBOL ptr, _
484  byval attrib as integer _
485  )
486 
487  '' Disallow Static member vars inside anonymous UDTs
488  if( symbGetUDTIsAnon( parent ) ) then
489  errReport( FB_ERRMSG_STATICVARINANONUDT )
490  '' error recovery: skip stmt
491  hSkipStmt( )
492  exit sub
493  end if
494 
495  '' The UDT becomes a "class"
497 
498  symbSetUdtHasStaticVar( parent )
499 
500  '' Static member variables are really EXTERNs,
501  '' the corresponding DIM must be present in one (and only one) module.
502  ''
503  '' This is necessary to avoid duplicating the static var in every
504  '' module that sees the UDT declaration, otherwise the static var
505  '' wouldn't be shared between different modules, and each had its own.
506  ''
507  '' Unfortunately this means the static var cannot be initialized
508  '' at its declaration in the TYPE compound, only at the DIM later.
509 
510  attrib or= FB_SYMBATTRIB_EXTERN or _
511  FB_SYMBATTRIB_SHARED or _
512  FB_SYMBATTRIB_STATIC
513 
514  cVarDecl( attrib, FALSE, FB_TK_EXTERN, FALSE )
515 
516 end sub
517 
518 function hTypeAdd _
519  ( _
520  byval parent as FBSYMBOL ptr, _
521  byval id as zstring ptr, _
522  byval id_alias as zstring ptr, _
523  byval isunion as integer, _
524  byval align as integer, _
525  byval baseSubtype as FBSYMBOL ptr = NULL _
526  ) as FBSYMBOL ptr
527 
528  dim as FBSYMBOL ptr s = any
529 
530  s = symbStructBegin( NULL, parent, id, id_alias, isunion, align, baseSubtype, 0 )
531  if( s = NULL ) then
532  errReportEx( FB_ERRMSG_DUPDEFINITION, id )
533  '' error recovery: create a fake symbol
534  s = symbStructBegin( NULL, parent, symbUniqueLabel( ), NULL, isunion, align, NULL, 0 )
535  end if
536 
537  '' Comment? SttSeparator
538  cComment( )
539 
540  '' emit the current line in text form
541  hEmitCurrLine( )
542 
543  if( cStmtSeparator( ) = FALSE ) then
544  errReport( FB_ERRMSG_SYNTAXERROR )
545  '' error recovery: skip until next line or stmt
546  hSkipUntil( INVALID, TRUE )
547  end if
548 
549  '' TypeBody
550  hTypeBody( s )
551 
552  '' finalize
553  symbStructEnd( s, symbGetIsUnique( s ) )
554 
555  '' END TYPE|UNION
556  if( lexGetToken( ) <> FB_TK_END ) then
557  errReport( FB_ERRMSG_EXPECTEDENDTYPE )
558  '' error recovery: skip until next stmt
559  hSkipStmt( )
560  else
561  lexSkipToken( )
562 
563  if( lexGetToken( ) <> iif( isunion, FB_TK_UNION, FB_TK_TYPE ) ) then
564  errReport( FB_ERRMSG_EXPECTEDENDTYPE )
565  '' error recovery: skip until next stmt
566  hSkipStmt( )
567  else
568  lexSkipToken( )
569  end if
570  end if
571 
572  function = s
573 end function
574 
575 '' [FIELD '=' ConstExpression]
576 function cFieldAlignmentAttribute( ) as integer
577  '' FIELD
578  if( lexGetToken( ) <> FB_TK_FIELD ) then
579  return 0
580  end if
581 
582  lexSkipToken( )
583 
584  '' '='
585  if( cAssignToken( ) = FALSE ) then
586  errReport( FB_ERRMSG_SYNTAXERROR )
587  end if
588 
589  '' ConstExpression
590  dim as ASTNODE ptr expr = cExpression( )
591  if( expr = NULL ) then
592  errReport( FB_ERRMSG_EXPECTEDEXPRESSION )
593  '' error recovery: fake an expr
594  expr = astNewCONSTi( 0 )
595  end if
596 
597  if( astIsCONST( expr ) = FALSE ) then
598  errReport( FB_ERRMSG_EXPECTEDCONST )
599  '' error recovery: fake an expr
600  astDelTree( expr )
601  expr = astNewCONSTi( 0 )
602  end if
603 
604  '' follow the GCC 3.x ABI
605  var align = astConstFlushToInt( expr )
606  if( align < 0 ) then
607  align = 0
608  elseif( align > env.pointersize ) then
609  align = 0
610  elseif( align = 3 ) then
611  align = 2
612  end if
613 
614  function = align
615 end function
616 
617 '' TypeBody =
618 '' ( (UNION|TYPE Comment? SttSeparator
619 '' ElementDecl
620 '' END UNION|TYPE)
621 '' | ElementDecl
622 '' | AS AsElementDecl )+ .
623 ''
624 sub hTypeBody( byval s as FBSYMBOL ptr )
625  dim as integer isunion = any
626  dim as FB_SYMBATTRIB attrib = any
627  dim as FBSYMBOL ptr inner = any
628 
629  attrib = FB_SYMBATTRIB_NONE '' Used to hold visibility attributes
630 
631  do
632  select case as const lexGetToken( )
633  '' visibility?
634  case FB_TK_PRIVATE, FB_TK_PUBLIC, FB_TK_PROTECTED
635  if( symbGetUDTIsUnion( s ) ) then
636  errReport( FB_ERRMSG_SYNTAXERROR )
637  end if
638 
639  select case lexGetToken( )
640  case FB_TK_PUBLIC
641  attrib = FB_SYMBATTRIB_NONE
642  case FB_TK_PRIVATE
643  attrib = FB_SYMBATTRIB_VIS_PRIVATE
644  case FB_TK_PROTECTED
645  attrib = FB_SYMBATTRIB_VIS_PROTECTED
646  end select
647 
648  lexSkipToken( )
649 
650  '' ':'
651  if( lexGetToken( ) <> FB_TK_STMTSEP ) then
652  errReport( FB_ERRMSG_EXPECTEDSTMTSEP )
653  end if
654 
655  '' ':' will be skipped bellow to allow stmt separators
656 
657  '' single-line comment?
658  case FB_TK_COMMENT, FB_TK_REM
659  cComment( )
660 
661  '' newline?
662  case FB_TK_EOL
663  lexSkipToken( )
664  continue do
665 
666  '' EOF?
667  case FB_TK_EOF
668  exit do
669 
670  '' END?
671  case FB_TK_END
672  '' isn't it a field called "end"?
673  select case lexGetLookAhead( 1 )
674  case FB_TK_AS, CHAR_LPRNT, FB_TK_STMTSEP
675  hTypeElementDecl( s, attrib )
676 
677  '' it's not a field, exit
678  case else
679  exit do
680 
681  end select
682 
683  '' (TYPE|UNION)?
684  case FB_TK_TYPE, FB_TK_UNION
685  '' isn't it a field called TYPE|UNION?
686  select case as const lexGetLookAhead( 1 )
687  case FB_TK_EOL, FB_TK_EOF, FB_TK_COMMENT, FB_TK_REM, _
688  FB_TK_FIELD
689 
690 decl_inner: '' it's an anonymous inner UDT
691  isunion = lexGetToken( ) = FB_TK_UNION
692  if( symbGetUDTIsUnion( s ) = isunion ) then
693  errReport( FB_ERRMSG_SYNTAXERROR )
694  '' error recovery: fake type
695  isunion = not isunion
696  end if
697 
698  lexSkipToken( )
699 
700  '' [FIELD '=' ConstExpression]
701  dim as integer align = cFieldAlignmentAttribute( )
702  if( align = 0 ) then
703  align = symbGetUDTAlign( s )
704  end if
705 
706  '' create a "temp" one
707  inner = hTypeAdd( s, symbUniqueId( ), NULL, isunion, align )
708 
709  if( isunion ) then
710  symbSetUDTIsUnion( inner )
711  symbSetUDTHasAnonUnion( s )
712  end if
713 
714  '' walk through all the anon UDT's symbols, and
715  '' promote their attributes from the root
716  dim as FBSYMBOL ptr walkSymbols = symbGetUDTSymbTbHead( inner )
717  do while( walkSymbols <> NULL )
718  symbGetAttrib( walkSymbols ) or= attrib
719  walkSymbols = symbGetNext( walkSymbols )
720  loop
721 
722  '' insert it into the parent UDT
723  symbInsertInnerUDT( s, inner )
724 
725  '' ambiguity: can be a stmt separator or bitfield
726  case FB_TK_STMTSEP
727  '' not a bitfield? separator..
728  if( lexGetLookAheadClass( 2 ) <> FB_TKCLASS_NUMLITERAL ) then
729  goto decl_inner
730  end if
731 
732  '' bitfield..
733  hTypeElementDecl( s, attrib )
734 
735  '' it's a field, parse it
736  case else
737  hTypeElementDecl( s, attrib )
738 
739  end select
740 
741  '' AS?
742  case FB_TK_AS
743  '' it's a multi-declaration
744  lexSkipToken( )
745  hTypeMultElementDecl( s, attrib )
746 
747  case FB_TK_DECLARE
748  hTypeProtoDecl( s, attrib )
749 
750  case FB_TK_ENUM, FB_TK_CONST
751  hTypeEnumDecl( s, lexGetToken( ), attrib )
752 
753  case FB_TK_DIM
754  '' Field(s) with explicit DIM
755  lexSkipToken( )
756 
757  '' multi-decl?
758  if( lexGetToken( ) = FB_TK_AS ) then
759  lexSkipToken( )
760  hTypeMultElementDecl( s, attrib )
761  else
762  hTypeElementDecl( s, attrib )
763  end if
764 
765  case FB_TK_STATIC
766  '' Static member variable
767  lexSkipToken( )
768 
769  hTypeStaticVarDecl( s, attrib )
770 
771  '' anything else, must be a field
772  case else
773  hTypeElementDecl( s, attrib )
774 
775  end select
776 
777  '' Comment?
778  cComment( )
779 
780  '' emit the current line in text form
781  hEmitCurrLine( )
782 
783  if( cStmtSeparator( ) = FALSE ) then
784  errReport( FB_ERRMSG_EXPECTEDEOL )
785  '' error recovery: skip until next line or stmt
786  hSkipUntil( INVALID, TRUE )
787  end if
788  loop
789 
790  '' no fields added?
791  if( symbUdtGetFirstField( s ) = NULL ) then
792  errReport( FB_ERRMSG_NOELEMENTSDEFINED )
793  end if
794 end sub
795 
796 sub hCheckForCDtorOrMethods( byval sym as FBSYMBOL ptr )
797  dim as FBSYMBOL ptr member = any
798  '' Not at module level?
799  if( parser.scope > FB_MAINSCOPE ) then
800  '' Shouldn't allow any member procedures - they couldn't be
801  '' implemented since we don't allow nested procedures.
802  '' (Note: assuming symbStructEnd() was already called,
803  '' thus any implicit members were already added by
804  '' symbUdtAddDefaultMembers())
805  member = symbGetCompSymbTb( sym ).head
806  while( member )
807  if( symbIsProc( member ) ) then
808  errReportEx( FB_ERRMSG_NOOOPINFUNCTIONS, symbGetName( member ) )
809  end if
810  member = member->next
811  wend
812  end if
813 end sub
814 
815 '' TypeDecl =
816 '' TYPE|UNION ID (ALIAS LITSTR)? (EXTENDS SymbolType)? (FIELD '=' Expression)?
817 '' TypeLine+
818 '' END (TYPE|UNION) .
819 sub cTypeDecl( byval attrib as integer )
820  static as zstring * FB_MAXNAMELEN+1 id
821  dim as integer isunion = any, checkid = any
822  dim as FBSYMBOL ptr sym = any
823  dim as FB_CMPSTMTSTK ptr stk = any
824 
825  isunion = (lexGetToken( ) = FB_TK_UNION)
826 
827  '' TYPE|UNION
828  lexSkipToken( )
829 
830  '' ID
831  checkid = TRUE
832  select case as const lexGetClass( )
833  case FB_TKCLASS_IDENTIFIER
834 
835  case FB_TKCLASS_KEYWORD
836  if( isunion = FALSE ) then
837  '' AS?
838  if( lexGetToken( ) = FB_TK_AS ) then
839  '' (Note: the typedef parser will skip the AS)
841  exit sub
842  end if
843  end if
844 
845  errReport( FB_ERRMSG_EXPECTEDIDENTIFIER )
846  '' error recovery: fake an ID
847  checkid = FALSE
848 
849  case FB_TKCLASS_QUIRKWD
850 
851  case else
852  errReport( FB_ERRMSG_EXPECTEDIDENTIFIER )
853  '' error recovery: fake an ID
854  checkid = FALSE
855  end select
856 
857  if( checkid ) then
858  '' Namespace identifier if it matches the current namespace
860 
861  if( fbLangOptIsSet( FB_LANG_OPT_PERIODS ) ) then
862  '' if inside a namespace, symbols can't contain periods (.)'s
863  if( symbIsGlobalNamespc( ) = FALSE ) then
864  if( lexGetPeriodPos( ) > 0 ) then
865  errReport( FB_ERRMSG_CANTINCLUDEPERIODS )
866  end if
867  end if
868  end if
869 
870  lexEatToken( @id )
871  else
872  id = *symbUniqueId( )
873  end if
874 
875  '' AS?
876  if (lexGetToken() = FB_TK_AS) then
877  if( isunion ) then
878  errReport( FB_ERRMSG_SYNTAXERROR )
879  end if
880 
881  '' (Note: the typedef parser will skip the AS)
882  cTypedefSingleDecl( id )
883  exit sub
884  end if
885 
886  if( cCompStmtIsAllowed( FB_CMPSTMT_MASK_DECL or FB_CMPSTMT_MASK_CODE ) = FALSE ) then
887  hSkipCompound( FB_TK_TYPE )
888  exit sub
889  end if
890 
891  '' [ALIAS "id"]
892  dim as zstring ptr palias = cAliasAttribute()
893 
894  '' (EXTENDS SymbolType)?
895  dim as FBSYMBOL ptr baseSubtype = NULL
896  if( lexGetToken( ) = FB_TK_EXTENDS ) then
897  lexSkipToken( )
898 
899  '' SymbolType
900  dim as integer baseDtype
901  hSymbolType( baseDtype, baseSubtype, 0 )
902 
903  '' is the base type a struct?
904  if( baseDType <> FB_DATATYPE_STRUCT ) then
905  errReport( FB_ERRMSG_EXPECTEDCLASSTYPE )
906  '' error recovery: skip
907  baseSubtype = NULL
908  end if
909  end if
910 
911  '' [FIELD '=' ConstExpression]
912  dim as integer align = cFieldAlignmentAttribute( )
913 
914  '' start a new compound, or any EXTERN..END EXTERN used around this struct
915  '' would turn-off function mangling depending on the mode passed
916  cCompStmtPush( FB_TK_TYPE, _
917  FB_CMPSTMT_MASK_ALL and (not FB_CMPSTMT_MASK_CODE) _
918  and (not FB_CMPSTMT_MASK_DATA) )
919 
920  '' we have to store some contextual information,
921  '' while there's no proper scope stack
922 
923  dim as ASTNODE ptr currproc = ast.proc.curr, currblock = ast.currblock
924  dim as FBSYMBOL ptr currprocsym = parser.currproc, currblocksym = parser.currblock
925  dim as integer scope_depth = parser.scope
926 
927  sym = hTypeAdd( NULL, id, palias, isunion, align, baseSubtype )
928 
929  '' restore the context
930  ast.proc.curr = currproc
931  ast.currblock = currblock
932 
933  parser.currproc = currprocsym
934  parser.currblock = currblocksym
935  parser.scope = scope_depth
936 
938 
939  '' end the compound
940  stk = cCompStmtGetTOS( FB_TK_TYPE )
941  if( stk <> NULL ) then
942  cCompStmtPop( stk )
943  end if
944 
945  '' has methods? must be unique..
946  if( symbGetIsUnique( sym ) ) then
947  '' any preview declaration than itself?
948  dim as FBSYMCHAIN ptr chain_ = symbLookupAt( symbGetCurrentNamespc( ), _
949  id, _
950  FALSE, _
951  FALSE )
952  '' could be NULL, because error recovery
953  if( chain_ <> NULL ) then
954  if( chain_->sym <> sym ) then
955  errReportEx( FB_ERRMSG_STRUCTISNOTUNIQUE, id )
956  end if
957  end if
958 
959  '' don't allow field named as keywords
960  if( symbGetUDTHasKwdField( sym ) ) then
961  errReport( FB_ERRMSG_KEYWORDFIELDSNOTALLOWEDINCLASSES )
962  end if
963  end if
964 
965  '' byval params to self?
966  if( symbGetUdtHasRecByvalParam( sym ) ) then
967  if( symbCompIsTrivial( sym ) = FALSE ) then
969  end if
970  end if
971 
972  '' byval results to self?
973  if( symbGetUdtHasRecByvalRes( sym ) ) then
975  end if
976 end sub
977 
978 sub hPatchByvalParamsToSelf( byval parent as FBSYMBOL ptr )
979  dim as FBSYMBOL ptr sym = any, param = any
980 
981  '' For each method...
982  sym = symbGetUDTSymbtb( parent ).head
983  while( sym )
984  if( symbIsProc( sym ) ) then
985  '' For each param...
986  param = symbGetProcHeadParam( sym )
987  while( param )
988  '' BYVAL AS ParentUDT?
989  if( (symbGetType( param ) = FB_DATATYPE_STRUCT) and _
990  (symbGetSubtype( param ) = parent) ) then
991  if( symbGetParamMode( param ) = FB_PARAMMODE_BYVAL ) then
992  symbRecalcLen( param )
993  end if
994  end if
995 
996  param = param->next
997  wend
998  end if
999 
1000  sym = sym->next
1001  wend
1002 
1003 end sub
1004 
1005 '':::::
1007  ( _
1008  byval parent as FBSYMBOL ptr _
1009  ) static
1010 
1011  dim as FBSYMBOL ptr sym
1012 
1013  '' for each method..
1014  sym = symbGetUDTSymbtb( parent ).head
1015  do while( sym <> NULL )
1016  if( symbIsProc( sym ) ) then
1017  '' byval result to self? reset..
1018  if( symbGetSubtype( sym ) = parent ) then
1019  symbProcRecalcRealType( sym )
1020  end if
1021  end if
1022 
1023  sym = sym->next
1024  loop
1025 
1026 end sub
1027