diff options
author | Tristan Gingold <tgingold@free.fr> | 2018-08-04 06:59:25 +0200 |
---|---|---|
committer | Tristan Gingold <tgingold@free.fr> | 2018-08-04 17:02:16 +0200 |
commit | afa72384251e121988501ac22f16d0110bd2305f (patch) | |
tree | 4d6a5568d8d4995565f7e08268832ed670d9520c | |
parent | 919206e884d423925170c3735421b9b5e35cd183 (diff) | |
download | ghdl-afa72384251e121988501ac22f16d0110bd2305f.tar.gz ghdl-afa72384251e121988501ac22f16d0110bd2305f.tar.bz2 ghdl-afa72384251e121988501ac22f16d0110bd2305f.zip |
rework parse_expression to add parse_binary_expression.
This is needed to complete PSL expression parsing.
-rw-r--r-- | src/ghdldrv/ghdlprint.adb | 14 | ||||
-rw-r--r-- | src/std_names.adb | 12 | ||||
-rw-r--r-- | src/std_names.ads | 203 | ||||
-rw-r--r-- | src/vhdl/disp_vhdl.adb | 1 | ||||
-rw-r--r-- | src/vhdl/parse.adb | 513 | ||||
-rw-r--r-- | src/vhdl/parse.ads | 18 | ||||
-rw-r--r-- | src/vhdl/parse_psl.adb | 22 | ||||
-rw-r--r-- | src/vhdl/tokens.ads | 21 |
8 files changed, 377 insertions, 427 deletions
diff --git a/src/ghdldrv/ghdlprint.adb b/src/ghdldrv/ghdlprint.adb index f95e266ee..531d6125a 100644 --- a/src/ghdldrv/ghdlprint.adb +++ b/src/ghdldrv/ghdlprint.adb @@ -378,23 +378,11 @@ package body Ghdlprint is Disp_Text; Put ("</tt>"); end case; - when Tok_Access .. Tok_Elsif - | Tok_Entity .. Tok_With - | Tok_Mod .. Tok_Rem - | Tok_And .. Tok_Not => - Disp_Reserved; - when Tok_End => + when Tok_Mod .. Tok_Parameter => Disp_Reserved; when Tok_Semi_Colon => Disp_Spaces; Disp_Text; - when Tok_Xnor .. Tok_Ror => - Disp_Reserved; - when Tok_Protected => - Disp_Reserved; - when Tok_Context - | Tok_Parameter => - Disp_Reserved; when Tok_Across .. Tok_Tolerance => Disp_Reserved; when Tok_Psl_Default diff --git a/src/std_names.adb b/src/std_names.adb index ffee4645e..dfe322136 100644 --- a/src/std_names.adb +++ b/src/std_names.adb @@ -31,12 +31,6 @@ package body Std_Names is Def ("mod", Name_Mod); Def ("rem", Name_Rem); - Def ("and", Name_And); - Def ("or", Name_Or); - Def ("xor", Name_Xor); - Def ("nand", Name_Nand); - Def ("nor", Name_Nor); - Def ("abs", Name_Abs); Def ("not", Name_Not); @@ -131,6 +125,12 @@ package body Std_Names is Def ("while", Name_While); Def ("with", Name_With); + Def ("and", Name_And); + Def ("or", Name_Or); + Def ("xor", Name_Xor); + Def ("nand", Name_Nand); + Def ("nor", Name_Nor); + -- VHDL93 reserved words. Def ("xnor", Name_Xnor); Def ("group", Name_Group); diff --git a/src/std_names.ads b/src/std_names.ads index ff273de02..b1e39ca6e 100644 --- a/src/std_names.ads +++ b/src/std_names.ads @@ -34,112 +34,113 @@ package Std_Names is Name_Mod : constant Name_Id := Name_First_Keyword + 000; Name_Rem : constant Name_Id := Name_First_Keyword + 001; - Name_And : constant Name_Id := Name_First_Keyword + 002; - Name_Or : constant Name_Id := Name_First_Keyword + 003; - Name_Xor : constant Name_Id := Name_First_Keyword + 004; - Name_Nand : constant Name_Id := Name_First_Keyword + 005; - Name_Nor : constant Name_Id := Name_First_Keyword + 006; + Name_Abs : constant Name_Id := Name_First_Keyword + 002; + Name_Not : constant Name_Id := Name_First_Keyword + 003; - Name_Abs : constant Name_Id := Name_First_Keyword + 007; - Name_Not : constant Name_Id := Name_First_Keyword + 008; + subtype Name_Word_Operators is Name_Id range Name_Mod .. Name_Not; + + Name_Access : constant Name_Id := Name_First_Keyword + 004; + Name_After : constant Name_Id := Name_First_Keyword + 005; + Name_Alias : constant Name_Id := Name_First_Keyword + 006; + Name_All : constant Name_Id := Name_First_Keyword + 007; + Name_Architecture : constant Name_Id := Name_First_Keyword + 008; + Name_Array : constant Name_Id := Name_First_Keyword + 009; + Name_Assert : constant Name_Id := Name_First_Keyword + 010; + Name_Attribute : constant Name_Id := Name_First_Keyword + 011; + + Name_Begin : constant Name_Id := Name_First_Keyword + 012; + Name_Block : constant Name_Id := Name_First_Keyword + 013; + Name_Body : constant Name_Id := Name_First_Keyword + 014; + Name_Buffer : constant Name_Id := Name_First_Keyword + 015; + Name_Bus : constant Name_Id := Name_First_Keyword + 016; + + Name_Case : constant Name_Id := Name_First_Keyword + 017; + Name_Component : constant Name_Id := Name_First_Keyword + 018; + Name_Configuration : constant Name_Id := Name_First_Keyword + 019; + Name_Constant : constant Name_Id := Name_First_Keyword + 020; + + Name_Disconnect : constant Name_Id := Name_First_Keyword + 021; + Name_Downto : constant Name_Id := Name_First_Keyword + 022; + + Name_Else : constant Name_Id := Name_First_Keyword + 023; + Name_Elsif : constant Name_Id := Name_First_Keyword + 024; + Name_End : constant Name_Id := Name_First_Keyword + 025; + Name_Entity : constant Name_Id := Name_First_Keyword + 026; + Name_Exit : constant Name_Id := Name_First_Keyword + 027; + + Name_File : constant Name_Id := Name_First_Keyword + 028; + Name_For : constant Name_Id := Name_First_Keyword + 029; + Name_Function : constant Name_Id := Name_First_Keyword + 030; + + Name_Generate : constant Name_Id := Name_First_Keyword + 031; + Name_Generic : constant Name_Id := Name_First_Keyword + 032; + Name_Guarded : constant Name_Id := Name_First_Keyword + 033; + + Name_If : constant Name_Id := Name_First_Keyword + 034; + Name_In : constant Name_Id := Name_First_Keyword + 035; + Name_Inout : constant Name_Id := Name_First_Keyword + 036; + Name_Is : constant Name_Id := Name_First_Keyword + 037; + + Name_Label : constant Name_Id := Name_First_Keyword + 038; + Name_Library : constant Name_Id := Name_First_Keyword + 039; + Name_Linkage : constant Name_Id := Name_First_Keyword + 040; + Name_Loop : constant Name_Id := Name_First_Keyword + 041; + + Name_Map : constant Name_Id := Name_First_Keyword + 042; + + Name_New : constant Name_Id := Name_First_Keyword + 043; + Name_Next : constant Name_Id := Name_First_Keyword + 044; + Name_Null : constant Name_Id := Name_First_Keyword + 045; + + Name_Of : constant Name_Id := Name_First_Keyword + 046; + Name_On : constant Name_Id := Name_First_Keyword + 047; + Name_Open : constant Name_Id := Name_First_Keyword + 048; + Name_Others : constant Name_Id := Name_First_Keyword + 049; + Name_Out : constant Name_Id := Name_First_Keyword + 050; + + Name_Package : constant Name_Id := Name_First_Keyword + 051; + Name_Port : constant Name_Id := Name_First_Keyword + 052; + Name_Procedure : constant Name_Id := Name_First_Keyword + 053; + Name_Process : constant Name_Id := Name_First_Keyword + 054; + + Name_Range : constant Name_Id := Name_First_Keyword + 055; + Name_Record : constant Name_Id := Name_First_Keyword + 056; + Name_Register : constant Name_Id := Name_First_Keyword + 057; + Name_Report : constant Name_Id := Name_First_Keyword + 058; + Name_Return : constant Name_Id := Name_First_Keyword + 059; + + Name_Select : constant Name_Id := Name_First_Keyword + 060; + Name_Severity : constant Name_Id := Name_First_Keyword + 061; + Name_Signal : constant Name_Id := Name_First_Keyword + 062; + Name_Subtype : constant Name_Id := Name_First_Keyword + 063; + + Name_Then : constant Name_Id := Name_First_Keyword + 064; + Name_To : constant Name_Id := Name_First_Keyword + 065; + Name_Transport : constant Name_Id := Name_First_Keyword + 066; + Name_Type : constant Name_Id := Name_First_Keyword + 067; + + Name_Units : constant Name_Id := Name_First_Keyword + 068; + Name_Until : constant Name_Id := Name_First_Keyword + 069; + Name_Use : constant Name_Id := Name_First_Keyword + 070; + + Name_Variable : constant Name_Id := Name_First_Keyword + 071; + + Name_Wait : constant Name_Id := Name_First_Keyword + 072; + Name_When : constant Name_Id := Name_First_Keyword + 073; + Name_While : constant Name_Id := Name_First_Keyword + 074; + Name_With : constant Name_Id := Name_First_Keyword + 075; + + Name_And : constant Name_Id := Name_First_Keyword + 076; + Name_Or : constant Name_Id := Name_First_Keyword + 077; + Name_Xor : constant Name_Id := Name_First_Keyword + 078; + Name_Nand : constant Name_Id := Name_First_Keyword + 079; + Name_Nor : constant Name_Id := Name_First_Keyword + 080; subtype Name_Logical_Operators is Name_Id range Name_And .. Name_Nor; - subtype Name_Word_Operators is Name_Id range Name_Mod .. Name_Not; - Name_Access : constant Name_Id := Name_First_Keyword + 009; - Name_After : constant Name_Id := Name_First_Keyword + 010; - Name_Alias : constant Name_Id := Name_First_Keyword + 011; - Name_All : constant Name_Id := Name_First_Keyword + 012; - Name_Architecture : constant Name_Id := Name_First_Keyword + 013; - Name_Array : constant Name_Id := Name_First_Keyword + 014; - Name_Assert : constant Name_Id := Name_First_Keyword + 015; - Name_Attribute : constant Name_Id := Name_First_Keyword + 016; - - Name_Begin : constant Name_Id := Name_First_Keyword + 017; - Name_Block : constant Name_Id := Name_First_Keyword + 018; - Name_Body : constant Name_Id := Name_First_Keyword + 019; - Name_Buffer : constant Name_Id := Name_First_Keyword + 020; - Name_Bus : constant Name_Id := Name_First_Keyword + 021; - - Name_Case : constant Name_Id := Name_First_Keyword + 022; - Name_Component : constant Name_Id := Name_First_Keyword + 023; - Name_Configuration : constant Name_Id := Name_First_Keyword + 024; - Name_Constant : constant Name_Id := Name_First_Keyword + 025; - - Name_Disconnect : constant Name_Id := Name_First_Keyword + 026; - Name_Downto : constant Name_Id := Name_First_Keyword + 027; - - Name_Else : constant Name_Id := Name_First_Keyword + 028; - Name_Elsif : constant Name_Id := Name_First_Keyword + 029; - Name_End : constant Name_Id := Name_First_Keyword + 030; - Name_Entity : constant Name_Id := Name_First_Keyword + 031; - Name_Exit : constant Name_Id := Name_First_Keyword + 032; - - Name_File : constant Name_Id := Name_First_Keyword + 033; - Name_For : constant Name_Id := Name_First_Keyword + 034; - Name_Function : constant Name_Id := Name_First_Keyword + 035; - - Name_Generate : constant Name_Id := Name_First_Keyword + 036; - Name_Generic : constant Name_Id := Name_First_Keyword + 037; - Name_Guarded : constant Name_Id := Name_First_Keyword + 038; - - Name_If : constant Name_Id := Name_First_Keyword + 039; - Name_In : constant Name_Id := Name_First_Keyword + 040; - Name_Inout : constant Name_Id := Name_First_Keyword + 041; - Name_Is : constant Name_Id := Name_First_Keyword + 042; - - Name_Label : constant Name_Id := Name_First_Keyword + 043; - Name_Library : constant Name_Id := Name_First_Keyword + 044; - Name_Linkage : constant Name_Id := Name_First_Keyword + 045; - Name_Loop : constant Name_Id := Name_First_Keyword + 046; - - Name_Map : constant Name_Id := Name_First_Keyword + 047; - - Name_New : constant Name_Id := Name_First_Keyword + 048; - Name_Next : constant Name_Id := Name_First_Keyword + 049; - Name_Null : constant Name_Id := Name_First_Keyword + 050; - - Name_Of : constant Name_Id := Name_First_Keyword + 051; - Name_On : constant Name_Id := Name_First_Keyword + 052; - Name_Open : constant Name_Id := Name_First_Keyword + 053; - Name_Others : constant Name_Id := Name_First_Keyword + 054; - Name_Out : constant Name_Id := Name_First_Keyword + 055; - - Name_Package : constant Name_Id := Name_First_Keyword + 056; - Name_Port : constant Name_Id := Name_First_Keyword + 057; - Name_Procedure : constant Name_Id := Name_First_Keyword + 058; - Name_Process : constant Name_Id := Name_First_Keyword + 059; - - Name_Range : constant Name_Id := Name_First_Keyword + 060; - Name_Record : constant Name_Id := Name_First_Keyword + 061; - Name_Register : constant Name_Id := Name_First_Keyword + 062; - Name_Report : constant Name_Id := Name_First_Keyword + 063; - Name_Return : constant Name_Id := Name_First_Keyword + 064; - - Name_Select : constant Name_Id := Name_First_Keyword + 065; - Name_Severity : constant Name_Id := Name_First_Keyword + 066; - Name_Signal : constant Name_Id := Name_First_Keyword + 067; - Name_Subtype : constant Name_Id := Name_First_Keyword + 068; - - Name_Then : constant Name_Id := Name_First_Keyword + 069; - Name_To : constant Name_Id := Name_First_Keyword + 070; - Name_Transport : constant Name_Id := Name_First_Keyword + 071; - Name_Type : constant Name_Id := Name_First_Keyword + 072; - - Name_Units : constant Name_Id := Name_First_Keyword + 073; - Name_Until : constant Name_Id := Name_First_Keyword + 074; - Name_Use : constant Name_Id := Name_First_Keyword + 075; - - Name_Variable : constant Name_Id := Name_First_Keyword + 076; - - Name_Wait : constant Name_Id := Name_First_Keyword + 077; - Name_When : constant Name_Id := Name_First_Keyword + 078; - Name_While : constant Name_Id := Name_First_Keyword + 079; - Name_With : constant Name_Id := Name_First_Keyword + 080; - - Name_Last_Vhdl87 : constant Name_Id := Name_With; + Name_Last_Vhdl87 : constant Name_Id := Name_Nor; subtype Name_Id_Vhdl87_Reserved_Words is - Name_Id range Name_First_Keyword .. Name_With; + Name_Id range Name_First_Keyword .. Name_Nor; -- VHDL93 reserved words. Name_Xnor : constant Name_Id := Name_First_Keyword + 081; diff --git a/src/vhdl/disp_vhdl.adb b/src/vhdl/disp_vhdl.adb index b82abe602..e675e718c 100644 --- a/src/vhdl/disp_vhdl.adb +++ b/src/vhdl/disp_vhdl.adb @@ -159,6 +159,7 @@ package body Disp_Vhdl is case Id is when Name_Id_Operators | Name_Word_Operators + | Name_Logical_Operators | Name_Xnor | Name_Shift_Operators => Put (""""); diff --git a/src/vhdl/parse.adb b/src/vhdl/parse.adb index 37257914a..7c840de4f 100644 --- a/src/vhdl/parse.adb +++ b/src/vhdl/parse.adb @@ -49,8 +49,6 @@ package body Parse is -- current_token must be valid. -- Leaves a token. - function Parse_Simple_Expression (Primary : Iir := Null_Iir) - return Iir_Expression; function Parse_Primary return Iir_Expression; function Parse_Use_Clause return Iir_Use_Clause; @@ -299,7 +297,7 @@ package body Parse is -- Skip 'to' or 'downto'. Scan; - Set_Right_Limit_Expr (Res, Parse_Simple_Expression); + Set_Right_Limit_Expr (Res, Parse_Expression (Prio_Simple)); return Res; end Parse_Range_Expression; @@ -309,7 +307,7 @@ package body Parse is is Left: Iir; begin - Left := Parse_Simple_Expression; + Left := Parse_Expression (Prio_Simple); case Current_Token is when Tok_To @@ -367,7 +365,7 @@ package body Parse is is Left: Iir; begin - Left := Parse_Simple_Expression; + Left := Parse_Expression (Prio_Simple); case Current_Token is when Tok_To @@ -2014,7 +2012,7 @@ package body Parse is -- Parse a simple expression (for the range), which can also parse a -- name. - Type_Mark := Parse_Simple_Expression; + Type_Mark := Parse_Expression (Prio_Simple); case Current_Token is when Tok_Range => @@ -5255,7 +5253,7 @@ package body Parse is | Tok_Plus => Error_Msg_Parse ("'-' and '+' are not allowed in primary, use parenthesis"); - return Parse_Simple_Expression; + return Parse_Expression (Prio_Simple); when Tok_Comma | Tok_Semi_Colon @@ -5272,80 +5270,118 @@ package body Parse is end case; end Parse_Primary; - -- precond : next token - -- postcond: next token + -- [ LRM08 9 Expressions ] -- - -- [ LRM93 7.1 ] - -- factor ::= primary [ ** primary ] - -- | ABS primary - -- | NOT primary - -- | logical_operator primary [ VHDL08 9.1 ] - function Build_Unary_Factor (Primary : Iir; Op : Iir_Kind) return Iir is + -- expression ::= + -- condition_operator primary + -- | logical_expression + -- + -- logical_expression ::= + -- relation { and relation } + -- | relation { or relation } + -- | relation { xor relation } + -- | relation [ nand relation ] + -- | relation [ nor relation ] + -- | relation { xnor relation } + -- + -- relation ::= + -- shift_expression [ relational_operator shift_expression ] + -- + -- shift_expression ::= + -- simple_expression [ shift_operator simple_expression ] + -- + -- simple_expression ::= + -- [ sign ] term { adding_operator term } + -- + -- term ::= + -- factor { multiplying_operator factor } + -- + -- factor ::= + -- primary [ ** primary ] + -- | abs primary + -- | not primary + -- | logical_operator primary + function Build_Unary_Factor (Op : Iir_Kind) return Iir + is Res : Iir; begin - if Primary /= Null_Iir then - return Primary; - end if; Res := Create_Iir (Op); Set_Location (Res); + + -- Skip operator. Scan; + Set_Operand (Res, Parse_Primary); + return Res; end Build_Unary_Factor; - function Build_Unary_Factor_08 (Primary : Iir; Op : Iir_Kind) return Iir is + function Build_Unary_Simple (Op : Iir_Kind) return Iir + is + Res : Iir; + begin + Res := Create_Iir (Op); + Set_Location (Res); + + -- Skip operator. + Scan; + + Set_Operand (Res, Parse_Expression (Prio_Term)); + + return Res; + end Build_Unary_Simple; + + function Build_Unary_Factor_08 (Op : Iir_Kind) return Iir is begin - if Primary /= Null_Iir then - return Primary; - end if; if Flags.Vhdl_Std < Vhdl_08 then Error_Msg_Parse ("missing left operand of logical expression"); + -- Skip operator Scan; + return Parse_Primary; else - return Build_Unary_Factor (Primary, Op); + return Build_Unary_Factor (Op); end if; end Build_Unary_Factor_08; - function Parse_Factor (Primary : Iir := Null_Iir) return Iir_Expression is - Res, Left: Iir_Expression; + function Parse_Unary_Expression return Iir + is + Res, Left : Iir_Expression; begin case Current_Token is + when Tok_Plus => + return Build_Unary_Simple (Iir_Kind_Identity_Operator); + when Tok_Minus => + return Build_Unary_Simple (Iir_Kind_Negation_Operator); + when Tok_Abs => - return Build_Unary_Factor (Primary, Iir_Kind_Absolute_Operator); + return Build_Unary_Factor (Iir_Kind_Absolute_Operator); when Tok_Not => - return Build_Unary_Factor (Primary, Iir_Kind_Not_Operator); + return Build_Unary_Factor (Iir_Kind_Not_Operator); when Tok_And => - return Build_Unary_Factor_08 - (Primary, Iir_Kind_Reduction_And_Operator); + return Build_Unary_Factor_08 (Iir_Kind_Reduction_And_Operator); when Tok_Or => - return Build_Unary_Factor_08 - (Primary, Iir_Kind_Reduction_Or_Operator); + return Build_Unary_Factor_08 (Iir_Kind_Reduction_Or_Operator); when Tok_Nand => - return Build_Unary_Factor_08 - (Primary, Iir_Kind_Reduction_Nand_Operator); + return Build_Unary_Factor_08 (Iir_Kind_Reduction_Nand_Operator); when Tok_Nor => - return Build_Unary_Factor_08 - (Primary, Iir_Kind_Reduction_Nor_Operator); + return Build_Unary_Factor_08 (Iir_Kind_Reduction_Nor_Operator); when Tok_Xor => - return Build_Unary_Factor_08 - (Primary, Iir_Kind_Reduction_Xor_Operator); + return Build_Unary_Factor_08 (Iir_Kind_Reduction_Xor_Operator); when Tok_Xnor => - return Build_Unary_Factor_08 - (Primary, Iir_Kind_Reduction_Xnor_Operator); + return Build_Unary_Factor_08 (Iir_Kind_Reduction_Xnor_Operator); when others => - if Primary /= Null_Iir then - Left := Primary; - else - Left := Parse_Primary; - end if; + Left := Parse_Primary; if Current_Token = Tok_Double_Star then Res := Create_Iir (Iir_Kind_Exponentiation_Operator); Set_Location (Res); + + -- Skip '**'. Scan; + Set_Left (Res, Left); Set_Right (Res, Parse_Primary); return Res; @@ -5353,272 +5389,135 @@ package body Parse is return Left; end if; end case; - end Parse_Factor; + end Parse_Unary_Expression; - -- precond : next token - -- postcond: next token - -- - -- [ LRM93 7.1 ] - -- term ::= factor { multiplying_operator factor } - -- - -- [ LRM93 7.2 ] - -- multiplying_operator ::= * | / | MOD | REM - function Parse_Term (Primary : Iir) return Iir_Expression is - Res, Tmp: Iir_Expression; + -- Example: When PRIO is Prio_Simple, a simple expression will be returned. + function Parse_Binary_Expression (Left : Iir; Prio : Prio_Type) return Iir + is + Res : Iir; + Expr : Iir; + Op : Iir_Kind; + Op_Prio : Prio_Type; + Op_Tok : Token_Type; begin - Res := Parse_Factor (Primary); - while Current_Token in Token_Multiplying_Operator_Type loop - case Current_Token is + Res := Left; + loop + Op_Tok := Current_Token; + case Op_Tok is when Tok_Star => - Tmp := Create_Iir (Iir_Kind_Multiplication_Operator); + Op := Iir_Kind_Multiplication_Operator; + Op_Prio := Prio_Term; when Tok_Slash => - Tmp := Create_Iir (Iir_Kind_Division_Operator); + Op := Iir_Kind_Division_Operator; + Op_Prio := Prio_Term; when Tok_Mod => - Tmp := Create_Iir (Iir_Kind_Modulus_Operator); + Op := Iir_Kind_Modulus_Operator; + Op_Prio := Prio_Term; when Tok_Rem => - Tmp := Create_Iir (Iir_Kind_Remainder_Operator); - when others => - raise Program_Error; - end case; - Set_Location (Tmp); - Set_Left (Tmp, Res); - Scan; - Set_Right (Tmp, Parse_Factor); - Res := Tmp; - end loop; - return Res; - end Parse_Term; + Op := Iir_Kind_Remainder_Operator; + Op_Prio := Prio_Term; - -- precond : next token - -- postcond: next token - -- - -- [ LRM93 7.1 ] - -- simple_expression ::= [ sign ] term { adding_operator term } - -- - -- [ LRM93 7.2 ] - -- sign ::= + | - - -- - -- [ LRM93 7.2 ] - -- adding_operator ::= + | - | & - function Parse_Simple_Expression (Primary : Iir := Null_Iir) - return Iir_Expression - is - Res, Tmp: Iir_Expression; - begin - if Current_Token in Token_Sign_Type - and then Primary = Null_Iir - then - case Current_Token is - when Tok_Plus => - Res := Create_Iir (Iir_Kind_Identity_Operator); - when Tok_Minus => - Res := Create_Iir (Iir_Kind_Negation_Operator); - when others => - raise Program_Error; - end case; - Set_Location (Res); - Scan; - Set_Operand (Res, Parse_Term (Null_Iir)); - else - Res := Parse_Term (Primary); - end if; - while Current_Token in Token_Adding_Operator_Type loop - case Current_Token is when Tok_Plus => - Tmp := Create_Iir (Iir_Kind_Addition_Operator); + Op := Iir_Kind_Addition_Operator; + Op_Prio := Prio_Simple; when Tok_Minus => - Tmp := Create_Iir (Iir_Kind_Substraction_Operator); + Op := Iir_Kind_Substraction_Operator; + Op_Prio := Prio_Simple; when Tok_Ampersand => - Tmp := Create_Iir (Iir_Kind_Concatenation_Operator); - when others => - raise Program_Error; - end case; - Set_Location (Tmp); - Scan; - Set_Left (Tmp, Res); - Set_Right (Tmp, Parse_Term (Null_Iir)); - Res := Tmp; - end loop; - return Res; - end Parse_Simple_Expression; - - -- precond : next token - -- postcond: next token - -- - -- [ LRM93 7.1 ] - -- shift_expression ::= - -- simple_expression [ shift_operator simple_expression ] - -- - -- [ LRM93 7.2 ] - -- shift_operator ::= SLL | SRL | SLA | SRA | ROL | ROR - function Parse_Shift_Expression return Iir_Expression is - Res, Tmp: Iir_Expression; - begin - Tmp := Parse_Simple_Expression; - if Current_Token not in Token_Shift_Operator_Type then - return Tmp; - elsif Flags.Vhdl_Std = Vhdl_87 then - Error_Msg_Parse ("shift operators not allowed in vhdl 87"); - end if; - case Current_Token is - when Tok_Sll => - Res := Create_Iir (Iir_Kind_Sll_Operator); - when Tok_Sla => - Res := Create_Iir (Iir_Kind_Sla_Operator); - when Tok_Srl => - Res := Create_Iir (Iir_Kind_Srl_Operator); - when Tok_Sra => - Res := Create_Iir (Iir_Kind_Sra_Operator); - when Tok_Rol => - Res := Create_Iir (Iir_Kind_Rol_Operator); - when Tok_Ror => - Res := Create_Iir (Iir_Kind_Ror_Operator); - when others => - raise Program_Error; - end case; - Set_Location (Res); - Scan; - Set_Left (Res, Tmp); - Set_Right (Res, Parse_Simple_Expression); - return Res; - end Parse_Shift_Expression; + Op := Iir_Kind_Concatenation_Operator; + Op_Prio := Prio_Simple; + + when Tok_Sll => + Op := Iir_Kind_Sll_Operator; + Op_Prio := Prio_Shift; + when Tok_Sla => + Op := Iir_Kind_Sla_Operator; + Op_Prio := Prio_Shift; + when Tok_Srl => + Op := Iir_Kind_Srl_Operator; + Op_Prio := Prio_Shift; + when Tok_Sra => + Op := Iir_Kind_Sra_Operator; + Op_Prio := Prio_Shift; + when Tok_Rol => + Op := Iir_Kind_Rol_Operator; + Op_Prio := Prio_Shift; + when Tok_Ror => + Op := Iir_Kind_Ror_Operator; + Op_Prio := Prio_Shift; - -- precond : next token (relational_operator) - -- postcond: next token - -- - -- [ LRM93 7.1 ] - -- relational_operator shift_expression - function Parse_Relation_Rhs (Left : Iir) return Iir - is - Res, Tmp: Iir_Expression; - begin - Tmp := Left; - - -- This loop is just to handle errors such as a = b = c. - loop - case Current_Token is when Tok_Equal => - Res := Create_Iir (Iir_Kind_Equality_Operator); + Op := Iir_Kind_Equality_Operator; + Op_Prio := Prio_Relation; when Tok_Not_Equal => - Res := Create_Iir (Iir_Kind_Inequality_Operator); + Op := Iir_Kind_Inequality_Operator; + Op_Prio := Prio_Relation; when Tok_Less => - Res := Create_Iir (Iir_Kind_Less_Than_Operator); + Op := Iir_Kind_Less_Than_Operator; + Op_Prio := Prio_Relation; when Tok_Less_Equal => - Res := Create_Iir (Iir_Kind_Less_Than_Or_Equal_Operator); + Op := Iir_Kind_Less_Than_Or_Equal_Operator; + Op_Prio := Prio_Relation; when Tok_Greater => - Res := Create_Iir (Iir_Kind_Greater_Than_Operator); + Op := Iir_Kind_Greater_Than_Operator; + Op_Prio := Prio_Relation; when Tok_Greater_Equal => - Res := Create_Iir (Iir_Kind_Greater_Than_Or_Equal_Operator); + Op := Iir_Kind_Greater_Than_Or_Equal_Operator; + Op_Prio := Prio_Relation; when Tok_Match_Equal => - Res := Create_Iir (Iir_Kind_Match_Equality_Operator); + Op := Iir_Kind_Match_Equality_Operator; + Op_Prio := Prio_Relation; when Tok_Match_Not_Equal => - Res := Create_Iir (Iir_Kind_Match_Inequality_Operator); + Op := Iir_Kind_Match_Inequality_Operator; + Op_Prio := Prio_Relation; when Tok_Match_Less => - Res := Create_Iir (Iir_Kind_Match_Less_Than_Operator); + Op := Iir_Kind_Match_Less_Than_Operator; + Op_Prio := Prio_Relation; when Tok_Match_Less_Equal => - Res := Create_Iir (Iir_Kind_Match_Less_Than_Or_Equal_Operator); + Op := Iir_Kind_Match_Less_Than_Or_Equal_Operator; + Op_Prio := Prio_Relation; when Tok_Match_Greater => - Res := Create_Iir (Iir_Kind_Match_Greater_Than_Operator); + Op := Iir_Kind_Match_Greater_Than_Operator; + Op_Prio := Prio_Relation; when Tok_Match_Greater_Equal => - Res := Create_Iir - (Iir_Kind_Match_Greater_Than_Or_Equal_Operator); - when others => - raise Program_Error; - end case; - Set_Location (Res); - Scan; - Set_Left (Res, Tmp); - Set_Right (Res, Parse_Shift_Expression); - exit when Current_Token not in Token_Relational_Operator_Type; - Error_Msg_Parse - ("use parenthesis for consecutive relational expressions"); - Tmp := Res; - end loop; - return Res; - end Parse_Relation_Rhs; - - -- precond : next token - -- postcond: next token - -- - -- [ LRM93 7.1 ] - -- relation ::= shift_expression [ relational_operator shift_expression ] - -- - -- [ LRM93 7.2 ] - -- relational_operator ::= = | /= | < | <= | > | >= - -- | ?= | ?/= | ?< | ?<= | ?> | ?>= - function Parse_Relation return Iir - is - Tmp: Iir; - begin - Tmp := Parse_Shift_Expression; - if Current_Token not in Token_Relational_Operator_Type then - return Tmp; - end if; - - return Parse_Relation_Rhs (Tmp); - end Parse_Relation; - - -- precond : next token - -- postcond: next token - -- - -- [ LRM93 7.1 ] - -- expression ::= relation { AND relation } - -- | relation { OR relation } - -- | relation { XOR relation } - -- | relation [ NAND relation } - -- | relation [ NOR relation } - -- | relation { XNOR relation } - function Parse_Expression_Rhs (Left : Iir) return Iir - is - Res, Tmp: Iir; + Op := Iir_Kind_Match_Greater_Than_Or_Equal_Operator; + Op_Prio := Prio_Relation; - -- OP_TOKEN contains the operator combinaison. - Op_Token: Token_Type; - begin - Tmp := Left; - Op_Token := Tok_Invalid; - loop - case Current_Token is when Tok_And => - Res := Create_Iir (Iir_Kind_And_Operator); + Op := Iir_Kind_And_Operator; + Op_Prio := Prio_Logical; when Tok_Or => - Res := Create_Iir (Iir_Kind_Or_Operator); + Op := Iir_Kind_Or_Operator; + Op_Prio := Prio_Logical; when Tok_Xor => - Res := Create_Iir (Iir_Kind_Xor_Operator); + Op := Iir_Kind_Xor_Operator; + Op_Prio := Prio_Logical; when Tok_Nand => - Res := Create_Iir (Iir_Kind_Nand_Operator); + Op := Iir_Kind_Nand_Operator; + Op_Prio := Prio_Logical; when Tok_Nor => - Res := Create_Iir (Iir_Kind_Nor_Operator); + Op := Iir_Kind_Nor_Operator; + Op_Prio := Prio_Logical; when Tok_Xnor => - if Flags.Vhdl_Std = Vhdl_87 then - Error_Msg_Parse ("'xnor' keyword not allowed in vhdl 87"); - end if; - Res := Create_Iir (Iir_Kind_Xnor_Operator); + Op := Iir_Kind_Xnor_Operator; + Op_Prio := Prio_Logical; + when others => - return Tmp; + return Res; end case; - if Op_Token = Tok_Invalid then - Op_Token := Current_Token; - else - -- Check after the case, since current_token may not be an - -- operator... - -- TODO: avoid repetition of this message ? - if Op_Token = Tok_Nand or Op_Token = Tok_Nor then - Error_Msg_Parse - ("sequence of 'nor' or 'nand' not allowed", Cont => True); - Error_Msg_Parse - ("('nor' and 'nand' are not associative)"); - end if; - if Op_Token /= Current_Token then - -- Expression is a sequence of relations, with the same - -- operator. - Error_Msg_Parse ("only one type of logical operators may be " - & "used to combine relation"); - end if; + -- If the OP_PRIO is less than PRIO, the binary operator will apply + -- to the whole expression. + -- eg: A * B + C + if Op_Prio < Prio then + return Res; end if; - Set_Location (Res); + Expr := Create_Iir (Op); + Set_Location (Expr); + Set_Left (Expr, Res); + + -- Skip operator. Scan; -- Catch errors for Ada programmers. @@ -5630,23 +5529,55 @@ package body Parse is Scan; end if; - Set_Left (Res, Tmp); - Set_Right (Res, Parse_Relation); - Tmp := Res; + if Op_Prio >= Prio_Simple and then Current_Token in Token_Sign_Type + then + Error_Msg_Parse ("'-'/'+' can only appear before the first term"); + end if; + + -- Left association: A + B + C is (A + B) + C + Set_Right (Expr, Parse_Expression (Prio_Type'Succ (Op_Prio))); + Res := Expr; + + -- Only one relational_operator or shift_operator. + if Op_Prio = Prio_Relation then + if Current_Token in Token_Relational_Operator_Type then + Error_Msg_Parse + ("use parenthesis for consecutive relational expressions"); + end if; + elsif Op_Prio = Prio_Shift then + -- Only one shift_operator. + if Current_Token in Token_Shift_Operator_Type then + Error_Msg_Parse + ("use parenthesis for consecutive shift expressions"); + end if; + elsif Op_Prio = Prio_Logical then + if Current_Token = Op_Tok then + if Op_Tok = Tok_Nand or Op_Tok = Tok_Nor then + Error_Msg_Parse + ("sequence of 'nor' or 'nand' not allowed", Cont => True); + Error_Msg_Parse + ("('nor' and 'nand' are not associative)"); + end if; + elsif Current_Token in Token_Logical_Type then + -- Expression is a sequence of relations, with the same + -- operator. + Error_Msg_Parse ("only one type of logical operators may be " + & "used to combine relation"); + end if; + end if; end loop; - end Parse_Expression_Rhs; + end Parse_Binary_Expression; - -- precond : next token - -- postcond: next token - -- - -- LRM08 9.1 General - -- expression ::= condition_operator primary - -- | logical_expression - function Parse_Expression return Iir_Expression + function Parse_Expression (Prio : Prio_Type := Prio_Expression) return Iir is + Left : Iir; Res : Iir; begin if Current_Token = Tok_Condition then + if Prio /= Prio_Expression then + Error_Msg_Parse + ("'??' must be the first operator of an expression"); + end if; Res := Create_Iir (Iir_Kind_Condition_Operator); Set_Location (Res); @@ -5655,7 +5586,8 @@ package body Parse is Set_Operand (Res, Parse_Primary); else - Res := Parse_Expression_Rhs (Parse_Relation); + Left := Parse_Unary_Expression; + Res := Parse_Binary_Expression (Left, Prio); end if; return Res; @@ -8084,20 +8016,21 @@ package body Parse is -- or a simple simultaneous statement if AMS_Vhdl then Res := Create_Iir (Iir_Kind_Simple_Simultaneous_Statement); - Set_Simultaneous_Left (Res, Parse_Simple_Expression (Target)); + Set_Simultaneous_Left + (Res, Parse_Binary_Expression (Target, Prio_Simple)); if Current_Token /= Tok_Equal_Equal then Error_Msg_Parse ("'==' expected after expression"); else Set_Location (Res); Scan; end if; - Set_Simultaneous_Right (Res, Parse_Simple_Expression); + Set_Simultaneous_Right (Res, Parse_Expression (Prio_Simple)); Set_Tolerance (Res, Parse_Tolerance_Aspect_Opt); Expect (Tok_Semi_Colon); return Res; else return Parse_Concurrent_Conditional_Signal_Assignment - (Parse_Simple_Expression (Target)); + (Parse_Binary_Expression (Target, Prio_Simple)); end if; end case; end Parse_Concurrent_Assignment; diff --git a/src/vhdl/parse.ads b/src/vhdl/parse.ads index 9a80d1e33..8204a2d0e 100644 --- a/src/vhdl/parse.ads +++ b/src/vhdl/parse.ads @@ -22,13 +22,21 @@ package Parse is -- If True, create nodes for parenthesis expressions. Flag_Parse_Parenthesis : Boolean := False; + type Prio_Type is + ( + Prio_Expression, + Prio_Logical, + Prio_Relation, + Prio_Shift, + Prio_Simple, + Prio_Term, + Prio_Factor + ); + -- Parse an expression. -- (Used by PSL). - function Parse_Expression return Iir; - function Parse_Expression_Rhs (Left : Iir) return Iir; - - -- Parse an relationnal operator and its rhs. - function Parse_Relation_Rhs (Left : Iir) return Iir; + function Parse_Expression (Prio : Prio_Type := Prio_Expression) return Iir; + function Parse_Binary_Expression (Left : Iir; Prio : Prio_Type) return Iir; -- Convert the STR (0 .. LEN - 1) into a operator symbol identifier. -- Emit an error message if the name is not an operator name. diff --git a/src/vhdl/parse_psl.adb b/src/vhdl/parse_psl.adb index 4c682ae3f..6a0e906e4 100644 --- a/src/vhdl/parse_psl.adb +++ b/src/vhdl/parse_psl.adb @@ -359,13 +359,26 @@ package body Parse_Psl is Error_Msg_Parse ("'(' expected around property"); return Parse_FL_Property (Prio_Lowest); else + -- Skip '('. Scan; + Res := Parse_FL_Property (Prio_Lowest); - if Current_Token /= Tok_Right_Paren then + if Current_Token = Tok_Right_Paren then + -- Skip ')'. + Scan; + else Error_Msg_Parse ("missing matching ')' for '(' at line " & Image (Loc, False)); - else - Scan; + end if; + + if Get_Kind (Res) = N_HDL_Expr then + declare + N : Iirs.Iir; + begin + N := Psl_To_Vhdl (Res); + N := Parse.Parse_Binary_Expression (N, Parse.Prio_Expression); + Res := Vhdl_To_Psl (N); + end; end if; return Res; end if; @@ -558,7 +571,8 @@ package body Parse_Psl is Res := Parse_Binary_FL_Property (N_And_Prop, Res, Prio_Seq_And); when Token_Relational_Operator_Type => return Vhdl_To_Psl - (Parse.Parse_Relation_Rhs (Psl_To_Vhdl (Res))); + (Parse.Parse_Binary_Expression + (Psl_To_Vhdl (Res), Parse.Prio_Relation)); when Tok_Colon | Tok_Bar | Tok_Ampersand diff --git a/src/vhdl/tokens.ads b/src/vhdl/tokens.ads index 42def9f3d..fc555ce71 100644 --- a/src/vhdl/tokens.ads +++ b/src/vhdl/tokens.ads @@ -106,13 +106,6 @@ package Tokens is Tok_Mod, -- mod Tok_Rem, -- rem - -- relation token: - Tok_And, - Tok_Or, - Tok_Xor, - Tok_Nand, - Tok_Nor, - -- miscellaneous operator Tok_Abs, Tok_Not, @@ -209,8 +202,17 @@ package Tokens is Tok_While, Tok_With, - -- Tokens below this line are key words in vhdl93 but not in vhdl87 + -- logical token: + Tok_And, + Tok_Or, + Tok_Xor, + Tok_Nand, + Tok_Nor, + + -- Tokens below this line are key words in vhdl93 but not in vhdl87 + -- Note: xnor is the first one, as it is a logical token. Tok_Xnor, + Tok_Group, Tok_Impure, Tok_Inertial, @@ -279,6 +281,9 @@ package Tokens is -- To ease interfacing pragma Convention (C, Token_Type); + subtype Token_Logical_Type is Token_Type range + Tok_And .. Tok_Xnor; + subtype Token_Relational_Operator_Type is Token_Type range Tok_Equal .. Tok_Match_Greater_Equal; subtype Token_Shift_Operator_Type is Token_Type range |