11.8 CASE--An Extended Example

In the example of section 9.5, routines were presented to print out a cardinal value as a binary numeral by interpreting it as a BITSET using a CAST. A non-discriminated union can be employed instead, and that example re-coded as below.

MODULE ShiftDemo2;

(* Written by R.J. Sutcliffe *)
(* to demonstrate the use of packedset *)
(* using ISO standard Modula-2  *)
(* last revision 1994 03 01 *)

FROM STextIO IMPORT
  WriteString, WriteLn, SkipLine, ReadChar, WriteChar;
FROM SWholeIO IMPORT
  WriteCard, ReadCard;
FROM SYSTEM IMPORT
  BITSPERLOC, SHIFT, ROTATE;
  
CONST
  maxBitNum = BITSPERLOC * SIZE(CARDINAL) - 1;
  
TYPE
  CardSet = PACKEDSET OF [0..maxBitNum];
  Card =
    RECORD
      CASE : BOOLEAN OF (* undiscriminated variant *)
        TRUE:
          c : CARDINAL |
        FALSE:
          s : CardSet
        END
    END;
  
PROCEDURE WriteCardBin (num: Card);

VAR
  count : CARDINAL;
  
BEGIN
  FOR count := maxBitNum TO 0 BY -1 
    DO 
      IF count IN num.s
        THEN
          WriteCard (1,1)
        ELSE
          WriteCard (0,1)
        END;
      IF count MOD 8 = 0 (* break into groups of 8 bits *)
        THEN
          WriteChar (" ");
        END;
    END;
END WriteCardBin;

VAR
  theNumber : Card;
  answer : CHAR;
  again : BOOLEAN;
 
BEGIN
  WriteString ("This program illustrates bit shifting ");
  WriteLn;

REPEAT
  WriteString ("Enter the number to be shifted ");
  ReadCard (theNumber.c);
  SkipLine;
  WriteLn;
  WriteString ("The cardinal ");
  WriteCard (theNumber.c, 0);
  WriteString (" binary: ");
  WriteCardBin (theNumber);
  WriteLn;
  WriteString ("Shifted one position right yields ");
  theNumber.s := SHIFT (theNumber.s, -1);
  WriteCard (theNumber.c, 0);
  WriteString (" binary: ");
  WriteCardBin (theNumber);
  WriteLn;
  WriteString ("and, then rotated one position right yields ");
  theNumber.s := ROTATE (theNumber.s, -1);
  WriteCard (theNumber.c, 0);
  WriteString (" binary: ");
  WriteCardBin (theNumber);
  WriteLn;
 
  WriteString ("Do another? Y/N ");
  ReadChar (answer);
  SkipLine;
  again := (CAP (answer) = "Y");
UNTIL NOT again;

END ShiftDemo2.

In addition, the binary printing routines could be altered to print in hexadecimal by putting hexadecimal digits together one at a time starting from the most significant bits in the bitset representation of a number. Here is a short demonstration program. Note the additional use of the case statement for the printing of each hexadecimal digit. It must distinguish between the case of decimal digits and non-decimal digits.

MODULE HexDemo;

(* Written by R.J. Sutcliffe *)
(* to demonstrate the use of variant records and case statements *)
(* using ISO standard Modula-2  *)
(* last revision 1995 03 24 *)

FROM STextIO IMPORT
  WriteString, WriteLn, SkipLine, ReadChar, WriteChar;
FROM SWholeIO IMPORT
  WriteCard, ReadCard;
FROM SYSTEM IMPORT
  BITSPERLOC;
  
CONST
  maxBitNum = BITSPERLOC * SIZE (CARDINAL) - 1;
  
TYPE
(* allow interpretation of a cardinal as a set without casting *)
  Hex = CARDINAL [0..15];
  BitCount = [0..maxBitNum];
  CardSet = PACKEDSET OF BitCount;
  Card =
    RECORD
      CASE : BOOLEAN OF (* undiscriminated variant *)
        TRUE:
          c : CARDINAL |
        FALSE:
          s : CardSet
        END
    END;

PROCEDURE WriteCardBin (num: Card);
VAR
  count : CARDINAL;
BEGIN
  FOR count := maxBitNum TO 0 BY -1 
    DO 
      IF count IN num.s
        THEN
          WriteCard (1,1)
        ELSE
          WriteCard (0,1)
        END;
      IF count MOD 8 = 0 (* break into groups of 8 bits *)
        THEN
          WriteChar (" ");
        END;
    END;
END WriteCardBin;

PROCEDURE WriteHexDigit (digit : Hex);
BEGIN
  CASE digit OF
    0..9: (* numeric hex digit *)
      WriteChar (CHR (ORD ("0") + digit));
    ELSE (* 10 -- 15 or A to E digits *)
      WriteChar (CHR (ORD ("A") + digit - 10));
    END;
END WriteHexDigit;

PROCEDURE WriteCardHex (num: Card);

VAR
  count, tcount : CARDINAL;
  temp : Card;
  
BEGIN
  temp.c := 0; (* holder for four bits at a time *)
  tcount:= 4; (* count down from most significant bit *)
  FOR count := maxBitNum TO 0 BY -1 
    DO 
      DEC (tcount); (* so, we actually start at three *)
      IF count IN num.s 
        THEN (* transfer four bits to the temporary item *)
          INCL (temp.s, tcount)
        END;
      IF count MOD 4 = 0 (* break into nibbles *)
        THEN
          WriteHexDigit (temp.c); (* and go print one digit *)
          temp.c := 0; (* now, reset for the next nibble *)
          tcount:= 4; (* and reset the count too *)
        END;
    END;
END WriteCardHex;

VAR (* main *)
  card : Card;
  answer : CHAR;
  again : BOOLEAN;
 
BEGIN  (* main *)
  WriteString ("This program illustrates binary and hex output ");
  WriteLn;

REPEAT
  WriteString ("Enter a cardinal number to be printed ");
  ReadCard (card.c);
  SkipLine;
  WriteString ("The cardinal ");
  WriteCard (card.c, 0);
  WriteString (" in binary is: ");
  WriteCardBin (card);
  WriteString (" and in hex is: ");
  WriteCardHex (card);
  WriteLn;
 
  WriteString ("Do another? Y/N ");
  ReadChar (answer);
  SkipLine;
  WriteLn;
  again := (CAP (answer) = "Y");
UNTIL NOT again;

END HexDemo.

Selected output from a run of this program follows to illustrate its correctness. As usual, user inputs are in bold.

This program illustrates binary and hexadecimal output 
Enter a cardinal number to be printed 1
The cardinal 1 in binary is: 00000000 00000000 00000000 00000001  and in hex is: 00000001
Do another? Y/N y

Enter a cardinal number to be printed 14
The cardinal 14 in binary is: 00000000 00000000 00000000 00001110  and in hex is: 0000000E
Do another? Y/N y

Enter a cardinal number to be printed 65535
The cardinal 65535 in binary is: 00000000 00000000 11111111 11111111  and in hex is: 0000FFFF
Do another? Y/N y

Enter a cardinal number to be printed 31415
The cardinal 31415 in binary is: 00000000 00000000 01111010 10110111  and in hex is: 00007AB7
Do another? Y/N y

Enter a cardinal number to be printed 4294967295
The cardinal 4294967295 in binary is: 11111111 11111111 11111111 11111111  and in hex is: FFFFFFFF
Do another? Y/N n

The reader will note that the implementation employed happened to use a thirty-two bit or eight hexadecimal digit representation for its cardinals, but that the program itself should work regardless of this, because of the way it is crafted.


Contents