Add UINT16/32/64 array and DSC include support.
authorMa, Maurice <maurice.ma@intel.com>
Wed, 4 Mar 2015 01:03:20 +0000 (01:03 +0000)
committerjyao1 <jyao1@Edk2>
Wed, 4 Mar 2015 01:03:20 +0000 (01:03 +0000)
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: "Ma, Maurice" <maurice.ma@intel.com>
Reviewed-by: "Yao, Jiewen" <jiewen.yao@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17003 6f19259b-4bc3-4df7-8a09-765794883524

IntelFspPkg/Tools/GenCfgOpt.py

index 7e59801..6b850f6 100644 (file)
@@ -88,8 +88,206 @@ are permitted provided that the following conditions are met:
 **/\r
 """\r
 \r
+class CLogicalExpression:\r
+    def __init__(self):\r
+        self.index    = 0\r
+        self.string   = ''\r
+\r
+    def errExit(self, err = ''):\r
+        print "ERROR: Express parsing for:"\r
+        print "       %s" % self.string\r
+        print "       %s^" % (' ' * self.index)\r
+        if err:\r
+            print "INFO : %s" % err\r
+        raise SystemExit\r
+\r
+    def getNonNumber (self, n1, n2):\r
+        if not n1.isdigit():\r
+            return n1\r
+        if not n2.isdigit():\r
+            return n2\r
+        return None\r
+\r
+    def getCurr(self, lens = 1):\r
+        try:\r
+            if lens == -1:\r
+                return self.string[self.index :]\r
+            else:\r
+                if self.index + lens > len(self.string):\r
+                    lens = len(self.string) - self.index\r
+                return self.string[self.index : self.index + lens]\r
+        except Exception:\r
+            return ''\r
+\r
+    def isLast(self):\r
+        return self.index == len(self.string)\r
+\r
+    def moveNext(self, len = 1):\r
+        self.index += len\r
+\r
+    def skipSpace(self):\r
+        while not self.isLast():\r
+            if self.getCurr() in ' \t':\r
+                self.moveNext()\r
+            else:\r
+                return\r
+\r
+    def normNumber (self, val):\r
+        return True if val else False\r
+\r
+    def getNumber(self, var):\r
+        var = var.strip()\r
+        if   re.match('^0x[a-fA-F0-9]+$', var):\r
+            value = int(var, 16)\r
+        elif re.match('^[+-]?\d+$', var):\r
+            value = int(var, 10)\r
+        else:\r
+            value = None\r
+        return value\r
+\r
+    def parseValue(self):\r
+        self.skipSpace()\r
+        var = ''\r
+        while not self.isLast():\r
+            char = self.getCurr()\r
+            if re.match('^[\w.]', char):\r
+                var += char\r
+                self.moveNext()\r
+            else:\r
+                break\r
+        val = self.getNumber(var)\r
+        if val is None:\r
+            value = var\r
+        else:\r
+            value = "%d" % val\r
+        return value\r
+\r
+    def parseSingleOp(self):\r
+        self.skipSpace()\r
+        if re.match('^NOT\W', self.getCurr(-1)):\r
+            self.moveNext(3)\r
+            op  = self.parseBrace()\r
+            val = self.getNumber (op)\r
+            if val is None:\r
+                self.errExit ("'%s' is not a number" % op)\r
+            return "%d" % (not self.normNumber(int(op)))\r
+        else:\r
+            return self.parseValue()\r
+\r
+    def parseBrace(self):\r
+        self.skipSpace()\r
+        char = self.getCurr()\r
+        if char == '(':\r
+            self.moveNext()\r
+            value = self.parseExpr()\r
+            self.skipSpace()\r
+            if self.getCurr() != ')':\r
+                self.errExit ("Expecting closing brace or operator")\r
+            self.moveNext()\r
+            return value\r
+        else:\r
+            value = self.parseSingleOp()\r
+            return value\r
+\r
+    def parseCompare(self):\r
+        value = self.parseBrace()\r
+        while True:\r
+            self.skipSpace()\r
+            char = self.getCurr()\r
+            if char in ['<', '>']:\r
+                self.moveNext()\r
+                next = self.getCurr()\r
+                if next == '=':\r
+                    op = char + next\r
+                    self.moveNext()\r
+                else:\r
+                    op = char\r
+                result = self.parseBrace()\r
+                test = self.getNonNumber(result, value)\r
+                if test is None:\r
+                    value = "%d" % self.normNumber(eval (value + op + result))\r
+                else:\r
+                    self.errExit ("'%s' is not a valid number for comparision" % test)\r
+            elif char in ['=', '!']:\r
+                op = self.getCurr(2)\r
+                if op in ['==', '!=']:\r
+                    self.moveNext(2)\r
+                    result = self.parseBrace()\r
+                    test = self.getNonNumber(result, value)\r
+                    if test is None:\r
+                        value = "%d" % self.normNumber((eval (value + op + result)))\r
+                    else:\r
+                        value = "%d" % self.normNumber(eval ("'" + value + "'" + op + "'" + result + "'"))\r
+                else:\r
+                    break\r
+            else:\r
+                break\r
+        return value\r
+\r
+    def parseAnd(self):\r
+        value = self.parseCompare()\r
+        while True:\r
+            self.skipSpace()\r
+            if re.match('^AND\W', self.getCurr(-1)):\r
+                self.moveNext(3)\r
+                result = self.parseCompare()\r
+                test = self.getNonNumber(result, value)\r
+                if test is None:\r
+                    value = "%d" % self.normNumber(int(value) & int(result))\r
+                else:\r
+                    self.errExit ("'%s' is not a valid op number for AND" % test)\r
+            else:\r
+                break\r
+        return value\r
+\r
+    def parseOrXor(self):\r
+        value  = self.parseAnd()\r
+        op     = None\r
+        while True:\r
+            self.skipSpace()\r
+            op = None\r
+            if re.match('^XOR\W', self.getCurr(-1)):\r
+                self.moveNext(3)\r
+                op = '^'\r
+            elif re.match('^OR\W', self.getCurr(-1)):\r
+                self.moveNext(2)\r
+                op = '|'\r
+            else:\r
+                break\r
+            if op:\r
+                result = self.parseAnd()\r
+                test = self.getNonNumber(result, value)\r
+                if test is None:\r
+                    value = "%d" % self.normNumber(eval (value + op + result))\r
+                else:\r
+                    self.errExit ("'%s' is not a valid op number for XOR/OR" % test)\r
+        return value\r
+\r
+    def parseExpr(self):\r
+        return self.parseOrXor()\r
+\r
+    def getResult(self):\r
+        value = self.parseExpr()\r
+        self.skipSpace()\r
+        if not self.isLast():\r
+            self.errExit ("Unexpected character found '%s'" % self.getCurr())\r
+        test = self.getNumber(value)\r
+        if test is None:\r
+            self.errExit ("Result '%s' is not a number" % value)\r
+        return int(value)\r
+\r
+    def evaluateExpress (self, Expr):\r
+        self.index     = 0\r
+        self.string    = Expr\r
+        if self.getResult():\r
+            Result = True\r
+        else:\r
+            Result = False\r
+        return Result\r
+\r
 class CGenCfgOpt:\r
     def __init__(self):\r
+        self.Debug          = False\r
         self.Error          = ''\r
 \r
         self._GlobalDataDef = """\r
