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
- emits the assignment
- declares the end label
- each CASE
- if there was a previous CASE
- closes the previous CASE's scope
- emits a jump to the end label
- 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
- 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
- any EXIT SELECTs jump immediately to the end label
SELECT CASE on strings/zstrings/fixstrs
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
- 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)
SELECT CASE on wstrings
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
- this way, the temp wstring is destroyed at scope end or scope breaks
SELECT CASE without temp var
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