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.