@@ -139,12 +337,71 @@ EndList
                     if Match:\r
                         self._MacroDict[Match.group(1)] = ''\r
         if len(self._MacroDict) == 0:\r
-            self.Error = "Invalid MACRO arguments"\r
             Error = 1\r
         else:\r
             Error = 0\r
+            if self.Debug:\r
+                print "INFO : Macro dictionary:"\r
+                for Each in self._MacroDict:\r
+                    print "       $(%s) = [ %s ]" % (Each , self._MacroDict[Each])\r
         return Error\r
 \r
+    def EvaulateIfdef   (self, Macro):\r
+        Result = Macro in self._MacroDict\r
+        if self.Debug:\r
+            print "INFO : Eval Ifdef [%s] : %s" % (Macro, Result)\r
+        return  Result\r
+\r
+    def ExpandMacros (self, Input):\r
+        Line = Input\r
+        Match = re.findall("\$\(\w+\)", Input)\r
+        if Match:\r
+            for Each in Match:\r
+              Variable = Each[2:-1]\r
+              if Variable in self._MacroDict:\r
+                  Line = Line.replace(Each, self._MacroDict[Variable])\r
+              else:\r
+                  if self.Debug:\r
+                      print "WARN : %s is not defined" % Each\r
+                  Line = Line.replace(Each, Each[2:-1])\r
+        return Line\r
+\r
+    def EvaluateExpress (self, Expr):\r
+        ExpExpr = self.ExpandMacros(Expr)\r
+        LogExpr = CLogicalExpression()\r
+        Result  = LogExpr.evaluateExpress (ExpExpr)\r
+        if self.Debug:\r
+            print "INFO : Eval Express [%s] : %s" % (Expr, Result)\r
+        return Result\r
+\r
+    def FormatListValue(self, ConfigDict):\r
+        Struct = ConfigDict['struct']\r
+        if Struct not in ['UINT8','UINT16','UINT32','UINT64']:\r
+            return\r
+\r
+        dataarray = []\r
+        binlist = ConfigDict['value'][1:-1].split(',')\r
+        for each in binlist:\r
+            each = each.strip()\r
+            if each.startswith('0x'):\r
+                value = int(each, 16)\r
+            else:\r
+                value = int(each)\r
+            dataarray.append(value)\r
+\r
+        unit = int(Struct[4:]) / 8\r
+        if int(ConfigDict['length']) != unit * len(dataarray):\r
+            raise Exception("Array size is not proper for '%s' !" % ConfigDict['cname'])\r
+\r
+        bytearray = []\r
+        for each in dataarray:\r
+            value = each\r
+            for loop in xrange(unit):\r
+                bytearray.append("0x%02X" % (value & 0xFF))\r
+                value = value >> 8\r
+        newvalue  = '{'  + ','.join(bytearray) + '}'\r
+        ConfigDict['value'] = newvalue\r
+        return ""\r
 \r
     def ParseDscFile (self, DscFile, FvDir):\r
         self._CfgItemList = []\r
