From afa72384251e121988501ac22f16d0110bd2305f Mon Sep 17 00:00:00 2001
From: Tristan Gingold <tgingold@free.fr>
Date: Sat, 4 Aug 2018 06:59:25 +0200
Subject: rework parse_expression to add parse_binary_expression.

This is needed to complete PSL expression parsing.
---
 src/ghdldrv/ghdlprint.adb |  14 +-
 src/std_names.adb         |  12 +-
 src/std_names.ads         | 203 +++++++++---------
 src/vhdl/disp_vhdl.adb    |   1 +
 src/vhdl/parse.adb        | 513 ++++++++++++++++++++--------------------------
 src/vhdl/parse.ads        |  18 +-
 src/vhdl/parse_psl.adb    |  22 +-
 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
-- 
cgit v1.2.3