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#
15from Common.GlobalData import *
16from CommonDataClass.Exceptions import BadExpression
17from CommonDataClass.Exceptions import WrnExpression
18import uuid
19
20ERR_STRING_EXPR = 'This operator cannot be used in string expression: [%s].'
21ERR_SNYTAX = 'Syntax error, the rest of expression cannot be evaluated: [%s].'
22ERR_MATCH = 'No matching right parenthesis.'
23ERR_STRING_TOKEN = 'Bad string token: [%s].'
24ERR_MACRO_TOKEN = 'Bad macro token: [%s].'
25ERR_EMPTY_TOKEN = 'Empty token is not allowed.'
26ERR_PCD_RESOLVE = 'PCD token cannot be resolved: [%s].'
27ERR_VALID_TOKEN = 'No more valid token found from rest of string: [%s].'
28ERR_EXPR_TYPE = 'Different types found in expression.'
29ERR_OPERATOR_UNSUPPORT = 'Unsupported operator: [%s]'
30ERR_REL_NOT_IN = 'Expect "IN" after "not" operator.'
31WRN_BOOL_EXPR = 'Operand of boolean type cannot be used in arithmetic expression.'
32WRN_EQCMP_STR_OTHERS = '== Comparison between Operand of string type and Boolean/Number Type always return False.'
33WRN_NECMP_STR_OTHERS = '!= Comparison between Operand of string type and Boolean/Number Type always return True.'
34ERR_RELCMP_STR_OTHERS = 'Operator taking Operand of string type and Boolean/Number Type is not allowed: [%s].'
35ERR_STRING_CMP = 'Unicode string and general string cannot be compared: [%s %s %s]'
36ERR_ARRAY_TOKEN = 'Bad C array or C format GUID token: [%s].'
37ERR_ARRAY_ELE = 'This must be HEX value for NList or Array: [%s].'
38ERR_EMPTY_EXPR = 'Empty expression is not allowed.'
39ERR_IN_OPERAND = 'Macro after IN operator can only be: $(FAMILY), $(ARCH), $(TOOL_CHAIN_TAG) and $(TARGET).'
40
41def 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
51class 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
62class 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
103class 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
117class 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
129class 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
142class 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
155class 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
168class 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
181def 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
197class 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