Topics

[EXTERNAL] [edk2-devel] [PATCH 1/1] BaseTools/Ecc: Update structpcd parsing method.


Bret Barkelew
 

What does “update” mean in this context? What behavior is changing?

 

- Bret

 

From: Yuwei Chen via groups.io
Sent: Thursday, April 1, 2021 12:04 AM
To: devel@edk2.groups.io
Cc: mliang2x; Feng, Bob C; Liming Gao
Subject: [EXTERNAL] [edk2-devel] [PATCH 1/1] BaseTools/Ecc: Update structpcd parsing method.

 

From: mliang2x <mingyuex.liang@...>

Update the pcdparser method in Dec and DSC files.

Signed-off-by: Mingyue Liang <mingyuex.liang@...>
Cc: Bob Feng <bob.c.feng@...>
Cc: Liming Gao <gaoliming@...>
Cc: Yuwei Chen <yuwei.chen@...>
---
 .../Ecc/MetaFileWorkspace/MetaFileParser.py   | 464 ++++++++++--------
 1 file changed, 265 insertions(+), 199 deletions(-)

diff --git a/BaseTools/Source/Python/Ecc/MetaFileWorkspace/MetaFileParser.py b/BaseTools/Source/Python/Ecc/MetaFileWorkspace/MetaFileParser.py
index 9c27c8e16a05..588d3dbe6ed5 100644
--- a/BaseTools/Source/Python/Ecc/MetaFileWorkspace/MetaFileParser.py
+++ b/BaseTools/Source/Python/Ecc/MetaFileWorkspace/MetaFileParser.py
@@ -22,7 +22,7 @@ import Ecc.EccToolError as EccToolError
 from CommonDataClass.DataClass import *
 from Common.DataType import *
 from Common.StringUtils import *
-from Common.Misc import GuidStructureStringToGuidString, CheckPcdDatum, PathClass, AnalyzePcdData
+from Common.Misc import GuidStructureStringToGuidString, CheckPcdDatum, PathClass, AnalyzePcdData, AnalyzeDscPcd, AnalyzePcdExpression, ParseFieldValue, StructPattern
 from Common.Expression import *
 from CommonDataClass.Exceptions import *
 
@@ -31,6 +31,8 @@ from GenFds.FdfParser import FdfParser
 from Common.LongFilePathSupport import OpenLongFilePath as open
 from Common.LongFilePathSupport import CodecOpenLongFilePath
 
+CODEPattern = re.compile(r"{CODE\([a-fA-F0-9Xx\{\},\s]*\)}")
+
 ## A decorator used to parse macro definition
 def ParseMacro(Parser):
     def MacroParser(self):
@@ -174,6 +176,11 @@ class MetaFileParser(object):
         # UNI object and extra UNI object
         self._UniObj = None
         self._UniExtraObj = None
+        # StructPcd var
+        self._PcdCodeValue = ""
+        self._PcdDataTypeCODE = False
+        self._CurrentPcdName = ""
+        self._GuidDict = {}  # for Parser PCD value {GUID(gTokeSpaceGuidName)}
 
     ## Store the parsed data in table
     def _Store(self, *Args):
@@ -395,6 +402,40 @@ class MetaFileParser(object):
                 Macros.update(self._SectionsMacroDict[(self._SectionType, Scope1, Scope2)])
         return Macros
 
+    def ProcessMultipleLineCODEValue(self, Content):
+        CODEBegin = False
+        CODELine = ""
+        continuelinecount = 0
+        newContent = []
+        for Index in range(0, len(Content)):
+            Line = Content[Index]
+            if CODEBegin:
+                CODELine = CODELine + Line
+                continuelinecount +=1
+                if ")}" in Line:
+                    newContent.append(CODELine)
+                    for _ in range(continuelinecount):
+                        newContent.append("")
+                    CODEBegin = False
+                    CODELine = ""
+                    continuelinecount = 0
+            else:
+                if not Line:
+                    newContent.append(Line)
+                    continue
+                if "{CODE(" not in Line:
+                    newContent.append(Line)
+                    continue
+                elif CODEPattern.findall(Line):
+                    newContent.append(Line)
+                    continue
+                else:
+                    CODEBegin = True
+                    CODELine = Line
+
+        return newContent
+
+
     _SectionParser  = {}
     Finished        = property(_GetFinished, _SetFinished)
     _Macros         = property(_GetMacros)
@@ -812,6 +853,8 @@ class DscParser(MetaFileParser):
             Content = open(str(self.MetaFile.Path), 'r').readlines()
         except:
             EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
+
+        Content = self.ProcessMultipleLineCODEValue(Content)
         #
         # Insert a record for file
         #
@@ -1018,24 +1061,71 @@ class DscParser(MetaFileParser):
     #
     @ParseMacro
     def _PcdParser(self):
+        if self._PcdDataTypeCODE:
+            self._PcdCodeValue = self._PcdCodeValue + "\n " + self._CurrentLine
+            if self._CurrentLine.endswith(")}"):
+                self._CurrentLine = "|".join((self._CurrentPcdName, self._PcdCodeValue))
+                self._PcdDataTypeCODE = False
+                self._PcdCodeValue = ""
+            else:
+                self._ValueList = None
+                return
         TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
+        self._CurrentPcdName = TokenList[0]
+        if len(TokenList) == 2 and TokenList[1].strip().startswith("{CODE"):
+            self._PcdDataTypeCODE = True
+            self._PcdCodeValue = TokenList[1].strip()
+
+        if self._PcdDataTypeCODE:
+            if self._CurrentLine.endswith(")}"):
+                self._PcdDataTypeCODE = False
+                self._PcdCodeValue = ""
+            else:
+                self._ValueList = None
+                return
         self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
+        PcdNameTockens = GetSplitValueList(TokenList[0], TAB_SPLIT)
+        if len(PcdNameTockens) == 2:
+            self._ValueList[0], self._ValueList[1] = PcdNameTockens[0], PcdNameTockens[1]
+        elif len(PcdNameTockens) == 3:
+            self._ValueList[0], self._ValueList[1] = ".".join((PcdNameTockens[0], PcdNameTockens[1])), PcdNameTockens[2]
+        elif len(PcdNameTockens) > 3:
+            self._ValueList[0], self._ValueList[1] = ".".join((PcdNameTockens[0], PcdNameTockens[1])), ".".join(PcdNameTockens[2:])
         if len(TokenList) == 2:
             self._ValueList[2] = TokenList[1]
         if self._ValueList[0] == '' or self._ValueList[1] == '':
             EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
                             ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<TokenCName>|<PcdValue>)",
-                            File=self.MetaFile, Line=self._LineIndex+1)
+                            File=self.MetaFile, Line=self._LineIndex + 1)
         if self._ValueList[2] == '':
+            #
+            # The PCD values are optional for FIXEDATBUILD, PATCHABLEINMODULE, Dynamic/DynamicEx default
+            #
+            if self._SectionType in (MODEL_PCD_FIXED_AT_BUILD, MODEL_PCD_PATCHABLE_IN_MODULE, MODEL_PCD_DYNAMIC_DEFAULT, MODEL_PCD_DYNAMIC_EX_DEFAULT):
+                return
             EdkLogger.error('Parser', FORMAT_INVALID, "No PCD value given",
                             ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<TokenCName>|<PcdValue>)",
-                            File=self.MetaFile, Line=self._LineIndex+1)
+                            File=self.MetaFile, Line=self._LineIndex + 1)
+
+        # Validate the datum type of Dynamic Defaul PCD and DynamicEx Default PCD
+        ValueList = GetSplitValueList(self._ValueList[2])
+        if len(ValueList) > 1 and ValueList[1] in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64] \
+                              and self._ItemType in [MODEL_PCD_DYNAMIC_DEFAULT, MODEL_PCD_DYNAMIC_EX_DEFAULT]:
+            EdkLogger.error('Parser', FORMAT_INVALID, "The datum type '%s' of PCD is wrong" % ValueList[1],
+                            ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex + 1)
+
+        # Validate the VariableName of DynamicHii and DynamicExHii for PCD Entry must not be an empty string
+        if self._ItemType in [MODEL_PCD_DYNAMIC_HII, MODEL_PCD_DYNAMIC_EX_HII]:
+            DscPcdValueList = GetSplitValueList(TokenList[1], TAB_VALUE_SPLIT, 1)
+            if len(DscPcdValueList[0].replace('L', '').replace('"', '').strip()) == 0:
+                EdkLogger.error('Parser', FORMAT_INVALID, "The VariableName field in the HII format PCD entry must not be an empty string",
+                            ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex + 1)
         # if value are 'True', 'true', 'TRUE' or 'False', 'false', 'FALSE', replace with integer 1 or 0.
         DscPcdValueList = GetSplitValueList(TokenList[1], TAB_VALUE_SPLIT, 1)
         if DscPcdValueList[0] in ['True', 'true', 'TRUE']:
-            self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '1', 1);
+            self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '1', 1)
         elif DscPcdValueList[0] in ['False', 'false', 'FALSE']:
-            self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '0', 1);
+            self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '0', 1)
 
     ## [components] section parser
     @ParseMacro
@@ -1502,6 +1592,10 @@ class DecParser(MetaFileParser):
         self._include_flag = False
         self._package_flag = False
 
+        self._AllPCDs = [] # Only for check duplicate PCD
+        self._AllPcdDict = {}
+
+
     ## Parser starter
     def Start(self):
         Content = ''
@@ -1510,6 +1604,7 @@ class DecParser(MetaFileParser):
         except:
             EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
 
+        Content = self.ProcessMultipleLineCODEValue(Content)
         #
         # Insert a record for file
         #
@@ -1707,51 +1802,6 @@ class DecParser(MetaFileParser):
                 namelist[2] = ".".join((arrayindex,namelist[2]))
         return namelist
 
-    def StructPcdParser(self):
-        self._ValueList[0] = self._CurrentStructurePcdName
-
-        if "|" not in self._CurrentLine:
-            if "<HeaderFiles>" == self._CurrentLine:
-                self._include_flag = True
-                self._package_flag = False
-                self._ValueList = None
-                return
-            if "<Packages>" == self._CurrentLine:
-                self._package_flag = True
-                self._ValueList = None
-                self._include_flag = False
-                return
-
-            if self._include_flag:
-                self._ValueList[1] = "<HeaderFiles>_" + md5(self._CurrentLine.encode('utf-8')).hexdigest()
-                self._ValueList[2] = self._CurrentLine
-            if self._package_flag and "}" != self._CurrentLine:
-                self._ValueList[1] = "<Packages>_" + md5(self._CurrentLine.encode('utf-8')).hexdigest()
-                self._ValueList[2] = self._CurrentLine
-            if self._CurrentLine == "}":
-                self._package_flag = False
-                self._include_flag = False
-                self._ValueList = None
-        else:
-            PcdTockens = self._CurrentLine.split(TAB_VALUE_SPLIT)
-            PcdNames = self.ParsePcdName(PcdTockens[0].split(TAB_SPLIT))
-            if len(PcdNames) == 2:
-                if PcdNames[1].strip().endswith("]"):
-                    PcdName = PcdNames[1][:PcdNames[1].index('[')]
-                    Index = PcdNames[1][PcdNames[1].index('['):]
-                    self._ValueList[0] = TAB_SPLIT.join((PcdNames[0], PcdName))
-                    self._ValueList[1] = Index
-                    self._ValueList[2] = PcdTockens[1]
-                else:
-                    self._CurrentStructurePcdName = ""
-            else:
-                if self._CurrentStructurePcdName != TAB_SPLIT.join(PcdNames[:2]):
-                    EdkLogger.error('Parser', FORMAT_INVALID, "Pcd Name does not match: %s and %s " % (
-                    self._CurrentStructurePcdName, TAB_SPLIT.join(PcdNames[:2])),
-                                    File=self.MetaFile, Line=self._LineIndex + 1)
-                self._ValueList[1] = TAB_SPLIT.join(PcdNames[2:])
-                self._ValueList[2] = PcdTockens[1]
-
     ## PCD sections parser
     #
     #   [PcdsFixedAtBuild]
