aboutsummaryrefslogtreecommitdiffstats
path: root/src/vhdl/parse.adb
diff options
context:
space:
mode:
Diffstat (limited to 'src/vhdl/parse.adb')
-rw-r--r--src/vhdl/parse.adb224
1 files changed, 201 insertions, 23 deletions
diff --git a/src/vhdl/parse.adb b/src/vhdl/parse.adb
index dedcee1a7..0633cad67 100644
--- a/src/vhdl/parse.adb
+++ b/src/vhdl/parse.adb
@@ -3943,6 +3943,176 @@ package body Parse is
return Res;
end Parse_Allocator;
+ -- precond : tok_bit_string
+ -- postcond: tok_bit_string
+ --
+ -- Simply create the node for a bit string.
+ function Parse_Bit_String return Iir
+ is
+ Res : Iir;
+ C : Character;
+ B : Base_Type;
+ begin
+ Res := Create_Iir (Iir_Kind_String_Literal8);
+ Set_Location (Res);
+ Set_String8_Id (Res, Current_String_Id);
+ Set_String_Length (Res, Current_String_Length);
+ if Name_Table.Name_Buffer (1) = 's' then
+ Set_Has_Sign (Res, True);
+ Set_Has_Signed (Res, True);
+ pragma Assert (Name_Table.Name_Length = 2);
+ C := Name_Table.Name_Buffer (2);
+ elsif Name_Table.Name_Buffer (1) = 'u' then
+ Set_Has_Sign (Res, True);
+ Set_Has_Signed (Res, False);
+ pragma Assert (Name_Table.Name_Length = 2);
+ C := Name_Table.Name_Buffer (2);
+ else
+ Set_Has_Sign (Res, False);
+ Set_Has_Signed (Res, False);
+ pragma Assert (Name_Table.Name_Length = 1);
+ C := Name_Table.Name_Buffer (1);
+ end if;
+
+ case C is
+ when 'b' =>
+ B := Base_2;
+ when 'o' =>
+ B := Base_8;
+ when 'd' =>
+ B := Base_10;
+ when 'x' =>
+ B := Base_16;
+ when others =>
+ raise Internal_Error;
+ end case;
+ Set_Bit_String_Base (Res, B);
+
+ return Res;
+ end Parse_Bit_String;
+
+ -- Scan returns an expanded bit value. Adjust the expanded bit value as
+ -- required by the length.
+ procedure Resize_Bit_String (Lit : Iir; Nlen : Nat32)
+ is
+ use Str_Table;
+
+ Old_Len : constant Nat32 := Get_String_Length (Lit);
+ Is_Signed : constant Boolean := Get_Has_Signed (Lit);
+ Id : constant String8_Id := Get_String8_Id (Lit);
+ C : Nat8;
+ begin
+ if Nlen > Old_Len then
+ -- Extend.
+
+ -- LRM08 15.8
+ -- -- If the length is greater than the number of characters in the
+ -- expanded bit value and the base specifier is B, UB, O, UO, X,
+ -- UX or D, the bit string value is obtained by concatenating a
+ -- string of 0 digits to the left of the expanded bit value. The
+ -- number of 0 digits in the string is such that the number of
+ -- characters in the result of the concatenation is the length of
+ -- the bit string literal.
+ --
+ -- -- If the length is greater than the number of characters in the
+ -- expanded bit value and the base specifier is SB, SO or SX, the
+ -- bit string value is obtained by concatenating the the left of
+ -- the expanded bit value a string, each of whose characters is
+ -- the leftmost character of the expanded bit value. The number
+ -- of characters in the string is such that the number of
+ -- characters in the result of the concatenation is the length of
+ -- the bit string literal.
+ if Is_Signed then
+ if Old_Len = 0 then
+ Error_Msg_Parse
+ ("cannot expand an empty signed bit string", Lit);
+ C := Character'Pos ('0');
+ else
+ C := Element_String8 (Id, 1);
+ end if;
+ else
+ C := Character'Pos ('0');
+ end if;
+ Resize_String8 (Nlen);
+ -- Shift (position 1 is the MSB).
+ for I in reverse 1 .. Old_Len loop
+ Set_Element_String8 (Id, I + Nlen - Old_Len,
+ Element_String8 (Id, I));
+ end loop;
+ for I in 1 .. Nlen - Old_Len loop
+ Set_Element_String8 (Id, I, C);
+ end loop;
+ Set_String_Length (Lit, Nlen);
+
+ elsif Nlen < Old_Len then
+ -- Reduce.
+
+ -- LRM08 15.8
+ -- -- If the length is less than the number of characters in the
+ -- expanded bit value and the base specifier is B, UB, O, UO, X,
+ -- UX or D, the bit string value is obtained by deleting
+ -- sufficient characters from the left of the expanded bit value
+ -- to yield a string whose length is the length of the bit string
+ -- literal. It is an error if any of the character so deleted is
+ -- other than the digit 0.
+ --
+ -- -- If the length is less than the number of characters in the
+ -- expanded bit value and the base specifier is SB, SO or SX, the
+ -- bit string value is obtained by deleting sufficient characters
+ -- from the left of the expanded bit value to yield a string whose
+ -- length is the length of the bit string literal. It is an error
+ -- if any of the characters so deleted differs from the leftmost
+ -- remaining character.
+ if Is_Signed then
+ C := Element_String8 (Id, 1 + Old_Len - Nlen);
+ else
+ C := Character'Pos ('0');
+ end if;
+ for I in 1 .. Old_Len - Nlen loop
+ if Element_String8 (Id, I) /= C then
+ Error_Msg_Parse
+ ("truncation of bit string changes the value", Lit);
+ -- Avoid error storm.
+ exit;
+ end if;
+ end loop;
+ -- Shift (position 1 is the MSB).
+ for I in 1 .. Nlen loop
+ Set_Element_String8 (Id, I,
+ Element_String8 (Id, I + Old_Len - Nlen));
+ end loop;
+ Resize_String8 (Nlen);
+ Set_String_Length (Lit, Nlen);
+
+ else
+ -- LRM08 15.8
+ -- -- If the length is equal to the number of characters in the
+ -- expanded bit value, the string literal value is the expanded
+ -- bit value itself.
+ null;
+ end if;
+ end Resize_Bit_String;
+
+ -- Precond : next token after tok_integer
+ -- postcond: likewise
+ --
+ -- Return an integer_literal or a physical_literal.
+ function Parse_Integer_Literal (Val : Iir_Int64) return Iir
+ is
+ Res : Iir;
+ begin
+ if Current_Token = Tok_Identifier then
+ -- physical literal
+ Res := Create_Iir (Iir_Kind_Physical_Int_Literal);
+ Set_Unit_Name (Res, Parse_Name (Allow_Indexes => False));
+ else
+ -- integer literal
+ Res := Create_Iir (Iir_Kind_Integer_Literal);
+ end if;
+ Set_Value (Res, Val);
+ return Res;
+ end Parse_Integer_Literal;
+
-- precond : next token
-- postcond: next token
--
@@ -3987,16 +4157,8 @@ package body Parse is
-- Skip integer
Scan;
- if Current_Token = Tok_Identifier then
- -- physical literal
- Res := Create_Iir (Iir_Kind_Physical_Int_Literal);
- Set_Unit_Name (Res, Parse_Name (Allow_Indexes => False));
- else
- -- integer literal
- Res := Create_Iir (Iir_Kind_Integer_Literal);
- end if;
+ Res := Parse_Integer_Literal (Int);
Set_Location (Res, Loc);
- Set_Value (Res, Int);
return Res;
when Tok_Real =>
@@ -4043,23 +4205,39 @@ package body Parse is
return Res;
when Tok_New =>
return Parse_Allocator;
+
+ when Tok_Integer_Letter =>
+ Int := Current_Iir_Int64;
+ Loc := Get_Token_Location;
+
+ -- Skip integer
+ Scan;
+
+ if Current_Token = Tok_Bit_String then
+ Res := Parse_Bit_String;
+
+ -- Skip bit string
+ Scan;
+
+ -- Resize.
+ Resize_Bit_String (Res, Nat32 (Int));
+ else
+ Error_Msg_Parse
+ ("space is required between number and unit name",
+ Get_Token_Location);
+ Res := Parse_Integer_Literal (Int);
+ end if;
+ Set_Location (Res, Loc);
+ return Res;
+
when Tok_Bit_String =>
- Res := Create_Iir (Iir_Kind_String_Literal8);
- Set_Location (Res);
- Set_String8_Id (Res, Current_String_Id);
- Set_String_Length (Res, Current_String_Length);
- case Current_Iir_Int64 is
- when 1 =>
- Set_Bit_String_Base (Res, Base_2);
- when 3 =>
- Set_Bit_String_Base (Res, Base_8);
- when 4 =>
- Set_Bit_String_Base (Res, Base_16);
- when others =>
- raise Internal_Error;
- end case;
+ Res := Parse_Bit_String;
+
+ -- Skip bit string
Scan;
+
return Res;
+
when Tok_Minus
| Tok_Plus =>
Error_Msg_Parse