@@ -158,20 +415,19 @@ EndList
         IsVpdSect       = False\r
         Found           = False\r
 \r
-        IfStack         = [True]\r
+        IfStack         = []\r
         ElifStack       = []\r
         Error           = 0\r
+        ConfigDict      = {}\r
 \r
         DscFd        = open(DscFile, "r")\r
         DscLines     = DscFd.readlines()\r
         DscFd.close()\r
 \r
-        ConfigDict      = {}\r
-\r
-        for DscLine in DscLines:\r
-            Handle     = False\r
-            DscLine = DscLine.strip()\r
-            Match = re.match("^\[(.+)\]", DscLine)\r
+        while len(DscLines):\r
+            DscLine  = DscLines.pop(0).strip()            \r
+            Handle   = False\r
+            Match    = re.match("^\[(.+)\]", DscLine)\r
             if Match is not None:\r
                 if  Match.group(1).lower() == "Defines".lower():\r
                     IsDefSect = True\r
@@ -210,66 +466,78 @@ EndList
                     IsVpdSect = False\r
             else:\r
                 if IsDefSect or IsUpdSect or IsVpdSect:\r
-                    if DscLine == "!else":\r
-                        IfStack[-1] = not IfStack[-1]\r
-                    elif DscLine == "!endif":\r
-                        IfStack.pop()\r
-                        Level = ElifStack.pop()\r
-                        while Level > 0:\r
+                    if re.match("^!else($|\s+#.+)", DscLine):\r
+                        if IfStack:\r
+                            IfStack[-1] = not IfStack[-1]\r
+                        else:\r
+                            print("ERROR: No paired '!if' found for '!else' for line '%s'" % DscLine)\r
+                            raise SystemExit\r
+                    elif re.match("^!endif($|\s+#.+)", DscLine):\r
+                        if IfStack:\r
                             IfStack.pop()\r
-                            Level = Level - 1\r
+                            Level = ElifStack.pop()\r
+                            if Level > 0:\r
+                                del IfStack[-Level:]\r
+                        else:\r
+                            print("ERROR: No paired '!if' found for '!endif' for line '%s'" % DscLine)\r
+                            raise SystemExit\r
                     else:\r
                         Result = False\r