@@ -1763,159 +1813,175 @@ class DecParser(MetaFileParser):
     @ParseMacro
     def _PcdParser(self):
         if self._CurrentStructurePcdName:
-            self.StructPcdParser()
-            return
-        TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
-        self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
-        # check PCD information
-        if self._ValueList[0] == '' or self._ValueList[1] == '':
-            EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
-                            ExtraData=self._CurrentLine + \
-                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
-                            File=self.MetaFile, Line=self._LineIndex+1)
-        # check PCD datum information
-        if len(TokenList) < 2 or TokenList[1] == '':
-            EdkLogger.error('Parser', FORMAT_INVALID, "No PCD Datum information given",
-                            ExtraData=self._CurrentLine + \
-                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
-                            File=self.MetaFile, Line=self._LineIndex+1)
-
-
-        ValueRe  = re.compile(r'^\s*L?\".*\|.*\"')
-        PtrValue = ValueRe.findall(TokenList[1])
-
-        # Has VOID* type string, may contain "|" character in the string.
-        if len(PtrValue) != 0:
-            ptrValueList = re.sub(ValueRe, '', TokenList[1])
-            ValueList    = GetSplitValueList(ptrValueList)
-            ValueList[0] = PtrValue[0]
-        else:
-            ValueList = GetSplitValueList(TokenList[1])
-
-
-        # check if there's enough datum information given
-        if len(ValueList) != 3:
-            EdkLogger.error('Parser', FORMAT_INVALID, "Invalid PCD Datum information given",
-                            ExtraData=self._CurrentLine + \
-                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
-                            File=self.MetaFile, Line=self._LineIndex+1)
-        # check default value
-        if ValueList[0] == '':
-            EdkLogger.error('Parser', FORMAT_INVALID, "Missing DefaultValue in PCD Datum information",
-                            ExtraData=self._CurrentLine + \
-                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
-                            File=self.MetaFile, Line=self._LineIndex+1)
-        # check datum type
-        if ValueList[1] == '':
-            EdkLogger.error('Parser', FORMAT_INVALID, "Missing DatumType in PCD Datum information",
-                            ExtraData=self._CurrentLine + \
-                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
-                            File=self.MetaFile, Line=self._LineIndex+1)
-        # check token of the PCD
-        if ValueList[2] == '':
-            EdkLogger.error('Parser', FORMAT_INVALID, "Missing Token in PCD Datum information",
-                            ExtraData=self._CurrentLine + \
-                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
-                            File=self.MetaFile, Line=self._LineIndex+1)
-        # check format of default value against the datum type
-        IsValid, Cause = CheckPcdDatum(ValueList[1], ValueList[0])
-        if not IsValid:
-            EdkLogger.error('Parser', FORMAT_INVALID, Cause, ExtraData=self._CurrentLine,
-                            File=self.MetaFile, Line=self._LineIndex+1)
-        if Cause == "StructurePcd":
-            self._CurrentStructurePcdName = TAB_SPLIT.join(self._ValueList[0:2])
             self._ValueList[0] = self._CurrentStructurePcdName
-            self._ValueList[1] = ValueList[1].strip()
 
