Difference between revisions of "Case"

From Free Pascal wiki
Jump to navigationJump to search
m (→‎see also: corrected the link to the case statement page as it was incorrectly pointing to the if statement page in the FreePascal reference manual.)
(26 intermediate revisions by 5 users not shown)
Line 1: Line 1:
 
{{Case}}
 
{{Case}}
  
Case opens a case statement. The case statement compares the value of an ordinal expression to each selector, which can be a [[Const|constant]], a subrange, or a list of them separated by [[Comma|commas]]. The selector field is separated from action field by [[Colon]].
+
The [[Reserved word|reserved word]] <syntaxhighlight lang="pascal" inline>case</syntaxhighlight> starts a clause where alternatives are chosen.
  
The case statement includes the [[Reserved word|reserved words]] [[Of]] and [[End]]. [[Else]] can be used if needed, too.
+
== structure ==
 
+
The general structure of <syntaxhighlight lang="pascal" inline>case</syntaxhighlight>-clauses looks like this:
 
+
<syntaxhighlight lang="pascal">
<syntaxhighlight>
+
case selector of
case place of
+
caseValue0: ;
  1: ShowMessage('Gold medal');
+
caseValue1: ;
  2: ShowMessage('Silver medal');
+
caseValue2, caseValue3: ;
  3: ShowMessage('Bronze medal');  
+
caseValue4..caseValue7: …;
  else ShowMessage('Better luck next time');
 
end;
 
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
The following constraints have to be met:
 +
* The data type of <syntaxhighlight lang="pascal" inline>selector</syntaxhighlight> has to be an ordinal type. [[FPC|FreePascal]] additionally allows [[Character and string types|strings]].
 +
* All case values have to be the same data type as <syntaxhighlight lang="pascal" inline>selector</syntaxhighlight> is.
 +
* They have to be constant expressions, i.e. known at compile-time.
 +
* All <syntaxhighlight lang="pascal" inline>case</syntaxhighlight>-labels have to be mutually disjoint. For every discrete value there applies exactly one or no cases.
 +
* A <syntaxhighlight lang="pascal" inline>case</syntaxhighlight>-clause has to have at least one <syntaxhighlight lang="pascal" inline>case</syntaxhighlight>-label. Imperative <syntaxhighlight lang="pascal" inline>case</syntaxhighlight>-statements can have at most one anonymous cases (at most one <syntaxhighlight lang="pascal" inline>else</syntaxhighlight>/<syntaxhighlight lang="delphi" inline>otherwise</syntaxhighlight>-branches).
  
=== WhatIsChar ===
+
The actual order of <syntaxhighlight lang="pascal" inline>case</syntaxhighlight>-labels is not relevant.
 +
They may be ascending, descending, or mixed up, it does not matter.
  
<syntaxhighlight>
+
Originally, standard Pascal also set the constraint, that ''all possible'' values of the selector have to have a corresponding match.
function WhatIsChar( c:char ):string;
+
This is no longer the case with modern compilers.
var
 
  s : string;
 
begin
 
  s := '';
 
  case c of
 
    '0' .. '9' : s := 'digit (0-9)';
 
    'a' .. 'z' : s := 'lowercase letter (a-z)';
 
    'A' .. 'Z' : s := 'uppercase letter (A-Z)';
 
    '+' , '-'  : s := 'sign (+ or -)';
 
  end;
 
  result := s;
 
end;
 
</syntaxhighlight>
 
  
== Case string ==
+
<syntaxhighlight lang="pascal" inline>case</syntaxhighlight> can have both, imperative and declarative meanings, depending on where it is written.
 +
The former are “statements”, whereas the latter start a “variant part” of records.
  
Case of works on strings. The Pascal language allows you to "Case of" on a string variable.
+
=== <syntaxhighlight lang="pascal" inline>case</syntaxhighlight>-statements ===
 +
<syntaxhighlight lang="pascal" inline>case</syntaxhighlight>-statements are a concise way of writing [[Branch|branches]].
 +
They suit best, where alternative paths are taken ''exclusively''.
 +
They may contain an [[Else|<syntaxhighlight lang="pascal" inline>else</syntaxhighlight>]]-branch catching all cases that are not listed.
 +
<syntaxhighlight lang="pascal" line highlight="8-20">program asciiTest(input, output, stderr);
  
