diff options
-rw-r--r-- | canon.adb | 4 | ||||
-rw-r--r-- | evaluation.adb | 138 | ||||
-rw-r--r-- | translate/grt/grt-disp_rti.adb | 4 | ||||
-rw-r--r-- | translate/grt/grt-values.adb | 331 |
4 files changed, 435 insertions, 42 deletions
@@ -241,7 +241,9 @@ package body Canon is --Canon_Extract_Sensitivity -- (Get_Prefix (Expr), Sensitivity_List, Is_Target); - when Iir_Kinds_Scalar_Type_Attribute => + when Iir_Kind_Value_Attribute + | Iir_Kind_Image_Attribute + | Iir_Kinds_Scalar_Type_Attribute => Canon_Extract_Sensitivity (Get_Parameter (Expr), Sensitivity_List, Is_Target); diff --git a/evaluation.adb b/evaluation.adb index 07cc313..3bd18ce 100644 --- a/evaluation.adb +++ b/evaluation.adb @@ -22,6 +22,7 @@ with Iirs_Utils; use Iirs_Utils; with Std_Package; use Std_Package; with Flags; use Flags; with Std_Names; +with Ada.Characters.Handling; package body Evaluation is function Get_Physical_Value (Expr : Iir) return Iir_Int64 @@ -1346,6 +1347,104 @@ package body Evaluation is return Res; end Eval_Floating_Image; + function Eval_Enumeration_Image (Enum, Expr : Iir) return Iir + is + Name : constant String := Image_Identifier (Enum); + Image_Id : constant String_Id := Str_Table.Start; + begin + for i in Name'range loop + Str_Table.Append(Name(i)); + end loop; + Str_Table.Finish; + return Build_String (Image_Id, Nat32(Name'Length), Expr); + end Eval_Enumeration_Image; + + function Build_Enumeration_Value (Val : String; Enum, Expr : Iir) return Iir + is + Value : String(Val'range); + List : constant Iir_List := Get_Enumeration_Literal_List(Enum); + begin + for i in Val'range loop + Value(i) := Ada.Characters.Handling.To_Lower (Val(i)); + end loop; + for i in 0 .. Get_Nbr_Elements(List) - 1 loop + if Value = Image_Identifier(Get_Nth_Element(List, i)) then + return Build_Discrete(Iir_Int64(i), Expr); + end if; + end loop; + Error_Msg_Sem ("value """ & Value & """ not in enumeration", Expr); + return Null_Iir; + end Build_Enumeration_Value; + + function Eval_Physical_Image (Phys, Expr : Iir) return Iir + -- reduces to the base unit (e.g. femtoseconds) + is + Value : constant String := Iir_Int64'image( + Get_Physical_Literal_Value(Phys)); + Unit : constant Iir := Get_Primary_Unit (Get_Base_Type (Get_Type(Phys))); + UnitName : constant String := Image_Identifier (Unit); + Image_Id : constant String_Id := Str_Table.Start; + Length : Nat32 := Value'Length + UnitName'Length + 1; + begin + for i in Value'range loop + -- Suppress the Ada +ve integer'image leading space + if i > Value'first or else Value(i) /= ' ' then + Str_Table.Append(Value(i)); + else + Length := Length - 1; + end if; + end loop; + Str_Table.Append(' '); + for i in UnitName'range loop + Str_Table.Append(UnitName(i)); + end loop; + Str_Table.Finish; + + return Build_String (Image_Id, Length, Expr); + end Eval_Physical_Image; + + function Build_Physical_Value (Val: String; Phys_Type, Expr: Iir) return Iir + is + function White (C : in Character) return Boolean is + NBSP : constant Character := Character'Val (160); + HT : constant Character := Character'Val (9); + begin + return C = ' ' or C = NBSP or C = HT; + end White; + + UnitName : String(Val'range); + Sep : Natural; + Found_Unit : Boolean := false; + Unit : Iir := Get_Primary_Unit (Phys_Type); + begin + -- Separate string into numeric value and make lowercase unit. + for i in reverse Val'range loop + UnitName(i) := Ada.Characters.Handling.To_Lower (Val(i)); + if White(Val(i)) and Found_Unit then + Sep := i; + exit; + else + Found_Unit := true; + end if; + end loop; + -- Unit name is UnitName(Sep+1..Unit'Last) + + -- Chain down the units looking for matching one + Unit := Get_Primary_Unit (Phys_Type); + while Unit /= Null_Iir loop + exit when UnitName(Sep+1..UnitName'Last) = Image_Identifier(Unit); + Unit := Get_Chain (Unit); + end loop; + if Unit = Null_Iir then + Error_Msg_Sem ("Unit """ & UnitName(Sep+1..UnitName'Last) + & """ not in physical type", Expr); + return Null_Iir; + end if; + -- FIXME: Should we support real values too? + return Build_Physical(Iir_Int64'value(Val(Val'first .. Sep)), Expr); + end Build_Physical_Value; + + function Eval_Incdec (Expr : Iir; N : Iir_Int64) return Iir is P : Iir_Int64; @@ -1625,10 +1724,47 @@ package body Evaluation is return Eval_Integer_Image (Get_Value (Param), Expr); when Iir_Kind_Floating_Type_Definition => return Eval_Floating_Image (Get_Fp_Value (Param), Expr); + when Iir_Kind_Enumeration_Type_Definition => + return Eval_Enumeration_Image (Param, Expr); + when Iir_Kind_Physical_Type_Definition => + return Eval_Physical_Image (Param, Expr); when others => - Error_Kind ("eval_static_expr('image)", Param_Type); + Error_Kind ("eval_static_expr('image)", Param); end case; end; + when Iir_Kind_Value_Attribute => + declare + Param : Iir; + Param_Type : Iir; + begin + Param := Get_Parameter (Expr); + Param := Eval_Static_Expr (Param); + Set_Parameter (Expr, Param); + if Get_Kind (Param) /= Iir_Kind_String_Literal then + Error_Msg_Sem ("'value argument not a string", Expr); + return Null_Iir; -- or Expr? + else + -- what type are we converting the string to? + Param_Type := Get_Base_Type (Get_Type (Expr)); + declare + Value : constant String := Image_String_Lit(Param); + begin + case Get_Kind (Param_Type) is + when Iir_Kind_Integer_Type_Definition => + return Build_Discrete(Iir_Int64'value(Value), Expr); + when Iir_Kind_Enumeration_Type_Definition => + return Build_Enumeration_Value (Value, Param_Type, + Expr); + when Iir_Kind_Floating_Type_Definition => + return Build_Floating (Iir_Fp64'value (Value), Expr); + when Iir_Kind_Physical_Type_Definition => + return Build_Physical_Value (Value, Param_Type, Expr); + when others => + Error_Kind ("eval_static_expr('value)", Param); + end case; + end; + end if; + end; when Iir_Kind_Left_Type_Attribute => return Build_Constant diff --git a/translate/grt/grt-disp_rti.adb b/translate/grt/grt-disp_rti.adb index c926775..d6f891a 100644 --- a/translate/grt/grt-disp_rti.adb +++ b/translate/grt/grt-disp_rti.adb @@ -253,8 +253,10 @@ package body Grt.Disp_Rti is Disp_Record_Value (Stream, To_Ghdl_Rtin_Type_Record_Acc (Rti), Ctxt, Obj, Is_Sig); when others => - Put (Stream, "??"); + Put (Stream, "Unknown Rti Kind : "); + Disp_Kind(Rti.Kind); end case; + Put_Line(":"); end Disp_Value; procedure Disp_Kind (Kind : Ghdl_Rtik) is diff --git a/translate/grt/grt-values.adb b/translate/grt/grt-values.adb index c60c667..173c8ce 100644 --- a/translate/grt/grt-values.adb +++ b/translate/grt/grt-values.adb @@ -16,12 +16,19 @@ -- Software Foundation, 59 Temple Place - Suite 330, Boston, MA -- 02111-1307, USA. with Grt.Errors; use Grt.Errors; +with System; +with Ada.Unchecked_Conversion; package body Grt.Values is NBSP : constant Character := Character'Val (160); HT : constant Character := Character'Val (9); + function White (C : in Character) return Boolean is + begin + return C = ' ' or C = NBSP or C = HT; + end White; + procedure Remove_Whitespace(S : in Std_String_Basep; Pos : in out Ghdl_Index_Type; Len : in Ghdl_Index_Type; @@ -30,24 +37,15 @@ package body Grt.Values is Chars := False; -- GHDL: allow several leading whitespace. while Pos < Len loop - case S (Pos) is - when ' ' - | NBSP - | HT => - Pos := Pos + 1; - when others => - Chars := True; - exit; - end case; + if White (S (Pos)) then + Pos := Pos + 1; + else + Chars := True; + exit; + end if; end loop; end Remove_Whitespace; - procedure Stub_Error(S : String) is - begin - Error_E ("'value: function Ghdl_Value_" & S & " is a stub!" - & "Please report as missing to http://gna.org/projects/ghdl"); - end Stub_Error; - function LC(C : in Character) return Character is begin if C >= 'A' and then C <= 'Z' then @@ -60,12 +58,10 @@ package body Grt.Values is procedure Make_LC_String(S : Std_String_Basep; Pos : in out Ghdl_Index_Type; - Len : Ghdl_Index_Type; Str : out String) is - pragma unreferenced(Len); begin for i in Str'range loop - Str(i) := LC(S(Pos)); -- LC it later + Str(i) := LC(S(Pos)); Pos := Pos + 1; end loop; end Make_LC_String; @@ -108,7 +104,7 @@ package body Grt.Values is Str : String(1..Natural(Len - Pos)); Found : Boolean := False; begin - Make_LC_String(S, Pos, Len, Str); + Make_LC_String(S, Pos, Str); for i in 0 .. Enum_Rti.Nbr - 1 loop if StringMatch(Str, Enum_Rti.Names.all(i)) then Found := True; @@ -126,7 +122,6 @@ package body Grt.Values is if Chars then Error_E ("'value: trailing characters after blank"); end if; - -- Stub_Error("E8"); return Val; end Ghdl_Value_Enum; @@ -151,14 +146,14 @@ package body Grt.Values is return Ghdl_E32'Val(Ghdl_Value_Enum (Str , Rti )); end Ghdl_Value_E32; - function Ghdl_Value_I32 (Str : Std_String_Ptr) return Ghdl_I32 + function Ghdl_Value_I64 (Str : Std_String_Ptr) return Ghdl_I64 is S : constant Std_String_Basep := Str.Base; Len : constant Ghdl_Index_Type := Str.Bounds.Dim_1.Length; Pos : Ghdl_Index_Type := 0; C : Character; Sep : Character; - Val, D, Base : Ghdl_I32; + Val, D, Base : Ghdl_I64; Exp : Integer; Chars : Ghdl_B2; begin @@ -320,40 +315,298 @@ package body Grt.Values is -- GHDL: allow several trailing whitespace. Remove_Whitespace(S, Pos, Len, Chars); if Chars then - Error_E ("'value: trailing characters after blank"); + Error_E ("integer'value: trailing characters after blank"); end if; return Val; + end Ghdl_Value_I64; + + function Ghdl_Value_I32 (Str : Std_String_Ptr) return Ghdl_I32 + is + begin + return Ghdl_I32 (Ghdl_Value_I64 (Str)); end Ghdl_Value_I32; - function Ghdl_Value_F64 (Str : Std_String_Ptr) return Ghdl_F64 is - pragma unreferenced(Str); - Val : constant Ghdl_F64 := 0.0; + function Ghdl_Value_Physical_Type (Str : Std_String_Ptr; + Rti : Ghdl_Rti_Access) + return Ghdl_I64 + is + function To_Std_String_Ptr is new Ada.Unchecked_Conversion + (Source => System.Address, Target => Std_String_Ptr); + function To_Std_String_Boundp is new Ada.Unchecked_Conversion + (Source => System.Address, Target => Std_String_Boundp); + + S : aliased Std_String := Str.all; + Bound : aliased Std_String_Bound := Str.Bounds.all; + + Base_Val : Ghdl_I64; + Multiple : Ghdl_Rti_Unit_Val; + + Phys_Rti : Ghdl_Rtin_Type_Physical_Acc; + Unit : Ghdl_Rtin_Unit_Acc; + Start, Finish : Ghdl_Index_Type; + begin - Stub_Error("F64"); - return Val; - end Ghdl_Value_F64; + Phys_Rti := To_Ghdl_Rtin_Type_Physical_Acc (Rti); + + S.Bounds := To_Std_String_Boundp(Bound'Address); + -- find characters at the end... + Finish := Ghdl_Index_Type(Bound.Dim_1.Length)-1; + while White(S.Base.all(Finish)) loop + Finish := Finish - 1; + end loop; + Start := Finish; + while not White(S.Base.all(Start - 1)) loop + Start := Start - 1; + end loop; + -- shorten Bounds to exclude non-numeric part + Bound.Dim_1.Right := Bound.Dim_1.Right + - Std_Integer(Bound.Dim_1.Length - Start); + Bound.Dim_1.Length := Start; + -- and capture integer value + -- FIXME: Should we support real values too? + Base_Val := Ghdl_Value_I64(To_Std_String_Ptr(S'Address)); + + declare + Unit_Str : String(1 .. Natural(1 + Finish - Start)); + Found : Boolean := False; + begin + Make_LC_String(Str.Base, Start, Unit_Str); + for i in 0 .. Phys_Rti.Nbr - 1 loop + Unit := To_Ghdl_Rtin_Unit_Acc(Phys_Rti.Units(i)); + if StringMatch(Unit_Str, Unit.Name) then + Found := True; + Multiple := To_Ghdl_Rtin_Unit_Acc (Phys_Rti.Units (i)).Value; + exit; + end if; + end loop; + if not Found then + Error_E ("'value: Unit " & Unit_Str & " not in physical type" & + Phys_Rti.Name.all(1..strlen(Phys_Rti.Name))); + end if; + end; + + if Rti.Kind = Ghdl_Rtik_Type_P64 then + return Base_Val * Ghdl_I64(Multiple.Unit_64); + else + return Base_Val * Ghdl_I64(Multiple.Unit_32); + end if; + end Ghdl_Value_Physical_Type; function Ghdl_Value_P64 (Str : Std_String_Ptr; Rti : Ghdl_Rti_Access) return Ghdl_I64 is - pragma unreferenced(Str); - pragma unreferenced(Rti); - Val : constant Ghdl_I64 := 0; begin - Stub_Error("P64"); - return Val; + if Rti.Kind /= Ghdl_Rtik_Type_P64 then + Error_E ("Physical_Type_64'value: incorrect RTI"); + end if; + return Ghdl_Value_Physical_Type(Str, Rti); end Ghdl_Value_P64; function Ghdl_Value_P32 (Str : Std_String_Ptr; Rti : Ghdl_Rti_Access) return Ghdl_I32 is - pragma unreferenced(Str); - pragma unreferenced(Rti); - Val : constant Ghdl_I32 := 0; begin - Stub_Error("P32"); - return Val; + if Rti.Kind /= Ghdl_Rtik_Type_P32 then + Error_E ("Physical_Type_32'value: incorrect RTI"); + end if; + return Ghdl_I32(Ghdl_Value_Physical_Type(Str, Rti)); end Ghdl_Value_P32; + -- From patch attached to https://gna.org/bugs/index.php?18352 + -- thanks to Christophe Curis https://gna.org/users/lobotomy + function Ghdl_Value_F64 (Str : Std_String_Ptr) return Ghdl_F64 + is + S : constant Std_String_Basep := Str.Base; + Len : constant Ghdl_Index_Type := Str.Bounds.Dim_1.Length; + Pos : Ghdl_Index_Type := 0; + C : Character; + Chars : Ghdl_B2; + Is_Negative, Is_Neg_Exp : Boolean := False; + Base : Ghdl_F64; + Intg : Ghdl_I32; + Val, Df : Ghdl_F64; + Sep : Character; + FrcExp : Ghdl_F64; + begin + -- LRM 14.1 + -- Leading [and trailing] whitespace is allowed and ignored. + -- + -- GHDL: allow several leading whitespace. + Remove_Whitespace(S, Pos, Len, Chars); + + if Pos = Len then + Error_E ("'value: empty string"); + end if; + + C := S (Pos); + if C = '-' then + Is_Negative := True; + Pos := Pos + 1; + elsif C = '+' then + Pos := Pos + 1; + end if; + + if Pos >= Len then + Error_E ("'value: decimal digit expected"); + end if; + + -- Read Integer-or-Base part (may be optional) + Intg := 0; + while Pos < Len loop + C := S (Pos); + if C in '0' .. '9' then + Intg := Intg * 10 + Character'Pos (C) - Character'Pos ('0'); + elsif C /= '_' then + exit; + end if; + Pos := Pos + 1; + end loop; + + if Pos = Len then + return Ghdl_F64 (Intg); + end if; + + -- Special case: base was specified + if C = '#' or C = ':' then + if Intg < 2 or Intg > 16 then + Error_E ("'value: bad base"); + end if; + Base := Ghdl_F64 (Intg); + Val := 0.0; + Sep := C; + Pos := Pos + 1; + if Pos >= Len then + Error_E ("'value: missing based decimal"); + end if; + + -- Get the Integer part of the Value + while Pos < Len loop + C := S (Pos); + case C is + when '0' .. '9' => + Df := Ghdl_F64 (Character'Pos (C) - Character'Pos('0') ); + when 'A' .. 'F' => + Df := Ghdl_F64 (Character'Pos (C) - Character'Pos('A') + 10); + when 'a' .. 'f' => + Df := Ghdl_F64 (Character'Pos (C) - Character'Pos('a') + 10); + when others => + exit; + end case; + if C /= '_' then + if Df >= Base then + Error_E ("'value: digit greater than base"); + end if; + Val := Val * Base + Df; + end if; + Pos := Pos + 1; + end loop; + if Pos >= Len then + Error_E ("'value: missing end sign number"); + end if; + else + Base := 10.0; + Sep := ' '; + Val := Ghdl_F64 (Intg); + end if; + + -- Handle the Fractional part + if C = '.' then + Pos := Pos + 1; + FrcExp := 1.0; + while Pos < Len loop + C := S (Pos); + case C is + when '0' .. '9' => + Df := Ghdl_F64 (Character'Pos (C) - Character'Pos('0')); + when 'A' .. 'F' => + exit when Sep = ' '; + Df := Ghdl_F64 (Character'Pos (C) - Character'Pos('A') + 10); + when 'a' .. 'f' => + exit when Sep = ' '; + Df := Ghdl_F64 (Character'Pos (C) - Character'Pos('a') + 10); + when others => + exit; + end case; + if C /= '_' then + FrcExp := FrcExp / Base; + if Df > Base then + Error_E ("'value: digit greater than base"); + end if; + Val := Val + Df * FrcExp; + end if; + Pos := Pos + 1; + end loop; + end if; + + -- If base was specified, we must find here the end marker + if Sep /= ' ' then + if Pos >= Len then + Error_E ("'value: missing end sign number"); + end if; + if C /= Sep then + Error_E ("'value: sign number mismatch"); + end if; + Pos := Pos + 1; + end if; + + -- Handle exponent + if Pos < Len then + C := S (Pos); + if C = 'e' or C = 'E' then + Pos := Pos + 1; + if Pos >= Len then + Error_E ("'value: no character after exponent"); + end if; + C := S (Pos); + if C = '-' then + Is_Neg_Exp := True; + Pos := Pos + 1; + elsif C = '+' then + Pos := Pos + 1; + end if; + Intg := 0; + while Pos < Len loop + C := S (Pos); + if C in '0' .. '9' then + Intg := Intg * 10 + Character'Pos (C) - Character'Pos ('0'); + else + exit; + end if; + Pos := Pos + 1; + end loop; + -- This Exponentiation method is sub-optimal, + -- but it does not depend on any library + FrcExp := 1.0; + if Is_Neg_Exp then + while Intg > 0 loop + FrcExp := FrcExp / 10.0; + Intg := Intg - 1; + end loop; + else + while Intg > 0 loop + FrcExp := FrcExp * 10.0; + Intg := Intg - 1; + end loop; + end if; + Val := Val * FrcExp; + end if; + end if; + + -- LRM 14.1 + -- [Leading] and trailing whitespace is allowed and ignored. + -- + -- GHDL: allow several leading whitespace. + Remove_Whitespace(S, Pos, Len, Chars); + if Chars then + Error_E ("'value: trailing characters after blank"); + end if; + + if Is_Negative then + Val := -Val; + end if; + + return Val; + end Ghdl_Value_F64; + end Grt.Values; |