-        if EccGlobalData.gConfig.UniCheckPCDInfo == '1' or EccGlobalData.gConfig.UniCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
-            # check Description, Prompt information
-            PatternDesc = re.compile('##\s*([\x21-\x7E\s]*)', re.S)
-            PatternPrompt = re.compile('#\s+@Prompt\s+([\x21-\x7E\s]*)', re.S)
-            Description = None
-            Prompt = None
-            # check @ValidRange, @ValidList and @Expression format valid
-            ErrorCodeValid = '0x0 <= %s <= 0xFFFFFFFF'
-            PatternValidRangeIn = '(NOT)?\s*(\d+\s*-\s*\d+|0[xX][a-fA-F0-9]+\s*-\s*0[xX][a-fA-F0-9]+|LT\s*\d+|LT\s*0[xX][a-fA-F0-9]+|GT\s*\d+|GT\s*0[xX][a-fA-F0-9]+|LE\s*\d+|LE\s*0[xX][a-fA-F0-9]+|GE\s*\d+|GE\s*0[xX][a-fA-F0-9]+|XOR\s*\d+|XOR\s*0[xX][a-fA-F0-9]+|EQ\s*\d+|EQ\s*0[xX][a-fA-F0-9]+)'
-            PatternValidRng = re.compile('^' + '(NOT)?\s*' + PatternValidRangeIn + '$')
-            for Comment in self._Comments:
-                Comm = Comment[0].strip()
-                if not Comm:
-                    continue
-                if not Description:
-                    Description = PatternDesc.findall(Comm)
-                if not Prompt:
-                    Prompt = PatternPrompt.findall(Comm)
-                if Comm[0] == '#':
-                    ValidFormt = Comm.lstrip('#')
-                    ValidFormt = ValidFormt.lstrip()
-                    if ValidFormt[0:11] == '@ValidRange':
-                        ValidFormt = ValidFormt[11:]
-                        ValidFormt = ValidFormt.lstrip()
-                        try:
-                            ErrorCode, Expression = ValidFormt.split('|', 1)
-                        except ValueError:
-                            ErrorCode = '0x0'
-                            Expression = ValidFormt
-                        ErrorCode, Expression = ErrorCode.strip(), Expression.strip()
-                        try:
-                            if not eval(ErrorCodeValid % ErrorCode):
-                                EdkLogger.warn('Parser', '@ValidRange ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
-                        except:
-                            EdkLogger.warn('Parser', '@ValidRange ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
-                        if not PatternValidRng.search(Expression):
-                            EdkLogger.warn('Parser', '@ValidRange Expression(%s) of PCD %s is incorrect format.' % (Expression, TokenList[0]))
-                    if ValidFormt[0:10] == '@ValidList':
-                        ValidFormt = ValidFormt[10:]
-                        ValidFormt = ValidFormt.lstrip()
-                        try:
-                            ErrorCode, Expression = ValidFormt.split('|', 1)
-                        except ValueError:
-                            ErrorCode = '0x0'
-                            Expression = ValidFormt
-                        ErrorCode, Expression = ErrorCode.strip(), Expression.strip()
-                        try:
-                            if not eval(ErrorCodeValid % ErrorCode):
-                                EdkLogger.warn('Parser', '@ValidList ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
-                        except:
-                            EdkLogger.warn('Parser', '@ValidList ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
-                        Values = Expression.split(',')
-                        for Value in Values:
-                            Value = Value.strip()
-                            try:
-                                eval(Value)
-                            except:
-                                EdkLogger.warn('Parser', '@ValidList Expression of PCD %s include a invalid value(%s).' % (TokenList[0], Value))
-                                break
-                    if ValidFormt[0:11] == '@Expression':
-                        ValidFormt = ValidFormt[11:]
-                        ValidFormt = ValidFormt.lstrip()
-                        try:
-                            ErrorCode, Expression = ValidFormt.split('|', 1)
-                        except ValueError:
-                            ErrorCode = '0x0'
-                            Expression = ValidFormt
-                        ErrorCode, Expression = ErrorCode.strip(), Expression.strip()
-                        try:
-                            if not eval(ErrorCodeValid % ErrorCode):
-                                EdkLogger.warn('Parser', '@Expression ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
-                        except:
-                            EdkLogger.warn('Parser', '@Expression ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
-                        if not Expression:
-                            EdkLogger.warn('Parser', '@Expression Expression of PCD %s is incorrect format.' % TokenList[0])
-            if not Description:
-                EdkLogger.warn('Parser', 'PCD %s Description information is not provided.' % TokenList[0])
-            if not Prompt:
-                EdkLogger.warn('Parser', 'PCD %s Prompt information is not provided.' % TokenList[0])
-            # check Description, Prompt localization information
-            if self._UniObj:
-                self._UniObj.CheckPcdInfo(TokenList[0])
+            if "|" not in self._CurrentLine:
+                if "<HeaderFiles>" == self._CurrentLine:
+                    self._include_flag = True
+                    self._package_flag = False
+                    self._ValueList = None
+                    return
+                if "<Packages>" == self._CurrentLine:
+                    self._package_flag = True
+                    self._ValueList = None
+                    self._include_flag = False
+                    return
 
-        if ValueList[0] in ['True', 'true', 'TRUE']:
-            ValueList[0] = '1'
-        elif ValueList[0] in ['False', 'false', 'FALSE']:
-            ValueList[0] = '0'
+                if self._include_flag:
+                    self._ValueList[1] = "<HeaderFiles>_" + md5(self._CurrentLine.encode('utf-8')).hexdigest()
+                    self._ValueList[2] = self._CurrentLine
+                if self._package_flag and "}" != self._CurrentLine:
+                    self._ValueList[1] = "<Packages>_" + md5(self._CurrentLine.encode('utf-8')).hexdigest()
+                    self._ValueList[2] = self._CurrentLine
+                if self._CurrentLine == "}":
+                    self._package_flag = False
+                    self._include_flag = False
+                    self._ValueList = None
+                    return
+            else:
+                PcdTockens = self._CurrentLine.split(TAB_VALUE_SPLIT)
+                PcdNames = self.ParsePcdName(PcdTockens[0].split(TAB_SPLIT))
+                if len(PcdNames) == 2:
+                    if PcdNames[1].strip().endswith("]"):
+                        PcdName = PcdNames[1][:PcdNames[1].index('[')]
+                        Index = PcdNames[1][PcdNames[1].index('['):]
+                        self._ValueList[0] = TAB_SPLIT.join((PcdNames[0],PcdName))
+                        self._ValueList[1] = Index
+                        self._ValueList[2] = PcdTockens[1]
+                    else:
+                        self._CurrentStructurePcdName = ""
+                else:
+                    if self._CurrentStructurePcdName != TAB_SPLIT.join(PcdNames[:2]):
+                        EdkLogger.error('Parser', FORMAT_INVALID, "Pcd Name does not match: %s and %s " % (self._CurrentStructurePcdName, TAB_SPLIT.join(PcdNames[:2])),
+                                File=self.MetaFile, Line=self._LineIndex + 1)
+                    self._ValueList[1] = TAB_SPLIT.join(PcdNames[2:])
+                    self._ValueList[2] = PcdTockens[1]
 
-        self._ValueList[2] = ValueList[0].strip() + '|' + ValueList[1].strip() + '|' + ValueList[2].strip()
+        if not self._CurrentStructurePcdName:
+            if self._PcdDataTypeCODE:
+                if ")}" in self._CurrentLine:
+                    ValuePart, RestofValue = self._CurrentLine.split(")}")
+                    self._PcdCodeValue = self._PcdCodeValue + "\n " + ValuePart
+                    self._CurrentLine = "|".join((self._CurrentPcdName, self._PcdCodeValue, RestofValue))
+                    self._PcdDataTypeCODE = False
+                    self._PcdCodeValue = ""
+                else:
+                    self._PcdCodeValue = self._PcdCodeValue + "\n " + self._CurrentLine
+                    self._ValueList = None
+                    return
+            TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
+            self._CurrentPcdName = TokenList[0]
+            if len(TokenList) == 2 and TokenList[1].strip().startswith("{CODE"):
+                if ")}" in self._CurrentLine:
+                    self._PcdDataTypeCODE = False
+                    self._PcdCodeValue = ""
+                else:
+                    self._PcdDataTypeCODE = True
+                    self._PcdCodeValue = TokenList[1].strip()
+                    self._ValueList = None
+                    return
+
+            self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
+            ValueRe = re.compile(r'^[a-zA-Z_][a-zA-Z0-9_]*')
+            # check PCD information
+            if self._ValueList[0] == '' or self._ValueList[1] == '':
+                EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
+                                ExtraData=self._CurrentLine + \
+                                          " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
+                                File=self.MetaFile, Line=self._LineIndex+1)
+            # check format of token space GUID CName
+            if not ValueRe.match(self._ValueList[0]):
+                EdkLogger.error('Parser', FORMAT_INVALID,
+                                "The format of the token space GUID CName is invalid. The correct format is '(a-zA-Z_)[a-zA-Z0-9_]*'",
+                                ExtraData=self._CurrentLine + \
+                                          " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
+                                File=self.MetaFile, Line=self._LineIndex + 1)
+            # check format of PCD CName
+            if not ValueRe.match(self._ValueList[1]):
+                EdkLogger.error('Parser', FORMAT_INVALID,
+                                "The format of the PCD CName is invalid. The correct format is '(a-zA-Z_)[a-zA-Z0-9_]*'",
+                                ExtraData=self._CurrentLine + \
+                                          " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
+                                File=self.MetaFile, Line=self._LineIndex + 1)
+
+            # check PCD datum information
+            if len(TokenList) < 2 or TokenList[1] == '':
+                EdkLogger.error('Parser', FORMAT_INVALID, "No PCD Datum information given",
+                                ExtraData=self._CurrentLine + \
+                                          " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
+                                File=self.MetaFile, Line=self._LineIndex+1)
+
+
+            ValueRe = re.compile(r'^\s*L?\".*\|.*\"')
+            PtrValue = ValueRe.findall(TokenList[1])
+
+            # Has VOID* type string, may contain "|" character in the string.
+            if len(PtrValue) != 0:
+                ptrValueList = re.sub(ValueRe, '', TokenList[1])
+                ValueList = AnalyzePcdExpression(ptrValueList)
+                ValueList[0] = PtrValue[0]
+            else:
+                ValueList = AnalyzePcdExpression(TokenList[1])
+
+
+            # check if there's enough datum information given
+            if len(ValueList) != 3:
+                EdkLogger.error('Parser', FORMAT_INVALID, "Invalid PCD Datum information given",
+                                ExtraData=self._CurrentLine + \
+                                          " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
+                                File=self.MetaFile, Line=self._LineIndex + 1)
+            # check default value
+            if ValueList[0] == '':
+                EdkLogger.error('Parser', FORMAT_INVALID, "Missing DefaultValue in PCD Datum information",
+                                ExtraData=self._CurrentLine + \
+                                          " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
+                                File=self.MetaFile, Line=self._LineIndex + 1)
+            # check datum type
+            if ValueList[1] == '':
+                EdkLogger.error('Parser', FORMAT_INVALID, "Missing DatumType in PCD Datum information",
+                                ExtraData=self._CurrentLine + \
+                                          " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
+                                File=self.MetaFile, Line=self._LineIndex + 1)
+            # check token of the PCD
+            if ValueList[2] == '':
+                EdkLogger.error('Parser', FORMAT_INVALID, "Missing Token in PCD Datum information",
+                                ExtraData=self._CurrentLine + \
+                                          " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
+                                File=self.MetaFile, Line=self._LineIndex + 1)
+
+            PcdValue = ValueList[0]
+            if PcdValue:
+                try:
+                    self._GuidDict.update(self._AllPcdDict)
+                    ValueList[0] = ValueExpressionEx(ValueList[0], ValueList[1], self._GuidDict)(True)
+                except BadExpression as Value:
+                    EdkLogger.error('Parser', FORMAT_INVALID, Value, ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex + 1)
+            # check format of default value against the datum type
+            IsValid, Cause = CheckPcdDatum(ValueList[1], ValueList[0])
+            if not IsValid:
+                EdkLogger.error('Parser', FORMAT_INVALID, Cause, ExtraData=self._CurrentLine,
+                                File=self.MetaFile, Line=self._LineIndex + 1)
+
+            if Cause == "StructurePcd":
+                self._CurrentStructurePcdName = TAB_SPLIT.join(self._ValueList[0:2])
+                self._ValueList[0] = self._CurrentStructurePcdName
+                self._ValueList[1] = ValueList[1].strip()
+
+            if ValueList[0] in ['True', 'true', 'TRUE']:
+                ValueList[0] = '1'
+            elif ValueList[0] in ['False', 'false', 'FALSE']:
+                ValueList[0] = '0'
+
+            # check for duplicate PCD definition
+            if (self._Scope[0], self._ValueList[0], self._ValueList[1]) in self._AllPCDs:
+                EdkLogger.error('Parser', FORMAT_INVALID,
+                                "The same PCD name and GUID have been already defined",
+                                ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex + 1)
+            else:
+                self._AllPCDs.append((self._Scope[0], self._ValueList[0], self._ValueList[1]))
+                self._AllPcdDict[TAB_SPLIT.join(self._ValueList[0:2])] = ValueList[0]
+
+            self._ValueList[2] = ValueList[0].strip() + '|' + ValueList[1].strip() + '|' + ValueList[2].strip()
 
     _SectionParser = {
         MODEL_META_DATA_HEADER          :   MetaFileParser._DefineParser,
--
2.26.2.windows.1





 


Yuwei Chen
 

Hi Bret,

 

This patch adds the ECC check for structurePcd written in des/dsc file, as the origin check is only for non-structured Pcd.

 

Best Regards,

Yuwei (Christine)

 

From: Bret Barkelew <Bret.Barkelew@...>
Sent: Friday, April 2, 2021 12:43 AM
To: devel@edk2.groups.io; Chen, Christine <yuwei.chen@...>
Cc: Liang, MingyueX <mingyuex.liang@...>; Feng, Bob C <bob.c.feng@...>; Liming Gao <gaoliming@...>
Subject: RE: [EXTERNAL] [edk2-devel] [PATCH 1/1] BaseTools/Ecc: Update structpcd parsing method.

 

What does “update” mean in this context? What behavior is changing?

 

- Bret

 

From: Yuwei Chen via groups.io
Sent: Thursday, April 1, 2021 12:04 AM
To: devel@edk2.groups.io
Cc: mliang2x; Feng, Bob C; Liming Gao
Subject: [EXTERNAL] [edk2-devel] [PATCH 1/1] BaseTools/Ecc: Update structpcd parsing method.

 

From: mliang2x <mingyuex.liang@...>

Update the pcdparser method in Dec and DSC files.

Signed-off-by: Mingyue Liang <mingyuex.liang@...>
Cc: Bob Feng <bob.c.feng@...>
Cc: Liming Gao <gaoliming@...>
Cc: Yuwei Chen <yuwei.chen@...>
---
 .../Ecc/MetaFileWorkspace/MetaFileParser.py   | 464 ++++++++++--------
 1 file changed, 265 insertions(+), 199 deletions(-)

diff --git a/BaseTools/Source/Python/Ecc/MetaFileWorkspace/MetaFileParser.py b/BaseTools/Source/Python/Ecc/MetaFileWorkspace/MetaFileParser.py
index 9c27c8e16a05..588d3dbe6ed5 100644
--- a/BaseTools/Source/Python/Ecc/MetaFileWorkspace/MetaFileParser.py
+++ b/BaseTools/Source/Python/Ecc/MetaFileWorkspace/MetaFileParser.py
@@ -22,7 +22,7 @@ import Ecc.EccToolError as EccToolError
 from CommonDataClass.DataClass import *
 from Common.DataType import *
 from Common.StringUtils import *
-from Common.Misc import GuidStructureStringToGuidString, CheckPcdDatum, PathClass, AnalyzePcdData
+from Common.Misc import GuidStructureStringToGuidString, CheckPcdDatum, PathClass, AnalyzePcdData, AnalyzeDscPcd, AnalyzePcdExpression, ParseFieldValue, StructPattern
 from Common.Expression import *
 from CommonDataClass.Exceptions import *
 
@@ -31,6 +31,8 @@ from GenFds.FdfParser import FdfParser
 from Common.LongFilePathSupport import OpenLongFilePath as open
 from Common.LongFilePathSupport import CodecOpenLongFilePath
 
+CODEPattern = re.compile(r"{CODE\([a-fA-F0-9Xx\{\},\s]*\)}")
+
 ## A decorator used to parse macro definition
 def ParseMacro(Parser):
     def MacroParser(self):
@@ -174,6 +176,11 @@ class MetaFileParser(object):
         # UNI object and extra UNI object
         self._UniObj = None
         self._UniExtraObj = None
+        # StructPcd var
+        self._PcdCodeValue = ""
+        self._PcdDataTypeCODE = False
+        self._CurrentPcdName = ""
+        self._GuidDict = {}  # for Parser PCD value {GUID(gTokeSpaceGuidName)}
 
     ## Store the parsed data in table
     def _Store(self, *Args):
@@ -395,6 +402,40 @@ class MetaFileParser(object):
                 Macros.update(self._SectionsMacroDict[(self._SectionType, Scope1, Scope2)])
         return Macros
 
+    def ProcessMultipleLineCODEValue(self, Content):
+        CODEBegin = False
+        CODELine = ""
+        continuelinecount = 0
+        newContent = []
+        for Index in range(0, len(Content)):
+            Line = Content[Index]
+            if CODEBegin:
+                CODELine = CODELine + Line
+                continuelinecount +=1
+                if ")}" in Line:
+                    newContent.append(CODELine)
+                    for _ in range(continuelinecount):
+                        newContent.append("")
+                    CODEBegin = False
+                    CODELine = ""
+                    continuelinecount = 0
+            else:
+                if not Line:
+                    newContent.append(Line)
+                    continue
+                if "{CODE(" not in Line:
+                    newContent.append(Line)
+                    continue
+                elif CODEPattern.findall(Line):
+                    newContent.append(Line)
+                    continue
+                else:
+                    CODEBegin = True
+                    CODELine = Line
+
+        return newContent
+
+
     _SectionParser  = {}
     Finished        = property(_GetFinished, _SetFinished)
     _Macros         = property(_GetMacros)
@@ -812,6 +853,8 @@ class DscParser(MetaFileParser):
             Content = open(str(self.MetaFile.Path), 'r').readlines()
         except:
             EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
+
+        Content = self.ProcessMultipleLineCODEValue(Content)
         #
         # Insert a record for file
         #
@@ -1018,24 +1061,71 @@ class DscParser(MetaFileParser):
     #
     @ParseMacro
     def _PcdParser(self):
+        if self._PcdDataTypeCODE:
+            self._PcdCodeValue = self._PcdCodeValue + "\n " + self._CurrentLine
+            if self._CurrentLine.endswith(")}"):
+                self._CurrentLine = "|".join((self._CurrentPcdName, self._PcdCodeValue))
+                self._PcdDataTypeCODE = False
+                self._PcdCodeValue = ""
+            else:
+                self._ValueList = None
+                return
         TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
+        self._CurrentPcdName = TokenList[0]
+        if len(TokenList) == 2 and TokenList[1].strip().startswith("{CODE"):
+            self._PcdDataTypeCODE = True
+            self._PcdCodeValue = TokenList[1].strip()
+
+        if self._PcdDataTypeCODE:
+            if self._CurrentLine.endswith(")}"):
+                self._PcdDataTypeCODE = False
+                self._PcdCodeValue = ""
+            else:
+                self._ValueList = None
+                return
         self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
+        PcdNameTockens = GetSplitValueList(TokenList[0], TAB_SPLIT)
+        if len(PcdNameTockens) == 2:
+            self._ValueList[0], self._ValueList[1] = PcdNameTockens[0], PcdNameTockens[1]
+        elif len(PcdNameTockens) == 3:
+            self._ValueList[0], self._ValueList[1] = ".".join((PcdNameTockens[0], PcdNameTockens[1])), PcdNameTockens[2]
+        elif len(PcdNameTockens) > 3:
+            self._ValueList[0], self._ValueList[1] = ".".join((PcdNameTockens[0], PcdNameTockens[1])), ".".join(PcdNameTockens[2:])
         if len(TokenList) == 2:
             self._ValueList[2] = TokenList[1]
         if self._ValueList[0] == '' or self._ValueList[1] == '':
             EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
                             ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<TokenCName>|<PcdValue>)",
-                            File=self.MetaFile, Line=self._LineIndex+1)
+                            File=self.MetaFile, Line=self._LineIndex + 1)
         if self._ValueList[2] == '':
+            #
+            # The PCD values are optional for FIXEDATBUILD, PATCHABLEINMODULE, Dynamic/DynamicEx default
+            #
+            if self._SectionType in (MODEL_PCD_FIXED_AT_BUILD, MODEL_PCD_PATCHABLE_IN_MODULE, MODEL_PCD_DYNAMIC_DEFAULT, MODEL_PCD_DYNAMIC_EX_DEFAULT):
+                return
             EdkLogger.error('Parser', FORMAT_INVALID, "No PCD value given",
                             ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<TokenCName>|<PcdValue>)",
-                            File=self.MetaFile, Line=self._LineIndex+1)
+                            File=self.MetaFile, Line=self._LineIndex + 1)
+
+        # Validate the datum type of Dynamic Defaul PCD and DynamicEx Default PCD
+        ValueList = GetSplitValueList(self._ValueList[2])
+        if len(ValueList) > 1 and ValueList[1] in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64] \
+                              and self._ItemType in [MODEL_PCD_DYNAMIC_DEFAULT, MODEL_PCD_DYNAMIC_EX_DEFAULT]:
+            EdkLogger.error('Parser', FORMAT_INVALID, "The datum type '%s' of PCD is wrong" % ValueList[1],
+                            ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex + 1)
+
+        # Validate the VariableName of DynamicHii and DynamicExHii for PCD Entry must not be an empty string
+        if self._ItemType in [MODEL_PCD_DYNAMIC_HII, MODEL_PCD_DYNAMIC_EX_HII]:
+            DscPcdValueList = GetSplitValueList(TokenList[1], TAB_VALUE_SPLIT, 1)
+            if len(DscPcdValueList[0].replace('L', '').replace('"', '').strip()) == 0:
+                EdkLogger.error('Parser', FORMAT_INVALID, "The VariableName field in the HII format PCD entry must not be an empty string",
+                            ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex + 1)
         # if value are 'True', 'true', 'TRUE' or 'False', 'false', 'FALSE', replace with integer 1 or 0.
         DscPcdValueList = GetSplitValueList(TokenList[1], TAB_VALUE_SPLIT, 1)
         if DscPcdValueList[0] in ['True', 'true', 'TRUE']:
