FreeBASIC  0.91.0
parser-compound-select-const.bas
Go to the documentation of this file.
1 '' SELECT CASE AS CONST..CASE..END SELECT compound statement parsing
2 ''
3 '' chng: sep/2004 written [v1ctor]
4 
5 #include once "fb.bi"
6 #include once "fbint.bi"
7 #include once "parser.bi"
8 #include once "ast.bi"
9 #include once "rtl.bi"
10 
11 const FB_MAXSWTCASEEXPR = 8192
12 const FB_MAXSWTCASERANGE= 4096
13 
15  base as integer
16  casevalues(0 to FB_MAXSWTCASEEXPR-1) as ulongint
17  caselabels(0 to FB_MAXSWTCASEEXPR-1) as FBSYMBOL ptr
18 end type
19 
20 dim shared ctx as SELECTCTX
21 
23  ctx.base = 0
24 end sub
25 
27 end sub
28 
29 '':::::
30 ''SelConstStmtBegin = SELECT CASE AS CONST Expression{int} .
31 ''
33  dim as ASTNODE ptr expr
34  dim as FBSYMBOL ptr sym, el, cl
35  dim as FB_CMPSTMTSTK ptr stk
36  dim as integer options = any
37 
38  '' Open outer scope (perhaps not really needed, but done to match the
39  '' normal SELECT CASE, also the scope might help with stack usage)
40  dim as ASTNODE ptr outerscopenode = astScopeBegin( )
41  if( outerscopenode = NULL ) then
42  errReport( FB_ERRMSG_RECLEVELTOODEEP )
43  end if
44 
45  '' Expression
46  expr = cExpression( )
47  if( expr = NULL ) then
48  errReport( FB_ERRMSG_EXPECTEDEXPRESSION )
49  '' error recovery: fake an expr
50  expr = astNewCONSTi( 0 )
51  end if
52 
53  if( astGetDataClass( expr ) <> FB_DATACLASS_INTEGER ) then
54  astDelTree( expr )
55  expr = NULL
56 
57  '' CHAR and WCHAR literals are also from the INTEGER class
58  else
59  select case astGetDataType( expr )
60  case FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR
61  '' don't allow, unless it's a deref pointer
62  if( astIsDEREF( expr ) = FALSE ) then
63  astDelTree( expr )
64  expr = NULL
65  end if
66  end select
67  end if
68 
69  if( expr = NULL ) then
70  errReport( FB_ERRMSG_INVALIDDATATYPES )
71  '' error recovery: fake an expr
72  expr = astNewCONSTi( 0 )
73  end if
74 
75  if( astGetDataType( expr ) <> FB_DATATYPE_UINT ) then
76  if( typeGetSize( astGetDataType( expr ) ) <= typeGetSize( FB_DATATYPE_UINT ) ) then
77  expr = astNewCONV( FB_DATATYPE_UINT, NULL, expr )
78  else
79  expr = astNewCONV( FB_DATATYPE_ULONGINT, NULL, expr )
80  end if
81  end if
82 
83  '' add labels
84  el = symbAddLabel( NULL, FB_SYMBOPT_NONE )
85  cl = symbAddLabel( NULL, FB_SYMBOPT_NONE )
86 
87  options = 0
88  if( fbLangOptIsSet( FB_LANG_OPT_SCOPE ) = FALSE ) then
89  options or= FB_SYMBOPT_UNSCOPE
90  end if
91 
92  '' dim temp as uinteger = expr
93  sym = symbAddImplicitVar( astGetDataType( expr ), NULL, options )
94 
95  '' a) Don't bother clearing the temp var, it's just an integer
96  '' b) Silence "branch crossing" warnings, the temp var won't be
97  '' accessed anymore once a CASE was entered anyways
98  symbSetDontInit( sym )
99 
100  if( options and FB_SYMBOPT_UNSCOPE ) then
101  astAddUnscoped( astNewDECL( sym, TRUE ) )
102  astAdd( astNewASSIGN( astNewVAR( sym ), expr ) )
103  else
104  astAdd( astNewDECL( sym, FALSE ) )
105  astAdd( astNewASSIGN( astNewVAR( sym ), expr, AST_OPOPT_ISINI ) )
106  end if
107 
108  '' skip the statements
109  astAdd( astNewBRANCH( AST_OP_JMP, cl ) )
110 
111  '' push to stmt stack
112  stk = cCompStmtPush( FB_TK_SELECT, _
113  FB_CMPSTMT_MASK_NOTHING ) '' nothing allowed but CASE's
114  stk->select.isconst = TRUE
115  stk->select.sym = sym
116  stk->select.casecnt = 0
117  stk->select.const_.base = ctx.base
118  stk->select.const_.deflabel = NULL
119  stk->select.const_.minval = &hFFFFFFFFu
120  stk->select.const_.maxval = 0
121  stk->select.cmplabel = cl
122  stk->select.endlabel = el
123  stk->select.outerscopenode = outerscopenode
124 end sub
125 
126 function hSelConstAddCase _
127  ( _
128  byval swtbase as integer, _
129  byval value as ulongint, _
130  byval label as FBSYMBOL ptr _
131  ) as integer static
132 
133  dim as integer probe, high, low, i
134  dim as ulongint v
135 
136  '' nothing left?
137  if( ctx.base >= FB_MAXSWTCASEEXPR ) then
138  return FALSE
139  end if
140 
141  '' find the slot using bin-search
142  high = ctx.base - swtbase
143  low = -1
144 
145  do while( high - low > 1 )
146  probe = cunsg(high + low) \ 2
147  v = ctx.casevalues(swtbase+probe)
148  if( v < value ) then
149  low = probe
150  elseif( v > value ) then
151  high = probe
152  else
153  exit function
154  end if
155  loop
156 
157  '' move up
158  for i = ctx.base+1 to swtbase+high+1 step -1
159  ctx.casevalues(i) = ctx.casevalues(i-1)
160  ctx.caselabels(i) = ctx.caselabels(i-1)
161  next
162 
163  '' insert new item
164  ctx.casevalues(swtbase+high) = value
165  ctx.caselabels(swtbase+high) = label
166  ctx.base += 1
167 
168  function = TRUE
169 end function
170 
171 '' cSelConstStmtNext = CASE (ELSE | (ConstExpression{int} (',' ConstExpression{int})*)) .
172 sub cSelConstStmtNext( byval stk as FB_CMPSTMTSTK ptr )
173  dim as ulongint value, tovalue, maxval, minval
174  dim as FBSYMBOL ptr label
175  dim as integer swtbase
176 
177  '' CASE
178  lexSkipToken( )
179 
180  '' end scope
181  if( stk->scopenode <> NULL ) then
182  astScopeEnd( stk->scopenode )
183  end if
184 
185  if( stk->select.casecnt > 0 ) then
186  '' break from block
187  astAdd( astNewBRANCH( AST_OP_JMP, stk->select.endlabel ) )
188  end if
189 
190  '' ELSE?
191  if( lexGetToken( ) = FB_TK_ELSE ) then
192  lexSkipToken( )
193 
194  stk->select.const_.deflabel = symbAddLabel( NULL )
195  astAdd( astNewLABEL( stk->select.const_.deflabel ) )
196 
197  '' begin scope
198  stk->scopenode = astScopeBegin( )
199 
200  stk->select.casecnt = -1
201 
202  return
203  end if
204 
205  '' ConstExpression{int} ((',' | TO) ConstExpression{int})*
206  swtbase = stk->select.const_.base
207 
208  '' add label
209  label = symbAddLabel( NULL, FB_SYMBOPT_NONE )
210 
211  do
212  '' ConstExpression{int}
213  value = cConstIntExpr( cExpression( ) )
214 
215  minval = stk->select.const_.minval
216  maxval = stk->select.const_.maxval
217 
218  '' TO?
219  if( lexGetToken( ) = FB_TK_TO ) then
220  lexSkipToken( )
221 
222  tovalue = cConstIntExpr( cExpression( ) )
223 
224  for value = value to tovalue
225  if( value < minval ) then
226  minval = value
227  end if
228  if( value > maxval ) then
229  maxval = value
230  end if
231 
232  '' too big?
233  if( (minval > maxval) or _
234  (maxval - minval > FB_MAXSWTCASERANGE) or _
235  (culngint(minval) * typeGetSize( FB_DATATYPE_INTEGER ) > 4294967292ULL) ) then
236 
237  errReport( FB_ERRMSG_RANGETOOLARGE )
238  '' error recovery: reset values
239  minval = stk->select.const_.minval
240  maxval = stk->select.const_.maxval
241  else
242  '' add item
243  if( hSelConstAddCase( swtbase, value, label ) = FALSE ) then
244  errReport( FB_ERRMSG_DUPDEFINITION )
245  end if
246  end if
247  next
248  else
249  if( value < minval ) then
250  minval = value
251  end if
252  if( value > maxval ) then
253  maxval = value
254  end if
255 
256  '' too big?
257  if( (minval > maxval) or _
258  (maxval - minval > FB_MAXSWTCASERANGE) or _
259  (culngint(minval) * typeGetSize( FB_DATATYPE_INTEGER ) > 4294967292ULL) ) then
260 
261  errReport( FB_ERRMSG_RANGETOOLARGE )
262  '' error recovery: reset values
263  minval = stk->select.const_.minval
264  maxval = stk->select.const_.maxval
265  else
266  '' add item
267  if( hSelConstAddCase( swtbase, value, label ) = FALSE ) then
268  errReport( FB_ERRMSG_DUPDEFINITION )
269  end if
270  end if
271  end if
272 
273  stk->select.const_.minval = minval
274  stk->select.const_.maxval = maxval
275  loop while( hMatch( CHAR_COMMA ) )
276 
277  ''
278  astAdd( astNewLABEL( label ) )
279 
280  '' begin scope
281  stk->scopenode = astScopeBegin( )
282 
283  stk->select.casecnt += 1
284 end sub
285 
286 '' SelConstStmtEnd = END SELECT .
287 sub cSelConstStmtEnd( byval stk as FB_CMPSTMTSTK ptr )
288  dim as FBSYMBOL ptr deflabel = any
289 
290  '' END SELECT
291  lexSkipToken( )
292  lexSkipToken( )
293 
294  deflabel = stk->select.const_.deflabel
295  if( deflabel = NULL ) then
296  deflabel = stk->select.endlabel
297  end if
298 
299  '' end scope
300  if( stk->scopenode <> NULL ) then
301  astScopeEnd( stk->scopenode )
302  end if
303 
304  '' break from block
305  astAdd( astNewBRANCH( AST_OP_JMP, stk->select.endlabel ) )
306 
307  '' emit comp label
308  astAdd( astNewLABEL( stk->select.cmplabel ) )
309 
310  astAdd( astBuildJMPTB( stk->select.sym, _
311  @ctx.casevalues(stk->select.const_.base), _
312  @ctx.caselabels(stk->select.const_.base), _
313  ctx.base - stk->select.const_.base, _
314  deflabel, _
315  stk->select.const_.minval, _
316  stk->select.const_.maxval ) )
317 
318  ctx.base = stk->select.const_.base
319 
320  '' emit exit label
321  astAdd( astNewLABEL( stk->select.endlabel ) )
322 
323  '' Close the outer scope block
324  if( stk->select.outerscopenode <> NULL ) then
325  astScopeEnd( stk->select.outerscopenode )
326  end if
327 
328  '' pop from stmt stack
329  cCompStmtPop( stk )
330 end sub
331