-                        Match = re.match("!(ifdef|ifndef)\s+\$\((\w+)\)", DscLine)\r
-                        if Match is not None:\r
-                            if Match.group(2) in self._MacroDict:\r
-                                if Match.group(1) == 'ifdef':\r
-                                    Result = True\r
-                            else:\r
-                                if Match.group(1) == 'ifndef':\r
-                                    Result = True\r
-                            ElifStack.append(0)\r
+                        Match = re.match("!(ifdef|ifndef)\s+(.+)", DscLine)\r
+                        if Match:\r
+                            Result = self.EvaulateIfdef (Match.group(2))\r
+                            if Match.group(1) == 'ifndef':\r
+                                Result = not Result\r
                             IfStack.append(Result)\r
+                            ElifStack.append(0)\r
                         else:\r
-                            Match = re.match("!(if|elseif)\s+\$\\((\w+)\)\s*==\s*(\w+|\$\(\w+\))", DscLine)\r
-                            if Match is not None:\r
-                                if Match.group(2) in self._MacroDict:\r
-                                    MacroName = self._MacroDict[Match.group(2)]\r
-                                else:\r
-                                    MacroName = ''\r
-                                Value = Match.group(3)\r
-                                if Value.startswith('$'):\r
-                                    if Value[2:-1] in self._MacroDict:\r
-                                        Value = self._MacroDict[Value[2:-1]]\r
-                                    else:\r
-                                        Value = ''\r
-                                if MacroName == Value:\r
-                                    Result = True\r
+                            Match  = re.match("!(if|elseif)\s+(.+)", DscLine)\r
+                            if Match:\r
+                                Result = self.EvaluateExpress(Match.group(2))\r
                                 if Match.group(1) == "if":\r
                                     ElifStack.append(0)\r
                                     IfStack.append(Result)\r
                                 else:   #elseif\r
-                                    IfStack[-1] = not IfStack[-1]\r
-                                    IfStack.append(Result)\r
-                                    ElifStack[-1] = ElifStack[-1] + 1\r
+                                    if IfStack:\r
+                                        IfStack[-1] = not IfStack[-1]\r
+                                        IfStack.append(Result)\r
+                                        ElifStack[-1] = ElifStack[-1] + 1\r
+                                    else:\r
+                                        print("ERROR: No paired '!if' found for '!elif' for line '%s'" % DscLine)\r
+                                        raise SystemExit\r
                             else:\r
-                                if len(DscLine) > 0 and DscLine[0] == '!':\r
-                                    #\r
-                                    # Current it can only handle build switch.\r
-                                    # It does not support INF file in included dsc.\r
-                                    #\r
+                                if IfStack:\r
+                                    Handle = reduce(lambda x,y: x and y, IfStack)\r
                                 else:\r
-                                    if reduce(lambda x,y: x and y, IfStack):\r
-                                        Handle = True\r
-\r
+                                    Handle = True\r
+                                if Handle:\r
+                                    Match = re.match("!include\s+(.+)", DscLine)\r
+                                    if Match:\r
+                                        IncludeFilePath = Match.group(1)\r
+                                        IncludeFilePath = self.ExpandMacros(IncludeFilePath)\r
+                                        try:\r
+                                            IncludeDsc  = open(IncludeFilePath, "r")\r
+                                        except:\r
+                                            print("ERROR: Cannot open file '%s'" % IncludeFilePath)\r
+                                            raise SystemExit\r
+                                        NewDscLines = IncludeDsc.readlines()\r
+                                        IncludeDsc.close()\r
+                                        DscLines = NewDscLines + DscLines\r
+                                    else:\r
+                                        if DscLine.startswith('!'):\r
+                                            print("ERROR: Unrecoginized directive for line '%s'" % DscLine)\r
+                                            raise SystemExit\r
+                                        \r
             if not Handle:\r
                 continue\r
 \r
             if IsDefSect:\r
                 #DEFINE UPD_TOOL_GUID = 8C3D856A-9BE6-468E-850A-24F7A8D38E09\r
-                Match = re.match("^\s*(?:DEFINE\s+)*(\w+)\s*=\s*([-\w]+)", DscLine)\r
+                Match = re.match("^\s*(?:DEFINE\s+)*(\w+)\s*=\s*([-.\w]+)", DscLine)\r
                 if Match:\r
                     self._MacroDict[Match.group(1)] = Match.group(2)\r
