FreeBASIC  0.91.0
parser-decl-enum.bas
Go to the documentation of this file.
1 '' enumerator (ENUM) 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 '':::
12 ''EnumConstDecl = ID ('=' ConstExpression)? .
13 ''
14 sub hEnumConstDecl( byval id as zstring ptr, byref value as longint )
15  dim as ASTNODE ptr expr = any
16 
17  '' '='?
18  if( cAssignToken( ) ) then
19  '' ConstExpression
20  expr = cExpression( )
21  if( expr = NULL ) then
22  errReport( FB_ERRMSG_EXPECTEDCONST )
23  '' error recovery: skip till next ','
24  hSkipUntil( CHAR_COMMA )
25  return
26  end if
27 
28  if( astIsCONST( expr ) = FALSE ) then
29  errReport( FB_ERRMSG_EXPECTEDCONST )
30  '' error recovery: no value change
31  astDelTree( expr )
32  return
33  end if
34 
35  '' not an integer? (CHAR or WCHAR will fail in astIsCONST())
36  if( astGetDataClass( expr ) <> FB_DATACLASS_INTEGER ) then
37  errReportWarn( FB_WARNINGMSG_IMPLICITCONVERSION, id )
38  end if
39 
40  value = astConstFlushToInt( expr )
41  end if
42 end sub
43 
44 '':::::
45 ''EnumBody = (EnumDecl (',' EnumDecl)? Comment? SttSeparator)+ .
46 ''
47 sub cEnumBody(byval s as FBSYMBOL ptr, byval attrib as integer)
48  static as zstring * FB_MAXNAMELEN+1 id
49  dim as longint value = any
50 
51  value = 0
52 
53  do
54  '' Comment? SttSeparator?
55  while( (cComment( ) or cStmtSeparator( )) and _
56  (lexGetToken( ) <> FB_TK_EOF) )
57  wend
58 
59  select case lexGetToken( )
60  '' EOF?
61  case FB_TK_EOF
62  exit do
63 
64  '' END?
65  case FB_TK_END
66  exit do
67 
68  case else
69 
70  '' ID ConstDecl (',' ID ConstDecl)*
71  do
72  '' ID?
73  select case lexGetClass( )
74  case FB_TKCLASS_IDENTIFIER
75  if( fbLangOptIsSet( FB_LANG_OPT_PERIODS ) ) then
76  '' if inside a namespace, symbols can't contain periods (.)'s
77  if( symbIsGlobalNamespc( ) = FALSE ) then
78  if( lexGetPeriodPos( ) > 0 ) then
79  errReport( FB_ERRMSG_CANTINCLUDEPERIODS )
80  end if
81  end if
82  end if
83 
84  id = *lexGetText( )
85 
86  case FB_TKCLASS_QUIRKWD
87  '' only if inside a ns and if not local
88  if( (symbIsGlobalNamespc( )) or (parser.scope > FB_MAINSCOPE) ) then
89  errReport( FB_ERRMSG_DUPDEFINITION )
90  '' error recovery: fake an id
91  id = *symbUniqueLabel( )
92  else
93  id = *lexGetText( )
94  end if
95 
96  case else
97  exit do
98  end select
99 
100  lexSkipToken( )
101 
102  '' ConstDecl
103  hEnumConstDecl( @id, value )
104 
105  if( symbAddEnumElement( s, @id, value, attrib ) = NULL ) then
106  errReportEx( FB_ERRMSG_DUPDEFINITION, id )
107  end if
108 
109  value += 1
110 
111  '' ','?
112  if( lexGetToken( ) <> CHAR_COMMA ) then
113  exit do
114  end if
115 
116  lexSkipToken( )
117  loop
118 
119  '' Comment? SttSeparator
120  cComment( )
121 
122  '' emit the current line in text form
123  hEmitCurrLine( )
124 
125  if( cStmtSeparator( ) = FALSE ) then
126  errReport( FB_ERRMSG_EXPECTEDEOL )
127  '' error recovery: skip until next line or stmt
128  hSkipUntil( INVALID, TRUE )
129  end if
130  end select
131  loop
132 
133  '' nothing added?
134  if( symbGetEnumElements( s ) = 0 ) then
135  errReport( FB_ERRMSG_NOELEMENTSDEFINED )
136  end if
137 end sub
138 
139 '' EnumDecl =
140 '' ENUM ID? (ALIAS LITSTR)? EXPLICIT?
141 '' EnumLine+
142 '' END ENUM .
143 sub cEnumDecl( byval attrib as integer )
144  static as zstring * FB_MAXNAMELEN+1 id
145  dim as FBSYMBOL ptr e = any
146 
147  '' ENUM
148  lexSkipToken( )
149 
150  '' Namespace identifier if it matches the current namespace
152 
153  '' ID?
154  select case lexGetClass( )
155  case FB_TKCLASS_IDENTIFIER, FB_TKCLASS_QUIRKWD
156 
157  if( fbLangOptIsSet( FB_LANG_OPT_PERIODS ) ) then
158  '' if inside a namespace, symbols can't contain periods (.)'s
159  if( symbIsGlobalNamespc( ) = FALSE ) then
160  if( lexGetPeriodPos( ) > 0 ) then
161  errReport( FB_ERRMSG_CANTINCLUDEPERIODS )
162  end if
163  end if
164  end if
165 
166  id = *lexGetText( )
167  lexSkipToken( )
168 
169  case else
170  id = *symbUniqueId( )
171  end select
172 
173  '' [ALIAS "id"]
174  dim as zstring ptr palias = cAliasAttribute()
175 
176  '' EXPLICIT?
177  dim as integer isexplicit = FALSE
178  if( lexGetToken( ) = FB_TK_EXPLICIT ) then
179  lexSkipToken( )
180  isexplicit = TRUE
181  end if
182 
183  '' Enums are namespaces containing their constants, and a Using will
184  '' automatically be done below to import the constants into the parent
185  '' namespace unless the Enum was declared Explicit.
186  ''
187  '' This way, an Enum's constants can be accessed via "constid" or
188  '' "enumid.constid", and an Explicit Enum's constants can only be
189  '' accessed via the latter.
190 
191  e = symbAddEnum( @id, palias, attrib )
192  if( e = NULL ) then
193  errReportEx( FB_ERRMSG_DUPDEFINITION, id )
194  '' error recovery: create a fake symbol
195  e = symbAddEnum( symbUniqueLabel( ), NULL, FB_SYMBATTRIB_NONE )
196  end if
197 
198  '' Comment? SttSeparator
199  cComment( )
200 
201  '' emit the current line in text form
202  hEmitCurrLine( )
203 
204  if( cStmtSeparator( ) = FALSE ) then
205  errReport( FB_ERRMSG_SYNTAXERROR )
206  '' error recovery: skip until next line or stmt
207  hSkipUntil( INVALID, TRUE )
208  end if
209 
210  '' Start a new scope
211  symbNestBegin( e, FALSE )
212 
213  '' EnumBody
214  cEnumBody( e, attrib )
215 
216  '' close scope
217  symbNestEnd( FALSE )
218 
219  '' END ENUM
220  if( lexGetToken( ) <> FB_TK_END ) then
221  errReport( FB_ERRMSG_EXPECTEDENDENUM )
222  '' error recovery: skip until next stmt
223  hSkipStmt( )
224  else
225  lexSkipToken( )
226 
227  if( lexGetToken( ) <> FB_TK_ENUM ) then
228  errReport( FB_ERRMSG_EXPECTEDENDENUM )
229  '' error recovery: skip until next stmt
230  hSkipStmt( )
231  else
232  lexSkipToken( )
233 
234  '' Do an implicit 'USING enum', unless it's an EXPLICIT enum
235  if( isexplicit = FALSE ) then
237  end if
238  end if
239  end if
240 end sub
241