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.