Select Case
Basic implementation
dim i as integer dim i as integer scope select case i + 123 dim temp as integer = any temp = i + 123 case 1 if( temp
1 ) then goto cmplabel1 scope print "1" print "1" end scope goto endlabel case 2 cmplabel1: if( temp
2 ) then goto cmplabel2 scope print "2" print "2" end scope goto endlabel case else cmplabel2: scope print "else" print "else" end scope end select cmplabel3: '' unused only because in this example the last CASE is not conditional endlabel: end scope
- SELECT CASE
- opens the implicit outer scope
- declares the temp var
- when inside a procedure with STATIC, the temp var will be made STATIC
- the FB_SYMBATTRIB_TEMP is removed from the temp var, because it lives longer than just one statement
- when inside a procedure with STATIC, the temp var will be made STATIC
- emits the assignment
- declares the end label
- opens the implicit outer scope
- each CASE
- if there was a previous CASE
- closes the previous CASE's scope
- emits a jump to the end label
- closes the previous CASE's scope
- emits the label for this CASE
- emits a conditional branch that jumps to the next CASE if the CASE condition is not met
- opens the CASE's scope
- CASE ELSE does not emit a conditional branch
- once CASE ELSE was used, no further CASE blocks are allowed
- if there was a previous CASE
- END SELECT
- closes the previous CASE's scope
- emits an extra CASE label at the end (There is no CASE coming anymore, but this allows the last CASE to jump to the end, if it is a conditional CASE. The last CASE could jump to the SELECT's end label instead, but that would require some special case handling code.)
- emits the end label
- closes the previous CASE's scope
- any EXIT SELECTs jump immediately to the end label
dim s as string dim s as string scope select case s + "1" dim temp as string fb_StrAssign( temp, s ) fb_StrConcatAssign( temp, "1" ) case "1" if( fb_StrCompare( temp, "1" )
0 ) then goto cmplabel1 scope print "1" print "1" end scope goto endlabel cmplabel1: end select endlabel: fb_StrDelete( temp ) '' destroying the temp var at scope end end scope fb_StrDelete( s )
- SELECT CASE on string/zstring/fixstr expressions uses a string temp var
- probably because that's easiest
- knowing the string length will potentially speed up the following comparisons
- the dynamic memory allocation can be a slow down too
- probably because that's easiest
- the string temp var is destroyed at scope end or scope breaks (e.g. reaching END SELECT, or EXIT FUNCTION from within a CASE block)
dim w as wstring * 10 dim w as wstring * 10 scope select case w + wstr( "1" ) dim temp as wstring ptr dim tempexpr as wstring ptr = w + wstr( "1" ) temp = fb_WstrAlloc( fb_WstrLen( tempexpr ) ) fb_WstrAssign( temp, tempexpr ) case wstr( "1" ) if( fb_WstrCompare( temp, wstr( "1" ) )
0 ) then goto cmplabel1 scope print "1" print "1" end scope goto endlabel cmplabel1: end select endlabel: fb_WstrDelete( temp ) '' destroying the temp var at scope end end scope
- similar to SELECT CASE on zstrings, for wstring expressions a wstring is dynamically allocated
- the temp wstring is treated much like a dynamic wstring object would be
- it is a VAR symbol with type WCHAR PTR
- marked with FB_SYMBSTATS_WSTRING
- this allows ctor/dtor checks to recognize it and give it the needed treatment
- it is a VAR symbol with type WCHAR PTR
- this way, the temp wstring is destroyed at scope end or scope breaks
When the expression given to the select statement is just a simple variable access, then no temporary variable needs to be created. In this case, the given variable itself will be used in the comparisons at each case statement. For example:
dim i as integer dim i as integer scope select case i case 1 if( i
1 ) then goto cmplabel1 scope print "1" print "1" end scope goto endlabel end select cmplabel1: endlabel: end scope