PROGRAM DECBINCNV;

USES crt;

{//////////////////////////////////////////////////////////////////////////////
  AUTHOR    : Lo Ching Chin James (950208778)
  COURSE    : CIS101 - Introduction to Computer and Computer Programming
  ASSIGN    : CW3A.PAS
  DATE      : 20 Nov 1997
  COPYRIGHT : JAMES LO NOVEMBER 1997, HONG KONG

  This program provides function to :

  1. Convert a positive or negative integer into binary string.
  2. Convert a binary string into a positive or negative integer.
  3. Convert a real number to binary string.
  4. Convert a binary string to real number.

  Input :

  User select appropriate options and input data such as no. of bytes, binary
  strings or integers to perform conversion.

  Output :

  Systems will display the results depending on what task has been performed.

///////////////////////////////////////////////////////////////////////////////}


CONST

    i_LowLimit       = 1;  { Define the lower limit of choice value }
    i_HighLimit      = 5;  { Define the higher limit of the choice value }
    i_1Byte          = 1;  { Define the value for 1 byte }
    i_2Byte          = 2;  { Define the value for 2 bytes }
    i_NoOfBit        = 8;  { Define the number of bits per byte }
    i_Base2          = 2;  { Define base 2 value }
    i_8ExpStartBit   = 2;  { Define the starting bit of exponent real num 8 bit }
    i_8ExpEndBit     = 4;  { Define the ending bit of exponent real num 8 bit }
    i_8ManStartBit   = 5;  { Define the starting bit mantissa of real num 8 bit }
    i_8ManEndBit     = 8;  { Define the ending bit mantissa of real num 8 bit }
    i_16ExpStartBit  = 2;  { Define the starting bit exponent of real num 16 bit }
    i_16ExpEndBit    = 6;  { Define the ending bit exponent of real num 16 bit }
    i_16ManStartBit  = 7;  { Define the starting bit mantissa of real num 16 bit }
    i_16ManEndBit    = 16; { Define the ending bit mantissa of real num 16 bit }
    i_8BitExpInd     = 4;  { Define the 8 bit indicator }
    i_16BitExpInd    = 16; { Define the 16 bit indicator }
    r_8posbinary     = 7.5;  {Define real number limit for 8 bit}
    r_16posbinary    = 32736.0; {Define real number limit for 16 bit}
    i_MultipleOfByte = 2;    {Define the mutiple of bits per byte}
    s_ZeroString     = '0';  {Define '0' string}
    s_OneString      = '1';  {Define '1' string}
    i_OKIOResult     = 0;    {Define good I/O result}
    s_Space          = ' ';  {Define space value}
    r_OneHalf        = 0.5;  {Define one half value}
    i_NegativeOne    = -1;
    i_PositiveOne    =  1;

TYPE

    bit_string       = ARRAY[1..i_NoOfBit * i_MultipleOfByte] OF Char;

VAR

    s_Response     : char;       {Define a char for response}
    i_Choice       : integer;    {Define choice variable}
    i_Byte,i_Bit   : integer;    {Define byte and bit variable}
    i_integer      : Longint;    {Define variable for integer input}
    r_RealNum      : Real;       {Define variable for real number input }
    s_string       : bit_string; {Define variable for converted string}
    s_dummy        : char;       {Define dummy variable for enter key}
    i_LowRange,
    i_HighRange    : LONGINT;    {Define variable for hi and low integers}
    r_LowRange,
    r_HighRange    : REAL;       {Define variable for hi and low real number}


{////////////////////////////////////////////////////////////////////////////
 TRIM() - this function trims trailing space.
////////////////////////////////////////////////////////////////////////////}
FUNCTION TRIM(inStr:STRING):STRING;

BEGIN

    WHILE (inStr[LENGTH (inStr)] = ' ') DO
        inStr := COPY (inStr, 1, LENGTH (inStr ) - 1);
    WHILE (inStr[1] = ' ') DO
          DELETE (inStr, 1, 1);
    TRIM := inStr

END; {TRIM}


{/////////////////////////////////////////////////////////////////////////////
 Press any key to continue procedure
/////////////////////////////////////////////////////////////////////////////}
PROCEDURE PRESSKEY;

BEGIN

    WRITE('Press any key to continue ...');

END;


{/////////////////////////////////////////////////////////////////////////////
 Raise X to power Y
/////////////////////////////////////////////////////////////////////////////}
FUNCTION RAISEPOWER(base,exponent:INTEGER): LONGINT;

VAR

     i_temp, i : LONGINT;

BEGIN

     i_temp := 1;

     FOR i := 1 TO exponent DO
         i_temp := i_temp * i_base2;

     RAISEPOWER := i_temp;

END; {RAISEPOWER}


{////////////////////////////////////////////////////////////////////////////
 Print bit string to screen
////////////////////////////////////////////////////////////////////////////}
PROCEDURE BIT_STRING_PRINT(VAR b:bit_string; nbit:INTEGER);

VAR

     i    : INTEGER;

BEGIN

     FOR i := 1 TO nbit DO
         WRITE (b[i]);

END; {BIT_STRING_PRINT}


{////////////////////////////////////////////////////////////////////////////
 Set bit value of '0' or '1' based on passed parameter value
////////////////////////////////////////////////////////////////////////////}
PROCEDURE BIT_STRING_SETBIT(VAR b:bit_string; nth:INTEGER; value:INTEGER);

VAR

     s  : STRING[1];

BEGIN

     STR(value,s);
     b[nth] := s[1];

END; {BIT_STRING_SETBIT}


{////////////////////////////////////////////////////////////////////////////
 Fill in '0's to the trailing space
////////////////////////////////////////////////////////////////////////////}
PROCEDURE BIT_STRING_ZERO(VAR b:bit_string; i_frvalue:INTEGER; i_tovalue: INTEGER);

VAR

     i : integer;

BEGIN

      FOR i := i_frvalue TO i_tovalue DO
           b[i] := s_ZeroString;

END; {BIT_STRING_ZERO}


{////////////////////////////////////////////////////////////////////////////
 Reverse bit string order e.g. '00100000' --> '00000100'
////////////////////////////////////////////////////////////////////////////}
PROCEDURE BIT_STRING_REVERSE(VAR b:bit_string; value:INTEGER);

VAR

    i,j        : INTEGER;
    tmp_string : bit_string;

BEGIN

     j := 0;
     FOR i := value DOWNTO 1 DO   { Reverse the order }
         BEGIN
            INC(j);
            tmp_string[j] := b[i];
         END;

     FOR i := 1 TO value DO       { Move from temp array to actual array }
         BEGIN
            b[i] := tmp_string[i];
         END;

END; {BIT_STRING_REVERSE}


{////////////////////////////////////////////////////////////////////////////
 2's complement routine e.g. '00100000' --> '11100000'
////////////////////////////////////////////////////////////////////////////}
PROCEDURE BIT_STRING_2COM(VAR b:bit_string; nbit:INTEGER);

VAR

    b_finish   : boolean;
    j, i       : INTEGER;

BEGIN

      FOR i := nbit DOWNTO 1 DO  { Reverse the bit '0' to '1' or vice versa }
          IF b[i] = s_ZeroString THEN
             b[i] := SUCC(b[i])
          ELSE
             b[i] := PRED(b[i]);

      b_finish  := FALSE;
      j := nbit;

      REPEAT

         BEGIN
            IF b[j] = s_ZeroString THEN
               BEGIN
                   b[j] := SUCC(b[j]);
                   b_finish := TRUE;    { Exit from this loop }
               END
            ELSE
               BEGIN
                   b[j] := PRED(b[j]);
               END;
            DEC(j);                     { Decrease from right to left }
         END;

      UNTIL b_finish;

END; {BIT_STRING_2COM}


{////////////////////////////////////////////////////////////////////////////
 To copy the string into the array
////////////////////////////////////////////////////////////////////////////}
PROCEDURE BIT_STRING_COPY(s_inString        : STRING;
                         i_ExpStart,i_ExpEnd: INTEGER;
                          VAR b             : bit_string);


VAR

      j, i : INTEGER;

BEGIN

      j := 1 ;
      FOR i := i_ExpStart TO i_ExpEnd DO
          BEGIN
             b[i] := s_inString[j];
             INC(j);
          END

END; {BIT_STRING_COPY}


{////////////////////////////////////////////////////////////////////////////
 Routine to chop off zeros in extreme left in order to get the first 1
////////////////////////////////////////////////////////////////////////////}
PROCEDURE STRING_CHOPOFF_ZERO(VAR s_inString: STRING;
                              VAR i_expvalue: INTEGER);

VAR

      tmp_string : String;
      i, j       : INTEGER;

BEGIN

       i := 1;
       i_expvalue := 0;
       tmp_string := '';

       WHILE s_inString[i] <> s_OneString DO
         BEGIN
              INC(i_expvalue);
              INC(i);
         END;

       j := i;
       tmp_string := COPY(s_instring, j, LENGTH(s_inString) - i + 1);
       s_inString := tmp_String;

END;


{////////////////////////////////////////////////////////////////////////////
 Calculate no. of bits based on byte number
////////////////////////////////////////////////////////////////////////////}
FUNCTION GETBITNO(i_byte:INTEGER): INTEGER;

BEGIN

     IF i_byte = 1 THEN
        GETBITNO := i_NoOFBit
     ELSE
        GETBITNO := i_NoOFBit * i_MultipleOfByte;

END; {GETBITNO}


{////////////////////////////////////////////////////////////////////////////
 Capture number of bytes
////////////////////////////////////////////////////////////////////////////}
PROCEDURE GETBYTENO(i_1B,i_2B          : INTEGER;
                    VAR i_RByte, i_RBit: INTEGER);

VAR

      i_Number,i_X,i_Y   : INTEGER;

BEGIN

      REPEAT

            GOTOXY(1,11);
            WRITE  ('Enter how many bytes ','(1 Byte = ',i_NoOfBit, ' bits) (',i_1B:1,' or ',i_2B:1,') : ');
            i_X := WHEREX;
            i_Y := WHEREY;
            {$I-}
            TEXTCOLOR(YELLOW);
            READLN (i_Number);
            TEXTCOLOR(WHITE);
            {$I+}
            IF (IORESULT <> i_OKIOResult) OR (i_Number < i_1B) OR (i_Number > i_2B) THEN
               BEGIN
                 GOTOXY(i_X,i_Y);
                 CLREOL;
               END
            ELSE
               BEGIN
                 i_RByte := i_Number;
                 i_RBit  := GETBITNO(i_Number);
               END

      UNTIL (IORESULT = i_OKIOResult) AND (i_Number >= i_1B) AND (i_Number <= i_2B)

END; {GETBYTENO}


{/////////////////////////////////////////////////////////////////////////////
 Get user input a integer number
/////////////////////////////////////////////////////////////////////////////}
PROCEDURE GETNUMBER(i_Low,i_High  : INTEGER;
                    VAR i_Number  : LONGINT;
                    VAR b_OverFlow: BOOLEAN);

VAR

     i_X,i_Y, i_IORESULT   : INTEGER;

BEGIN

      REPEAT

          b_OverFlow := FALSE;
          GOTOXY(1,12);
          WRITE  ('Enter a positive or negative integer: ');
          i_X := WHEREX;
          i_Y := WHEREY;
          {$I-}
          TEXTCOLOR(YELLOW);
          READLN (i_Number);
          TEXTCOLOR(WHITE);
          {$I+}
          i_ioresult := IORESULT;
          IF (i_Number < i_Low) OR (i_Number > i_High) THEN
             BEGIN
                b_OverFlow := TRUE;    { Set this flag to true for overflow }
                GOTOXY(1,13);
                TEXTCOLOR(LIGHTRED+BLINK);
                WRITELN('Error: Data overflow. Range is ',i_Low, ' to ', i_High,' for ',i_Byte, ' byte(s).');
                TEXTCOLOR(WHITE);
             END;
          IF (i_IORESULT <> i_OKIOResult) THEN
             BEGIN
                GOTOXY(1,13);
                TEXTCOLOR(LIGHTRED+BLINK);
                WRITE('Error: Accepts only positive or negative integer.');
                TEXTCOLOR(WHITE);
                s_dummy := READKEY;
                GOTOXY(1,13);
                CLREOL;
                GOTOXY(i_X,i_Y);
                CLREOL;
             END;
      UNTIL (i_IORESULT = i_OKIOResult)


END; {GETNUMBER}


{/////////////////////////////////////////////////////////////////////////////
 Get user input a integer number
/////////////////////////////////////////////////////////////////////////////}
PROCEDURE GETREALNUM(r_Low,r_High  : REAL;
                     VAR r_Number  : REAL;
                     VAR b_OverFlow: BOOLEAN);

VAR

     i_X,i_Y, i_IORESULT   : INTEGER;

BEGIN

      REPEAT

          b_OverFlow := FALSE;
          GOTOXY(1,12);
          WRITE  ('Enter a positive or negative real number : ');
          i_X := WHEREX;
          i_Y := WHEREY;
          {$I-}
          TEXTCOLOR(YELLOW);
          READLN (r_Number);
          TEXTCOLOR(WHITE);
          {$I+}
          i_IORESULT := IORESULT;
          IF (r_Number < r_Low) OR (r_Number > r_High) THEN
             BEGIN
                b_OverFlow := TRUE;
                GOTOXY(1,13);
                TEXTCOLOR(LIGHTRED+BLINK);
                WRITELN('Error: Data overflow, range is ',r_Low:5:4,' to ',r_High:5:4,' for ',i_Byte, ' byte(s).');
                TEXTCOLOR(WHITE);
             END;

          IF (i_IORESULT <> i_OKIOResult) THEN
             BEGIN
                GOTOXY(1,13);
                WRITE('Error: Accepts only real number.');
                s_dummy := READKEY;
                GOTOXY(1,13);
                CLREOL;
                GOTOXY(i_X,i_Y);
                CLREOL;
             END;

      UNTIL (i_IORESULT = i_OKIOResult)

END; {GETREALNUM}


{//////////////////////////////////////////////////////////////////////////////
 Process calculate integer to binary
//////////////////////////////////////////////////////////////////////////////}
PROCEDURE CALINTBIN(i_Num: LONGINT; i_Bit :INTEGER; VAR b:bit_string;
                    b_OFFlag:BOOLEAN);

VAR

       i_quotient,i_remainder, i, j, k  : INTEGER;
       s                                : String[1];
       tmp_string, bin_string           : bit_string;
       i_absnum                         : LONGINT;

BEGIN

       FOR j := 1 TO i_bit DO    { Initialize array }
          BEGIN
             tmp_string[j] := s_Space;
             bin_string[j] := s_Space;
          END;

       i := 0;
       i_absnum := ABS(i_num);
       WHILE (i_absnum <> 0) DO   { IF number is 10, the base 2 is 0101 }
          BEGIN
             i_quotient := i_absnum DIV i_MultipleOfByte;
             i_remainder:= i_absnum MOD i_MultipleOfByte;
             i_absnum := i_quotient;
             INC(i);
             BIT_STRING_SETBIT(tmp_string,i,i_remainder);
          END;

       k := i + 1;   { Should add 1 here for next bit }
       BIT_STRING_ZERO(tmp_string, k, i_bit); { Fill in '0' }

       { At this point, the bit pattern is filled with '0's but in reverse
         order.  e.g.  4 ---> '00100000', should be '00000100'.
         So, we have to reverse it. }

       BIT_STRING_REVERSE(tmp_string,i_bit); { Reverse the bit pattern }

       bin_string := tmp_string;
       { At this point, the bit pattern is in proper order }

       IF i_num < 0  THEN   { Input number is a negative number }
          BEGIN
             BIT_STRING_2COM(bin_string,i_bit);  {Get the 2's complement}
             b := bin_string;
          END
       ELSE
          b := bin_string;

      IF b_OFFlag THEN   {If the number inputed is overflow }
         IF i_num < 0 THEN
            b[1] := s_OneString   {Set to '1'}
         ELSE
            b[1] := s_ZeroString; {Set to '0'}


END; {CALINTBIN}


{/////////////////////////////////////////////////////////////////////////////
 Binary to decimal
/////////////////////////////////////////////////////////////////////////////}
FUNCTION BINTODEC (s_binary:STRING):INTEGER;

VAR

     j              : integer;  { Define counter }
     i_value        : LONGINT;  { Define converted binary to decimal value }

BEGIN

     i_value := 0;

     FOR j := LENGTH(TRIM(s_binary)) DOWNTO 2 DO
         { Not downto 1 because 1 is a sign bit }
         BEGIN
              IF s_binary[j] = s_OneString THEN
                  i_value := i_value + TRUNC(EXP(((LENGTH(TRIM(s_binary)) - j) * LN(i_Base2) )))
              ELSE
                  i_value := i_value + 0;
         END;

     IF s_binary[1] = s_OneString THEN    {Input number is a negative value}
        BINTODEC := i_value - RAISEPOWER(i_Base2,i_bit - i_PositiveOne)
     ELSE
        BINTODEC := i_value;

END; {BINTODEC}


{/////////////////////////////////////////////////////////////////////////////
 Binary to integer routine
/////////////////////////////////////////////////////////////////////////////}
PROCEDURE BINTOINT;

VAR

     i,j,i_X,i_Y      : integer;
     b_okay           : boolean;
     s_binary         : String;

BEGIN

     GETBYTENO(i_1Byte,i_2Byte,i_Byte,i_Bit);

     REPEAT

         BEGIN

           b_okay := TRUE;
           s_binary := '';
           GOTOXY(1,12);
           WRITE ('Please enter a binary string in ',i_Bit, ' bit format : ');
           i_X := WHEREX;
           i_Y := WHEREY;
           CLREOL;
           TEXTCOLOR(YELLOW);
           READLN (s_binary);
           TEXTCOLOR(WHITE);
           FOR i := LENGTH(TRIM(s_binary)) DOWNTO i_PositiveOne DO
               IF NOT (s_binary[i] = s_ZeroString) AND NOT (s_binary[i] = s_OneString) THEN
                   BEGIN
                        b_okay := FALSE;
                        GOTOXY(i_X,i_Y);
                        CLREOL;
                   END
         END

     UNTIL b_okay AND (LENGTH(TRIM(s_binary)) = (i_Bit));

     WRITE  ('"', s_binary, '" binary string represents integer value : ');
     TEXTCOLOR(YELLOW);
     WRITE(BINTODEC(s_binary));
     TEXTCOLOR(WHITE);
     WRITELN('.');

END; {BINTOINT}


{////////////////////////////////////////////////////////////////////////////
 Integer to binary conversion
////////////////////////////////////////////////////////////////////////////}
PROCEDURE INTTOBIN;

VAR

      b_OFlowFlag : BOOLEAN;

BEGIN

      GETBYTENO(i_1Byte,i_2Byte,i_Byte,i_Bit);
      i_LowRange  := RAISEPOWER(i_Base2,i_Bit - i_PositiveOne) * i_NegativeOne;
      i_HighRange := RAISEPOWER(i_Base2,i_Bit - i_PositiveOne) - i_PositiveOne;
      GETNUMBER(i_LowRange,i_HighRange,i_Integer,b_OFlowFlag);
      WRITE (i_integer,' will be stored in ',i_byte, ' byte(s) as : ');
      WRITE('"');
      TEXTCOLOR(YELLOW);
      CALINTBIN(i_integer,i_Bit,s_string,b_OFlowFlag);  { Integer to binary routine }
      BIT_STRING_PRINT(s_string,i_bit);   { Print binary string }
      TEXTCOLOR(WHITE);
      WRITE('".');
      WRITELN;

END; {INTTOBIN}


{///////////////////////////////////////////////////////////////////////////
 Calculate exponent value
///////////////////////////////////////////////////////////////////////////}
FUNCTION CALEXP(s:Char; p:INTEGER):REAL;

VAR

      r_value   : REAL;
      i_errcode : INTEGER;
      i,j       : INTEGER;

BEGIN

      VAL(s,i,i_errcode);
      r_value := 1.0;

      FOR j := 1 TO p DO
          r_value := r_value * r_OneHalf;

      CALEXP := r_value * i;

END;  {CALEXP}


{/////////////////////////////////////////////////////////////////////////////
 Calculate the exponent value of the bit string to real numbers
/////////////////////////////////////////////////////////////////////////////}
FUNCTION CALEXPVAL(s_bitchar:Char; i: INTEGER): INTEGER;

VAR

      i_bitcharval,i_expval,i_errcode : INTEGER;

BEGIN

      i_expval := 0;
      i_bitcharval := 0;
      VAL(s_bitchar,i_bitcharval,i_errcode);
      i_expval := TRUNC(EXP(i * LN (i_base2)));

      CALEXPVAL := i_bitcharval * i_expval;
      { bit value (e.g. '1' -> 1 * 2 ^ i value }

END; {CALEXPVAL}


{/////////////////////////////////////////////////////////////////////////////
 Calculate exponent value of the bit string to real number
/////////////////////////////////////////////////////////////////////////////}
FUNCTION GETEXPVAL(s_binary:STRING;
                   i_start,i_end,i_expvalue:INTEGER):INTEGER;

VAR

      r_temp  : INTEGER;
      j,i     : INTEGER;

BEGIN

      r_temp := 0;
           j := 0;  {Starting point}

      FOR i:= i_end DOWNTO i_start DO

          BEGIN
             r_temp := r_temp + CALEXPVAL(s_binary[i],j);
             INC(j);
          END;

      GETEXPVAL := r_temp - i_expvalue;  { value of the exponent - 4 or 16 }

END; {GETEXPVAL}


{/////////////////////////////////////////////////////////////////////////////
 Calculate mantissa value of the bit string to real number
/////////////////////////////////////////////////////////////////////////////}
FUNCTION GETMANVAL(s_binary:STRING;i_start,i_end:INTEGER):REAL;

VAR

      r_temp  : REAL;
      j,i     : INTEGER;

BEGIN

      r_temp := 0.0;

      j := 1;
      FOR i:= i_start TO i_end DO
          BEGIN
               r_temp := r_temp + CALEXP(s_binary[i],j);
               INC(j);
          END;

      GETMANVAL := r_temp;

END;  {GETMANVAL}


{/////////////////////////////////////////////////////////////////////////////
 This function calculates parameter value in real type and return also in real
 type but in base 2
/////////////////////////////////////////////////////////////////////////////}
FUNCTION REMAINBASE2(r_fractionValue:REAL):STRING;

VAR

      s_base2value                        : STRING;
      r_temp, r_fraction                  : REAL;
      i, j, i_string, icode, i_divisor    : INTEGER;
      s_temp_string                       : String[1];
      s_string                            : String;

BEGIN

      r_fraction := r_fractionValue;
      i          := 0;
      s_string   := '';
      r_temp     := 0;

      REPEAT
           BEGIN
             r_temp        := r_fraction * i_MultipleOfByte;
             STR(TRUNC(r_temp),s_temp_string);
             s_string      := s_string + s_temp_string;
             r_fraction    := r_temp - TRUNC(r_temp);
             INC(i);
           END
      UNTIL r_fraction = 0.0;

      {At this point, the s_string contains e.g. 01 Base 2 for 0.25 value}
      s_base2value := s_string;
      REMAINBASE2 := s_base2value;

END;


{//////////////////////////////////////////////////////////////////////////////
 Process calculate integer to binary
//////////////////////////////////////////////////////////////////////////////}
PROCEDURE INTBASE2(i_Num: LONGINT;  VAR i_exponent:INTEGER;
                                    VAR bin_string:STRING);

VAR

       i_quotient,i_remainder, p,
       j, k, i_intBase2, icode          : INTEGER;
       s                                : String[1];
       tmp_string                       : String;
       i_absnum                         : LONGINT;

BEGIN

       i_exponent := 0;
       i_absnum := ABS(i_num);
       tmp_string := '';
       bin_string := '          '; 
       WHILE (i_absnum <> 0) DO
       { IF number is 10, the base 2 is 0101, if number is 0 then it will
         skip this part }
          BEGIN
             i_quotient := i_absnum DIV i_MultipleOfByte;
             i_remainder:= i_absnum MOD i_MultipleOfByte;
             i_absnum := i_quotient;
             STR(i_remainder,s);
             tmp_string := tmp_string + s;
             INC(i_exponent);
          END;

       { At this point, the string value in tmp_string is in reverse order
         so we have to reverse back it}

       IF ABS(i_num) <> 0 THEN
          BEGIN
              p := i_exponent;
              FOR j := 1 TO p DO
              BEGIN
                 bin_string[j] := tmp_string[p];
                 DEC(p);
              END
          END
       ELSE
          BEGIN
             i_exponent := 0;
             bin_string := s_ZeroString;
          END


END; {INTBASE2}


{/////////////////////////////////////////////////////////////////////////////
 Copy temporary bit string to the final bit string
/////////////////////////////////////////////////////////////////////////////}
PROCEDURE BIT_STRING_SETMAN(s_inString:STRING;
                            i_nBit    :INTEGER;
                            VAR b     :bit_string);

VAR

     i_StartBit, i_EndBit, i, j, k, q, p : INTEGER;

BEGIN

      IF i_nBit = i_NoOfBit THEN
         BEGIN
            i_StartBit := i_8ManStartBit ;
            i_EndBit   := i_8ManEndBit   ;
         END
      ELSE
         BEGIN
            i_StartBit := i_16ManStartBit ;
            i_EndBit   := i_16ManEndBit   ;
         END;

      j := i_EndBit - i_StartBit + 1;   { j refers to no. of bit for mantissa }
      k := i_StartBit;
      IF LENGTH(TRIM(s_inString)) > j THEN
         BEGIN
            WRITELN('Note: Round off error.');
            FOR i := 1 TO j DO    { How many times to fill the s_InString }
            BEGIN
               b[k] := s_InString[i];
               INC(k);
            END
         END
      ELSE
         FOR i := 1 TO LENGTH(TRIM(s_inString)) DO    { How many times to fill the s_InString }
         BEGIN
             b[k] := s_InString[i];
             INC(k);
         END;


      { If there is available space to fill in, we have to do the following
        routine, e.g. if the input is 16 bit the storage for 2.25 is like
        this for mantissa:
                    16 bit
        +-------------------------------+
        | | | | | | |1|0|0|1| | | | | | |
        +-------------------------------+
                     |       | | | | | | ----> these should be filled with '0'
                     +----Start of mantissa
      }

      q := k;
      p := LENGTH(TRIM(s_inString));

      IF p < (i_EndBit - i_StartBit + i_PositiveOne) THEN
      { To check whether any zero to fill }

         BEGIN
           BIT_STRING_ZERO(b,q,i_EndBit);
         END

END; {BIT_STRING_SETMAN}


{/////////////////////////////////////////////////////////////////////////////
 To set the bit string for exponent value
/////////////////////////////////////////////////////////////////////////////}
PROCEDURE BIT_STRING_SETEXP(i_exponent:INTEGER;
                            c_Sign    :CHAR;
                            i_Bit     :INTEGER;
                            VAR b     :bit_string);

VAR

    k, i, p, q, r, t, u, w, y, z, x, i_dummy : INTEGER;
    s_rtnstring,s_finalString, tmp_string    : STRING;

BEGIN

       s_finalstring := '';

       IF i_Bit = i_NoOfBit THEN
          BEGIN
             q := i_8BitExpInd;          { q is excess 4 }
             t := i_8ExpStartBit;
             u := i_8ExpEndBit;
             w := i_8ExpEndBit - i_8ExpStartBit;
          END
       ELSE
          BEGIN
             q := i_16BitExpInd;         { q in excess 16 }
             t := i_16ExpStartBit;
             u := i_16ExpEndBit;
             w := i_16ExpEndBit - i_16ExpStartBit;
          END;

       IF i_exponent = 0 THEN { Logically meant, no need to do with the exponent }
          BEGIN
              p := q;
              INTBASE2(p,i_dummy,s_rtnstring);
          END
       ELSE
          BEGIN
              IF c_Sign = '+' THEN
                 p := i_exponent + q
              ELSE
                 p := i_exponent * i_NegativeOne + q;
              INTBASE2(p,i_dummy,s_rtnstring);
          END;

       tmp_string := TRIM(s_rtnString);
       x := LENGTH(tmp_string);

       IF x < w + 1 THEN
          BEGIN
            y  := ( w + 1 ) - x;
            FOR z := 1 TO y DO
              s_finalString := s_finalString + s_ZeroString;
          END;

       s_finalString := s_finalString + tmp_string;

       {At this point, we have already the string for exponent side and ready
        to put it into the final bit string array }

       BIT_STRING_COPY(s_finalstring,t,u,b);

END; {BIT_STRING_SETEXP}


{///////////////////////////////////////////////////////////////////////////
 Real to bin
///////////////////////////////////////////////////////////////////////////}
PROCEDURE CALREALBIN (r_inputReal   :REAL;
                     i_Bit          :INTEGER;
                     b_OFFlag       :BOOLEAN;
                     VAR s_outstring:bit_string);

VAR

    r_RealNumInBase2 : REAL;
    r_ABSValNum      : REAL;
    r_remain         : REAL;
    s_remainBase2    : STRING;
    s_totvalBase2    : STRING;
    s_intBase2       : STRING;
    i_intBase2       : INTEGER;
    icode            : INTEGER;
    i_exponent       : INTEGER;
    i_expvalue       : INTEGER;
    i,ierrcode,j,k   : INTEGER;
    bin_string       : bit_string;
    i_totexpval,q    : INTEGER;
    i_dummy,i_loop   : INTEGER;
    c_Sign           : CHAR;

    { Fractional value in base 2, e.g. 6.25 (base 10) --> 110.01 (base 2) }

BEGIN

    r_ABSValNum   := ABS(r_inputReal);      { Get the absolute value}
    r_remain      := r_ABSValNum - TRUNC(r_ABSValNum); { e.g. 6.25 - 6.0 = .25 }

    IF r_ABSValNum < r_OneHalf THEN  { Check the inputed value in absolute value }
       c_Sign := '-'
    ELSE
       c_Sign := '+';

    s_remainBase2 := REMAINBASE2(r_remain);    { 0.25 Base 10 --> '01' }
    INTBASE2(TRUNC(r_ABSValNum), i_exponent, s_intBase2);  {6 Base 10 --> '110' }
    s_intBase2 := TRIM(s_intBase2);

    IF s_intBase2 = s_ZeroString THEN       { if the integer part is 0 }
       s_totvalBase2 := s_remainBase2 { '01' = '01' }
    ELSE
       s_totvalBase2 := s_intBase2 + s_remainBase2; { '110'+'01' = '11001' }

    {At this point, there are cases which the s_totvalbase2 string will
     start with '0....'. e.g. 0.4 base10 with be 0.01100110011... in base 2,
     so we must chop off the first 0 until the first bit is 1}

    STRING_CHOPOFF_ZERO(s_totvalBase2, i_expvalue);
    { i_expvalue is exponent to the right }

    FOR i := 1 TO i_Bit DO            { Initialize the final bit string }
       bin_string[i] := s_Space;

    IF i_exponent = 0 THEN
       i_exponent := i_expvalue;

    BIT_STRING_SETMAN(s_totvalBase2,i_Bit,bin_string);
    { To copy the bit string value of mantissa e.g. 6.25 ,
      the mantissa is '11001'}

    BIT_STRING_SETEXP(i_exponent,c_Sign,i_Bit,bin_string);
    { To set the exponent bit string e.g. 6.25 , the exponent bit string is
      '111' because '111' is 3 in excess 4 notation }

    { So, at this point, the bit string for 6.25 is '01111100' for 8 bit or
      '0100111100000000' for 16 bit }

    IF r_inputReal < 0 THEN
       bin_string[1] := s_OneString
    ELSE
       bin_string[1] := s_ZeroString;

    IF b_OFFlag THEN
       WRITELN('Note: The inputed real value has been overflowed.');

    s_outstring := bin_string;

END; {CALREALBIN}


{/////////////////////////////////////////////////////////////////////////////
 Convert real number to binary string
/////////////////////////////////////////////////////////////////////////////}
PROCEDURE REALTOBIN;

VAR

      r_realposval, r_realnegval  : REAL;
      b_OverFlow                  : BOOLEAN;
      s_binString                 : bit_String;

BEGIN

      GETBYTENO(i_1Byte,i_2Byte,i_Byte,i_Bit);
      IF i_Bit = i_NoOfBit THEN
          BEGIN
            r_realposval :=  1.0 * r_8posbinary;
            r_realnegval := -1.0 * r_8posbinary;
          END
      ELSE
          BEGIN
            r_realposval :=  1.0 * r_16posbinary;
            r_realnegval := -1.0 * r_16posbinary;
          END;

      r_LowRange  := r_realnegval;
      r_HighRange := r_realposval;

      GETREALNUM(r_LowRange,r_HighRange,r_RealNum,b_Overflow);
      WRITE (r_RealNum:5:5,' will be stored in ',i_byte, ' byte(s) as : ');
      WRITE('"');
      TEXTCOLOR(YELLOW);
      CALREALBIN(r_RealNum,i_Bit,b_OverFlow,s_binstring);  { Real Integer to binary routine }
      BIT_STRING_PRINT(s_binstring,i_bit);   { Print binary string }
      TEXTCOLOR(WHITE);
      WRITE('".');
      WRITELN;

END; {REALTOBIN}


{/////////////////////////////////////////////////////////////////////////////
 Binary to real number calculation
/////////////////////////////////////////////////////////////////////////////}
FUNCTION BINTOREALNUM(s_binary:STRING;  i_Bit:INTEGER):REAL;

VAR

      i,j, r_num : REAL;
      k,l        : INTEGER;
      m          : LONGINT;

BEGIN

       r_num := 0;

       IF i_Bit = i_NoOfBit THEN  { No. of bits per bytes }

          BEGIN

             k := i_8BitExpInd;     {4 for 8 bit, 16 for 16 bit}
             l := GETEXPVAL(s_binary,i_8ExpStartBit,i_8ExpEndBit,k);
             m := RAISEPOWER(i_base2,ABS(l));

             IF l < 0 THEN
                i := 1.0 / m
             ELSE
                i := m;

             j := GETMANVAL(s_binary,i_8ManStartBit,i_8ManEndBit);

          END

       ELSE

          BEGIN
             k := i_16BitExpInd;    {16}
             l := GETEXPVAL(s_binary,i_16ExpStartBit,i_16ExpEndBit, k);
             m := RAISEPOWER(i_base2,ABS(l));

             IF l < 0 THEN  { If l is negative }
                i := 1.0 / m
             ELSE
                i := m;

             j := GETMANVAL(s_binary,i_16ManStartBit,i_16ManEndBit);
          END;

       r_num := i * j;   { Exponent * mantissa }

       IF s_binary[1] = s_OneString THEN { Negative }
          r_num := r_num * i_NegativeOne;

       BINTOREALNUM := r_num;

END; {BINTOREALNUM}


{/////////////////////////////////////////////////////////////////////////////
 Binary string to real number
/////////////////////////////////////////////////////////////////////////////}
PROCEDURE BINTOREAL;

VAR

     b_okay      : boolean;
     s_binary    : string;
     i_X,i_Y, i  : INTEGER;
     r_realnum   : REAL;

BEGIN

     GETBYTENO(i_1Byte,i_2Byte,i_Byte,i_Bit);

     REPEAT

         BEGIN

           b_okay := TRUE;
           s_binary := '';
           GOTOXY(1,12);
           WRITE ('Please enter a binary string in ',i_Bit, ' bit format : ');
           i_X := WHEREX;
           i_Y := WHEREY;
           CLREOL;
           TEXTCOLOR(YELLOW);
           READLN (s_binary);
           TEXTCOLOR(WHITE);
           FOR i := LENGTH(TRIM(s_binary)) DOWNTO 1 DO
                  IF NOT (s_binary[i] = s_ZeroString) AND NOT (s_binary[i] = s_OneString) THEN
                      BEGIN
                            b_okay := FALSE;
                            GOTOXY(i_X,i_Y);
                            CLREOL;
                      END

         END

     UNTIL (b_okay = TRUE) AND (LENGTH(TRIM(s_binary)) = (i_Bit));

     r_realnum := BINTOREALNUM(s_binary,i_Bit);

     WRITE ('"', s_binary, '" binary string represents real number : ');
     TEXTCOLOR(YELLOW);
     WRITE(r_realnum:6:13);
     TEXTCOLOR(WHITE);
     WRITELN('.');

END; {BINTOREALNUM}


{/////////////////////////////////////////////////////////////////////////////
 Make appropriate choice from the options
/////////////////////////////////////////////////////////////////////////////}
PROCEDURE MAKECHOICE;

BEGIN

      CASE i_choice OF

          1: INTTOBIN;
          2: BINTOINT;
          3: REALTOBIN;
          4: BINTOREAL;

      END;

END; {MAKECHOICE}


{////////////////////////////////////////////////////////////////////////////
 Get what option the user wants
////////////////////////////////////////////////////////////////////////////}
PROCEDURE GETCHOICE(i_LoLimit,i_HiLimit:INTEGER;
                    VAR     i_getChoice:INTEGER);

VAR

       i_X,i_Y      : INTEGER;  { Local variable for x,y coordinate value }

BEGIN

       REPEAT

           GOTOXY(1,10);
           WRITE('Enter your choice (',i_LowLimit:1,' - ',i_HighLimit:1,') : ');
           i_X := WHEREX;
           i_Y := WHEREY;
           {$I-}
           TEXTCOLOR(YELLOW);
           READLN(i_getChoice);
           TEXTCOLOR(WHITE);
           {$I+}
           IF (IORESULT <> i_OKIOResult) OR (i_choice < i_LoLimit) OR
              (i_choice > i_HiLimit) THEN
              GOTOXY(i_X,i_Y);
              CLREOL;

       UNTIL (IORESULT = i_OKIOResult) AND
             (i_choice >= i_LoLimit) AND
             (i_choice <= i_HiLimit)

END; {GETCHOICE}


{/////////////////////////////////////////////////////////////////////////////
 Displays the main menu for user to choose
/////////////////////////////////////////////////////////////////////////////}
PROCEDURE DISPMENU;

BEGIN

    CLRSCR;
    WRITELN ('              +--------------------------------------------------+');
    WRITELN ('              |  << BASE 10/BASE 2 NUMBER CONVERSION PROGRAM >>  |');
    WRITELN ('              |      1. Integer Number ---> Binary  String       |');
    WRITELN ('              |      2. Binary  String ---> Integer Number       |');
    WRITELN ('              +--------------------------------------------------+');
    WRITELN ('              |      3. Real    Number ---> Binary  String       |');
    WRITELN ('              |      4. Binary  String ---> Real    Number       |');
    WRITELN ('              |      5. Quit                                     |');
    WRITELN ('              +--------------------------------------------------+');

END; {DISPMENU}


{/////////////////////////////////////////////////////////////////////////////
 Main Pogram
/////////////////////////////////////////////////////////////////////////////}
BEGIN

     TEXTCOLOR(WHITE);
     TEXTBACKGROUND(BLUE);

     REPEAT

         CLRSCR;
         DISPMENU;                                    { Display heading }
         GETCHOICE(i_LowLimit,i_HighLimit,i_Choice);  { Get choice option }
         IF i_Choice < i_highLimit THEN
            BEGIN
                MAKECHOICE;                           { Make a choice }
                PRESSKEY;
                s_response := READKEY;
            END;

     UNTIL (i_choice = i_highlimit)

END. {MAIN PROGRAM}
