/** \brief Calls a parser function with its corresponding arguments.
      \param a_stOpt The operator stack
      \param a_stVal The value stack
      \param a_iArgCount The number of function arguments
  */
void ParserXBase::ApplyFunc(Stack<ptr_tok_type> &a_stOpt,
                            int a_iArgCount) const
{
    if (a_stOpt.empty())
        return;

    ptr_tok_type tok = a_stOpt.pop();
    ICallback *pFun = tok->AsICallback();

    int iArgCount = (pFun->GetArgc()>=0) ? pFun->GetArgc() : a_iArgCount;
    pFun->SetNumArgsPresent(iArgCount);

    m_nPos -= (iArgCount - 1);
    m_rpn.Add(tok);
}
Ejemplo n.º 2
0
  /** \brief Calls a parser function with its corresponding arguments. 
      \param a_stOpt The operator stack
      \param a_stVal The value stack
      \param a_iArgCount The number of function arguments
  */
  void ParserXBase::ApplyFunc(Stack<ptr_tok_type> &a_stOpt,
                              Stack<ptr_val_type> &a_stVal, 
                              int a_iArgCount) const
  { 
    if (a_stOpt.empty())
      return;

    ptr_tok_type tok = a_stOpt.pop();
    ICallback *pFun = tok->AsICallback();

    int iArgCount = (pFun->GetArgc()>=0) ? pFun->GetArgc() : a_iArgCount;
    int iOffset = a_stVal.size() - iArgCount;
    MUP_ASSERT(iOffset>=0);

    // The paramater stack may be empty since functions may not
    // have a parameter. They do always have a return value though.
    // If the param stack is empty create an entry for the function 
    // return value.
    if (iArgCount==0)
      a_stVal.push(ptr_val_type(new Value()));

    MUP_ASSERT((std::size_t)iOffset<a_stVal.size());
    ptr_val_type *pArg = a_stVal.get_data() + iOffset;
    
    //if (pFun->GetArgc()==0)
    //  a_stVal.push(ptr_val_type(new Value()));

    //ptr_val_type *pArg = a_stVal.get_data() + iOffset;

    try
    {
      // Make sure to pass on a volatile flag to the function result
      bool bResultIsVolatile = false;
      for (int i=0; i<iArgCount && bResultIsVolatile==false; ++i)
      {
        if (pArg[i]->IsFlagSet(IToken::flVOLATILE))
          bResultIsVolatile = true;
      }

      // Instead of evaluating the function merely a dummy value of the same type as the function return value
      // is created 
      *pArg = ptr_val_type(new Value());
      pFun->SetNumArgsPresent(iArgCount);
      
      if (bResultIsVolatile)
        (*pArg)->AddFlags(IToken::flVOLATILE);

      m_rpn.Add(tok);
    }
    catch(ParserError &e)
    {
      // This are type related errors caused by undefined
      // variables. They must be ignored if the parser is
      // just checking the presence of expression variables
      if (!m_bIsQueryingExprVar)
      {
        ErrorContext &err = e.GetContext();
        err.Pos   = m_pTokenReader->GetPos();
        err.Expr  = m_pTokenReader->GetExpr();

        if (err.Ident.empty())
          err.Ident = pFun->GetIdent();

        throw;
      }
    }

    if (iArgCount>0)
      a_stVal.pop(iArgCount-1); // remove the arguments
  }
//---------------------------------------------------------------------------
void ParserXBase::CreateRPN() const
{
    if (!m_pTokenReader->GetExpr().length())
        Error(ecUNEXPECTED_EOF, 0);

    // The Stacks take the ownership over the tokens
    Stack<ptr_tok_type> stOpt;
    Stack<ICallback*>   stFunc;
    Stack<int>  stArgCount;
    Stack<int>  stIdxCount;
    ptr_tok_type pTok, pTokPrev;
    Value val;

    ReInit();

    for (;;)
    {
        pTokPrev = pTok;
        pTok = m_pTokenReader->ReadNextToken();

#if defined(MUP_DUMP_TOKENS)
        console() << pTok->AsciiDump() << endl;
#endif

        ECmdCode eCmd = pTok->GetCode();
        switch (eCmd)
        {
        case  cmVAL:
            m_nPos++;
            m_rpn.Add(pTok);
            break;

        case  cmCBC:
        case  cmIC:
        {
            ECmdCode eStarter = (ECmdCode)(eCmd - 1);
            MUP_VERIFY(eStarter == cmCBO || eStarter == cmIO);

            // The argument count for parameterless functions is zero
            // by default an opening bracket sets parameter count to 1
            // in preparation of arguments to come. If the last token
            // was an opening bracket we know better...
            if (pTokPrev.Get() != nullptr && pTokPrev->GetCode() == eStarter)
                --stArgCount.top();

            ApplyRemainingOprt(stOpt);

            // if opt is "]" and opta is "[" the bracket content has been evaluated.
            // Now check whether there is an index operator on the stack.
            if (stOpt.size() && stOpt.top()->GetCode() == eStarter)
            {
                //
                // Find out how many dimensions were used in the index operator.
                //
                std::size_t iArgc = stArgCount.pop();
                stOpt.pop(); // Take opening bracket from stack

                ICallback *pOprtIndex = pTok->AsICallback();
                MUP_VERIFY(pOprtIndex != nullptr);

                pOprtIndex->SetNumArgsPresent(iArgc);
                m_rpn.Add(pOprtIndex);

                // If this is an index operator there must be something else in the register (the variable to index)
                MUP_VERIFY(eCmd != cmIC || m_nPos >= (int)iArgc + 1);

                // Reduce the index into the value registers accordingly
                m_nPos -= iArgc;

                if (eCmd == cmCBC)
                {
                    ++m_nPos;
                }
            } // if opening index bracket is on top of operator stack
        }
        break;

        case  cmBC:
        {
            // The argument count for parameterless functions is zero
            // by default an opening bracket sets parameter count to 1
            // in preparation of arguments to come. If the last token
            // was an opening bracket we know better...
            if (pTokPrev.Get() != nullptr && pTokPrev->GetCode() == cmBO)
                --stArgCount.top();

            ApplyRemainingOprt(stOpt);

            // if opt is ")" and opta is "(" the bracket content has been evaluated.
            // Now its time to check if there is either a function or a sign pending.
            // - Neither the opening nor the closing bracket will be pushed back to
            //   the operator stack
            // - Check if a function is standing in front of the opening bracket,
            //   if so evaluate it afterwards to apply an infix operator.
            if (stOpt.size() && stOpt.top()->GetCode() == cmBO)
            {
                //
                // Here is the stuff to evaluate a function token
                //
                int iArgc = stArgCount.pop();

                stOpt.pop(); // Take opening bracket from stack
                if (stOpt.empty())
                    break;

                if ((stOpt.top()->GetCode() != cmFUNC) && (stOpt.top()->GetCode() != cmOPRT_INFIX))
                    break;

                ICallback *pFun = stOpt.top()->AsICallback();
                stFunc.pop();

                if (pFun->GetArgc() != -1 && iArgc > pFun->GetArgc())
                    Error(ecTOO_MANY_PARAMS, pTok->GetExprPos(), pFun);

                if (iArgc < pFun->GetArgc())
                    Error(ecTOO_FEW_PARAMS, pTok->GetExprPos(), pFun);

                // Apply function, if present
                if (stOpt.size() &&
                    stOpt.top()->GetCode() != cmOPRT_INFIX &&
                    stOpt.top()->GetCode() != cmOPRT_BIN)
                {
                    ApplyFunc(stOpt, iArgc);
                }
            }
        }
        break;

        case  cmELSE:
            ApplyRemainingOprt(stOpt);
            m_rpn.Add(pTok);
            stOpt.push(pTok);
            break;

        case  cmSCRIPT_NEWLINE:
            ApplyRemainingOprt(stOpt);
            m_rpn.AddNewline(pTok, m_nPos);
            stOpt.clear();
            m_nPos = 0;
            break;

        case  cmARG_SEP:
            if (stArgCount.empty())
                Error(ecUNEXPECTED_COMMA, m_pTokenReader->GetPos() - 1);

            ++stArgCount.top();

            ApplyRemainingOprt(stOpt);
            break;

        case  cmEOE:
            ApplyRemainingOprt(stOpt);
            m_rpn.Finalize();
            break;

        case  cmIF:
        case  cmOPRT_BIN:
        {
            while (stOpt.size() &&
                stOpt.top()->GetCode() != cmBO   &&
                stOpt.top()->GetCode() != cmIO   &&
                stOpt.top()->GetCode() != cmCBO  &&
                stOpt.top()->GetCode() != cmELSE &&
                stOpt.top()->GetCode() != cmIF)
            {
                IToken *pOprt1 = stOpt.top().Get();
                IToken *pOprt2 = pTok.Get();
                MUP_VERIFY(pOprt1 && pOprt2);
                MUP_VERIFY(pOprt1->AsIPrecedence() && pOprt2->AsIPrecedence());

                int nPrec1 = pOprt1->AsIPrecedence()->GetPri(),
                    nPrec2 = pOprt2->AsIPrecedence()->GetPri();

                if (pOprt1->GetCode() == pOprt2->GetCode())
                {
                    // Deal with operator associativity
                    EOprtAsct eOprtAsct = pOprt1->AsIPrecedence()->GetAssociativity();
                    if ((eOprtAsct == oaRIGHT && (nPrec1 <= nPrec2)) ||
                        (eOprtAsct == oaLEFT && (nPrec1 < nPrec2)))
                    {
                        break;
                    }
                }
                else if (nPrec1 < nPrec2)
                {
                    break;
                }

                // apply the operator now
                // (binary operators are identic to functions with two arguments)
                ApplyFunc(stOpt, 2);
            } // while ( ... )

            if (pTok->GetCode() == cmIF)
                m_rpn.Add(pTok);

            stOpt.push(pTok);
        }
        break;

        //
        //  Postfix Operators
        //
        case  cmOPRT_POSTFIX:
            MUP_VERIFY(m_nPos);
            m_rpn.Add(pTok);
            break;

        case  cmCBO:
        case  cmIO:
        case  cmBO:
            stOpt.push(pTok);
            stArgCount.push(1);
            break;

            //
            // Functions
            //
        case  cmOPRT_INFIX:
        case  cmFUNC:
        {
            ICallback *pFunc = pTok->AsICallback();
            MUP_VERIFY(pFunc);

            // Check if this function is a argument to another function
            // if so check if the the return type fits.
            if (!stFunc.empty() && stFunc.top()->GetCode() == cmFUNC)
            {
                MUP_VERIFY(stArgCount.size());
                int iArgc = (int)stArgCount.top() /*+ 1*/;

                ICallback *pOuterFunc = stFunc.top();
                if (pOuterFunc->GetArgc() != -1 && iArgc > pOuterFunc->GetArgc())
                    Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos());

                MUP_VERIFY(pOuterFunc->GetArgc() == -1 || iArgc <= pOuterFunc->GetArgc());
            }

            stOpt.push(pTok);
            stFunc.push(pFunc); // to collect runtime type information
        }
        break;

        default:
            Error(ecINTERNAL_ERROR);
        } // switch Code

        if (ParserXBase::s_bDumpStack)
        {
            StackDump(stOpt);
        }

        if (pTok->GetCode() == cmEOE)
            break;
    } // for (all tokens)

    if (ParserXBase::s_bDumpRPN)
    {
        m_rpn.AsciiDump();
    }

    if (m_nPos > 1)
    {
        Error(ecUNEXPECTED_COMMA, -1);
    }
}