Select Case

FreeBASIC

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
    • 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