-            self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '1', 1);
+            self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '1', 1)
         elif DscPcdValueList[0] in ['False', 'false', 'FALSE']:
-            self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '0', 1);
+            self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '0', 1)
 
     ## [components] section parser
     @ParseMacro
@@ -1502,6 +1592,10 @@ class DecParser(MetaFileParser):
         self._include_flag = False
         self._package_flag = False
 
+        self._AllPCDs = [] # Only for check duplicate PCD
+        self._AllPcdDict = {}
+
+
     ## Parser starter
     def Start(self):
         Content = ''
@@ -1510,6 +1604,7 @@ class DecParser(MetaFileParser):
         except:
             EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
 
+        Content = self.ProcessMultipleLineCODEValue(Content)
         #
         # Insert a record for file
         #
@@ -1707,51 +1802,6 @@ class DecParser(MetaFileParser):
                 namelist[2] = ".".join((arrayindex,namelist[2]))
         return namelist
 
-    def StructPcdParser(self):
-        self._ValueList[0] = self._CurrentStructurePcdName
-
-        if "|" not in self._CurrentLine:
-            if "<HeaderFiles>" == self._CurrentLine:
-                self._include_flag = True
-                self._package_flag = False
-                self._ValueList = None
-                return
-            if "<Packages>" == self._CurrentLine:
-                self._package_flag = True
-                self._ValueList = None
-                self._include_flag = False
-                return
-
-            if self._include_flag:
-                self._ValueList[1] = "<HeaderFiles>_" + md5(self._CurrentLine.encode('utf-8')).hexdigest()
-                self._ValueList[2] = self._CurrentLine
-            if self._package_flag and "}" != self._CurrentLine:
-                self._ValueList[1] = "<Packages>_" + md5(self._CurrentLine.encode('utf-8')).hexdigest()
-                self._ValueList[2] = self._CurrentLine
-            if self._CurrentLine == "}":
-                self._package_flag = False
-                self._include_flag = False
-                self._ValueList = None
-        else:
-            PcdTockens = self._CurrentLine.split(TAB_VALUE_SPLIT)
-            PcdNames = self.ParsePcdName(PcdTockens[0].split(TAB_SPLIT))
-            if len(PcdNames) == 2:
-                if PcdNames[1].strip().endswith("]"):
-                    PcdName = PcdNames[1][:PcdNames[1].index('[')]
-                    Index = PcdNames[1][PcdNames[1].index('['):]
-                    self._ValueList[0] = TAB_SPLIT.join((PcdNames[0], PcdName))
-                    self._ValueList[1] = Index
-                    self._ValueList[2] = PcdTockens[1]
-                else:
-                    self._CurrentStructurePcdName = ""
-            else:
-                if self._CurrentStructurePcdName != TAB_SPLIT.join(PcdNames[:2]):
-                    EdkLogger.error('Parser', FORMAT_INVALID, "Pcd Name does not match: %s and %s " % (
-                    self._CurrentStructurePcdName, TAB_SPLIT.join(PcdNames[:2])),
-                                    File=self.MetaFile, Line=self._LineIndex + 1)
-                self._ValueList[1] = TAB_SPLIT.join(PcdNames[2:])
-                self._ValueList[2] = PcdTockens[1]
-
     ## PCD sections parser
     #
     #   [PcdsFixedAtBuild]
@@ -1763,159 +1813,175 @@ class DecParser(MetaFileParser):
     @ParseMacro
     def _PcdParser(self):
         if self._CurrentStructurePcdName:
-            self.StructPcdParser()
-            return
-        TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
-        self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
-        # check PCD information
-        if self._ValueList[0] == '' or self._ValueList[1] == '':
-            EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
-                            ExtraData=self._CurrentLine + \
-                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
-                            File=self.MetaFile, Line=self._LineIndex+1)
-        # check PCD datum information
-        if len(TokenList) < 2 or TokenList[1] == '':
-            EdkLogger.error('Parser', FORMAT_INVALID, "No PCD Datum information given",
-                            ExtraData=self._CurrentLine + \
-                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
-                            File=self.MetaFile, Line=self._LineIndex+1)
-
-
-        ValueRe  = re.compile(r'^\s*L?\".*\|.*\"')
-        PtrValue = ValueRe.findall(TokenList[1])
-
-        # Has VOID* type string, may contain "|" character in the string.
-        if len(PtrValue) != 0:
-            ptrValueList = re.sub(ValueRe, '', TokenList[1])
-            ValueList    = GetSplitValueList(ptrValueList)
-            ValueList[0] = PtrValue[0]
-        else:
-            ValueList = GetSplitValueList(TokenList[1])
-
-
-        # check if there's enough datum information given
-        if len(ValueList) != 3:
-            EdkLogger.error('Parser', FORMAT_INVALID, "Invalid PCD Datum information given",
-                            ExtraData=self._CurrentLine + \
-                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
-                            File=self.MetaFile, Line=self._LineIndex+1)
-        # check default value
-        if ValueList[0] == '':
-            EdkLogger.error('Parser', FORMAT_INVALID, "Missing DefaultValue in PCD Datum information",
-                            ExtraData=self._CurrentLine + \
-                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
-                            File=self.MetaFile, Line=self._LineIndex+1)
-        # check datum type
-        if ValueList[1] == '':
-            EdkLogger.error('Parser', FORMAT_INVALID, "Missing DatumType in PCD Datum information",
-                            ExtraData=self._CurrentLine + \
-                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
-                            File=self.MetaFile, Line=self._LineIndex+1)
-        # check token of the PCD
-        if ValueList[2] == '':
-            EdkLogger.error('Parser', FORMAT_INVALID, "Missing Token in PCD Datum information",
-                            ExtraData=self._CurrentLine + \
-                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
-                            File=self.MetaFile, Line=self._LineIndex+1)
-        # check format of default value against the datum type
-        IsValid, Cause = CheckPcdDatum(ValueList[1], ValueList[0])
-        if not IsValid:
-            EdkLogger.error('Parser', FORMAT_INVALID, Cause, ExtraData=self._CurrentLine,
-                            File=self.MetaFile, Line=self._LineIndex+1)
-        if Cause == "StructurePcd":
-            self._CurrentStructurePcdName = TAB_SPLIT.join(self._ValueList[0:2])
             self._ValueList[0] = self._CurrentStructurePcdName