<syntaxhighlight>
+
var
const
+
c: char;
  ISO_3166_1_ALPHA_3_ANDORRA  = 'AND';
 
  ISO_3166_1_ALPHA_3_AUSTRALIA = 'AUS';
 
  ISO_3166_1_ALPHA_3_AUSTRIA = 'AUT';
 
  ISO_3166_1_ALPHA_3_BELGIUM = 'BEL';
 
  ISO_3166_1_ALPHA_3_BRAZIL = 'BRA';
 
  ISO_3166_1_ALPHA_3_CANADA = 'CAN';
 
  ISO_3166_1_ALPHA_3_CHINA = 'CHN';
 
  ISO_3166_1_ALPHA_3_CZECH_REPUBLIC = 'CZE';
 
  ISO_3166_1_ALPHA_3_CYPRUS = 'CYP';
 
  ISO_3166_1_ALPHA_3_GERMANY = 'DEU';
 
  ISO_3166_1_ALPHA_3_DENMARK = 'DNK';
 
  ISO_3166_1_ALPHA_3_SPAIN = 'ESP';
 
  ISO_3166_1_ALPHA_3_ESTONIA = 'EST';
 
  ISO_3166_1_ALPHA_3_FINLAND = 'FIN';
 
  ISO_3166_1_ALPHA_3_FRANCE = 'FRA';
 
  ISO_3166_1_ALPHA_3_GREECE = 'GRC';
 
  ISO_3166_1_ALPHA_3_INDIA = 'IND';
 
  ISO_3166_1_ALPHA_3_IRELAND = 'IRL';
 
  ISO_3166_1_ALPHA_3_ITALY = 'ITA';
 
  ISO_3166_1_ALPHA_3_JAPAN = 'JPN';
 
  ISO_3166_1_ALPHA_3_LITHUANIA = 'LTU';
 
  ISO_3166_1_ALPHA_3_LATVIA = 'LVA';
 
  ISO_3166_1_ALPHA_3_LUXEMBOURG = 'LUX';
 
  ISO_3166_1_ALPHA_3_MALTA = 'MLT';
 
  ISO_3166_1_ALPHA_3_MEXICO = 'MEX';
 
  ISO_3166_1_ALPHA_3_MONACO = 'MCO';
 
  ISO_3166_1_ALPHA_3_MONTENEGRO = 'MNE';
 
  ISO_3166_1_ALPHA_3_NAURU = 'NRU';
 
  ISO_3166_1_ALPHA_3_NETHERLANDS = 'NLD';
 
  ISO_3166_1_ALPHA_3_NORWAY = 'NOR';
 
  ISO_3166_1_ALPHA_3_POLAND = 'POL';
 
  ISO_3166_1_ALPHA_3_PORTUGAL = 'PRT';
 
  ISO_3166_1_ALPHA_3_REPUBLIC_OF_KOREA = 'KOR';
 
  ISO_3166_1_ALPHA_3_RUSSIAN_FEDERATION = 'RUS';
 
  ISO_3166_1_ALPHA_3_SAN_MARINO = 'SMR';
 
  ISO_3166_1_ALPHA_3_SLOVAKIA = 'SVK';
 
  ISO_3166_1_ALPHA_3_SLOVENIA = 'SVN';
 
  ISO_3166_1_ALPHA_3_SWEDEN = 'SWE' ;
 
  ISO_3166_1_ALPHA_3_SWITZERLAND = 'CHE';
 
  ISO_3166_1_ALPHA_3_UNITED_KINGDOM_OF_GREAT_BRITAIN_AND_NORTHERN_IRELAND = 'GBR';
 
  ISO_3166_1_ALPHA_3_UNITED_STATES_OF_AMERICA = 'USA';
 
  
 
  ISO_4217_EURO = 'EUR';
 
  ISO_4217_AUSTRALIAN_DOLLAR = 'AUD';
 
  ISO_4217_BRAZILIAN_REAL = 'BRL';
 
  ISO_4217_CANADIAN_DOLLAR = 'CAD';
 
  ISO_4217_CHINESE_YUAN = 'CNY';
 
  ISO_4217_CZECH_KORUNA = 'CZK' ;
 
  ISO_4217_DANISH_KRONE = 'DKK' ;
 
  ISO_4217_INDIAN_RUPEE = 'INR';
 
  ISO_4217_POUND_STERLING = 'GBP' ;
 
  ISO_4217_JAPANESE_YEN  = 'JPY';
 
  ISO_4217_MEXICAN_PESO = 'MXN';
 
  ISO_4217_NORWEGIAN_KRONE = 'NOK' ;
 
  ISO_4217_POLISH_ZLOTY = 'PLN' ;
 
  ISO_4217_RUSSIAN_RUBLE = 'RUB' ;
 
  ISO_4217_SOUTH_KOREAN_WON = 'KRW';
 
  ISO_4217_SWEDISH_KRONA = 'SEK' ;
 
  ISO_4217_SWISS_FRANC = 'CHF' ;
 
  ISO_4217_UNITED_STATES_DOLLAR = 'USD' ;
 
 
