static HRESULT ExpressionToRpn()

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;
}