-            self._ValueList[1] = ValueList[1].strip()
 
-        if EccGlobalData.gConfig.UniCheckPCDInfo == '1' or EccGlobalData.gConfig.UniCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
-            # check Description, Prompt information
-            PatternDesc = re.compile('##\s*([\x21-\x7E\s]*)', re.S)
-            PatternPrompt = re.compile('#\s+@Prompt\s+([\x21-\x7E\s]*)', re.S)
-            Description = None
-            Prompt = None
-            # check @ValidRange, @ValidList and @Expression format valid
-            ErrorCodeValid = '0x0 <= %s <= 0xFFFFFFFF'
-            PatternValidRangeIn = '(NOT)?\s*(\d+\s*-\s*\d+|0[xX][a-fA-F0-9]+\s*-\s*0[xX][a-fA-F0-9]+|LT\s*\d+|LT\s*0[xX][a-fA-F0-9]+|GT\s*\d+|GT\s*0[xX][a-fA-F0-9]+|LE\s*\d+|LE\s*0[xX][a-fA-F0-9]+|GE\s*\d+|GE\s*0[xX][a-fA-F0-9]+|XOR\s*\d+|XOR\s*0[xX][a-fA-F0-9]+|EQ\s*\d+|EQ\s*0[xX][a-fA-F0-9]+)'
-            PatternValidRng = re.compile('^' + '(NOT)?\s*' + PatternValidRangeIn + '$')
-            for Comment in self._Comments:
-                Comm = Comment[0].strip()
-                if not Comm:
-                    continue
-                if not Description:
-                    Description = PatternDesc.findall(Comm)
-                if not Prompt:
-                    Prompt = PatternPrompt.findall(Comm)
-                if Comm[0] == '#':
-                    ValidFormt = Comm.lstrip('#')
-                    ValidFormt = ValidFormt.lstrip()
-                    if ValidFormt[0:11] == '@ValidRange':
-                        ValidFormt = ValidFormt[11:]
-                        ValidFormt = ValidFormt.lstrip()
-                        try:
-                            ErrorCode, Expression = ValidFormt.split('|', 1)
-                        except ValueError:
-                            ErrorCode = '0x0'
-                            Expression = ValidFormt
-                        ErrorCode, Expression = ErrorCode.strip(), Expression.strip()
-                        try:
-                            if not eval(ErrorCodeValid % ErrorCode):
-                                EdkLogger.warn('Parser', '@ValidRange ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
-                        except:
-                            EdkLogger.warn('Parser', '@ValidRange ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
-                        if not PatternValidRng.search(Expression):
-                            EdkLogger.warn('Parser', '@ValidRange Expression(%s) of PCD %s is incorrect format.' % (Expression, TokenList[0]))
-                    if ValidFormt[0:10] == '@ValidList':
-                        ValidFormt = ValidFormt[10:]
-                        ValidFormt = ValidFormt.lstrip()
-                        try:
-                            ErrorCode, Expression = ValidFormt.split('|', 1)
-                        except ValueError:
-                            ErrorCode = '0x0'
-                            Expression = ValidFormt
-                        ErrorCode, Expression = ErrorCode.strip(), Expression.strip()
-                        try:
-                            if not eval(ErrorCodeValid % ErrorCode):
-                                EdkLogger.warn('Parser', '@ValidList ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
-                        except:
-                            EdkLogger.warn('Parser', '@ValidList ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
-                        Values = Expression.split(',')
-                        for Value in Values:
-                            Value = Value.strip()
-                            try:
-                                eval(Value)
-                            except:
-                                EdkLogger.warn('Parser', '@ValidList Expression of PCD %s include a invalid value(%s).' % (TokenList[0], Value))
-                                break
-                    if ValidFormt[0:11] == '@Expression':
-                        ValidFormt = ValidFormt[11:]
-                        ValidFormt = ValidFormt.lstrip()
-                        try:
-                            ErrorCode, Expression = ValidFormt.split('|', 1)
-                        except ValueError:
-                            ErrorCode = '0x0'
-                            Expression = ValidFormt
-                        ErrorCode, Expression = ErrorCode.strip(), Expression.strip()
-                        try:
-                            if not eval(ErrorCodeValid % ErrorCode):
-                                EdkLogger.warn('Parser', '@Expression ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
-                        except:
-                            EdkLogger.warn('Parser', '@Expression ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
-                        if not Expression:
-                            EdkLogger.warn('Parser', '@Expression Expression of PCD %s is incorrect format.' % TokenList[0])
-            if not Description:
-                EdkLogger.warn('Parser', 'PCD %s Description information is not provided.' % TokenList[0])
-            if not Prompt:
-                EdkLogger.warn('Parser', 'PCD %s Prompt information is not provided.' % TokenList[0])
-            # check Description, Prompt localization information
-            if self._UniObj:
-                self._UniObj.CheckPcdInfo(TokenList[0])
+            if "|" not in self._CurrentLine:
+                if "<HeaderFiles>" == self._CurrentLine:
+                    self._include_flag = True
+                    self._package_flag = False
+                    self._ValueList = None
+                    return
+                if "<Packages>" == self._CurrentLine:
+                    self._package_flag = True
+                    self._ValueList = None
+                    self._include_flag = False
+                    return
 
-        if ValueList[0] in ['True', 'true', 'TRUE']:
-            ValueList[0] = '1'
-        elif ValueList[0] in ['False', 'false', 'FALSE']:
-            ValueList[0] = '0'
+                if self._include_flag:
+                    self._ValueList[1] = "<HeaderFiles>_" + md5(self._CurrentLine.encode('utf-8')).hexdigest()
+                    self._ValueList[2] = self._CurrentLine
+                if self._package_flag and "}" != self._CurrentLine:
+                    self._ValueList[1] = "<Packages>_" + md5(self._CurrentLine.encode('utf-8')).hexdigest()
+                    self._ValueList[2] = self._CurrentLine
+                if self._CurrentLine == "}":
+                    self._package_flag = False
+                    self._include_flag = False
+                    self._ValueList = None
+                    return
+            else:
+                PcdTockens = self._CurrentLine.split(TAB_VALUE_SPLIT)
+                PcdNames = self.ParsePcdName(PcdTockens[0].split(TAB_SPLIT))
+                if len(PcdNames) == 2:
+                    if PcdNames[1].strip().endswith("]"):
+                        PcdName = PcdNames[1][:PcdNames[1].index('[')]
+                        Index = PcdNames[1][PcdNames[1].index('['):]
+                        self._ValueList[0] = TAB_SPLIT.join((PcdNames[0],PcdName))
+                        self._ValueList[1] = Index
+                        self._ValueList[2] = PcdTockens[1]
+                    else:
+                        self._CurrentStructurePcdName = ""
+                else:
+                    if self._CurrentStructurePcdName != TAB_SPLIT.join(PcdNames[:2]):
+                        EdkLogger.error('Parser', FORMAT_INVALID, "Pcd Name does not match: %s and %s " % (self._CurrentStructurePcdName, TAB_SPLIT.join(PcdNames[:2])),
+                                File=self.MetaFile, Line=self._LineIndex + 1)
+                    self._ValueList[1] = TAB_SPLIT.join(PcdNames[2:])
+                    self._ValueList[2] = PcdTockens[1]
 
-        self._ValueList[2] = ValueList[0].strip() + '|' + ValueList[1].strip() + '|' + ValueList[2].strip()
+        if not self._CurrentStructurePcdName:
+            if self._PcdDataTypeCODE:
+                if ")}" in self._CurrentLine:
+                    ValuePart, RestofValue = self._CurrentLine.split(")}")
+                    self._PcdCodeValue = self._PcdCodeValue + "\n " + ValuePart
+                    self._CurrentLine = "|".join((self._CurrentPcdName, self._PcdCodeValue, RestofValue))
+                    self._PcdDataTypeCODE = False
+                    self._PcdCodeValue = ""
+                else:
+                    self._PcdCodeValue = self._PcdCodeValue + "\n " + self._CurrentLine
+                    self._ValueList = None
+                    return
+            TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
+            self._CurrentPcdName = TokenList[0]
+            if len(TokenList) == 2 and TokenList[1].strip().startswith("{CODE"):
+                if ")}" in self._CurrentLine:
+                    self._PcdDataTypeCODE = False
+                    self._PcdCodeValue = ""
+                else:
+                    self._PcdDataTypeCODE = True
+                    self._PcdCodeValue = TokenList[1].strip()
+                    self._ValueList = None
+                    return
+
+            self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
+            ValueRe = re.compile(r'^[a-zA-Z_][a-zA-Z0-9_]*')
+            # check PCD information
+            if self._ValueList[0] == '' or self._ValueList[1] == '':
+                EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
+                                ExtraData=self._CurrentLine + \
+                                          " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
+                                File=self.MetaFile, Line=self._LineIndex+1)
+            # check format of token space GUID CName
+            if not ValueRe.match(self._ValueList[0]):
+                EdkLogger.error('Parser', FORMAT_INVALID,
+                                "The format of the token space GUID CName is invalid. The correct format is '(a-zA-Z_)[a-zA-Z0-9_]*'",
+                                ExtraData=self._CurrentLine + \
+                                          " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
+                                File=self.MetaFile, Line=self._LineIndex + 1)
+            # check format of PCD CName
+            if not ValueRe.match(self._ValueList[1]):
+                EdkLogger.error('Parser', FORMAT_INVALID,
+                                "The format of the PCD CName is invalid. The correct format is '(a-zA-Z_)[a-zA-Z0-9_]*'",
+                                ExtraData=self._CurrentLine + \
+                                          " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
+                                File=self.MetaFile, Line=self._LineIndex + 1)
+
+            # check PCD datum information
+            if len(TokenList) < 2 or TokenList[1] == '':
+                EdkLogger.error('Parser', FORMAT_INVALID, "No PCD Datum information given",
+                                ExtraData=self._CurrentLine + \
+                                          " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
+                                File=self.MetaFile, Line=self._LineIndex+1)
+
+
+            ValueRe = re.compile(r'^\s*L?\".*\|.*\"')
+            PtrValue = ValueRe.findall(TokenList[1])
+
+            # Has VOID* type string, may contain "|" character in the string.
+            if len(PtrValue) != 0:
+                ptrValueList = re.sub(ValueRe, '', TokenList[1])
+                ValueList = AnalyzePcdExpression(ptrValueList)
+                ValueList[0] = PtrValue[0]
+            else:
+                ValueList = AnalyzePcdExpression(TokenList[1])
+
+
+            # check if there's enough datum information given
+            if len(ValueList) != 3:
+                EdkLogger.error('Parser', FORMAT_INVALID, "Invalid PCD Datum information given",
+                                ExtraData=self._CurrentLine + \
+                                          " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
+                                File=self.MetaFile, Line=self._LineIndex + 1)
+            # check default value
+            if ValueList[0] == '':
+                EdkLogger.error('Parser', FORMAT_INVALID, "Missing DefaultValue in PCD Datum information",
+                                ExtraData=self._CurrentLine + \
+                                          " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
+                                File=self.MetaFile, Line=self._LineIndex + 1)
+            # check datum type
+            if ValueList[1] == '':
+                EdkLogger.error('Parser', FORMAT_INVALID, "Missing DatumType in PCD Datum information",
+                                ExtraData=self._CurrentLine + \
+                                          " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
+                                File=self.MetaFile, Line=self._LineIndex + 1)
+            # check token of the PCD
+            if ValueList[2] == '':
+                EdkLogger.error('Parser', FORMAT_INVALID, "Missing Token in PCD Datum information",
+                                ExtraData=self._CurrentLine + \
+                                          " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
+                                File=self.MetaFile, Line=self._LineIndex + 1)
+
+            PcdValue = ValueList[0]
+            if PcdValue:
+                try:
+                    self._GuidDict.update(self._AllPcdDict)
+                    ValueList[0] = ValueExpressionEx(ValueList[0], ValueList[1], self._GuidDict)(True)
+                except BadExpression as Value:
+                    EdkLogger.error('Parser', FORMAT_INVALID, Value, ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex + 1)
+            # check format of default value against the datum type
+            IsValid, Cause = CheckPcdDatum(ValueList[1], ValueList[0])
+            if not IsValid:
+                EdkLogger.error('Parser', FORMAT_INVALID, Cause, ExtraData=self._CurrentLine,
+                                File=self.MetaFile, Line=self._LineIndex + 1)
+
+            if Cause == "StructurePcd":
+                self._CurrentStructurePcdName = TAB_SPLIT.join(self._ValueList[0:2])
+                self._ValueList[0] = self._CurrentStructurePcdName
+                self._ValueList[1] = ValueList[1].strip()
+
+            if ValueList[0] in ['True', 'true', 'TRUE']:
+                ValueList[0] = '1'
+            elif ValueList[0] in ['False', 'false', 'FALSE']:
+                ValueList[0] = '0'
+
+            # check for duplicate PCD definition
+            if (self._Scope[0], self._ValueList[0], self._ValueList[1]) in self._AllPCDs:
+                EdkLogger.error('Parser', FORMAT_INVALID,
+                                "The same PCD name and GUID have been already defined",
+                                ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex + 1)
+            else:
+                self._AllPCDs.append((self._Scope[0], self._ValueList[0], self._ValueList[1]))
+                self._AllPcdDict[TAB_SPLIT.join(self._ValueList[0:2])] = ValueList[0]
+
+            self._ValueList[2] = ValueList[0].strip() + '|' + ValueList[1].strip() + '|' + ValueList[2].strip()
 
     _SectionParser = {
         MODEL_META_DATA_HEADER          :   MetaFileParser._DefineParser,
--
2.26.2.windows.1



 


Bret Barkelew
 

Ah! Gotcha. I missed that this was specific to ECC. Thanks!

 

- Bret

 

From: Chen, Christine
Sent: Wednesday, April 7, 2021 6:42 PM
To: Bret Barkelew; devel@edk2.groups.io
Cc: Liang, MingyueX; Feng, Bob C; Liming Gao
Subject: RE: [EXTERNAL] [edk2-devel] [PATCH 1/1] BaseTools/Ecc: Update structpcd parsing method.

 

Hi Bret,

 

This patch adds the ECC check for structurePcd written in des/dsc file, as the origin check is only for non-structured Pcd.

 

Best Regards,

Yuwei (Christine)

 

From: Bret Barkelew <Bret.Barkelew@...>
Sent: Friday, April 2, 2021 12:43 AM
To: devel@edk2.groups.io; Chen, Christine <yuwei.chen@...>
Cc: Liang, MingyueX <mingyuex.liang@...>; Feng, Bob C <bob.c.feng@...>; Liming Gao <gaoliming@...>
Subject: RE: [EXTERNAL] [edk2-devel] [PATCH 1/1] BaseTools/Ecc: Update structpcd parsing method.

 

What does “update” mean in this context? What behavior is changing?

 

- Bret

 

From: Yuwei Chen via groups.io
Sent: Thursday, April 1, 2021 12:04 AM
To: devel@edk2.groups.io
Cc: mliang2x; Feng, Bob C; Liming Gao
Subject: [EXTERNAL] [edk2-devel] [PATCH 1/1] BaseTools/Ecc: Update structpcd parsing method.

 

From: mliang2x <mingyuex.liang@...>

Update the pcdparser method in Dec and DSC files.

Signed-off-by: Mingyue Liang <mingyuex.liang@...>
Cc: Bob Feng <bob.c.feng@...>
Cc: Liming Gao <gaoliming@...>
Cc: Yuwei Chen <yuwei.chen@...>
---
 .../Ecc/MetaFileWorkspace/MetaFileParser.py   | 464 ++++++++++--------
 1 file changed, 265 insertions(+), 199 deletions(-)

diff --git a/BaseTools/Source/Python/Ecc/MetaFileWorkspace/MetaFileParser.py b/BaseTools/Source/Python/Ecc/MetaFileWorkspace/MetaFileParser.py
index 9c27c8e16a05..588d3dbe6ed5 100644
--- a/BaseTools/Source/Python/Ecc/MetaFileWorkspace/MetaFileParser.py
+++ b/BaseTools/Source/Python/Ecc/MetaFileWorkspace/MetaFileParser.py
@@ -22,7 +22,7 @@ import Ecc.EccToolError as EccToolError
 from CommonDataClass.DataClass import *
 from Common.DataType import *
 from Common.StringUtils import *
-from Common.Misc import GuidStructureStringToGuidString, CheckPcdDatum, PathClass, AnalyzePcdData
+from Common.Misc import GuidStructureStringToGuidString, CheckPcdDatum, PathClass, AnalyzePcdData, AnalyzeDscPcd, AnalyzePcdExpression, ParseFieldValue, StructPattern
 from Common.Expression import *
 from CommonDataClass.Exceptions import *
 
@@ -31,6 +31,8 @@ from GenFds.FdfParser import FdfParser
 from Common.LongFilePathSupport import OpenLongFilePath as open
 from Common.LongFilePathSupport import CodecOpenLongFilePath
 
+CODEPattern = re.compile(r"{CODE\([a-fA-F0-9Xx\{\},\s]*\)}")
+
 ## A decorator used to parse macro definition
 def ParseMacro(Parser):
     def MacroParser(self):
@@ -174,6 +176,11 @@ class MetaFileParser(object):
         # UNI object and extra UNI object
         self._UniObj = None
         self._UniExtraObj = None
+        # StructPcd var
+        self._PcdCodeValue = ""
+        self._PcdDataTypeCODE = False
+        self._CurrentPcdName = ""
+        self._GuidDict = {}  # for Parser PCD value {GUID(gTokeSpaceGuidName)}
 
     ## Store the parsed data in table
     def _Store(self, *Args):
@@ -395,6 +402,40 @@ class MetaFileParser(object):
                 Macros.update(self._SectionsMacroDict[(self._SectionType, Scope1, Scope2)])
         return Macros
 
+    def ProcessMultipleLineCODEValue(self, Content):
+        CODEBegin = False
+        CODELine = ""
+        continuelinecount = 0
+        newContent = []
+        for Index in range(0, len(Content)):
+            Line = Content[Index]
+            if CODEBegin:
+                CODELine = CODELine + Line
+                continuelinecount +=1
+                if ")}" in Line:
+                    newContent.append(CODELine)
+                    for _ in range(continuelinecount):
+                        newContent.append("")
+                    CODEBegin = False
+                    CODELine = ""
+                    continuelinecount = 0
+            else:
+                if not Line:
+                    newContent.append(Line)
+                    continue
+                if "{CODE(" not in Line:
+                    newContent.append(Line)
+                    continue
+                elif CODEPattern.findall(Line):
+                    newContent.append(Line)
+                    continue
+                else:
+                    CODEBegin = True
+                    CODELine = Line
+
+        return newContent
+
+
     _SectionParser  = {}
     Finished        = property(_GetFinished, _SetFinished)
     _Macros         = property(_GetMacros)
@@ -812,6 +853,8 @@ class DscParser(MetaFileParser):
             Content = open(str(self.MetaFile.Path), 'r').readlines()
         except:
             EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
+
+        Content = self.ProcessMultipleLineCODEValue(Content)
         #
         # Insert a record for file
         #
@@ -1018,24 +1061,71 @@ class DscParser(MetaFileParser):
     #
     @ParseMacro
     def _PcdParser(self):
+        if self._PcdDataTypeCODE:
+            self._PcdCodeValue = self._PcdCodeValue + "\n " + self._CurrentLine
+            if self._CurrentLine.endswith(")}"):
+                self._CurrentLine = "|".join((self._CurrentPcdName, self._PcdCodeValue))
+                self._PcdDataTypeCODE = False
+                self._PcdCodeValue = ""
+            else:
+                self._ValueList = None
+                return
         TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
+        self._CurrentPcdName = TokenList[0]
+        if len(TokenList) == 2 and TokenList[1].strip().startswith("{CODE"):
+            self._PcdDataTypeCODE = True
+            self._PcdCodeValue = TokenList[1].strip()
+
+        if self._PcdDataTypeCODE:
+            if self._CurrentLine.endswith(")}"):
+                self._PcdDataTypeCODE = False
+                self._PcdCodeValue = ""
+            else:
+                self._ValueList = None
+                return
         self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
+        PcdNameTockens = GetSplitValueList(TokenList[0], TAB_SPLIT)
+        if len(PcdNameTockens) == 2:
+            self._ValueList[0], self._ValueList[1] = PcdNameTockens[0], PcdNameTockens[1]
+        elif len(PcdNameTockens) == 3:
+            self._ValueList[0], self._ValueList[1] = ".".join((PcdNameTockens[0], PcdNameTockens[1])), PcdNameTockens[2]
+        elif len(PcdNameTockens) > 3:
+            self._ValueList[0], self._ValueList[1] = ".".join((PcdNameTockens[0], PcdNameTockens[1])), ".".join(PcdNameTockens[2:])
         if len(TokenList) == 2:
             self._ValueList[2] = TokenList[1]
         if self._ValueList[0] == '' or self._ValueList[1] == '':
             EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
                             ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<TokenCName>|<PcdValue>)",
-                            File=self.MetaFile, Line=self._LineIndex+1)
+                            File=self.MetaFile, Line=self._LineIndex + 1)
         if self._ValueList[2] == '':
+            #
+            # The PCD values are optional for FIXEDATBUILD, PATCHABLEINMODULE, Dynamic/DynamicEx default
+            #
+            if self._SectionType in (MODEL_PCD_FIXED_AT_BUILD, MODEL_PCD_PATCHABLE_IN_MODULE, MODEL_PCD_DYNAMIC_DEFAULT, MODEL_PCD_DYNAMIC_EX_DEFAULT):
+                return
             EdkLogger.error('Parser', FORMAT_INVALID, "No PCD value given",
                             ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<TokenCName>|<PcdValue>)",
-                            File=self.MetaFile, Line=self._LineIndex+1)
+                            File=self.MetaFile, Line=self._LineIndex + 1)
+
+        # Validate the datum type of Dynamic Defaul PCD and DynamicEx Default PCD
+        ValueList = GetSplitValueList(self._ValueList[2])
+        if len(ValueList) > 1 and ValueList[1] in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64] \
+                              and self._ItemType in [MODEL_PCD_DYNAMIC_DEFAULT, MODEL_PCD_DYNAMIC_EX_DEFAULT]:
+            EdkLogger.error('Parser', FORMAT_INVALID, "The datum type '%s' of PCD is wrong" % ValueList[1],
+                            ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex + 1)
+
+        # Validate the VariableName of DynamicHii and DynamicExHii for PCD Entry must not be an empty string
+        if self._ItemType in [MODEL_PCD_DYNAMIC_HII, MODEL_PCD_DYNAMIC_EX_HII]:
+            DscPcdValueList = GetSplitValueList(TokenList[1], TAB_VALUE_SPLIT, 1)
+            if len(DscPcdValueList[0].replace('L', '').replace('"', '').strip()) == 0:
+                EdkLogger.error('Parser', FORMAT_INVALID, "The VariableName field in the HII format PCD entry must not be an empty string",
+                            ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex + 1)
         # if value are 'True', 'true', 'TRUE' or 'False', 'false', 'FALSE', replace with integer 1 or 0.
         DscPcdValueList = GetSplitValueList(TokenList[1], TAB_VALUE_SPLIT, 1)
         if DscPcdValueList[0] in ['True', 'true', 'TRUE']:
-            self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '1', 1);
+            self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '1', 1)
         elif DscPcdValueList[0] in ['False', 'false', 'FALSE']:
-            self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '0', 1);
+            self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '0', 1)
 
     ## [components] section parser
     @ParseMacro
@@ -1502,6 +1592,10 @@ class DecParser(MetaFileParser):
         self._include_flag = False
         self._package_flag = False
 
+        self._AllPCDs = [] # Only for check duplicate PCD
+        self._AllPcdDict = {}
+
+
     ## Parser starter
     def Start(self):
         Content = ''
@@ -1510,6 +1604,7 @@ class DecParser(MetaFileParser):
         except:
             EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
 
+        Content = self.ProcessMultipleLineCODEValue(Content)
         #
         # Insert a record for file
         #
@@ -1707,51 +1802,6 @@ class DecParser(MetaFileParser):
                 namelist[2] = ".".join((arrayindex,namelist[2]))
         return namelist
 
-    def StructPcdParser(self):
-        self._ValueList[0] = self._CurrentStructurePcdName
-
-        if "|" not in self._CurrentLine:
-            if "<HeaderFiles>" == self._CurrentLine:
-                self._include_flag = True
-                self._package_flag = False
-                self._ValueList = None
-                return
-            if "<Packages>" == self._CurrentLine:
-                self._package_flag = True
-                self._ValueList = None
-                self._include_flag = False
-                return
-
-            if self._include_flag:
-                self._ValueList[1] = "<HeaderFiles>_" + md5(self._CurrentLine.encode('utf-8')).hexdigest()
-                self._ValueList[2] = self._CurrentLine
-            if self._package_flag and "}" != self._CurrentLine:
-                self._ValueList[1] = "<Packages>_" + md5(self._CurrentLine.encode('utf-8')).hexdigest()
-                self._ValueList[2] = self._CurrentLine
-            if self._CurrentLine == "}":
-                self._package_flag = False
-                self._include_flag = False
-                self._ValueList = None
-        else:
-            PcdTockens = self._CurrentLine.split(TAB_VALUE_SPLIT)
-            PcdNames = self.ParsePcdName(PcdTockens[0].split(TAB_SPLIT))
-            if len(PcdNames) == 2:
-                if PcdNames[1].strip().endswith("]"):
-                    PcdName = PcdNames[1][:PcdNames[1].index('[')]
-                    Index = PcdNames[1][PcdNames[1].index('['):]
-                    self._ValueList[0] = TAB_SPLIT.join((PcdNames[0], PcdName))
-                    self._ValueList[1] = Index
-                    self._ValueList[2] = PcdTockens[1]
-                else:
-                    self._CurrentStructurePcdName = ""
-            else:
-                if self._CurrentStructurePcdName != TAB_SPLIT.join(PcdNames[:2]):
-                    EdkLogger.error('Parser', FORMAT_INVALID, "Pcd Name does not match: %s and %s " % (
-                    self._CurrentStructurePcdName, TAB_SPLIT.join(PcdNames[:2])),
-                                    File=self.MetaFile, Line=self._LineIndex + 1)
-                self._ValueList[1] = TAB_SPLIT.join(PcdNames[2:])
-                self._ValueList[2] = PcdTockens[1]
-
     ## PCD sections parser
     #
     #   [PcdsFixedAtBuild]