function ISO_4217_currency_name ( ISO_3166_1_alpha_3_code: string): string;
 
 
begin
 
begin
  Case ISO_3166_1_alpha_3_code  of
+
read(c);
    // Eurozone
+
case ord(c) of
    ISO_3166_1_ALPHA_3_ANDORRA, ISO_3166_1_ALPHA_3_AUSTRIA,
+
// empty statement, so the control characters are not
    ISO_3166_1_ALPHA_3_BELGIUM,ISO_3166_1_ALPHA_3_CYPRUS,
+
// considered by the else-branch as non-ASCII-characters
    ISO_3166_1_ALPHA_3_GERMANY, ISO_3166_1_ALPHA_3_SPAIN,
+
0..$1F, $7F: ;
    ISO_3166_1_ALPHA_3_ESTONIA, ISO_3166_1_ALPHA_3_FINLAND,
+
$20..$7E:
    ISO_3166_1_ALPHA_3_FRANCE, ISO_3166_1_ALPHA_3_GREECE,
+
begin
    ISO_3166_1_ALPHA_3_IRELAND, ISO_3166_1_ALPHA_3_ITALY,
+
writeLn('You entered an ASCII printable character.');
    ISO_3166_1_ALPHA_3_LITHUANIA, ISO_3166_1_ALPHA_3_LATVIA,
+
end;
    ISO_3166_1_ALPHA_3_LUXEMBOURG, ISO_3166_1_ALPHA_3_MONACO,
+
else
    ISO_3166_1_ALPHA_3_MALTA, ISO_3166_1_ALPHA_3_MONTENEGRO,
+
begin
    ISO_3166_1_ALPHA_3_NETHERLANDS, ISO_3166_1_ALPHA_3_PORTUGAL,
+
writeLn('You entered a non-ASCII character.');
    ISO_3166_1_ALPHA_3_SAN_MARINO, ISO_3166_1_ALPHA_3_SLOVAKIA,
+
end;
    ISO_3166_1_ALPHA_3_SLOVENIA : result := ISO_4217_EURO ;
+
end;
 +
end.</syntaxhighlight>
 +
Note, <syntaxhighlight lang="pascal" inline>case</syntaxhighlight>-statements accept expressions as selector.
 +
<!-- https://bugs.freepascal.org/view.php?id=34091 Starting in FPC version X.Y.Z records are comparable as well. -->
  
    ISO_3166_1_ALPHA_3_AUSTRALIA, ISO_3166_1_ALPHA_3_NAURU :
+
Instead of writing <syntaxhighlight lang="pascal" inline>else</syntaxhighlight> the word <syntaxhighlight lang="pascal" inline>otherwise</syntaxhighlight> is allowed, too.
          result := ISO_4217_AUSTRALIAN_DOLLAR;
+
This is an [[Extended Pascal]] extension.
    ISO_3166_1_ALPHA_3_BRAZIL : result := ISO_4217_BRAZILIAN_REAL;
 
    ISO_3166_1_ALPHA_3_CANADA : result := ISO_4217_CANADIAN_DOLLAR;
 
    ISO_3166_1_ALPHA_3_CHINA : result := ISO_4217_CHINESE_YUAN;
 
    ISO_3166_1_ALPHA_3_CZECH_REPUBLIC : result := ISO_4217_CZECH_KORUNA ;
 
    ISO_3166_1_ALPHA_3_DENMARK : result := ISO_4217_DANISH_KRONE ;
 
    ISO_3166_1_ALPHA_3_INDIA : result := ISO_4217_INDIAN_RUPEE;
 
    ISO_3166_1_ALPHA_3_JAPAN : result := ISO_4217_JAPANESE_YEN;
 
    ISO_3166_1_ALPHA_3_MEXICO : result := ISO_4217_MEXICAN_PESO;
 
    ISO_3166_1_ALPHA_3_NORWAY : result := ISO_4217_NORWEGIAN_KRONE ;
 
    ISO_3166_1_ALPHA_3_POLAND : result := ISO_4217_POLISH_ZLOTY ;
 
    ISO_3166_1_ALPHA_3_REPUBLIC_OF_KOREA : result := ISO_4217_SOUTH_KOREAN_WON ;
 
    ISO_3166_1_ALPHA_3_RUSSIAN_FEDERATION : result := ISO_4217_RUSSIAN_RUBLE ;
 
    ISO_3166_1_ALPHA_3_SWEDEN : result := ISO_4217_SWEDISH_KRONA ;
 
    ISO_3166_1_ALPHA_3_SWITZERLAND : result := ISO_4217_SWISS_FRANC ;
 
    ISO_3166_1_ALPHA_3_UNITED_KINGDOM_OF_GREAT_BRITAIN_AND_NORTHERN_IRELAND :
 
          result := ISO_4217_POUND_STERLING ;
 
    ISO_3166_1_ALPHA_3_UNITED_STATES_OF_AMERICA :
 
          result := ISO_4217_UNITED_STATES_DOLLAR ;
 
  end;
 
