Home | History | Annotate | Download | only in Common
      1 # # @file

      2 # This file is used to parse and evaluate range expression in Pcd declaration.

      3 #

      4 # Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>

      5 # This program and the accompanying materials

      6 # are licensed and made available under the terms and conditions of the BSD License

      7 # which accompanies this distribution.    The full text of the license may be found at

      8 # http://opensource.org/licenses/bsd-license.php

      9 #

     10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

     11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

     12 
     13 # # Import Modules

     14 #

     15 from Common.GlobalData import *
     16 from CommonDataClass.Exceptions import BadExpression
     17 from CommonDataClass.Exceptions import WrnExpression
     18 import uuid
     19 
     20 ERR_STRING_EXPR = 'This operator cannot be used in string expression: [%s].'
     21 ERR_SNYTAX = 'Syntax error, the rest of expression cannot be evaluated: [%s].'
     22 ERR_MATCH = 'No matching right parenthesis.'
     23 ERR_STRING_TOKEN = 'Bad string token: [%s].'
     24 ERR_MACRO_TOKEN = 'Bad macro token: [%s].'
     25 ERR_EMPTY_TOKEN = 'Empty token is not allowed.'
     26 ERR_PCD_RESOLVE = 'PCD token cannot be resolved: [%s].'
     27 ERR_VALID_TOKEN = 'No more valid token found from rest of string: [%s].'
     28 ERR_EXPR_TYPE = 'Different types found in expression.'
     29 ERR_OPERATOR_UNSUPPORT = 'Unsupported operator: [%s]'
     30 ERR_REL_NOT_IN = 'Expect "IN" after "not" operator.'
     31 WRN_BOOL_EXPR = 'Operand of boolean type cannot be used in arithmetic expression.'
     32 WRN_EQCMP_STR_OTHERS = '== Comparison between Operand of string type and Boolean/Number Type always return False.'
     33 WRN_NECMP_STR_OTHERS = '!= Comparison between Operand of string type and Boolean/Number Type always return True.'
     34 ERR_RELCMP_STR_OTHERS = 'Operator taking Operand of string type and Boolean/Number Type is not allowed: [%s].'
     35 ERR_STRING_CMP = 'Unicode string and general string cannot be compared: [%s %s %s]'
     36 ERR_ARRAY_TOKEN = 'Bad C array or C format GUID token: [%s].'
     37 ERR_ARRAY_ELE = 'This must be HEX value for NList or Array: [%s].'
     38 ERR_EMPTY_EXPR = 'Empty expression is not allowed.'
     39 ERR_IN_OPERAND = 'Macro after IN operator can only be: $(FAMILY), $(ARCH), $(TOOL_CHAIN_TAG) and $(TARGET).'
     40 
     41 def MaxOfType(DataType):
     42     if DataType == 'UINT8':
     43         return int('0xFF', 16)
     44     if DataType == 'UINT16':
     45         return int('0xFFFF', 16)
     46     if DataType == 'UINT32':
     47         return int('0xFFFFFFFF', 16)
     48     if DataType == 'UINT64':
     49         return int('0xFFFFFFFFFFFFFFFF', 16)
     50 
     51 class RangeObject(object):
     52     def __init__(self, start, end, empty = False):
     53         
     54         if int(start) < int(end):
     55             self.start = int(start)
     56             self.end = int(end)
     57         else:
     58             self.start = int(end)
     59             self.end = int(start)
     60         self.empty = empty
     61 
     62 class RangeContainer(object):
     63     def __init__(self):
     64         self.rangelist = []
     65         
     66     def push(self, RangeObject):
     67         self.rangelist.append(RangeObject)
     68         self.rangelist = sorted(self.rangelist, key = lambda rangeobj : rangeobj.start)
     69         self.merge()
     70         
     71     def pop(self):
     72         for item in self.rangelist:
     73             yield item
     74    
     75     def __clean__(self):   
     76         newrangelist = []
     77         for rangeobj in self.rangelist:
     78             if rangeobj.empty == True:
     79                 continue
     80             else:
     81                 newrangelist.append(rangeobj)
     82         self.rangelist = newrangelist      
     83     def merge(self):
     84         self.__clean__()
     85         for i in range(0, len(self.rangelist) - 1):
     86             if self.rangelist[i + 1].start > self.rangelist[i].end:
     87                 continue
     88             else:
     89                 self.rangelist[i + 1].start = self.rangelist[i].start
     90                 self.rangelist[i + 1].end = self.rangelist[i + 1].end > self.rangelist[i].end and self.rangelist[i + 1].end or self.rangelist[i].end 
     91                 self.rangelist[i].empty = True
     92 
     93         self.__clean__()
     94         
     95     def dump(self):
     96         print "----------------------"
     97         rangelist = ""
     98         for object in self.rangelist:
     99             rangelist = rangelist + "[%d , %d]" % (object.start, object.end)
    100         print rangelist
    101         
    102         
    103 class XOROperatorObject(object):   
    104     def __init__(self):     
    105         pass
    106     def Calculate(self, Operand, DataType, SymbolTable): 
    107         if type(Operand) == type('') and not Operand.isalnum():
    108             Expr = "XOR ..."
    109             raise BadExpression(ERR_SNYTAX % Expr)
    110         rangeId = str(uuid.uuid1())
    111         rangeContainer = RangeContainer()
    112         rangeContainer.push(RangeObject(0, int(Operand) - 1))
    113         rangeContainer.push(RangeObject(int(Operand) + 1, MaxOfType(DataType)))
    114         SymbolTable[rangeId] = rangeContainer
    115         return rangeId
    116 
    117 class LEOperatorObject(object):
    118     def __init__(self):     
    119         pass
    120     def Calculate(self, Operand, DataType, SymbolTable): 
    121         if type(Operand) == type('') and not Operand.isalnum():
    122             Expr = "LE ..."
    123             raise BadExpression(ERR_SNYTAX % Expr)
    124         rangeId1 = str(uuid.uuid1())
    125         rangeContainer = RangeContainer()
    126         rangeContainer.push(RangeObject(0, int(Operand)))
    127         SymbolTable[rangeId1] = rangeContainer
    128         return rangeId1
    129 class LTOperatorObject(object):
    130     def __init__(self):     
    131         pass
    132     def Calculate(self, Operand, DataType, SymbolTable):
    133         if type(Operand) == type('') and not Operand.isalnum():
    134             Expr = "LT ..." 
    135             raise BadExpression(ERR_SNYTAX % Expr) 
    136         rangeId1 = str(uuid.uuid1())
    137         rangeContainer = RangeContainer()
    138         rangeContainer.push(RangeObject(0, int(Operand) - 1))
    139         SymbolTable[rangeId1] = rangeContainer
    140         return rangeId1   
    141 
    142 class GEOperatorObject(object):
    143     def __init__(self):     
    144         pass
    145     def Calculate(self, Operand, DataType, SymbolTable): 
    146         if type(Operand) == type('') and not Operand.isalnum():
    147             Expr = "GE ..."
    148             raise BadExpression(ERR_SNYTAX % Expr)
    149         rangeId1 = str(uuid.uuid1())
    150         rangeContainer = RangeContainer()
    151         rangeContainer.push(RangeObject(int(Operand), MaxOfType(DataType)))
    152         SymbolTable[rangeId1] = rangeContainer
    153         return rangeId1   
    154       
    155 class GTOperatorObject(object):
    156     def __init__(self):     
    157         pass
    158     def Calculate(self, Operand, DataType, SymbolTable): 
    159         if type(Operand) == type('') and not Operand.isalnum():
    160             Expr = "GT ..."
    161             raise BadExpression(ERR_SNYTAX % Expr)
    162         rangeId1 = str(uuid.uuid1())
    163         rangeContainer = RangeContainer()
    164         rangeContainer.push(RangeObject(int(Operand) + 1, MaxOfType(DataType)))
    165         SymbolTable[rangeId1] = rangeContainer
    166         return rangeId1   
    167     
    168 class EQOperatorObject(object):
    169     def __init__(self):     
    170         pass
    171     def Calculate(self, Operand, DataType, SymbolTable): 
    172         if type(Operand) == type('') and not Operand.isalnum():
    173             Expr = "EQ ..."
    174             raise BadExpression(ERR_SNYTAX % Expr)
    175         rangeId1 = str(uuid.uuid1())
    176         rangeContainer = RangeContainer()
    177         rangeContainer.push(RangeObject(int(Operand) , int(Operand)))
    178         SymbolTable[rangeId1] = rangeContainer
    179         return rangeId1   
    180     
    181 def GetOperatorObject(Operator):
    182     if Operator == '>':
    183         return GTOperatorObject()
    184     elif Operator == '>=':
    185         return GEOperatorObject()
    186     elif Operator == '<':
    187         return LTOperatorObject()
    188     elif Operator == '<=':
    189         return LEOperatorObject()
    190     elif Operator == '==':
    191         return EQOperatorObject()
    192     elif Operator == '^':
    193         return XOROperatorObject()
    194     else:
    195         raise BadExpression("Bad Operator")
    196 
    197 class RangeExpression(object):
    198     # Logical operator mapping

    199     LogicalOperators = {
    200         '&&' : 'and', '||' : 'or',
    201         '!'  : 'not', 'AND': 'and',
    202         'OR' : 'or' , 'NOT': 'not',
    203         'XOR': '^'  , 'xor': '^',
    204         'EQ' : '==' , 'NE' : '!=',
    205         'GT' : '>'  , 'LT' : '<',
    206         'GE' : '>=' , 'LE' : '<=',
    207         'IN' : 'in'
    208     }
    209 
    210     NonLetterOpLst = ['+', '-', '&', '|', '^', '!', '=', '>', '<']
    211 
    212     PcdPattern = re.compile(r'[_a-zA-Z][0-9A-Za-z_]*\.[_a-zA-Z][0-9A-Za-z_]*$')
    213     HexPattern = re.compile(r'0[xX][0-9a-fA-F]+')
    214     RegGuidPattern = re.compile(r'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}')
    215     ExRegGuidPattern = re.compile(r'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$')
    216     
    217     SymbolPattern = re.compile("("
    218                                  "\$\([A-Z][A-Z0-9_]*\)|\$\(\w+\.\w+\)|\w+\.\w+|"
    219                                  "&&|\|\||!(?!=)|"
    220                                  "(?<=\W)AND(?=\W)|(?<=\W)OR(?=\W)|(?<=\W)NOT(?=\W)|(?<=\W)XOR(?=\W)|"
    221                                  "(?<=\W)EQ(?=\W)|(?<=\W)NE(?=\W)|(?<=\W)GT(?=\W)|(?<=\W)LT(?=\W)|(?<=\W)GE(?=\W)|(?<=\W)LE(?=\W)"
    222                                ")")
    223     
    224     RangePattern = re.compile(r'[0-9]+ - [0-9]+')
    225 
    226     def preProcessRangeExpr(self, expr):
    227         # convert hex to int

    228         # convert interval to object index. ex. 1 - 10 to a GUID

    229         expr = expr.strip()
    230         NumberDict = {}
    231         for HexNumber in self.HexPattern.findall(expr):
    232             Number = str(int(HexNumber, 16))
    233             NumberDict[HexNumber] = Number
    234         for HexNum in NumberDict:
    235             expr = expr.replace(HexNum, NumberDict[HexNum])
    236         
    237         rangedict = {}    
    238         for validrange in self.RangePattern.findall(expr):
    239             start, end = validrange.split(" - ")
    240             start = start.strip()
    241             end = end.strip()
    242             rangeid = str(uuid.uuid1())
    243             rangeContainer = RangeContainer()
    244             rangeContainer.push(RangeObject(start, end))
    245             self.operanddict[str(rangeid)] = rangeContainer
    246             rangedict[validrange] = str(rangeid)
    247             
    248         for validrange in rangedict:
    249             expr = expr.replace(validrange, rangedict[validrange])
    250          
    251         self._Expr = expr    
    252         return expr
    253             
    254         
    255     def EvalRange(self, Operator, Oprand):
    256 
    257         operatorobj = GetOperatorObject(Operator)
    258         return operatorobj.Calculate(Oprand, self.PcdDataType, self.operanddict)
    259         
    260     def Rangeintersection(self, Oprand1, Oprand2):
    261         rangeContainer1 = self.operanddict[Oprand1]
    262         rangeContainer2 = self.operanddict[Oprand2]
    263         rangeContainer = RangeContainer()
    264         for range1 in rangeContainer1.pop():
    265             for range2 in rangeContainer2.pop():
    266                 start1 = range1.start
    267                 end1 = range1.end
    268                 start2 = range2.start
    269                 end2 = range2.end
    270                 if start1 >= start2:
    271                     start1, start2 = start2, start1
    272                     end1, end2 = end2, end1
    273                 if range1.empty:
    274                     rangeid = str(uuid.uuid1())
    275                     rangeContainer.push(RangeObject(0, 0, True))
    276                 if end1 < start2:
    277                     rangeid = str(uuid.uuid1())
    278                     rangeContainer.push(RangeObject(0, 0, True))
    279                 elif end1 == start2:
    280                     rangeid = str(uuid.uuid1())
    281                     rangeContainer.push(RangeObject(end1, end1))
    282                 elif end1 <= end2 and end1 > start2:
    283                     rangeid = str(uuid.uuid1())
    284                     rangeContainer.push(RangeObject(start2, end1))
    285                 elif end1 >= end2:
    286                     rangeid = str(uuid.uuid1())
    287                     rangeContainer.push(RangeObject(start2, end2))
    288         
    289         self.operanddict[rangeid] = rangeContainer
    290 #        rangeContainer.dump()

    291         return rangeid
    292             
    293     def Rangecollections(self, Oprand1, Oprand2):
    294 
    295         rangeContainer1 = self.operanddict[Oprand1]
    296         rangeContainer2 = self.operanddict[Oprand2]
    297         rangeContainer = RangeContainer()
    298         
    299         for rangeobj in rangeContainer2.pop():
    300             rangeContainer.push(rangeobj)
    301         for rangeobj in rangeContainer1.pop():
    302             rangeContainer.push(rangeobj)
    303         
    304         rangeid = str(uuid.uuid1())
    305         self.operanddict[rangeid] = rangeContainer
    306         
    307 #        rangeContainer.dump()

    308         return rangeid
    309         
    310             
    311     def NegtiveRange(self, Oprand1):
    312         rangeContainer1 = self.operanddict[Oprand1]
    313         
    314         
    315         rangeids = []
    316         
    317         for rangeobj in rangeContainer1.pop():
    318             rangeContainer = RangeContainer()
    319             rangeid = str(uuid.uuid1())
    320             if rangeobj.empty:
    321                 rangeContainer.push(RangeObject(0, MaxOfType(self.PcdDataType)))
    322             else:
    323                 if rangeobj.start > 0:
    324                     rangeContainer.push(RangeObject(0, rangeobj.start - 1))
    325                 if rangeobj.end < MaxOfType(self.PcdDataType):
    326                     rangeContainer.push(RangeObject(rangeobj.end + 1, MaxOfType(self.PcdDataType)))
    327             self.operanddict[rangeid] = rangeContainer
    328             rangeids.append(rangeid)
    329 
    330         if len(rangeids) == 0:
    331             rangeContainer = RangeContainer()
    332             rangeContainer.push(RangeObject(0, MaxOfType(self.PcdDataType)))
    333             rangeid = str(uuid.uuid1())
    334             self.operanddict[rangeid] = rangeContainer
    335             return rangeid
    336 
    337         if len(rangeids) == 1:
    338             return rangeids[0]
    339 
    340         re = self.Rangeintersection(rangeids[0], rangeids[1])
    341         for i in range(2, len(rangeids)):
    342             re = self.Rangeintersection(re, rangeids[i])
    343             
    344         rangeid2 = str(uuid.uuid1())
    345         self.operanddict[rangeid2] = self.operanddict[re]
    346         return rangeid2
    347         
    348     def Eval(self, Operator, Oprand1, Oprand2 = None):
    349         
    350         if Operator in ["!", "NOT", "not"]:
    351             if not self.RegGuidPattern.match(Oprand1.strip()):
    352                 raise BadExpression(ERR_STRING_EXPR % Operator)
    353             return self.NegtiveRange(Oprand1)
    354         else:
    355             if Operator in ["==", ">=", "<=", ">", "<", '^']:
    356                 return self.EvalRange(Operator, Oprand1)
    357             elif Operator == 'and' :
    358                 if not self.ExRegGuidPattern.match(Oprand1.strip()) or not self.ExRegGuidPattern.match(Oprand2.strip()):
    359                     raise BadExpression(ERR_STRING_EXPR % Operator)
    360                 return self.Rangeintersection(Oprand1, Oprand2)    
    361             elif Operator == 'or':
    362                 if not self.ExRegGuidPattern.match(Oprand1.strip()) or not self.ExRegGuidPattern.match(Oprand2.strip()):
    363                     raise BadExpression(ERR_STRING_EXPR % Operator)
    364                 return self.Rangecollections(Oprand1, Oprand2)
    365             else:
    366                 raise BadExpression(ERR_STRING_EXPR % Operator)
    367 
    368 
    369     def __init__(self, Expression, PcdDataType, SymbolTable = {}):
    370         self._NoProcess = False
    371         if type(Expression) != type(''):
    372             self._Expr = Expression
    373             self._NoProcess = True
    374             return
    375 
    376         self._Expr = Expression.strip()
    377 
    378         if not self._Expr.strip():
    379             raise BadExpression(ERR_EMPTY_EXPR)
    380 
    381         #

    382         # The symbol table including PCD and macro mapping

    383         #

    384         self._Symb = SymbolTable
    385         self._Symb.update(self.LogicalOperators)
    386         self._Idx = 0
    387         self._Len = len(self._Expr)
    388         self._Token = ''
    389         self._WarnExcept = None
    390         
    391 
    392         # Literal token without any conversion

    393         self._LiteralToken = ''
    394         
    395         # store the operand object

    396         self.operanddict = {}
    397         # The Pcd max value depends on PcdDataType

    398         self.PcdDataType = PcdDataType
    399 
    400     # Public entry for this class

    401     #   @param RealValue: False: only evaluate if the expression is true or false, used for conditional expression

    402     #                     True : return the evaluated str(value), used for PCD value

    403     #

    404     #   @return: True or False if RealValue is False

    405     #            Evaluated value of string format if RealValue is True

    406     #

    407     def __call__(self, RealValue = False, Depth = 0):
    408         if self._NoProcess:
    409             return self._Expr
    410 
    411         self._Depth = Depth
    412 
    413         self._Expr = self._Expr.strip()
    414         
    415         self.preProcessRangeExpr(self._Expr)
    416         
    417         # check if the expression does not need to evaluate

    418         if RealValue and Depth == 0:
    419             self._Token = self._Expr
    420             if self.ExRegGuidPattern.match(self._Expr):
    421                 return [self.operanddict[self._Expr] ]
    422 
    423             self._Idx = 0
    424             self._Token = ''
    425 
    426         Val = self._OrExpr()
    427         RealVal = Val
    428         
    429         RangeIdList = RealVal.split("or")
    430         RangeList = []
    431         for rangeid in RangeIdList:
    432             RangeList.append(self.operanddict[rangeid.strip()])
    433             
    434         return RangeList
    435 
    436     # Template function to parse binary operators which have same precedence

    437     # Expr [Operator Expr]*

    438     def _ExprFuncTemplate(self, EvalFunc, OpLst):
    439         Val = EvalFunc()
    440         while self._IsOperator(OpLst):
    441             Op = self._Token
    442             try:
    443                 Val = self.Eval(Op, Val, EvalFunc())
    444             except WrnExpression, Warn:
    445                 self._WarnExcept = Warn
    446                 Val = Warn.result
    447         return Val
    448 
    449     # A [|| B]*

    450     def _OrExpr(self):
    451         return self._ExprFuncTemplate(self._AndExpr, ["OR", "or"])
    452 
    453     # A [&& B]*

    454     def _AndExpr(self):
    455         return self._ExprFuncTemplate(self._NeExpr, ["AND", "and"])
    456 
    457     def _NeExpr(self):
    458         Val = self._RelExpr()
    459         while self._IsOperator([ "!=", "NOT", "not"]):
    460             Op = self._Token
    461             if Op in ["!", "NOT", "not"]:
    462                 if not self._IsOperator(["IN", "in"]):
    463                     raise BadExpression(ERR_REL_NOT_IN)
    464                 Op += ' ' + self._Token
    465             try:
    466                 Val = self.Eval(Op, Val, self._RelExpr())
    467             except WrnExpression, Warn:
    468                 self._WarnExcept = Warn
    469                 Val = Warn.result
    470         return Val
    471 
    472     # [!]*A

    473     def _RelExpr(self):
    474         if self._IsOperator(["NOT" , "LE", "GE", "LT", "GT", "EQ", "XOR"]):
    475             Token = self._Token
    476             Val = self._NeExpr()
    477             try:
    478                 return self.Eval(Token, Val)
    479             except WrnExpression, Warn:
    480                 self._WarnExcept = Warn
    481                 return Warn.result
    482         return self._IdenExpr()
    483 
    484     # Parse identifier or encapsulated expression

    485     def _IdenExpr(self):
    486         Tk = self._GetToken()
    487         if Tk == '(':
    488             Val = self._OrExpr()
    489             try:
    490                 # _GetToken may also raise BadExpression

    491                 if self._GetToken() != ')':
    492                     raise BadExpression(ERR_MATCH)
    493             except BadExpression:
    494                 raise BadExpression(ERR_MATCH)
    495             return Val
    496         return Tk
    497 
    498     # Skip whitespace or tab

    499     def __SkipWS(self):
    500         for Char in self._Expr[self._Idx:]:
    501             if Char not in ' \t':
    502                 break
    503             self._Idx += 1
    504 
    505     # Try to convert string to number

    506     def __IsNumberToken(self):
    507         Radix = 10
    508         if self._Token.lower()[0:2] == '0x' and len(self._Token) > 2:
    509             Radix = 16
    510         try:
    511             self._Token = int(self._Token, Radix)
    512             return True
    513         except ValueError:
    514             return False
    515         except TypeError:
    516             return False
    517 
    518     # Parse array: {...}

    519     def __GetArray(self):
    520         Token = '{'
    521         self._Idx += 1
    522         self.__GetNList(True)
    523         Token += self._LiteralToken
    524         if self._Idx >= self._Len or self._Expr[self._Idx] != '}':
    525             raise BadExpression(ERR_ARRAY_TOKEN % Token)
    526         Token += '}'
    527 
    528         # All whitespace and tabs in array are already stripped.

    529         IsArray = IsGuid = False
    530         if len(Token.split(',')) == 11 and len(Token.split(',{')) == 2 \
    531             and len(Token.split('},')) == 1:
    532             HexLen = [11, 6, 6, 5, 4, 4, 4, 4, 4, 4, 6]
    533             HexList = Token.split(',')
    534             if HexList[3].startswith('{') and \
    535                 not [Index for Index, Hex in enumerate(HexList) if len(Hex) > HexLen[Index]]:
    536                 IsGuid = True
    537         if Token.lstrip('{').rstrip('}').find('{') == -1:
    538             if not [Hex for Hex in Token.lstrip('{').rstrip('}').split(',') if len(Hex) > 4]:
    539                 IsArray = True
    540         if not IsArray and not IsGuid:
    541             raise BadExpression(ERR_ARRAY_TOKEN % Token)
    542         self._Idx += 1
    543         self._Token = self._LiteralToken = Token
    544         return self._Token
    545 
    546     # Parse string, the format must be: "..."

    547     def __GetString(self):
    548         Idx = self._Idx
    549 
    550         # Skip left quote

    551         self._Idx += 1
    552 
    553         # Replace escape \\\", \"

    554         Expr = self._Expr[self._Idx:].replace('\\\\', '//').replace('\\\"', '\\\'')
    555         for Ch in Expr:
    556             self._Idx += 1
    557             if Ch == '"':
    558                 break
    559         self._Token = self._LiteralToken = self._Expr[Idx:self._Idx]
    560         if not self._Token.endswith('"'):
    561             raise BadExpression(ERR_STRING_TOKEN % self._Token)
    562         self._Token = self._Token[1:-1]
    563         return self._Token
    564 
    565     # Get token that is comprised by alphanumeric, underscore or dot(used by PCD)
    566     # @param IsAlphaOp: Indicate if parsing general token or script operator(EQ, NE...)
    567     def __GetIdToken(self, IsAlphaOp = False):
    568         IdToken = ''
    569         for Ch in self._Expr[self._Idx:]:
    570             if not self.__IsIdChar(Ch):
    571                 break
    572             self._Idx += 1
    573             IdToken += Ch
    574 
    575         self._Token = self._LiteralToken = IdToken
    576         if not IsAlphaOp:
    577             self.__ResolveToken()
    578         return self._Token
    579 
    580     # Try to resolve token
    581     def __ResolveToken(self):
    582         if not self._Token:
    583             raise BadExpression(ERR_EMPTY_TOKEN)
    584 
    585         # PCD token
    586         if self.PcdPattern.match(self._Token):
    587             if self._Token not in self._Symb:
    588                 Ex = BadExpression(ERR_PCD_RESOLVE % self._Token)
    589                 Ex.Pcd = self._Token
    590                 raise Ex
    591             self._Token = RangeExpression(self._Symb[self._Token], self._Symb)(True, self._Depth + 1)
    592             if type(self._Token) != type(''):
    593                 self._LiteralToken = hex(self._Token)
    594                 return
    595 
    596         if self._Token.startswith('"'):
    597             self._Token = self._Token[1:-1]
    598         elif self._Token in ["FALSE", "false", "False"]:
    599             self._Token = False
    600         elif self._Token in ["TRUE", "true", "True"]:
    601             self._Token = True
    602         else:
    603             self.__IsNumberToken()
    604 
    605     def __GetNList(self, InArray = False):
    606         self._GetSingleToken()
    607         if not self.__IsHexLiteral():
    608             if InArray:
    609                 raise BadExpression(ERR_ARRAY_ELE % self._Token)
    610             return self._Token
    611 
    612         self.__SkipWS()
    613         Expr = self._Expr[self._Idx:]
    614         if not Expr.startswith(','):
    615             return self._Token
    616 
    617         NList = self._LiteralToken
    618         while Expr.startswith(','):
    619             NList += ','
    620             self._Idx += 1
    621             self.__SkipWS()
    622             self._GetSingleToken()
    623             if not self.__IsHexLiteral():
    624                 raise BadExpression(ERR_ARRAY_ELE % self._Token)
    625             NList += self._LiteralToken
    626             self.__SkipWS()
    627             Expr = self._Expr[self._Idx:]
    628         self._Token = self._LiteralToken = NList
    629         return self._Token
    630 
    631     def __IsHexLiteral(self):
    632         if self._LiteralToken.startswith('{') and \
    633             self._LiteralToken.endswith('}'):
    634             return True
    635 
    636         if self.HexPattern.match(self._LiteralToken):
    637             Token = self._LiteralToken[2:]
    638             Token = Token.lstrip('0')
    639             if not Token:
    640                 self._LiteralToken = '0x0'
    641             else:
    642                 self._LiteralToken = '0x' + Token.lower()
    643             return True
    644         return False
    645 
    646     def _GetToken(self):
    647         return self.__GetNList()
    648 
    649     @staticmethod
    650     def __IsIdChar(Ch):
    651         return Ch in '._/:' or Ch.isalnum()
    652 
    653     # Parse operand
    654     def _GetSingleToken(self):
    655         self.__SkipWS()
    656         Expr = self._Expr[self._Idx:]
    657         if Expr.startswith('L"'):
    658             # Skip L
    659             self._Idx += 1
    660             UStr = self.__GetString()
    661             self._Token = 'L"' + UStr + '"'
    662             return self._Token
    663 
    664         self._Token = ''
    665         if Expr:
    666             Ch = Expr[0]
    667             Match = self.RegGuidPattern.match(Expr)
    668             if Match and not Expr[Match.end():Match.end() + 1].isalnum() \
    669                 and Expr[Match.end():Match.end() + 1] != '_':
    670                 self._Idx += Match.end()
    671                 self._Token = Expr[0:Match.end()]
    672                 return self._Token
    673             elif self.__IsIdChar(Ch):
    674                 return self.__GetIdToken()
    675             elif Ch == '(' or Ch == ')':
    676                 self._Idx += 1
    677                 self._Token = Ch
    678                 return self._Token
    679 
    680         raise BadExpression(ERR_VALID_TOKEN % Expr)
    681 
    682     # Parse operator
    683     def _GetOperator(self):
    684         self.__SkipWS()
    685         LegalOpLst = ['&&', '||', '!=', '==', '>=', '<='] + self.NonLetterOpLst
    686 
    687         self._Token = ''
    688         Expr = self._Expr[self._Idx:]
    689 
    690         # Reach end of expression
    691         if not Expr:
    692             return ''
    693 
    694         # Script operator: LT, GT, LE, GE, EQ, NE, and, or, xor, not
    695         if Expr[0].isalpha():
    696             return self.__GetIdToken(True)
    697 
    698         # Start to get regular operator: +, -, <, > ...
    699         if Expr[0] not in self.NonLetterOpLst:
    700             return ''
    701 
    702         OpToken = ''
    703         for Ch in Expr:
    704             if Ch in self.NonLetterOpLst:
    705                 if '!' == Ch and OpToken:
    706                     break
    707                 self._Idx += 1
    708                 OpToken += Ch
    709             else:
    710                 break
    711 
    712         if OpToken not in LegalOpLst:
    713             raise BadExpression(ERR_OPERATOR_UNSUPPORT % OpToken)
    714         self._Token = OpToken
    715         return OpToken
    716 
    717     # Check if current token matches the operators given from OpList
    718     def _IsOperator(self, OpList):
    719         Idx = self._Idx
    720         self._GetOperator()
    721         if self._Token in OpList:
    722             if self._Token in self.LogicalOperators:
    723                 self._Token = self.LogicalOperators[self._Token]
    724             return True
    725         self._Idx = Idx
    726         return False
    727 
    728 
    729     
    730     
    731     
    732     
    733 
    734 
    735 
    736 
    737 #    UTRangeList()
    738