@@ -1763,159 +1813,175 @@ class DecParser(MetaFileParser):
     @ParseMacro
     def _PcdParser(self):
         if self._CurrentStructurePcdName:
-            self.StructPcdParser()
-            return
-        TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
-        self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
-        # check PCD information
-        if self._ValueList[0] == '' or self._ValueList[1] == '':
-            EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
-                            ExtraData=self._CurrentLine + \
-                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
-                            File=self.MetaFile, Line=self._LineIndex+1)
-        # check PCD datum information
-        if len(TokenList) < 2 or TokenList[1] == '':
-            EdkLogger.error('Parser', FORMAT_INVALID, "No PCD Datum information given",
-                            ExtraData=self._CurrentLine + \
-                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
-                            File=self.MetaFile, Line=self._LineIndex+1)
-
-
-        ValueRe  = re.compile(r'^\s*L?\".*\|.*\"')
-        PtrValue = ValueRe.findall(TokenList[1])
-
-        # Has VOID* type string, may contain "|" character in the string.
-        if len(PtrValue) != 0:
-            ptrValueList = re.sub(ValueRe, '', TokenList[1])
-            ValueList    = GetSplitValueList(ptrValueList)
-            ValueList[0] = PtrValue[0]
-        else:
-            ValueList = GetSplitValueList(TokenList[1])
-
-
-        # check if there's enough datum information given
-        if len(ValueList) != 3:
-            EdkLogger.error('Parser', FORMAT_INVALID, "Invalid PCD Datum information given",
-                            ExtraData=self._CurrentLine + \
-                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
-                            File=self.MetaFile, Line=self._LineIndex+1)
-        # check default value
-        if ValueList[0] == '':
-            EdkLogger.error('Parser', FORMAT_INVALID, "Missing DefaultValue in PCD Datum information",
-                            ExtraData=self._CurrentLine + \
-                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
-                            File=self.MetaFile, Line=self._LineIndex+1)
-        # check datum type
-        if ValueList[1] == '':
-            EdkLogger.error('Parser', FORMAT_INVALID, "Missing DatumType in PCD Datum information",
-                            ExtraData=self._CurrentLine + \
-                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
-                            File=self.MetaFile, Line=self._LineIndex+1)
-        # check token of the PCD
-        if ValueList[2] == '':
-            EdkLogger.error('Parser', FORMAT_INVALID, "Missing Token in PCD Datum information",
-                            ExtraData=self._CurrentLine + \
-                                      " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
-                            File=self.MetaFile, Line=self._LineIndex+1)
-        # check format of default value against the datum type
-        IsValid, Cause = CheckPcdDatum(ValueList[1], ValueList[0])
-        if not IsValid:
-            EdkLogger.error('Parser', FORMAT_INVALID, Cause, ExtraData=self._CurrentLine,
-                            File=self.MetaFile, Line=self._LineIndex+1)
-        if Cause == "StructurePcd":
-            self._CurrentStructurePcdName = TAB_SPLIT.join(self._ValueList[0:2])
             self._ValueList[0] = self._CurrentStructurePcdName
-            self._ValueList[1] = ValueList[1].strip()
 
