## @file
# This file is used to parse and evaluate expression in directive or PCD value.
#
# Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
## Import Modules
#
from Common.GlobalData import *
WRN_EQCMP_STR_OTHERS = '== Comparison between Operand of string type and Boolean/Number Type always return False.'
WRN_NECMP_STR_OTHERS = '!= Comparison between Operand of string type and Boolean/Number Type always return True.'
ERR_RELCMP_STR_OTHERS = 'Operator taking Operand of string type and Boolean/Number Type is not allowed: [%s].'
ERR_IN_OPERAND = 'Macro after IN operator can only be: $(FAMILY), $(ARCH), $(TOOL_CHAIN_TAG) and $(TARGET).'
## SplitString
# Split string to list according double quote
# For example: abc"de\"f"ghi"jkl"mn will be: ['abc', '"de\"f"', 'ghi', '"jkl"', 'mn']
#
# There might be escaped quote: "abc\"def\\\"ghi"
RetList = []
Item = ''
if ch == '"':
if not InQuote:
Item = ''
continue
if Item:
Item = ''
if InQuote:
if Item:
return RetList
## ReplaceExprMacro
#
if MacroStartPos < 0:
continue
RetStr = ''
while MacroStartPos >= 0:
if MacroEndPos < 0:
# From C reference manual:
# If an undefined macro name appears in the constant-expression of
# !if or !elif, it is replaced by the integer constant 0.
RetStr += '0'
elif not InQuote:
raise BadExpression(ERR_IN_OPERAND)
# Make sure the macro in exception list is encapsulated by double quote
# For example: DEFINE ARCH = IA32 X64
# $(ARCH) is replaced with "IA32 X64"
else:
RetStr += '""'
else:
# Logical operator mapping
LogicalOperators = {
'&&' : 'and', '||' : 'or',
'!' : 'not', 'AND': 'and',
'OR' : 'or' , 'NOT': 'not',
'XOR': '^' , 'xor': '^',
'EQ' : '==' , 'NE' : '!=',
'GT' : '>' , 'LT' : '<',
'GE' : '>=' , 'LE' : '<=',
'IN' : 'in'
}
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}')
"\$\([A-Z][A-Z0-9_]*\)|\$\(\w+\.\w+\)|\w+\.\w+|"
"&&|\|\||!(?!=)|"
"(?<=\W)AND(?=\W)|(?<=\W)OR(?=\W)|(?<=\W)NOT(?=\W)|(?<=\W)XOR(?=\W)|"
"(?<=\W)EQ(?=\W)|(?<=\W)NE(?=\W)|(?<=\W)GT(?=\W)|(?<=\W)LT(?=\W)|(?<=\W)GE(?=\W)|(?<=\W)LE(?=\W)"
")")
WrnExp = None
TypeDict = {
}
EvalStr = ''
EvalStr = 'not Oprand1'
else:
# Boolean in '+'/'-' will be evaluated but raise warning
if Operator == "==":
raise WrnExp
elif Operator == "!=":
raise WrnExp
else:
if Operator in ["==", "!=", ">=", "<=", ">", "<"] and set((TypeDict[type(Oprand1)], TypeDict[type(Oprand2)])) == set((TypeDict[type(True)], TypeDict[type(0)])):
# comparison between number and boolean is allowed
pass
elif Operator in ['&', '|', '^', "and", "or"] and set((TypeDict[type(Oprand1)], TypeDict[type(Oprand2)])) == set((TypeDict[type(True)], TypeDict[type(0)])):
# bitwise and logical operation between number and boolean is allowed
pass
else:
raise BadExpression(ERR_EXPR_TYPE)
# Local symbols used by built in eval function
Dict = {
'Oprand1' : Oprand1,
'Oprand2' : Oprand2
}
try:
if Val:
else:
if WrnExp:
raise WrnExp
return Val
return
raise BadExpression(ERR_EMPTY_EXPR)
#
# The symbol table including PCD and macro mapping
#
self._WarnExcept = None
# Literal token without any conversion
# Public entry for this class
# @param RealValue: False: only evaluate if the expression is true or false, used for conditional expression
# True : return the evaluated str(value), used for PCD value
#
# @return: True or False if RealValue is False
# Evaluated value of string format if RealValue is True
#
if self._NoProcess:
if RealValue:
if self.__IsNumberToken():
try:
if type(Token) == type('') and Token.startswith('{') and Token.endswith('}') and self._Idx >= self._Len:
except BadExpression:
pass
if Val == 'L""':
elif not Val:
RealVal = '""'
# The expression has been parsed, but the end of expression is not reached
# It means the rest does not comply EBNF of <Expression>
if RealValue:
elif Val:
else:
if self._WarnExcept:
raise self._WarnExcept
else:
return RetVal
# Template function to parse binary operators which have same precedence
# Expr [Operator Expr]*
try:
except WrnExpression, Warn:
return Val
# A [|| B]*
# A [&& B]*
# A [ | B]*
# A [ ^ B]*
# A [ & B]*
# A [ == B]*
raise BadExpression(ERR_REL_NOT_IN)
try:
except WrnExpression, Warn:
return Val
# A [ > B]*
# A [ + B]*
# [!]*A
try:
except WrnExpression, Warn:
# Parse identifier or encapsulated expression
if Tk == '(':
try:
# _GetToken may also raise BadExpression
raise BadExpression(ERR_MATCH)
except BadExpression:
raise BadExpression(ERR_MATCH)
return Val
return Tk
# Skip whitespace or tab
if Char not in ' \t':
break
# Try to convert string to number
Radix = 10
Radix = 16
try:
return True
except ValueError:
return False
except TypeError:
return False
# Parse array: {...}
Token = '{'
Token += '}'
# All whitespace and tabs in array are already stripped.
# Parse string, the format must be: "..."
# Skip left quote
# Replace escape \\\", \"
if Ch == '"':
break
# Get token that is comprised by alphanumeric, underscore or dot(used by PCD)
# @param IsAlphaOp: Indicate if parsing general token or script operator(EQ, NE...)
IdToken = ''
break
if not IsAlphaOp:
# Try to resolve token
raise BadExpression(ERR_EMPTY_TOKEN)
# PCD token
raise Ex
return
else:
if not self.__IsHexLiteral():
if InArray:
NList += ','
if not self.__IsHexLiteral():
return True
if not Token:
else:
return True
return False
return self.__GetNList()
# Parse operand
# Skip L
if Expr:
return self.__GetIdToken()
elif Ch == '"':
return self.__GetString()
elif Ch == '{':
return self.__GetArray()
# Parse operator
# Reach end of expression
if not Expr:
return ''
# Script operator: LT, GT, LE, GE, EQ, NE, and, or, xor, not
# Start to get regular operator: +, -, <, > ...
return ''
OpToken = ''
break
else:
break
if OpToken not in LegalOpLst:
return OpToken
# Check if current token matches the operators given from OpList
return True
return False
if __name__ == '__main__':
pass
while True:
if input in 'qQ':
break
try:
except WrnExpression, Ex: