]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/Python/UPT/Library/ExpressionValidate.py
BaseTools: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / BaseTools / Source / Python / UPT / Library / ExpressionValidate.py
index 91041c7a64dcc34473131616f9e2b4e75ea93b18..7718ca12e5cf7b22e63cc6fab089fad6ca22c4bb 100644 (file)
@@ -1,19 +1,14 @@
 ## @file\r
 # This file is used to check PCD logical expression\r
 #\r
-# Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
 #\r
-# This program and the accompanying materials are licensed and made available \r
-# under the terms and conditions of the BSD License which accompanies this \r
-# distribution. The full text of the license may be found at \r
-# http://opensource.org/licenses/bsd-license.php\r
-#\r
-# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 '''\r
 ExpressionValidate\r
 '''\r
+from __future__ import print_function\r
 \r
 ##\r
 # Import Modules\r
@@ -46,7 +41,7 @@ def IsValidBareCString(String):
                 and (IntChar < 0x23 or IntChar > 0x7e):\r
                 return False\r
         PreChar = Char\r
-    \r
+\r
     # Last char cannot be \ if PreChar is not \\r
     if LastChar == '\\' and PreChar == LastChar:\r
         return False\r
@@ -82,7 +77,7 @@ class _ExprBase:
         self.Token = Token\r
         self.Index = 0\r
         self.Len = len(Token)\r
-    \r
+\r
     ## SkipWhitespace\r
     #\r
     def SkipWhitespace(self):\r
@@ -90,14 +85,14 @@ class _ExprBase:
             if Char not in ' \t':\r
                 break\r
             self.Index += 1\r
-    \r
+\r
     ## IsCurrentOp\r
     #\r
-    # @param      OpList:   option list 
-    #    \r
+    # @param      OpList:   option list\r
+    #\r
     def IsCurrentOp(self, OpList):\r
         self.SkipWhitespace()\r
-        LetterOp = ["EQ", "NE", "GE", "LE", "GT", "LT", "NOT", "and", "AND", \r
+        LetterOp = ["EQ", "NE", "GE", "LE", "GT", "LT", "NOT", "and", "AND",\r
                     "or", "OR", "XOR"]\r
         OpMap = {\r
             '|' : '|',\r
@@ -106,43 +101,48 @@ class _ExprBase:
             '>' : '=',\r
             '<' : '='\r
         }\r
+\r
         for Operator in OpList:\r
             if not self.Token[self.Index:].startswith(Operator):\r
                 continue\r
+\r
             self.Index += len(Operator)\r
             Char = self.Token[self.Index : self.Index + 1]\r
+\r
             if (Operator in LetterOp and (Char == '_' or Char.isalnum())) \\r
                 or (Operator in OpMap and OpMap[Operator] == Char):\r
                 self.Index -= len(Operator)\r
                 break\r
+\r
             return True\r
+\r
         return False\r
 \r
 ## _LogicalExpressionParser\r
 #\r
 # @param      _ExprBase:   _ExprBase object\r
-#    \r
+#\r
 class _LogicalExpressionParser(_ExprBase):\r
     #\r
     # STRINGITEM can only be logical field according to spec\r
     #\r
     STRINGITEM = -1\r
-    \r
+\r
     #\r
     # Evaluate to True or False\r
     #\r
     LOGICAL = 0\r
     REALLOGICAL = 2\r
-    \r
+\r
     #\r
     # Just arithmetic expression\r
     #\r
     ARITH = 1\r
-    \r
+\r
     def __init__(self, Token):\r
         _ExprBase.__init__(self, Token)\r
         self.Parens = 0\r
-    \r
+\r
     def _CheckToken(self, MatchList):\r
         for Match in MatchList:\r
             if Match and Match.start() == 0:\r
@@ -150,7 +150,7 @@ class _LogicalExpressionParser(_ExprBase):
                             self.Token[self.Index:self.Index+Match.end()]\r
                         ):\r
                     return False\r
-                \r
+\r
                 self.Index += Match.end()\r
                 if self.Token[self.Index - 1] == '"':\r
                     return True\r
@@ -158,99 +158,100 @@ class _LogicalExpressionParser(_ExprBase):
                     self.Token[self.Index:self.Index+1].isalnum():\r
                     self.Index -= Match.end()\r
                     return False\r
-                \r
+\r
                 Token = self.Token[self.Index - Match.end():self.Index]\r
                 if Token.strip() in ["EQ", "NE", "GE", "LE", "GT", "LT",\r
                     "NOT", "and", "AND", "or", "OR", "XOR"]:\r
                     self.Index -= Match.end()\r
                     return False\r
-                \r
+\r
                 return True\r
+\r
         return False\r
-    \r
+\r
     def IsAtomicNumVal(self):\r
         #\r
         # Hex number\r
         #\r
         Match1 = re.compile(self.HEX_PATTERN).match(self.Token[self.Index:])\r
-        \r
+\r
         #\r
         # Number\r
         #\r
         Match2 = re.compile(self.INT_PATTERN).match(self.Token[self.Index:])\r
-        \r
+\r
         #\r
         # Macro\r
         #\r
         Match3 = re.compile(self.MACRO_PATTERN).match(self.Token[self.Index:])\r
-        \r
+\r
         #\r
         # PcdName\r
         #\r
         Match4 = re.compile(self.PCD_PATTERN).match(self.Token[self.Index:])\r
-        \r
+\r
         return self._CheckToken([Match1, Match2, Match3, Match4])\r
-    \r
+\r
 \r
     def IsAtomicItem(self):\r
         #\r
         # Macro\r
         #\r
         Match1 = re.compile(self.MACRO_PATTERN).match(self.Token[self.Index:])\r
-        \r
+\r
         #\r
         # PcdName\r
         #\r
         Match2 = re.compile(self.PCD_PATTERN).match(self.Token[self.Index:])\r
-        \r
+\r
         #\r
         # Quoted string\r
         #\r
         Match3 = re.compile(self.QUOTED_PATTERN).\\r
             match(self.Token[self.Index:].replace('\\\\', '//').\\r
                   replace('\\\"', '\\\''))\r
-        \r
+\r
         return self._CheckToken([Match1, Match2, Match3])\r
-    \r
+\r
     ## A || B\r
     #\r
     def LogicalExpression(self):\r
         Ret = self.SpecNot()\r
-        while self.IsCurrentOp(['||', 'OR', 'or', '&&', 'AND', 'and', 'XOR']):\r
+        while self.IsCurrentOp(['||', 'OR', 'or', '&&', 'AND', 'and', 'XOR', 'xor', '^']):\r
             if self.Token[self.Index-1] == '|' and self.Parens <= 0:\r
-                raise  _ExprError(ST.ERR_EXPR_OR)\r
-            if Ret == self.ARITH:\r
+                raise  _ExprError(ST.ERR_EXPR_OR % self.Token)\r
+            if Ret not in [self.ARITH, self.LOGICAL, self.REALLOGICAL, self.STRINGITEM]:\r
                 raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token)\r
             Ret = self.SpecNot()\r
-            if Ret == self.ARITH:\r
+            if Ret not in [self.ARITH, self.LOGICAL, self.REALLOGICAL, self.STRINGITEM]:\r
                 raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token)\r
             Ret = self.REALLOGICAL\r
         return Ret\r
-    \r
+\r
     def SpecNot(self):\r
-        if self.IsCurrentOp(["NOT", "!"]):\r
+        if self.IsCurrentOp(["NOT", "!", "not"]):\r
             return self.SpecNot()\r
         return self.Rel()\r
-    \r
-    ## A < B, A > B, A <= B, A >= b\r
+\r
+    ## A < B, A > B, A <= B, A >= B\r
     #\r
     def Rel(self):\r
         Ret = self.Expr()\r
         if self.IsCurrentOp(["<=", ">=", ">", "<", "GT", "LT", "GE", "LE",\r
                              "==", "EQ", "!=", "NE"]):\r
-            if Ret == self.STRINGITEM or Ret == self.REALLOGICAL:\r
+            if Ret == self.STRINGITEM:\r
                 raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token)\r
             Ret = self.Expr()\r
-            if Ret == self.STRINGITEM or Ret == self.REALLOGICAL:\r
+            if Ret == self.REALLOGICAL:\r
                 raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token)\r
             Ret = self.REALLOGICAL\r
         return Ret\r
-    \r
+\r
     ## A + B, A - B\r
     #\r
     def Expr(self):\r
         Ret = self.Factor()\r
-        while self.IsCurrentOp(["+", "-", "&", "|", "^"]):\r
+        while self.IsCurrentOp(["+", "-", "&", "|", "^", "XOR", "xor"]):\r
             if self.Token[self.Index-1] == '|' and self.Parens <= 0:\r
                 raise  _ExprError(ST.ERR_EXPR_OR)\r
             if Ret == self.STRINGITEM or Ret == self.REALLOGICAL:\r
@@ -262,7 +263,7 @@ class _LogicalExpressionParser(_ExprBase):
         return Ret\r
 \r
     ## Factor\r
-    #    \r
+    #\r
     def Factor(self):\r
         if self.IsCurrentOp(["("]):\r
             self.Parens += 1\r
@@ -272,7 +273,7 @@ class _LogicalExpressionParser(_ExprBase):
                                  (self.Token, self.Token[self.Index:]))\r
             self.Parens -= 1\r
             return Ret\r
-        \r
+\r
         if self.IsAtomicItem():\r
             if self.Token[self.Index - 1] == '"':\r
                 return self.STRINGITEM\r
@@ -281,17 +282,17 @@ class _LogicalExpressionParser(_ExprBase):
             return self.ARITH\r
         else:\r
             raise _ExprError(ST.ERR_EXPR_FACTOR % \\r
-                             (self.Token, self.Token[self.Index:]))\r
-            \r
+                             (self.Token[self.Index:], self.Token))\r
+\r
     ## IsValidLogicalExpression\r
     #\r
     def IsValidLogicalExpression(self):\r
         if self.Len == 0:\r
-            return False, ST.ERR_EXPR_EMPTY\r
+            return False, ST.ERR_EXPRESS_EMPTY\r
         try:\r
-            if self.LogicalExpression() == self.ARITH:\r
+            if self.LogicalExpression() not in [self.ARITH, self.LOGICAL, self.REALLOGICAL, self.STRINGITEM]:\r
                 return False, ST.ERR_EXPR_LOGICAL % self.Token\r
-        except _ExprError, XExcept:\r
+        except _ExprError as XExcept:\r
             return False, XExcept.Error\r
         self.SkipWhitespace()\r
         if self.Index != self.Len:\r
@@ -307,55 +308,84 @@ class _ValidRangeExpressionParser(_ExprBase):
         '[\t\s]*0[xX][a-fA-F0-9]+[\t\s]*-[\t\s]*0[xX][a-fA-F0-9]+'\r
     def __init__(self, Token):\r
         _ExprBase.__init__(self, Token)\r
-    \r
+        self.Parens = 0\r
+        self.HEX = 1\r
+        self.INT = 2\r
+        self.IsParenHappen = False\r
+        self.IsLogicalOpHappen = False\r
+\r
     ## IsValidRangeExpression\r
     #\r
     def IsValidRangeExpression(self):\r
         if self.Len == 0:\r
-            return False\r
+            return False, ST.ERR_EXPR_RANGE_EMPTY\r
         try:\r
-            self.RangeExpression()\r
-        except _ExprError:\r
-            return False\r
+            if self.RangeExpression() not in [self.HEX, self.INT]:\r
+                return False, ST.ERR_EXPR_RANGE % self.Token\r
+        except _ExprError as XExcept:\r
+            return False, XExcept.Error\r
+\r
         self.SkipWhitespace()\r
         if self.Index != self.Len:\r
-            return False\r
-        return True\r
-    \r
+            return False, (ST.ERR_EXPR_RANGE % self.Token)\r
+        return True, ''\r
+\r
     ## RangeExpression\r
     #\r
     def RangeExpression(self):\r
-        self.Unary()\r
-        while self.IsCurrentOp(['OR', 'AND', 'XOR']):\r
-            self.Unary()\r
-    \r
+        Ret = self.Unary()\r
+        while self.IsCurrentOp(['OR', 'AND', 'and', 'or']):\r
+            self.IsLogicalOpHappen = True\r
+            if not self.IsParenHappen:\r
+                raise _ExprError(ST.ERR_PAREN_NOT_USED % self.Token)\r
+            self.IsParenHappen = False\r
+            Ret = self.Unary()\r
+\r
+        if self.IsCurrentOp(['XOR']):\r
+            Ret = self.Unary()\r
+\r
+        return Ret\r
+\r
     ## Unary\r
     #\r
     def Unary(self):\r
-        if self.IsCurrentOp(["NOT", "-"]):\r
+        if self.IsCurrentOp(["NOT"]):\r
             return self.Unary()\r
+\r
         return self.ValidRange()\r
-    \r
+\r
     ## ValidRange\r
-    #    \r
+    #\r
     def ValidRange(self):\r
+        Ret = -1\r
         if self.IsCurrentOp(["("]):\r
-            self.RangeExpression()\r
+            self.IsLogicalOpHappen = False\r
+            self.IsParenHappen = True\r
+            self.Parens += 1\r
+            if self.Parens > 1:\r
+                raise _ExprError(ST.ERR_EXPR_RANGE_DOUBLE_PAREN_NESTED % self.Token)\r
+            Ret = self.RangeExpression()\r
             if not self.IsCurrentOp([")"]):\r
-                raise _ExprError('')\r
-            return\r
-        \r
-        if self.IsCurrentOp(["LT", "GT", "LE", "GE", "EQ"]):\r
+                raise _ExprError(ST.ERR_EXPR_RIGHT_PAREN % self.Token)\r
+            self.Parens -= 1\r
+            return Ret\r
+\r
+        if self.IsLogicalOpHappen:\r
+            raise _ExprError(ST.ERR_PAREN_NOT_USED % self.Token)\r
+\r
+        if self.IsCurrentOp(["LT", "GT", "LE", "GE", "EQ", "XOR"]):\r
             IntMatch = \\r
                 re.compile(self.INT_PATTERN).match(self.Token[self.Index:])\r
             HexMatch = \\r
                 re.compile(self.HEX_PATTERN).match(self.Token[self.Index:])\r
             if HexMatch and HexMatch.start() == 0:\r
                 self.Index += HexMatch.end()\r
+                Ret = self.HEX\r
             elif IntMatch and IntMatch.start() == 0:\r
                 self.Index += IntMatch.end()\r
+                Ret = self.INT\r
             else:\r
-                raise _ExprError('')\r
+                raise _ExprError(ST.ERR_EXPR_RANGE_FACTOR % (self.Token[self.Index:], self.Token))\r
         else:\r
             IntRangeMatch = re.compile(\r
                 self.INT_RANGE_PATTERN).match(self.Token[self.Index:]\r
@@ -365,14 +395,49 @@ class _ValidRangeExpressionParser(_ExprBase):
             )\r
             if HexRangeMatch and HexRangeMatch.start() == 0:\r
                 self.Index += HexRangeMatch.end()\r
+                Ret = self.HEX\r
             elif IntRangeMatch and IntRangeMatch.start() == 0:\r
                 self.Index += IntRangeMatch.end()\r
+                Ret = self.INT\r
             else:\r
-                raise _ExprError('')\r
-        \r
-        if self.Token[self.Index:self.Index+1] == '_' or \\r
-            self.Token[self.Index:self.Index+1].isalnum():\r
-            raise _ExprError('')\r
+                raise _ExprError(ST.ERR_EXPR_RANGE % self.Token)\r
+\r
+        return Ret\r
+\r
+## _ValidListExpressionParser\r
+#\r
+class _ValidListExpressionParser(_ExprBase):\r
+    VALID_LIST_PATTERN = '(0[xX][0-9a-fA-F]+|[0-9]+)([\t\s]*,[\t\s]*(0[xX][0-9a-fA-F]+|[0-9]+))*'\r
+    def __init__(self, Token):\r
+        _ExprBase.__init__(self, Token)\r
+        self.NUM = 1\r
+\r
+    def IsValidListExpression(self):\r
+        if self.Len == 0:\r
+            return False, ST.ERR_EXPR_LIST_EMPTY\r
+        try:\r
+            if self.ListExpression() not in [self.NUM]:\r
+                return False, ST.ERR_EXPR_LIST % self.Token\r
+        except _ExprError as XExcept:\r
+            return False, XExcept.Error\r
+\r
+        self.SkipWhitespace()\r
+        if self.Index != self.Len:\r
+            return False, (ST.ERR_EXPR_LIST % self.Token)\r
+\r
+        return True, ''\r
+\r
+    def ListExpression(self):\r
+        Ret = -1\r
+        self.SkipWhitespace()\r
+        ListMatch = re.compile(self.VALID_LIST_PATTERN).match(self.Token[self.Index:])\r
+        if ListMatch and ListMatch.start() == 0:\r
+            self.Index += ListMatch.end()\r
+            Ret = self.NUM\r
+        else:\r
+            raise _ExprError(ST.ERR_EXPR_LIST % self.Token)\r
+\r
+        return Ret\r
 \r
 ## _StringTestParser\r
 #\r
@@ -381,18 +446,18 @@ class _StringTestParser(_ExprBase):
         _ExprBase.__init__(self, Token)\r
 \r
     ## IsValidStringTest\r
-    #        \r
+    #\r
     def IsValidStringTest(self):\r
         if self.Len == 0:\r
             return False, ST.ERR_EXPR_EMPTY\r
         try:\r
             self.StringTest()\r
-        except _ExprError, XExcept:\r
+        except _ExprError as XExcept:\r
             return False, XExcept.Error\r
         return True, ''\r
 \r
     ## StringItem\r
-    #        \r
+    #\r
     def StringItem(self):\r
         Match1 = re.compile(self.QUOTED_PATTERN)\\r
             .match(self.Token[self.Index:].replace('\\\\', '//')\\r
@@ -418,42 +483,43 @@ class _StringTestParser(_ExprBase):
                              (self.Token, self.Token[self.Index:]))\r
 \r
     ## StringTest\r
-    #        \r
+    #\r
     def StringTest(self):\r
         self.StringItem()\r
         if not self.IsCurrentOp(["==", "EQ", "!=", "NE"]):\r
             raise _ExprError(ST.ERR_EXPR_EQUALITY % \\r
-                             (self.Token, self.Token[self.Index:]))\r
+                             (self.Token[self.Index:], self.Token))\r
         self.StringItem()\r
         if self.Index != self.Len:\r
             raise _ExprError(ST.ERR_EXPR_BOOLEAN % \\r
                              (self.Token[self.Index:], self.Token))\r
 \r
 ##\r
-# Check syntax of logical expression\r
+# Check syntax of string test\r
 #\r
-# @param Token: expression token\r
+# @param Token: string test token\r
 #\r
-def IsValidLogicalExpr(Token, Flag=False):\r
+def IsValidStringTest(Token, Flag=False):\r
     #\r
     # Not do the check right now, keep the implementation for future enhancement.\r
     #\r
     if not Flag:\r
         return True, ""\r
-    return _LogicalExpressionParser(Token).IsValidLogicalExpression()\r
+    return _StringTestParser(Token).IsValidStringTest()\r
+\r
 \r
 ##\r
-# Check syntax of string test\r
+# Check syntax of logical expression\r
 #\r
-# @param Token: string test token\r
+# @param Token: expression token\r
 #\r
-def IsValidStringTest(Token, Flag=False):\r
+def IsValidLogicalExpr(Token, Flag=False):\r
     #\r
     # Not do the check right now, keep the implementation for future enhancement.\r
     #\r
     if not Flag:\r
         return True, ""\r
-    return _StringTestParser(Token).IsValidStringTest()\r
+    return _LogicalExpressionParser(Token).IsValidLogicalExpression()\r
 \r
 ##\r
 # Check syntax of range expression\r
@@ -463,6 +529,14 @@ def IsValidStringTest(Token, Flag=False):
 def IsValidRangeExpr(Token):\r
     return _ValidRangeExpressionParser(Token).IsValidRangeExpression()\r
 \r
+##\r
+# Check syntax of value list expression token\r
+#\r
+# @param Token: value list expression token\r
+#\r
+def IsValidListExpr(Token):\r
+    return _ValidListExpressionParser(Token).IsValidListExpression()\r
+\r
 ##\r
 # Check whether the feature flag expression is valid or not\r
 #\r
@@ -482,8 +556,12 @@ def IsValidFeatureFlagExp(Token, Flag=False):
         if not Valid:\r
             Valid, Cause = IsValidLogicalExpr(Token, Flag)\r
         if not Valid:\r
-            return False, Cause   \r
+            return False, Cause\r
         return True, ""\r
 \r
 if __name__ == '__main__':\r
-    print _LogicalExpressionParser('a ^ b > a + b').IsValidLogicalExpression()\r
+#    print IsValidRangeExpr('LT 9')\r
+    print(_LogicalExpressionParser('gCrownBayTokenSpaceGuid.PcdPciDevice1BridgeAddressLE0').IsValidLogicalExpression())\r
+\r
+\r
+\r