{ History ------- 12/11/85 - Add bodies for ConstIntFunction and ConstRealFunction. (agh) 22/11/85 - Complete bodies for ConstWordFunction and ConstIntFunction. Add HostInt for mapping word-types onto host-integers. (agh) 25/11/85 - Add HostVal for recasting word values as host integers. (agh) } { MODULE 15 Object Value Manipulation } program ObjectValues; #include "globals.x" var MaxWordDiv, MaxWordMod: array [BaseValues] of ICLWord; #include "generator.pf" #include "datareps.pf" procedure SetIval(HostInteger: integer; var Velue: ObjectValue); visible; begin with Velue do begin Kind := IntValue; Ival := HostInteger; WordSize := 1 end end { setival }; procedure SetRval(HostReal: real; var Velue: ObjectValue); begin with Velue do begin Kind := RealValue; Rval := HostReal; WordSize := MCRealSize end end { setrval }; procedure SetBval(HostBoolean: Boolean; var Velue: ObjectValue); visible; begin with Velue do begin Kind := BoolValue; Ival := ord(HostBoolean); WordSize := 1 end end { setbval }; procedure SetWval(HostValue: ICLWord; var Velue: ObjectValue); visible; begin with Velue do begin Kind := BaseValue; Wval := HostValue; WordSize := 1 end end { SetWval }; function MapChar(HostChar: char): MCByte; begin MapChar := ord(HostChar) end; procedure SetCval(ChValue: MCByte; var Velue: ObjectValue); visible; begin with Velue do begin Kind := CharValue; Ival := ChValue; WordSize := 1 end end { SetCval }; { The procedure Evaluate carries out the conversion of source literal images in character form to the target values they denote. In addition to the assumptions listed above the following version of Evaluate makes the assumption that a host integer provides suf- ficient accuracy for accumulating the value of the mantissa in a real constant. For many host machines this would not be accept- able and an augmented mantissa representation would be necessary. It is important, however, to avoid accumulating mantissa values as host reals, since inaccuracies introduced during the accumulation may significantly degrade the accuracy of the final mantissa obtained. The strategy below uses real arithmetic only to compute a power-of-1O scale factor required for the final scaling opera- tion. Accuracy may be further increased by using table look-up to obtain the power of 1O required. } function ScaleWord(w: ICLWord; i: BaseValues): ICLWord; forward; procedure Evaluate(var SourceValue: ValueDetails); visible; var Index: integer; ByteIndex: MCByteIndex; Ivalu, Scale, Exponent: integer; Rvalu: real; Base: BaseValues; Wvalu: ICLWord; StringWord, Element: WordEntry; Negative, Overflow: Boolean; procedure AddDigitTo(var Number: integer); var Digit: 0..9; begin Digit := ord(SourceValue.String[Index]) - ord('0'); Overflow := Overflow or (Number > MCMaxintDiv10) or ((Number = MCMaxintDiv10) and (Digit > MCMaxintMod10)); if not Overflow then Number := Number * 10 + Digit end; procedure AddWDigitTo(var Number: ICLWord); var c: char; Digit: 10#0..10#15; begin c := SourceValue.String[Index]; if (c in ['0'..'9']) then Digit := wrd(ord(c) - ord('0')) else Digit := wrd(ord(c) - ord('A') + 10); Overflow := Overflow or (Number > MaxWordDiv[Base]) or ((Number = MaxWordDiv[Base]) and (Digit > MaxWordMod[Base])); if not Overflow then Number := ScaleWord(Number, Base) + Digit end; function PowerOf10(n: integer): real; var Factor, Power: real; begin Factor := 10.0; Power := 1.0; repeat if odd(n) then Power := Power * Factor; Factor := sqr(Factor); n := n div 2 until n = 0; PowerOf10 := Power end; begin with SourceValue do case Kind of OrdValue : SetIval(Ival, Velue); CharValue : SetCval(ord(String[1]), Velue); StringValue : with Velue do begin Kind := StringValue; Stringval := nil; Index := 1; ByteIndex := 0; while Index <= SourceValue.Length do begin if ByteIndex = 0 then begin new(Element); with Element^ do begin Word.WValue := 0; Next := nil end; if Stringval = nil then Stringval := Element else StringWord^.Next := Element; StringWord := Element end; with StringWord^ do MCSetByte(Word, ByteIndex, ord(String[Index])); ByteIndex := (ByteIndex + 1) mod MCBytesPerWord; Index := Index + 1 end; Length := SourceValue.Length; WordSize := WordsFor(Length, MCBytesPerWord) end; IntValue : begin Ivalu := 0; Overflow := false; for Index := 1 to Length do AddDigitTo(Ivalu); if Overflow then begin PredictedError(47); Velue := MaxintValue end else SetIval(Ivalu, Velue) end; BaseValue : begin Wvalu := 10#0; Base := Velue.Ival; Overflow := false; for Index := 1 to Length do AddWDigitTo(Wvalu); if Overflow then begin PredictedError(86); Velue := MaxWordValue end else SetWval(Wvalu, Velue) end; RealValue : begin Ivalu := 0; Scale := 0; Overflow := false; Index := 1; String[Length + 1] := ' '; while String[Index] in ['0'..'9'] do begin AddDigitTo(Ivalu); if Overflow then Scale := Scale + 1; Index := Index + 1 end; if String[Index] = '.' then begin Index := Index + 1; while String[Index] in ['0'..'9'] do begin AddDigitTo(Ivalu); if not Overflow then Scale := Scale - 1; Index := Index + 1 end end; if String[Index] = 'E' then begin Index := Index + 1; Negative := (String[Index] = '-'); Exponent := 0; for Index := Index + 1 to Length do AddDigitTo(Exponent); if Negative then Scale := Scale - Exponent else Scale := Scale + Exponent end; if Scale = 0 then Rvalu := Ivalu else if Scale < 0 then Rvalu := Ivalu / PowerOf10(Scale) else Rvalu := Ivalu * PowerOf10(Scale); SetRval(Rvalu, Velue) end end end; { evaluate } procedure MakeValue(Magnitude: integer; var Velue: ObjectValue); visible; var Buffer: ValueDetails; begin with Buffer do begin Kind := OrdValue; IVal := Magnitude end; Evaluate(Buffer); Velue := Buffer.Velue end { MakeValue }; { The following procedures implement the object value operators required by the analyser, within the assumptions listed above. } procedure NegateValue(var Velue: ObjectValue); visible; begin with Velue do case Kind of OrdValue, IntValue : Ival := -Ival; BoolValue : case Ival of 0 : Ival := 1; 1 : Ival := 0 end; RealValue : Rval := -Rval end end; { negatevalue } function SameValue(Value1, Value2: ObjectValue): Boolean; visible; begin case Value1.Kind of OrdValue, IntValue, BoolValue, CharValue : SameValue := Value1.Ival = Value2.Ival; RealValue : SameValue := Value1.Rval = Value2.Rval; BaseValue : SameValue := Value1.Wval = Value2.Wval end end { SameValue }; function OrderedValues(Value1, Value2: ObjectValue): Boolean; visible; begin case Value1.Kind of OrdValue, IntValue, BoolValue, CharValue : OrderedValues := Value1.Ival < Value2.Ival; RealValue : OrderedValues := Value1.Rval < Value2.Rval; BaseValue : OrderedValues := Value1.Wval < Value2.Wval end end { OrderedValues }; function Disjoint(Value1, Value2, Value3, Value4: ObjectValue): Boolean; visible; begin Disjoint := OrderedValues(Value2, Value3) or OrderedValues(Value4, Value1) end { Disjoint }; function InRange(Value1, Value, Value2: ObjectValue): Boolean; visible; begin InRange := not Disjoint(Value1, Value2, Value, Value) end { InRange }; procedure CheckValue(Min, Max, Value: ObjectValue; Code: Scalar); visible; begin if not InRange(Min, Value, Max) then PredictedError(Code) end { CheckValue }; procedure CompareValues(Value1, Value2: ObjectValue; RelOp: OpType; var Result: ObjectValue); visible; var BValue: Boolean; begin case RelOp of LtOp : BValue := OrderedValues(Value1, Value2); LeOp : BValue := OrderedValues(Value1, Value2) or SameValue(Value1, Value2); GeOp : BValue := OrderedValues(Value2, Value1) or SameValue(Value1, Value2); GtOp : BValue := OrderedValues(Value2, Value1); NeOp : BValue := not SameValue(Value1, Value2); EqOp : BValue := SameValue(Value1, Value2) end; SetBVal(BValue, Result) end { CompareValues }; { The following procedures provide host Boolean arithmetic. } procedure OrValues(Value1, Value2: ObjectValue; var Result: ObjectValue); visible; begin if (Value1.IVal = 1) or (Value2.IVal = 1) then Result.IVal := 1 else Result.IVal := 0 end { OrValues }; procedure AndValues(Value1, Value2: ObjectValue; var Result: ObjectValue); visible; begin if (Value1.IVal = 1) and (Value2.IVal = 1) then Result.IVal := 1 else Result.IVal := 0 end { AndValues }; { The following procedures implement compile-time integer, real } { and word-arithmetic on the host-machine. } procedure ConstArith(Operator: OpType; Left, Right: MCIntegerForm; var Result: MCIntegerForm); visible; var StoredMod: 0..MCMaxint; begin with Overflow do begin Occurred := false; Positive := false end; case Operator of Plus, Minus : begin if Operator = Minus then Right := -Right; if (Left > 0) and (Right > 0) then Overflow.Occurred := (Left > MCMaxint - Right); if (Left < 0) and (Right < 0) then Overflow.Occurred := (Left < -MCMaxint - Right); if Overflow.Occurred then Overflow.Positive := (Left > 0) else Result := Left + Right end; Mul : if Right = 0 then Result := 0 else if abs(Left) > MCMaxint div abs(Right) then begin Overflow.Occurred := true; Overflow.Positive := (Left > 0) and (Right > 0) or (Left < 0) and (Right < 0) end else Result := Left * Right; Idiv : if Right = 0 then Overflow.Occurred := true else Result := Left div Right; Imod : if Right <= 0 then Overflow.Occurred := true else begin StoredMod := abs(Left) mod Right; if (StoredMod = 0) or (Left > 0) then Result := StoredMod else Result := Right - StoredMod end end end { constarith }; procedure ConstWArith(Operator: OpType; Left, Right: ICLWord; var Result: ICLWord); visible; begin with Overflow do begin Occurred := false; Positive := false end; case Operator of Plus : begin Overflow.Occurred := Left > MCMaxWord - Right; if Overflow.Occurred then Overflow.Positive := true else Result := Left + Right end; Minus : begin Overflow.Occurred := Left < Right; if not Overflow.Occurred then Result := Left - Right end end end { ConstWArith }; function ScaleWord { w: ICLWord; i: BaseValues): ICLWord }; begin case i of 2 : ScaleWord := shw(w, 1); 3 : ScaleWord := shw(w, 1) + w; 4 : ScaleWord := shw(w, 2); 5 : ScaleWord := shw(w, 2) + w; 6 : ScaleWord := shw(w, 2) + shw(w, 1); 7 : ScaleWord := shw(w, 2) + shw(w, 1) + w; 8 : ScaleWord := shw(w, 3); 9 : ScaleWord := shw(w, 3) + w; 10 : ScaleWord := shw(w, 3) + shw(w, 1); 11 : ScaleWord := shw(w, 3) + shw(w, 1) + w; 12 : ScaleWord := shw(w, 3) + shw(w, 2); 13 : ScaleWord := shw(w, 3) + shw(w, 2) + w; 14 : ScaleWord := shw(w, 3) + shw(w, 2) + shw(w, 1); 15 : ScaleWord := shw(w, 3) + shw(w, 2) + shw(w, 1) + w; 16 : ScaleWord := shw(w, 4) end end { ScaleWord }; procedure ConstRArith(Operator: OpType; Left, Right: MCRealForm; var Result: MCRealForm); begin with Overflow do begin Occurred := false; Positive := false end; case Operator of Plus, Minus : begin if Operator = Minus then Right := -Right; if (Left > 0.0) and (Right > 0.0) then Overflow.Occurred := (Left > MCMaxReal - Right); if (Left < 0.0) and (Right < 0.0) then Overflow.Occurred := (Left < -MCMaxReal - Right); if Overflow.Occurred then Overflow.Positive := (Left > 0.0) else Result := Left + Right end; Mul : if Right = 0.0 then Result := 0.0 else if abs(Left) > MCMaxReal / abs(Right) then begin Overflow.Occurred := true; Overflow.Positive := (Left > 0.0) and (Right > 0.0) or (Left < 0.0) and (Right < 0.0) end else Result := Left * Right; Rdiv : if Right = 0.0 then Overflow.Occurred := true else Result := Left / Right end end { ConstRArith }; procedure AddValues(Value1, Value2: ObjectValue; var Result: ObjectValue); visible; var IntResult: MCIntegerForm; RealResult: MCRealForm; WordResult: ICLWord; begin case Value1.Kind of OrdValue, IntValue : begin ConstArith(Plus, Value1.Ival, Value2.Ival, IntResult); if Overflow.Occurred then begin PredictedError(47); Result := MaxintValue end else SetIval(IntResult, Result) end; RealValue : begin ConstRArith(Plus, Value1.Rval, Value2.Rval, RealResult); if Overflow.Occurred then Result := MaxRealValue else SetRval(RealResult, Result) end; BaseValue : begin ConstWArith(Plus, Value1.Wval, Value2.Wval, WordResult); if Overflow.Occurred then begin PredictedError(86); Result := MaxWordValue end else SetWval(WordResult, Result) end end end { AddValues }; procedure SubValues(Value1, Value2: ObjectValue; var Result: ObjectValue); visible; var IntResult: MCIntegerForm; RealResult: MCRealForm; WordResult: ICLWord; begin case Value1.Kind of OrdValue, IntValue : begin ConstArith(Minus, Value1.Ival, Value2.Ival, IntResult); if Overflow.Occurred then begin PredictedError(47); Result := MaxintValue; NegateValue(Result) end else SetIval(IntResult, Result) end; RealValue : begin ConstRArith(Minus, Value1.Rval, Value2.Rval, RealResult); if Overflow.Occurred then begin Result := MaxRealValue; NegateValue(Result) end else SetRval(RealResult, Result) end; BaseValue : begin ConstWArith(Minus, Value1.Wval, Value2.Wval, WordResult); if Overflow.Occurred then begin PredictedError(86); Result := ZeroValue end else SetWval(WordResult, Result) end end end { SubValues }; procedure MultiplyValues(Value1, Value2: ObjectValue; var Result: ObjectValue); visible; var IntResult: MCIntegerForm; RealResult: MCRealForm; begin case Value1.Kind of OrdValue, IntValue : begin ConstArith(Mul, Value1.Ival, Value2.Ival, IntResult); if Overflow.Occurred then begin PredictedError(47); Result := MaxintValue; if not Overflow.Positive then NegateValue(Result) end else SetIval(IntResult, Result) end; RealValue : begin ConstRArith(Mul, Value1.Rval, Value2.Rval, RealResult); if Overflow.Occurred then begin Result := MaxRealValue; if not Overflow.Positive then NegateValue(Result) end else SetRval(RealResult, Result) end end end { MultiplyValues }; procedure DivValues(Value1, Value2: ObjectValue; var Result: ObjectValue); visible; var IntResult: MCIntegerForm; RealResult: MCRealForm; begin case Value1.Kind of OrdValue, IntValue : begin ConstArith(Idiv, Value1.Ival, Value2.Ival, IntResult); if Overflow.Occurred then begin PredictedError(45); Result := MaxintValue end else SetIval(IntResult, Result) end; RealValue : begin ConstRArith(Rdiv, Value1.Rval, Value2.Rval, RealResult); if Overflow.Occurred then Result := MaxRealValue else SetRval(RealResult, Result) end end end { DivValues }; procedure ModValues(Value1, Value2: ObjectValue; var Result: ObjectValue); visible; var IntResult: MCIntegerForm; begin ConstArith(IMod, Value1.Ival, Value2.Ival, IntResult); if Overflow.Occurred then begin PredictedError(46); Result := MaxintValue end else SetIval(IntResult, Result) end { ModValues }; procedure ConstIntFn(Which: StdProcFuncs; ArgValue: ObjectValue; var Result: ObjectValue); visible; var IntResult: MCIntegerForm; WordResult: ICLWord; BoolResult: Boolean; ChResult: char; Overflowed: Boolean; procedure Truncate(Argument: MCrealForm); var Epsilon: MCRealForm; begin if abs(Argument) > MCMaxint then Overflowed := true else begin IntResult := trunc(Argument); Epsilon := Argument - IntResult; if Argument >= 0 then Overflowed := (Epsilon < 0) or (Epsilon > 1) else Overflowed := (Epsilon <= -1) or (Epsilon > 0) end end { Truncate }; begin if CodeIsToBeGenerated then case Which of Intf : begin IntResult := int(ArgValue.Wval); SetIval(IntResult, Result) end; Wrdf : begin WordResult := wrd(ArgValue.Ival); SetWval(WordResult, Result) end; Chrf : begin if ArgValue.Kind = BaseValue then ChResult := chr(ArgValue.Wval) else ChResult := chr(ArgValue.Ival); SetCVal(ord(ChResult), Result) end; Oddf : begin if ArgValue.Kind = BaseValue then BoolResult := odd(ArgValue.Wval) else BoolResult := odd(ArgValue.Ival); SetBval(BoolResult, Result) end; Ordf : begin if ArgValue.Kind = BaseValue then IntResult := ord(ArgValue.Wval) else IntResult := ord(ArgValue.Ival); SetIval(IntResult, Result) end; Absf : if ArgValue.Kind = IntValue then begin IntResult := abs(ArgValue.Ival); SetIval(IntResult, Result) end else Result := ArgValue; Truncf : begin Truncate(ArgValue.Rval); if Overflowed then begin PredictedError(35); Result := MaxRealValue end else SetIval(IntResult, Result) end; Roundf : begin if ArgValue.Rval >= 0.0 then Truncate(ArgValue.Rval + 0.5) else Truncate(ArgValue.Rval - 0.5); if Overflowed then begin PredictedError(36); Result := MaxRealValue end else SetIval(IntResult, Result) end; Predf : if ArgValue.Kind = BaseValue then begin ConstWArith(Minus, ArgValue.Wval, 10#1, WordResult); if Overflow.Occurred then begin PredictedError(39); Result := ArgValue end else SetWval(WordResult, Result) end else begin ConstArith(Minus, ArgValue.Ival, 1, IntResult); if Overflow.Occurred then begin PredictedError(39); Result := ArgValue end else SetIval(IntResult, Result) end; Succf : if ArgValue.Kind = BaseValue then begin ConstWArith(Plus, ArgValue.Wval, 10#1, WordResult); if Overflow.Occurred then begin PredictedError(38); Result := ArgValue end else SetWval(WordResult, Result) end else begin ConstArith(Plus, ArgValue.Ival, 1, IntResult); if Overflow.Occurred then begin PredictedError(38); Result := ArgValue end else SetIval(IntResult, Result) end; Sqrf : begin ConstArith(Mul, ArgValue.Ival, ArgValue.Ival, IntResult); if Overflow.Occurred then begin PredictedError(32); Result := MaxintValue end else SetIval(IntResult, Result) end end end { ConstIntFn }; procedure ConstRealFn(Which: StdProcFuncs; ArgValue: ObjectValue; var Result: ObjectValue); visible; var RealResult: MCRealForm; begin case Which of Absf : begin RealResult := abs(ArgValue.Rval); SetRval(RealResult, Result) end; Sqrf : MultiplyValues(ArgValue, ArgValue, Result); Sqrtf : if ArgValue.Rval < 0.0 then begin PredictedError(34); Result := ZeroReal end else begin RealResult := sqrt(ArgValue.Rval); SetRval(RealResult, Result) end; Lnf : if ArgValue.Rval <= 0.0 then begin PredictedError(33); Result := ZeroReal end else begin RealResult := ln(ArgValue.Rval); SetRval(RealResult, Result) end; Sinf, Cosf, Expf, Arctanf : begin case Which of Sinf : RealResult := sin(ArgValue.Rval); Cosf : RealResult := cos(ArgValue.Rval); Expf : RealResult := exp(ArgValue.Rval); Arctanf : RealResult := arctan(ArgValue.Rval) end; SetRval(RealResult, Result) end end end { ConstRealFn }; procedure ConstWrdFn(Which: StdProcFuncs; Arg1, Arg2: ObjectValue; var Result: ObjectValue); visible; var WordResult: ICLWord; begin case Which of AndWf : WordResult := andw(Arg1.Wval, Arg2.Wval); OrWf : WordResult := orw(Arg1.Wval, Arg2.Wval); NeqWf : WordResult := neqw(Arg1.Wval, Arg2.Wval); NotWf : WordResult := notw(Arg1.Wval); ShWf : WordResult := shw(Arg1.Wval, Arg2.Ival); RotWf : WordResult := rotw(Arg1.Wval, Arg2.Ival) end; SetWval(WordResult, Result) end { ConstWrdFn }; function HostInt(Value: ObjectValue): integer; visible; { Maps a target word-value or integer-value onto the } { host integer-space. } begin with Value do if Kind = BaseValue then if WVal >= wrd(maxint) then HostInt := maxint else HostInt := int(Wval) else HostInt := Ival end { HostInt }; function HostVal(Value: ObjectValue): integer; visible; { Recasts a target word-value or integer-value as a } { host integer value in contexts where this is known } { to be acceptable. } begin with Value do if Kind = BaseValue then HostVal := int(Wval) else HostVal := Ival end { HostVal }; function Range(Min, Max: ObjectValue): integer; visible; { Computes the range defined by two object values within } { the limits of the host integer-space. The value maxint } { is returned for those values whose range cannot be } { represented by a host integer value. } var WRange: ICLWord; IRange: integer; begin if Min.Kind = BaseValue then begin ConstWArith(Minus, Max.Wval, Min.Wval, WRange); if Overflow.Occurred or (WRange = wrd(maxint)) then Range := maxint else Range := int(WRange) + 1 end else begin ConstArith(Minus, Max.Ival, Min.Ival, IRange); if Overflow.Occurred or (IRange = maxint) then Range := maxint else Range := IRange + 1 end end; { range } { The procedure InitValues is called from within InitCodeGeneration to set up all predefined object values which the generation inter- face provides. } procedure InitWords; begin { MaxWord div Base } MaxWordDiv[ 2] := 2#1111111111111111111111111111111; MaxWordDiv[ 3] := 3#10200202220122111121; MaxWordDiv[ 4] := 4#333333333333333; MaxWordDiv[ 5] := 5#3224400242314; MaxWordDiv[ 6] := 6#155010401550; MaxWordDiv[ 7] := 7#21130142235; MaxWordDiv[ 8] := 8#3777777777; MaxWordDiv[ 9] := 9#1206865745; MaxWordDiv[10] := 10#429496729; MaxWordDiv[11] := 11#190444055; MaxWordDiv[12] := 12#9BA46159; MaxWordDiv[13] := 13#535A7988; MaxWordDiv[14] := 14#2CA5B746; MaxWordDiv[15] := 15#1A20DC8; MaxWordDiv[16] := 16#FFFFFFF; { MaxWord mod Base } MaxWordMod[ 2] := 2#1; MaxWordMod[ 3] := 3#0; MaxWordMod[ 4] := 4#3; MaxWordMod[ 5] := 5#0; MaxWordMod[ 6] := 6#3; MaxWordMod[ 7] := 7#3; MaxWordMod[ 8] := 8#7; MaxWordMod[ 9] := 9#3; MaxWordMod[10] := 10#5; MaxWordMod[11] := 11#3; MaxWordMod[12] := 12#3; MaxWordMod[13] := 13#8; MaxWordMod[14] := 14#3; MaxWordMod[15] := 15#0; MaxWordMod[16] := 16#F end { InitWord }; procedure InitValues; visible; begin SetIval(0, ZeroValue); SetIval(1, OneValue); SetIval(5, FiveValue); SetIval(8, EightValue); SetIval(11, ElevenValue); SetIval(16, SixteenValue); SetIval(22, TwentyTwoValue); SetIval(0, MinLabValue); SetIval(9999, MaxLabValue); SetIval(0, MinCharValue); SetIval(MCMaxChar, MaxCharValue); SetIval(0, DftValue); SetIval(MCMaxint, MaxintValue); SetIval(-MCMaxint, MinintValue); SetIval(MCMaxSet, MaxSetValue); SetRval(0.0, ZeroReal); SetRval(MCMaxReal, MaxRealValue); SetBval(false, FalseValue); SetBval(true, TrueValue); SetWval(MCMaxWord, MaxWordValue); with NilValue do begin Kind := PntrValue; Pval := nil; WordSize := 0 end; with EmptyValue do begin Kind := SetValue; Setval := nil; WordSize := 0 end; InitWords end { initvalues }; begin { module ends here } end.