+                    if self.Debug:\r
+                        print "INFO : DEFINE %s = [ %s ]" % (Match.group(1), Match.group(2))\r
             else:\r
                 Match = re.match("^\s*#\s+!(BSF|HDR)\s+(.+)", DscLine)\r
                 if Match:\r
@@ -338,7 +606,11 @@ EndList
                     if Match:\r
                         if Match.group(1) in self._MacroDict:\r
                             Value = self._MacroDict[Match.group(1)]\r
+\r
                     ConfigDict['value']  = Value\r
+                    if (len(Value) > 0)  and (Value[0] == '{'):\r
+                        Value = self.FormatListValue(ConfigDict)\r
+\r
                     if ConfigDict['name']  == '':\r
                         # Clear BSF specific items\r
                         ConfigDict['help']   = ''\r
@@ -502,26 +774,29 @@ EndList
         TxtFd.close()\r
         return 0\r
 \r
-    def CreateField (self, Name, Length, Offset, Struct):\r
+    def CreateField (self, Item, Name, Length, Offset, Struct):\r
         PosName    = 28\r
         PosComment = 30\r
 \r
         IsArray = False\r
-        if Length == 1:\r
-            Type = "UINT8"\r
-        elif Length == 2:\r
-            Type = "UINT16"\r
-        elif Length == 4:\r
-            Type = "UINT32"\r
-        elif Length == 8:\r
-            Type = "UINT64"\r
+        if Length in [1,2,4,8]:\r
+            Type = "UINT%d" % (Length * 8)\r
         else:\r
+            IsArray = True\r
+            Type = "UINT8"\r
+\r
+        if Item['value'].startswith('{'):\r
             Type = "UINT8"\r
             IsArray = True\r
 \r
         if Struct != '':\r
-            IsArray = False\r
             Type = Struct\r
+            if Struct in ['UINT8','UINT16','UINT32','UINT64']:\r
+                IsArray = True\r
+                Unit = int(Type[4:]) / 8\r
+                Length = Length / Unit\r
+            else:\r
+                IsArray = False\r
 \r
         if IsArray:\r
             Name = Name + '[%d]' % Length\r
@@ -644,12 +919,12 @@ EndList
                         NextVisible = True\r
                         Name = "Reserved" + Region[0] + "pdSpace%d" % ResvIdx\r
                         ResvIdx = ResvIdx + 1\r
-                        HeaderFd.write(self.CreateField (Name, Item["offset"] - ResvOffset, ResvOffset, ''))\r
+                        HeaderFd.write(self.CreateField (Item, Name, Item["offset"] - ResvOffset, ResvOffset, ''))\r
 \r
                 if  Offset < Item["offset"]:\r
                     if IsInternal or LastVisible:\r
                         Name = "Unused" + Region[0] + "pdSpace%d" % SpaceIdx\r
-                        LineBuffer.append(self.CreateField (Name, Item["offset"] - Offset, Offset, ''))\r
+                        LineBuffer.append(self.CreateField (Item, Name, Item["offset"] - Offset, Offset, ''))\r
                     SpaceIdx = SpaceIdx + 1\r
                     Offset   = Item["offset"]\r
 \r
@@ -665,7 +940,7 @@ EndList
                     for Each in LineBuffer:\r
                         HeaderFd.write (Each)\r
                     LineBuffer = []\r
-                    HeaderFd.write(self.CreateField (Item["cname"], Item["length"], Item["offset"], Item['struct']))\r
+                    HeaderFd.write(self.CreateField (Item, Item["cname"], Item["length"], Item["offset"], Item['struct']))\r
 \r
             HeaderFd.write("} " + Region[0] + "PD_DATA_REGION;\n\n")\r
         HeaderFd.write("#pragma pack()\n\n")\r
@@ -846,7 +1121,6 @@ def Main():
             print "ERROR: %s !" % GenCfgOpt.Error\r
             return 5\r
 \r
-\r
         if GenCfgOpt.UpdateVpdSizeField() != 0:\r
             print "ERROR: %s !" % GenCfgOpt.Error\r
             return 6\r