end;
 
</syntaxhighlight>
 
  
== Hexadecimal input ==
+
While the same semantics can be achieved by consecutive [[If|<syntaxhighlight lang="pascal" inline>if</syntaxhighlight>]]-[[Then|<syntaxhighlight lang="pascal" inline>then</syntaxhighlight>]]-branches, utilizing a [[Case Compiler Optimization|<syntaxhighlight lang="pascal" inline>case</syntaxhighlight>-statement allows the code generator to optimize the branch selection]].
If [[Hexadecimal|hexadecimal]] number are used, it is considered that they are unsigned:
 
  
<syntaxhighlight>
+
==== comparative remarks ====
case place of
+
There is no “fall-through” as it is the case with other languages such as shell or C.
  $1: ShowMessage('Gold medal');
+
In Pascal exactly one case matches, is processed, and program flow continues after the final [[End|<syntaxhighlight lang="pascal" inline>end</syntaxhighlight>]] of the <syntaxhighlight lang="pascal" inline>case</syntaxhighlight>-statement.
  $2: ShowMessage('Silver medal');
+
The [[Break|<syntaxhighlight lang="pascal" inline>break</syntaxhighlight>-statement]] with its special meaning only appears in loops.
  $3: ShowMessage('Bronze medal');
 
  else ShowMessage('Better luck next time');
 
end;
 
</syntaxhighlight>
 
  
 +
=== variant part in records ===
 +
A [[Record|<syntaxhighlight lang="pascal" inline>record</syntaxhighlight>]] may contain a variant part.
 +
The <syntaxhighlight lang="pascal" inline>case</syntaxhighlight>-selector has to be the name of a data type, but an identifier for accessing the current variant can be provided, too.
 +
<syntaxhighlight lang="pascal" line highlight="12-18">program variantRecordDemo(input, output, stderr);
  
If a hexadecimal is a different kind of a variable, for example Shortint, values shall be cast:
+
type
<syntaxhighlight>
+
sex = (female, male);
case place of
+
clothingSize = record
  Shortint($C3): ShowMessage('Gold medal'); //C3= -61;
+
// FIXED PART
  Shortint($34): ShowMessage('Silver medal');
+
shoulderWidth: word;
  Shortint($58): ShowMessage('Bronze medal');  
+
armLength: word;
  else ShowMessage('Better luck next time');  
+
bustGirth: word;
end;
+
waistSize: word;
</syntaxhighlight>
+
hipMeasurement: word;
or another solution can be used:
+
// VARIABLE PART
<syntaxhighlight>
+
case body: sex of
var
+
female: (
  myplace : ShortInt;
+
underbustMeasure: word;
  place  : Byte absolute myplace;
+
);
 +
male: (
 +
);
 +
end;
 
begin
 
begin
  myplace:=-61;
+
end.
  case place of
 
    $C3: ShowMessage('Gold medal');
 
    $34: ShowMessage('Silver medal');
 
    $58: ShowMessage('Bronze medal');
 
  else ShowMessage('Better luck next time');
 
  end;
 
</syntaxhighlight>
 
 
 
== Variant Record ==
 
 
 
Case is used in Variant [[Record]], too. A Variant Record is also called a tagged union.
 
 
 
