Page 1 of 1

Oberon 2011: CASE Statements

Posted: Sat Oct 08, 2011 12:06 pm
by cfbsoftware
Single-character strings can now be used as CASE labels as well as INTEGER constants. When the labels are strings the selector is a CHAR.

The 2011 Oberon Language Report does not explicitly specify implementation details of CASE statements such as:
  • What is the valid range of values for CASE labels?
  • What happens when a label appears more than once in the same CASE statement?
  • What happens if the CASE selector references a label that does not exist?
In Astrobe v4 the implementation details are equivalent to those in Astrobe v3.4:
  • Valid CASE labels are in the range 0..255 for INTEGERs and 0X..0FFX for strings.
  • Duplicate CASE labels are reported as compile-time errors.
  • A reference to a missing label results in a runtime error and program termination.
If you design your programs so that they do not result in errors when they are developed using Astrobe then you can be reasonably confident that they will also run without CASE-related errors on other systems that conform to Revision 22.9.2011 of the language report.

For example, when included in a module, the following code snippet should compile and run without errors on an Astrobe v4 system:

Code: Select all

PROCEDURE ToUpperCase(VAR ch: CHAR);
BEGIN
  IF (ch >= "a") & (ch <= "z") THEN 
    ch := CHR(ORD(ch) - ORD("a") + ORD("A"))
  END 
END ToUpperCase;
   
PROCEDURE SoundexCode(ch: CHAR): INTEGER;
VAR 
  value: INTEGER;
BEGIN
  ToUpperCase(ch);
  IF (ch < "A") OR (ch > "Z") THEN 
    value := 0
  ELSE
    CASE ch OF
     "A", "E", "I", "O", "U", "H", "W", "Y":
        value := 0 |
     "B", "F", "P", "V":
        value := 1 |
     "C", "G", "J", "K", "Q", "S", "X", "Z":
        value := 2 |
     "D", "T":
        value := 3 |
     "L":
        value := 4 |
     "M", "N":
        value := 5 |
     "R":
        value := 6 
    END
  END;
  RETURN value
END SoundexCode;
As recommended in the Astrobe documentation, for best results you should restrict the use of CASE statements to situations where:
  • The case labels are naturally integers or characters
  • The smallest case label is close to zero or 0X.
  • The case labels are relatively contiguous
  • There are a large (i.e. more than half-a-dozen) number of cases
  • All cases have similar probabilities of occurrence
Otherwise consider using an IF-ELSIF...ELSIF-ELSE series of statements instead.

In some cases a hybrid combination of CASE and IF statements can result in a good compromise between readability, efficiency and memory usage.

Re: Oberon 2011: CASE Statements

Posted: Thu Oct 27, 2011 12:22 pm
by cfbsoftware
Consider the following example which could be used to map a set of strings to a corresponding integer code:

Code: Select all

  PROCEDURE FindKeyword*(id: ARRAY OF CHAR; VAR sym: INTEGER);
  BEGIN
    sym := ident;
    IF    id = "ARRAY" THEN sym := array
    ELSIF id = "BEGIN" THEN sym := begin
    ELSIF id =    "BY" THEN sym := by
    ELSIF id =  "CASE" THEN sym := case
    ELSIF id = "CONST" THEN sym := const
    ELSIF id =   "DIV" THEN sym := div
...
...
You can write this more efficiently with a hybrid combination of CASE and IF-THEN as follows:

Code: Select all

  PROCEDURE FindKeyword*(id: ARRAY OF CHAR; VAR sym: INTEGER);
  BEGIN
    sym := ident;
    CASE id[0] OF
    "A": 
      IF id = "ARRAY" THEN sym := array
      END |
    "B":
      IF id = "BEGIN" THEN sym := begin
      ELSIF id = "BY" THEN sym := by
      END |
    "C":
      IF id = "CASE" THEN sym := case
      ELSIF id = "CONST" THEN sym := const
      END |
    "D":
      IF id = "DIV" THEN sym := div
      ELSIF id = "DO" THEN sym := do
      END |
...
...
Timing tests using an example with ~30 cases, assuming each word occurs with the same frequency, indicates that the CASE solution is 4 times faster than the IF-THEN ladder solution. However, the CASE approach generates 30% more code.