-- IeeeIOB.mesa -- Last Modified: August 27, 1982 1:05 pm -- String munging for IO DIRECTORY Ascii USING [CR, DEL, TAB], Ieee USING [BitOn, HalfLC, HiBit], Inline USING [HighHalf, LowHalf], String USING [AppendChar, AppendString], Real USING [DefaultSinglePrecision, NumberType, PairToReal, RealToPair]; IeeeIOB: CEDAR PROGRAM IMPORTS Ieee, Inline, String, Real EXPORTS Real = BEGIN OPEN Ascii, Ieee, Real, String; DefaultPutback: PUBLIC PROC [c: CHARACTER] = {NULL; }; ReadReal: PUBLIC PROC [get: PROC RETURNS [CHARACTER], putback: PROC [CHARACTER]] RETURNS [REAL] = { InsideProc: PROC RETURNS [REAL] = { exp, exp2, cVal, digits: INTEGER ← 0; val: REAL; intVal: LONG INTEGER ← 0; minus, expMinus: BOOLEAN ← FALSE; leadZeros: BOOLEAN ← TRUE; mode: {firstSymbol, intPart, fracPart, firstExpSymbol, expPart} ← firstSymbol; c: CHARACTER; Ten: INTEGER = 10; DigitLimit: INTEGER = 9; -- digits is a way to prevent overflow of intVal DO c ← get[]; cVal ← LOOPHOLE[c - '0, INTEGER]; SELECT c FROM ' , CR, TAB, DEL => SELECT mode FROM firstSymbol => NULL; ENDCASE => EXIT; '+ => SELECT mode FROM firstSymbol => mode ← intPart; firstExpSymbol => mode ← expPart; ENDCASE => EXIT; '- => SELECT mode FROM firstSymbol => {minus ← TRUE; mode ← intPart; }; firstExpSymbol => {expMinus ← TRUE; mode ← expPart; }; ENDCASE => EXIT; '. => SELECT mode FROM firstSymbol, intPart => mode ← fracPart; ENDCASE => EXIT; 'D, 'E, 'd, 'e => SELECT mode FROM intPart, fracPart => mode ← firstExpSymbol; ENDCASE => EXIT; IN ['0..'9] => SELECT mode FROM firstSymbol, intPart => IF digits < DigitLimit THEN { IF cVal # 0 THEN leadZeros ← FALSE; mode ← intPart; intVal ← intVal*Ten + cVal; IF NOT leadZeros THEN digits ← digits + 1; } ELSE exp ← exp + 1; fracPart => IF digits < DigitLimit THEN { IF cVal # 0 THEN leadZeros ← FALSE; intVal ← intVal*Ten + cVal; exp ← exp - 1; IF NOT leadZeros THEN digits ← digits + 1; }; firstExpSymbol, expPart => { mode ← expPart; exp2 ← exp2*10 + cVal; }; ENDCASE => EXIT; ENDCASE => EXIT; ENDLOOP; putback[c]; -- now put it together IF expMinus THEN exp2 ← -exp2; exp ← exp + exp2; val ← PairToReal[intVal, exp]; IF minus THEN LOOPHOLE[val, LONG CARDINAL] ← LOOPHOLE[val, LONG CARDINAL] + HalfLC; RETURN[val]; }; RETURN[InsideProc[]]; }; AppendReal: PROC [ s: STRING, r: REAL, precision: CARDINAL ← DefaultSinglePrecision, forceE: BOOLEAN ← FALSE] = TRUSTED { exp: INTEGER; z: LONG INTEGER; ty: NumberType; sign: BOOLEAN; Zeros: PROC [n: CARDINAL] = TRUSTED {THROUGH [1..n] DO AppendChar[s, '0]; ENDLOOP; }; { sign ← BitOn[Inline.HighHalf[r], HiBit]; [type: ty, fr: z, exp10: exp] ← RealToPair[r, precision]; IF sign THEN z ← -z; SELECT ty FROM nan => AppendString[to: s, from: ".."]; infinity => AppendString[to: s, from: IF sign THEN "--" ELSE "++"]; zero => AppendString[to: s, from: IF sign THEN "-0" ELSE "0"]; ENDCASE => GOTO Ok; EXITS Ok => { lds: STRING ← [20]; rds: STRING ← [20]; i, digit, digits, ld, rd: CARDINAL; IF sign THEN AppendChar[s, '-]; IF z = 0 THEN {AppendChar[s, '0]; RETURN; }; -- leading zeros digits ← precision ← MAX[1, MIN[precision, 9]]; WHILE (z MOD 10) = 0 DO -- strip trailing zeros z ← z/10; exp ← exp + 1; digits ← digits - 1; ENDLOOP; IF digits = 0 THEN ERROR; rd ← MAX[0, -exp]; rds.length ← MIN[digits, rd]; -- right digit string FOR i DECREASING IN [0..rds.length) DO digit ← Inline.LowHalf[z MOD 10]; z ← z/10; rds[i] ← digit + '0; ENDLOOP; ld ← MAX[0, LOOPHOLE[digits, INTEGER] + exp]; lds.length ← MIN[digits, ld]; -- left digit string FOR i DECREASING IN [0..lds.length) DO digit ← Inline.LowHalf[z MOD 10]; z ← z/10; lds[i] ← digit + '0; ENDLOOP; forceE ← forceE OR ld > 6 OR rd > 6; IF NOT forceE THEN SELECT TRUE FROM ld = 0 => { -- number entirely to right of decimal point AppendString[to: s, from: "0."]; Zeros[rd - rds.length]; AppendString[to: s, from: rds]; }; rd = 0 => { -- number entirely to left of decimal point AppendString[to: s, from: lds]; Zeros[ld - lds.length]; }; ENDCASE => { -- some of each AppendString[to: s, from: lds]; AppendChar[s, '.]; AppendString[to: s, from: rds]; } ELSE { -- e format AppendString[to: lds, from: rds]; AppendChar[s, lds[0]]; lds.length ← lds.length; exp ← exp + lds.length - 1; SELECT TRUE FROM precision = 1 => AppendChar[s, '.]; lds.length = 1 => AppendString[to: s, from: ".0"]; ENDCASE => { AppendChar[s, '.]; FOR i IN [1..lds.length) DO AppendChar[s, lds[i]]; ENDLOOP; }; -- print exponent IF exp = 0 THEN RETURN; AppendChar[s, 'e]; AppendChar[s, IF exp < 0 THEN '- ELSE '+]; exp ← ABS[exp]; IF exp > 9 THEN AppendChar[s, '0 + (exp/10)]; AppendChar[s, '0 + (exp MOD 10)]; }; }; }; }; WriteReal: PUBLIC PROC [ cp: PROC [CHARACTER], r: REAL, precision: CARDINAL ← DefaultSinglePrecision, forceE: BOOLEAN ← FALSE] = TRUSTED { s: STRING ← [50]; i: CARDINAL; AppendReal[s, r, precision, forceE]; FOR i IN [0..s.length) DO cp[s[i]]; ENDLOOP; }; END. L. Stewart, July 12, 1980 10:37 PM, Name changes L. Stewart, July 13, 1980 8:57 PM, delete WF procwedures (Moved to WFReal) August 24, 1980 8:42 PM, L. Stewart; formatting, fix ReadReal December 11, 1980 11:06 AM, L. Stewart; Use Ascii instead of IODefs June 5, 1982 5:58 pm, L. Stewart, removed STRING conversions August 27, 1982 1:05 pm, L. Stewart, CEDAR