-        if EccGlobalData.gConfig.UniCheckPCDInfo == '1' or EccGlobalData.gConfig.UniCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
-            # check Description, Prompt information
-            PatternDesc = re.compile('##\s*([\x21-\x7E\s]*)', re.S)
-            PatternPrompt = re.compile('#\s+@Prompt\s+([\x21-\x7E\s]*)', re.S)
-            Description = None
-            Prompt = None
-            # check @ValidRange, @ValidList and @Expression format valid
-            ErrorCodeValid = '0x0 <= %s <= 0xFFFFFFFF'
-            PatternValidRangeIn = '(NOT)?\s*(\d+\s*-\s*\d+|0[xX][a-fA-F0-9]+\s*-\s*0[xX][a-fA-F0-9]+|LT\s*\d+|LT\s*0[xX][a-fA-F0-9]+|GT\s*\d+|GT\s*0[xX][a-fA-F0-9]+|LE\s*\d+|LE\s*0[xX][a-fA-F0-9]+|GE\s*\d+|GE\s*0[xX][a-fA-F0-9]+|XOR\s*\d+|XOR\s*0[xX][a-fA-F0-9]+|EQ\s*\d+|EQ\s*0[xX][a-fA-F0-9]+)'
-            PatternValidRng = re.compile('^' + '(NOT)?\s*' + PatternValidRangeIn + '$')
-            for Comment in self._Comments:
-                Comm = Comment[0].strip()
-                if not Comm:
-                    continue
-                if not Description:
-                    Description = PatternDesc.findall(Comm)
-                if not Prompt:
-                    Prompt = PatternPrompt.findall(Comm)
-                if Comm[0] == '#':
-                    ValidFormt = Comm.lstrip('#')
-                    ValidFormt = ValidFormt.lstrip()
-                    if ValidFormt[0:11] == '@ValidRange':
-                        ValidFormt = ValidFormt[11:]
-                        ValidFormt = ValidFormt.lstrip()
-                        try:
-                            ErrorCode, Expression = ValidFormt.split('|', 1)
-                        except ValueError:
-                            ErrorCode = '0x0'
-                            Expression = ValidFormt
-                        ErrorCode, Expression = ErrorCode.strip(), Expression.strip()
-                        try:
-                            if not eval(ErrorCodeValid % ErrorCode):
-                                EdkLogger.warn('Parser', '@ValidRange ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
-                        except:
-                            EdkLogger.warn('Parser', '@ValidRange ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
-                        if not PatternValidRng.search(Expression):
-                            EdkLogger.warn('Parser', '@ValidRange Expression(%s) of PCD %s is incorrect format.' % (Expression, TokenList[0]))
-                    if ValidFormt[0:10] == '@ValidList':
-                        ValidFormt = ValidFormt[10:]
-                        ValidFormt = ValidFormt.lstrip()
-                        try:
-                            ErrorCode, Expression = ValidFormt.split('|', 1)
-                        except ValueError:
-                            ErrorCode = '0x0'
-                            Expression = ValidFormt
-                        ErrorCode, Expression = ErrorCode.strip(), Expression.strip()
-                        try:
-                            if not eval(ErrorCodeValid % ErrorCode):
-                                EdkLogger.warn('Parser', '@ValidList ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
-                        except:
-                            EdkLogger.warn('Parser', '@ValidList ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
-                        Values = Expression.split(',')
-                        for Value in Values:
-                            Value = Value.strip()
-                            try:
-                                eval(Value)
-                            except:
-                                EdkLogger.warn('Parser', '@ValidList Expression of PCD %s include a invalid value(%s).' % (TokenList[0], Value))
-                                break
-                    if ValidFormt[0:11] == '@Expression':
-                        ValidFormt = ValidFormt[11:]
-                        ValidFormt = ValidFormt.lstrip()
-                        try:
-                            ErrorCode, Expression = ValidFormt.split('|', 1)
-                        except ValueError:
-                            ErrorCode = '0x0'
-                            Expression = ValidFormt
-                        ErrorCode, Expression = ErrorCode.strip(), Expression.strip()
-                        try:
-                            if not eval(ErrorCodeValid % ErrorCode):
-                                EdkLogger.warn('Parser', '@Expression ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
-                        except:
-                            EdkLogger.warn('Parser', '@Expression ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
-                        if not Expression:
-                            EdkLogger.warn('Parser', '@Expression Expression of PCD %s is incorrect format.' % TokenList[0])
-            if not Description:
-                EdkLogger.warn('Parser', 'PCD %s Description information is not provided.' % TokenList[0])
-            if not Prompt:
-                EdkLogger.warn('Parser', 'PCD %s Prompt information is not provided.' % TokenList[0])
-            # check Description, Prompt localization information
-            if self._UniObj:
-                self._UniObj.CheckPcdInfo(TokenList[0])
+            if "|" not in self._CurrentLine:
+                if "<HeaderFiles>" == self._CurrentLine:
+                    self._include_flag = True
+                    self._package_flag = False
+                    self._ValueList = None
+                    return
+                if "<Packages>" == self._CurrentLine:
+                    self._package_flag = True
+                    self._ValueList = None
+                    self._include_flag = False
+                    return
 
-        if ValueList[0] in ['True', 'true', 'TRUE']:
-            ValueList[0] = '1'
-        elif ValueList[0] in ['False', 'false', 'FALSE']:
-            ValueList[0] = '0'
+                if self._include_flag:
+                    self._ValueList[1] = "<HeaderFiles>_" + md5(self._CurrentLine.encode('utf-8')).hexdigest()
+                    self._ValueList[2] = self._CurrentLine
+                if self._package_flag and "}" != self._CurrentLine:
+                    self._ValueList[1] = "<Packages>_" + md5(self._CurrentLine.encode('utf-8')).hexdigest()
+                    self._ValueList[2] = self._CurrentLine
+                if self._CurrentLine == "}":
+                    self._package_flag = False
+                    self._include_flag = False
+                    self._ValueList = None
+                    return
+            else:
+                PcdTockens = self._CurrentLine.split(TAB_VALUE_SPLIT)
+                PcdNames = self.ParsePcdName(PcdTockens[0].split(TAB_SPLIT))
+                if len(PcdNames) == 2:
+                    if PcdNames[1].strip().endswith("]"):
+                        PcdName = PcdNames[1][:PcdNames[1].index('[')]
+                        Index = PcdNames[1][PcdNames[1].index('['):]
+                        self._ValueList[0] = TAB_SPLIT.join((PcdNames[0],PcdName))
+                        self._ValueList[1] = Index
+                        self._ValueList[2] = PcdTockens[1]
+                    else:
+                        self._CurrentStructurePcdName = ""
+                else:
+                    if self._CurrentStructurePcdName != TAB_SPLIT.join(PcdNames[:2]):
+                        EdkLogger.error('Parser', FORMAT_INVALID, "Pcd Name does not match: %s and %s " % (self._CurrentStructurePcdName, TAB_SPLIT.join(PcdNames[:2])),
+                                File=self.MetaFile, Line=self._LineIndex + 1)
+                    self._ValueList[1] = TAB_SPLIT.join(PcdNames[2:])
+                    self._ValueList[2] = PcdTockens[1]
 
-        self._ValueList[2] = ValueList[0].strip() + '|' + ValueList[1].strip() + '|' + ValueList[2].strip()
+        if not self._CurrentStructurePcdName:
+            if self._PcdDataTypeCODE:
+                if ")}" in self._CurrentLine:
+                    ValuePart, RestofValue = self._CurrentLine.split(")}")
+                    self._PcdCodeValue = self._PcdCodeValue + "\n " + ValuePart
+                    self._CurrentLine = "|".join((self._CurrentPcdName, self._PcdCodeValue, RestofValue))
+                    self._PcdDataTypeCODE = False
+                    self._PcdCodeValue = ""
+                else:
+                    self._PcdCodeValue = self._PcdCodeValue + "\n " + self._CurrentLine
+                    self._ValueList = None
+                    return
+            TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
+            self._CurrentPcdName = TokenList[0]
+            if len(TokenList) == 2 and TokenList[1].strip().startswith("{CODE"):
+                if ")}" in self._CurrentLine:
+                    self._PcdDataTypeCODE = False
+                    self._PcdCodeValue = ""
+                else:
+                    self._PcdDataTypeCODE = True
+                    self._PcdCodeValue = TokenList[1].strip()
+                    self._ValueList = None
+                    return
+
+            self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
+            ValueRe = re.compile(r'^[a-zA-Z_][a-zA-Z0-9_]*')
+            # check PCD information
+            if self._ValueList[0] == '' or self._ValueList[1] == '':
+                EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
+                                ExtraData=self._CurrentLine + \
+                                          " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
+                                File=self.MetaFile, Line=self._LineIndex+1)
+            # check format of token space GUID CName
+            if not ValueRe.match(self._ValueList[0]):
+                EdkLogger.error('Parser', FORMAT_INVALID,
+                                "The format of the token space GUID CName is invalid. The correct format is '(a-zA-Z_)[a-zA-Z0-9_]*'",
+                                ExtraData=self._CurrentLine + \
+                                          " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
+                                File=self.MetaFile, Line=self._LineIndex + 1)
+            # check format of PCD CName
+            if not ValueRe.match(self._ValueList[1]):
+                EdkLogger.error('Parser', FORMAT_INVALID,
+                                "The format of the PCD CName is invalid. The correct format is '(a-zA-Z_)[a-zA-Z0-9_]*'",
+                                ExtraData=self._CurrentLine + \
+                                          " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
+                                File=self.MetaFile, Line=self._LineIndex + 1)
+
+            # check PCD datum information
+            if len(TokenList) < 2 or TokenList[1] == '':
+                EdkLogger.error('Parser', FORMAT_INVALID, "No PCD Datum information given",
+                                ExtraData=self._CurrentLine + \
+                                          " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
+                                File=self.MetaFile, Line=self._LineIndex+1)
+
+
+            ValueRe = re.compile(r'^\s*L?\".*\|.*\"')
+            PtrValue = ValueRe.findall(TokenList[1])
+
+            # Has VOID* type string, may contain "|" character in the string.
+            if len(PtrValue) != 0:
+                ptrValueList = re.sub(ValueRe, '', TokenList[1])
+                ValueList = AnalyzePcdExpression(ptrValueList)
+                ValueList[0] = PtrValue[0]
+            else:
+                ValueList = AnalyzePcdExpression(TokenList[1])
+
+
+            # check if there's enough datum information given
+            if len(ValueList) != 3:
+                EdkLogger.error('Parser', FORMAT_INVALID, "Invalid PCD Datum information given",
+                                ExtraData=self._CurrentLine + \
+                                          " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
+                                File=self.MetaFile, Line=self._LineIndex + 1)
+            # check default value
+            if ValueList[0] == '':
+                EdkLogger.error('Parser', FORMAT_INVALID, "Missing DefaultValue in PCD Datum information",
+                                ExtraData=self._CurrentLine + \
+                                          " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
+                                File=self.MetaFile, Line=self._LineIndex + 1)
+            # check datum type
+            if ValueList[1] == '':
+                EdkLogger.error('Parser', FORMAT_INVALID, "Missing DatumType in PCD Datum information",
+                                ExtraData=self._CurrentLine + \
+                                          " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
+                                File=self.MetaFile, Line=self._LineIndex + 1)
+            # check token of the PCD
+            if ValueList[2] == '':
+                EdkLogger.error('Parser', FORMAT_INVALID, "Missing Token in PCD Datum information",
+                                ExtraData=self._CurrentLine + \
+                                          " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
+                                File=self.MetaFile, Line=self._LineIndex + 1)
+
+            PcdValue = ValueList[0]
+            if PcdValue:
+                try:
+                    self._GuidDict.update(self._AllPcdDict)
+                    ValueList[0] = ValueExpressionEx(ValueList[0], ValueList[1], self._GuidDict)(True)
+                except BadExpression as Value:
+                    EdkLogger.error('Parser', FORMAT_INVALID, Value, ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex + 1)
+            # check format of default value against the datum type
+            IsValid, Cause = CheckPcdDatum(ValueList[1], ValueList[0])
+            if not IsValid:
+                EdkLogger.error('Parser', FORMAT_INVALID, Cause, ExtraData=self._CurrentLine,
+                                File=self.MetaFile, Line=self._LineIndex + 1)
+
+            if Cause == "StructurePcd":
+                self._CurrentStructurePcdName = TAB_SPLIT.join(self._ValueList[0:2])
+                self._ValueList[0] = self._CurrentStructurePcdName
+                self._ValueList[1] = ValueList[1].strip()
+
+            if ValueList[0] in ['True', 'true', 'TRUE']:
+                ValueList[0] = '1'
+            elif ValueList[0] in ['False', 'false', 'FALSE']:
+                ValueList[0] = '0'
+
+            # check for duplicate PCD definition
+            if (self._Scope[0], self._ValueList[0], self._ValueList[1]) in self._AllPCDs:
+                EdkLogger.error('Parser', FORMAT_INVALID,
+                                "The same PCD name and GUID have been already defined",
+                                ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex + 1)
+            else:
+                self._AllPCDs.append((self._Scope[0], self._ValueList[0], self._ValueList[1]))
+                self._AllPcdDict[TAB_SPLIT.join(self._ValueList[0:2])] = ValueList[0]
+
+            self._ValueList[2] = ValueList[0].strip() + '|' + ValueList[1].strip() + '|' + ValueList[2].strip()
 
     _SectionParser = {
         MODEL_META_DATA_HEADER          :   MetaFileParser._DefineParser,
--
2.26.2.windows.1