(*
** PROGRAM TITLE:       Alpha Numeric Numbers Conversions
**
** WRITTEN BY:          Raymond E. Penley
** DATE WRITTEN:        5 July 1980
**
** SUMMARY:
**
**      VAL =  Single character to integer value.
**      RDR =  Alphanumeric to real number.
**      STR =  Integer to alphanumeric.
**
**  Donated to PASCAL/Z USERS GROUP, July 1980
**
*)
const   default = 80;           { Default length }

type    Dstring = STRING default;
       str0    = STRING 0;
       str255  = STRING 255;

var     zx :real;               { the real numbers go here }
       done: boolean;
       number : integer;       { the integer number in here }
       answer : Dstring;       { String buffer         }

function length(x: str255): integer; external;
procedure setlength(var x: str0; y: integer); external;

(*------------------------------------------*)
Function VAL(ch: char): integer;
{ Returns the integer value of
 the single char passed }
const   z = 48; {  ORD('0')  }
begin
 VAL := ORD(ch) - z
end;

(*------------------------------------------*)
Function RDR(var f: Dstring  ): real;
{ read real numbers in free format.
 author: Niklaus Wirth
 book:   Pascal User Manual & Report
         pg 122-123
 ENTER WITH:
       f = a string containing ONLY the alphanumeric number
           to be converted to a real number.
 RETURNS:
       A real number.
       Any error returns RDR := 0.0
*}
label   9;{ error exit }
const
       t48 = 281474976710656.0 ;
       limit = 56294995342131.0 ;
       lim1 = 322;             { maximum exponent }
       lim2 = -292;            { minimum exponent }
       space = ' ';
       emsg1 = '**digit expected';
       emsg2 = '**number too large';
type
       posint = 0..323;
var
 ch    : char;
 y     : real;
 posn,
 a,i,e : integer;
 fatal,
 s,ss  : boolean; { signs }

procedure Getc(var ch: char);
begin
 posn := posn + 1;
 ch := f[posn];
end;

function TEN(e: posint): real; {  = 10**e,  0<e<322  }
var     i: integer;
       t: real;
begin
 i := 0;
 t := 1.0;
 repeat
   If ODD(e) then
     case i of
       0: t := t * 1.0E1;
       1: t := t * 1.0E2;
       2: t := t * 1.0E4;
       3: t := t * 1.0E8;
       4: t := t * 1.0E16;
       5: t := t * 1.0E32      { that's all! }
       6,7,8:
          begin
          writeln('**Floating point overflow');
          fatal := true;
          e := 2;{ sets e to zero on next division }
          end;
       {*===================*
       --- can not use ---
        6: t := t * 1.0E64;
        7: t := t * 1.0E128;
        8: t := t * 1.0E256
        *===================*}
     end{ case };
   e := e DIV 2;
   i := i + 1;
 until e=0;
 TEN := t;
end{of TEN};

begin
 fatal := false;
 posn := length(f);
 setlength(f,posn+1);
 f[posn+1] := space;
 posn := 0;
 getc(ch);
 { skip leading blanks }
 While ch=space do getc(ch);
 If ch='-' then
   begin
   s := true;
   getc(ch)
   end
 Else
   begin
   s := false;
   If ch='+' then getc(ch)
   end;
 If not(ch IN ['0'..'9']) then
   begin
   writeln(emsg1);
   {HALT} fatal := true; goto 9;
   end;
 a := 0;
 e := 0;
 repeat
   If a<limit then
     a := 10 * a + VAL(ch)
   Else
     e := e+1;
   getc(ch);
 until not(ch IN ['0'..'9']);
 If ch='.' then
   begin { read fraction }
   getc(ch);
   while ch IN ['0'..'9'] do
     begin
     If a<limit then
       begin
       a := 10 * a + VAL(ch);
       e := e - 1
       end;
     getc(ch);
     end{ while };
   end{ read fraction };
 If (ch='E') or (CH='e') then
   begin { read scale factor }
     getc(ch);
     i := 0;
     If ch='-' then
       begin ss := true; getc(ch) end
     Else
       begin
       ss := false;
       If ch='+' then getc(ch)
       end;
     If ch IN ['0'..'9'] then
       begin
       i := VAL(ch);
       getc(ch);
       while ch IN ['0'..'9'] do
         begin
         If i<limit then i := 10 * i + VAL(ch);
         getc(ch)
         end{ while}
       end{ If }
     Else
       begin
       writeln(emsg1);
       {HALT} fatal := true; goto 9;
       end;
     If ss
        then e := e - i
        Else e := e + i;
   end{ read scale factor };
 If e < lim2 then
   begin
   a := 0;
   e := 0;
   end
 Else
   If e > lim1 then
     begin
     writeln(emsg2);
     {HALT} fatal := true; goto 9;
     end;
 {  0 < a < 2**49  }
 If a >= t48 then
   y := ((a+1) DIV 2) * 2.0
 Else
   y := a;
 If s then y := -y;
 If e < 0 then
   RDR := y/TEN(-e)
 Else
   If e<>0 then
     RDR := y*TEN(e)
   Else
     RDR := y;
9: If fatal then RDR := 0.0;
End{of RDR};

(*------------------------------------------*)
Procedure STR( var S: Dstring;
               tval: integer );
{ ENTER WITH:
       tval = INTEGER to be converted to an alphanumeric
              string.
 RETURNS:
       An alphanumeric equal of tval in S.
}
const
       size = 15; { number of digits in the number }
var
       cix : char;
       digits : packed array[1..10] of char;
       i,              { length of number }
       d,t,j: integer;
begin
 digits := '0123456789';
 t := ABS(tval);
 setlength(S,0);       { null string }
 i := 0;
 repeat { generate digits }
   i := i + 1;
   d := t MOD 10;
   append(S,digits[d+1]);
   t := t DIV 10
 until (t=0) OR (i>=size);
 If (tval<0) AND (i<size) then
   begin { sign }
   i := i + 1;
   append(S,'-')
   end;
 j := 1;
 while j<i do
   begin{ reverse }
   cix := S[i]; S[i] := S[j]; S[j] := cix;
   i := i - 1;
   j := j + 1
   end{ revese }
End{of STR};

begin
 done := false;
 repeat
   writeln;
   write('Enter a number (real or integer) ?');
   readln(answer);
   writeln('literal number is ..... ', answer);
   writeln('with a length of  ..... ', length(answer):4 );
   zx := RDR(answer);
   writeln('the numeric equal of your literal .. ', zx);
   writeln('Formatted as ! Number:10:4 ! ....... ', zx:10:4);
   write('Five times ', zx, ' = ');writeln( zx * 5 );
   write('The integer portion is ............... ');writeln( trunc(zx) );
   writeln;
   write('Enter an integer ?');
   readln(number);
   STR(answer, number);
   writeln('The integer number is .............. ', number);
   writeln('Expressed as an alphanumeric is .... ', answer);
   writeln('the length of the literal is ....... ', length(answer) );
   append(answer,answer);
   writeln('Since we now have a string');
   writeln(' we can concatenate like so ........ ', answer);
 Until done;
End{ of Alpha_Numeric }.