<syntaxhighlight>
 
  type
 
     
 
  ScaleKelvin = 223 .. 323;
 
  ScaleCelsius = -50 .. 50;
 
   
 
  TemperatureScale = ( celsius, kelvin ) ;
 
  Temperature = record
 
    case scale :  TemperatureScale of
 
    celcius : (celsius_value : ScaleCelsius);
 
    kelvin : (kelvin_value : ScaleKelvin);
 
  end;
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
== See also ==
+
== see also ==
* [http://www.freepascal.org/docs-html/ref/refsu52.html#x149-15900013.2.2 The Case statement]
+
* [https://www.freepascal.org/docs-html/ref/refsu55.html “The <syntaxhighlight lang="pascal" inline>case</syntaxhighlight> statement” in the “FreePascal reference manual”]
* [http://www.freepascal.org/docs-html/ref/refsu19.html#x43-500003.3.2  Record types]
+
* [[CASE|“<syntaxhighlight lang="pascal" inline>case</syntaxhighlight>” as part of the “Object Pascal introduction”]]
* [http://lazarus-ccr.sourceforge.net/pascal/pas3cb.html Tao Yue: Learn Pascal!] Case
 
* [http://www.youtube.com/watch?v=pMr2xtUu3x0 Video: Free Pascal Tutorial 8 - Case Statements]
 
* [[Dialog_Examples#ShowMessage|ShowMessage]]
 
* [[Type]]
 
  
 +
== external references ==
 +
* [https://lazarus-ccr.sourceforge.io/pascal/pas3cb.html Tao Yue: “Learn Pascal!”. Chapter “case”]
  
[[Category:Pascal]]
+
[[Category: Code]]
[[Category:Control Structures]]
 

Revision as of 22:42, 28 July 2020

Deutsch (de) English (en) español (es) suomi (fi) français (fr) русский (ru)

The reserved word case starts a clause where alternatives are chosen.

structure

The general structure of case-clauses looks like this:

case selector of
	caseValue0: ;
	caseValue1: ;
	caseValue2, caseValue3: ;
	caseValue4..caseValue7: ;

The following constraints have to be met:

  • The data type of selector has to be an ordinal type. FreePascal additionally allows strings.
  • All case values have to be the same data type as selector is.
  • They have to be constant expressions, i.e. known at compile-time.
  • All case-labels have to be mutually disjoint. For every discrete value there applies exactly one or no cases.
  • A case-clause has to have at least one case-label. Imperative case-statements can have at most one anonymous cases (at most one else/otherwise-branches).

The actual order of case-labels is not relevant. They may be ascending, descending, or mixed up, it does not matter.

Originally, standard Pascal also set the constraint, that all possible values of the selector have to have a corresponding match. This is no longer the case with modern compilers.

case can have both, imperative and declarative meanings, depending on where it is written. The former are “statements”, whereas the latter start a “variant part” of records.

case-statements

case-statements are a concise way of writing branches. They suit best, where alternative paths are taken exclusively. They may contain an else-branch catching all cases that are not listed.

 1program asciiTest(input, output, stderr);
 2
 3var
 4	c: char;
 5
 6begin
 7	read(c);
 8	case ord(c) of
 9		// empty statement, so the control characters are not
10		// considered by the else-branch as non-ASCII-characters
11		0..$1F, $7F: ;
12		$20..$7E:
13		begin
14			writeLn('You entered an ASCII printable character.');
15		end;
16		else
17		begin
18			writeLn('You entered a non-ASCII character.');
19		end;
20	end;
21end.

Note, case-statements accept expressions as selector.

Instead of writing else the word otherwise is allowed, too. This is an Extended Pascal extension.

While the same semantics can be achieved by consecutive if-then-branches, utilizing a case-statement allows the code generator to optimize the branch selection.

comparative remarks

There is no “fall-through” as it is the case with other languages such as shell or C. In Pascal exactly one case matches, is processed, and program flow continues after the final end of the case-statement. The break-statement with its special meaning only appears in loops.

variant part in records

A record may contain a variant part. The case-selector has to be the name of a data type, but an identifier for accessing the current variant can be provided, too.

 1program variantRecordDemo(input, output, stderr);
 2
 3type
 4	sex = (female, male);
 5	clothingSize = record
 6			// FIXED PART
 7			shoulderWidth: word;
 8			armLength: word;
 9			bustGirth: word;
10			waistSize: word;
11			hipMeasurement: word;
12			// VARIABLE PART
13			case body: sex of
14				female: (
15					underbustMeasure: word;
16				);
17				male: (
18				);
19		end;
20begin
21end.

see also

external references