in src/foundation_library/Expression.cpp [320:576]
static HRESULT ExpressionToRpn(
const foundation::string_t& expression,
_TokenBaseVectorType &rpn,
std::set<foundation::string_t> &references)
{
const string_t _false_keyword(U("false"));
const string_t _true_keyword(U("true"));
std::stack<CTokenBase *> st;
for (size_t i=0; i < expression.length();i++)
{
CHAR_t nextToken = expression[i];
// skip white space
if (iswspace(nextToken))
{
continue;
}
// push left parenthesis
else if (nextToken == U('('))
{
st.push(new CTokenParenthesis(true));
continue;
}
// flush all stack till matching the left-parenthesis
else if (nextToken == U(')'))
{
for (;;)
{
// could not match left-parenthesis
if (st.empty())
return E_UNEXPECTED;
CTokenBase *pTopTokenBase = st.top();
st.pop();
if (IsLeftParenthesis(pTopTokenBase))
{
delete pTopTokenBase;
break;
}
rpn.push_back(pTopTokenBase);
}
continue;
}
// is this an operator?
int operatorTypeInfoIndex = isOperator(expression.substr(i));
// an operand
if (operatorTypeInfoIndex == -1)
{
size_t pos = foundation::string_t::npos;
if(nextToken == U('{'))
{
pos = expression.find(U('}'),i);
if(pos == expression.npos)
{
return E_UNEXPECTED;
}
foundation::string_t referenceToken = expression.substr(i+1, pos - i -1 );
if (referenceToken.length() ==0)
{
return E_UNEXPECTED;
}
references.insert(referenceToken);
rpn.push_back(new CTokenReferenceValue(referenceToken.data()));
}
else if(nextToken == U('\''))
{
// lookup for end of string
pos = expression.find(U('\''),i + 1);
if(pos == expression.npos)
{
return E_UNEXPECTED;
}
// construct a string
PropertyValuePtr stringValue =
pv_util::ToPropertyValuePtr
(
pv_util::CreateValue(expression.substr(i+1, pos - i -1 ).c_str())
);
rpn.push_back(new CTokenValue(stringValue));
}
else if (expression.compare(0, _false_keyword.length(),_false_keyword) == 0)
{
pos += _false_keyword.length();
rpn.push_back(new CTokenValue(false));
}
else if (expression.compare(0, _true_keyword.length(), _true_keyword) == 0)
{
pos += _true_keyword.length();
rpn.push_back(new CTokenValue(true));
}
else
{
foundation::string_t value_str;
// attempt to find the end token of a value
pos = i;
bool isDouble = false;
bool isHex = false;
bool isSigned = false;
while(pos < expression.size())
{
CHAR_t c = expression[pos];
if(c == U('x'))
{
if(pos > 0 && expression[pos-1]==U('0'))
{
isHex = true;
value_str = U("");
}
}
else if(c == '-')
{
isSigned = true;
value_str += c;
}
else if(c == '.')
{
isDouble = true;
value_str += c;
}
else if(isxdigit(c))
{
value_str += c;
}
else
{
break;
}
++pos;
}
--pos; // adjust the value termination position
if(value_str.length() > 0)
{
PropertyValuePtr value;
const CHAR_t *pValue = value_str.c_str();
CHAR_t *pEndPtr = nullptr;
// attempt to convert the value
if (isDouble)
{
// TODO: we need to PAL wcstod call
double d = _pal_strtod(pValue,&pEndPtr);
value = CTokenValue::create_property_value(d);
}
else
{
int base = isHex ? 16:10;
if(isSigned)
{
long val = _pal_strtol(pValue, &pEndPtr, base);
if (val != LONG_MAX)
{
value = CTokenValue::create_property_value((INT32)val);
}
else
{
// attempt 64 bit
value = CTokenValue::create_property_value(_pal_strtoll(pValue, &pEndPtr, base));
}
}
else
{
unsigned long val = _pal_strtoul(pValue,&pEndPtr,base);
if (val != ULONG_MAX)
{
value = CTokenValue::create_property_value((UINT32)val);
}
else
{
// attempt 64 bit
value = CTokenValue::create_property_value(_pal_strtoull(pValue, &pEndPtr, base));
}
}
}
if ((size_t)(pEndPtr - pValue) != value_str.size())
{
return E_UNEXPECTED; // error in conversion
}
rpn.push_back(new CTokenValue(value));
}
else
{
return E_UNEXPECTED; // zero length
}
}
foundation_assert(pos != std::string::npos);
i = pos;
continue;
}
// is an operator
else
{
// expression is empty or last operand an operator
//if (rpn.empty() || (isOperator(token) > 0))
//{
//rpn.append(SEP + "0");
//}
// get precedence
int topPrecedence = 0;
// get current operator
i += _pal_strlen(_operatorTypeInfos[operatorTypeInfoIndex]._operator_token) -1;
for (;;)
{
CTokenBase *pTopTokenBase = nullptr;
// get top's precedence
if (!st.empty())
{
pTopTokenBase = st.top();
if (pTopTokenBase->getType() != TokenType_operator)
topPrecedence = 1; // give a low priority if operator not ok!
else
topPrecedence = pTopTokenBase->As<CTokenOperator>()->getOperatorTypeInfo()._precedence;
}
if (st.empty() || IsLeftParenthesis(st.top()) || _operatorTypeInfos[operatorTypeInfoIndex]._precedence > topPrecedence)
{
st.push(new CTokenOperator(operatorTypeInfoIndex));
break;
}
// operator has lower precedence then pop it
else
{
st.pop();
foundation_assert(pTopTokenBase);
rpn.push_back(pTopTokenBase);
}
}
continue;
}
}
for (;;)
{
if (st.empty())
break;
CTokenBase *pTopTokenBase = st.top();
st.pop();
if (!IsLeftParenthesis(pTopTokenBase))
{
rpn.push_back(pTopTokenBase);
}
else
{
delete pTopTokenBase;
return E_UNEXPECTED;
}
}
return S_OK;
}