/** \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); }
/** \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); } }