//--------------------------------------------------------------------------- bool IValue::operator<=(const IValue &a_Val) const { char_type type1 = GetType(), type2 = a_Val.GetType(); if (type1 == type2 || (IsScalar() && a_Val.IsScalar())) { switch (GetType()) { case 's': return GetString() <= a_Val.GetString(); case 'i': case 'f': case 'c': return GetFloat() <= a_Val.GetFloat(); case 'b': return GetBool() <= a_Val.GetBool(); default: ErrorContext err; err.Errc = ecINTERNAL_ERROR; err.Pos = -1; err.Type1 = GetType(); err.Type2 = a_Val.GetType(); throw ParserError(err); } // switch this type } else { ErrorContext err; err.Errc = ecTYPE_CONFLICT_FUN; err.Arg = (type1 != 'f' && type1 != 'i') ? 1 : 2; err.Type1 = type2; err.Type2 = type1; throw ParserError(err); } }
//--------------------------------------------------------------------------- bool IValue::operator!=(const IValue &a_Val) const { char_type type1 = GetType(), type2 = a_Val.GetType(); if (type1 == type2 || (IsScalar() && a_Val.IsScalar())) { switch (GetType()) { case 's': return GetString() != a_Val.GetString(); case 'i': case 'f': return GetFloat() != a_Val.GetFloat(); case 'c': return (GetFloat() != a_Val.GetFloat()) || (GetImag() != a_Val.GetImag()); case 'b': return GetBool() != a_Val.GetBool(); case 'v': return true; case 'm': if (GetRows() != a_Val.GetRows() || GetCols() != a_Val.GetCols()) { return true; } else { for (int i = 0; i < GetRows(); ++i) { if (const_cast<IValue*>(this)->At(i) != const_cast<IValue&>(a_Val).At(i)) return true; } return false; } default: ErrorContext err; err.Errc = ecINTERNAL_ERROR; err.Pos = -1; err.Type2 = GetType(); err.Type1 = a_Val.GetType(); throw ParserError(err); } // switch this type } else { return true; } }
//--------------------------------------------------------------------------- Value::Value(const IValue &a_Val) :IValue(cmVAL) ,m_psVal(nullptr) ,m_pvVal(nullptr) ,m_pCache(nullptr) { Reset(); switch(a_Val.GetType()) { case 'i': case 'f': case 'b': m_val = cmplx_type(a_Val.GetFloat(), 0); break; case 'c': m_val = cmplx_type(a_Val.GetFloat(), a_Val.GetImag()); break; case 's': if (!m_psVal) m_psVal = new string_type(a_Val.GetString()); else *m_psVal = a_Val.GetString(); break; case 'm': if (!m_pvVal) m_pvVal = new matrix_type(a_Val.GetArray()); else *m_pvVal = a_Val.GetArray(); break; case 'v': break; default: MUP_FAIL(INVALID_TYPE_CODE); } m_cType = a_Val.GetType(); }
//--------------------------------------------------------------------------- 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<ptr_val_type> stVal; Stack<ICallback*> stFunc; Stack<int> stArgCount; Stack<int> stIdxCount; ptr_tok_type pTok, pTokPrev; Value val; ReInit(); // The outermost counter counts the number of seperated items // such as in "a=10,b=20,c=c+a" stArgCount.push(1); for(bool bLoop=true; bLoop;) { pTokPrev = pTok; pTok = m_pTokenReader->ReadNextToken(); #if defined(MUP_DUMP_TOKENS) cout << pTok->AsciiDump() << endl; #endif ECmdCode eCmd = pTok->GetCode(); switch (eCmd) { case cmVAR: case cmVAL: { IValue *pVal = pTok->AsIValue(); if (stFunc.empty() && pVal->GetType()=='n') { ErrorContext err; err.Errc = ecUNEXPECTED_PARENS; err.Ident = _T(")"); err.Pos = pTok->GetExprPos(); throw ParserError(err); } stVal.push( ptr_val_type(pVal) ); // Arrays can't be added directly to the reverse polish notation // since there may be an index operator following next... m_rpn.Add(pTok); // Apply infix operator if existant if (stOpt.size() && stOpt.top()->GetCode()==cmOPRT_INFIX) ApplyFunc(stOpt, stVal, 1); } break; case cmIC: { // 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()!=NULL && pTokPrev->GetCode()==cmIO) --stArgCount.top(); ApplyRemainingOprt(stOpt, stVal); // 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()==cmIO ) { // // Find out how many dimensions were used in the index operator. // std::size_t iArgc = stArgCount.pop(); stOpt.pop(); // Take opening bracket from stack IOprtIndex *pOprtIndex = pTok->AsIOprtIndex(); MUP_ASSERT(pOprtIndex!=NULL); pOprtIndex->SetNumArgsPresent(iArgc); m_rpn.Add(pTok); // Pop the index values from the stack MUP_ASSERT(stVal.size()>=iArgc+1); for (std::size_t i=0; i<iArgc; ++i) stVal.pop(); // Now i would need to pop the topmost value from the stack, apply the index // opertor and push the result back to the stack. But here we are just creating the // RPN and are working with dummy values anyway so i just mark the topmost value as // volatile and leave it were it is. The real index logic is in the RPN evaluator... stVal.top()->AddFlags(IToken::flVOLATILE); } // 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()!=NULL && pTokPrev->GetCode()==cmBO) --stArgCount.top(); ApplyRemainingOprt(stOpt, stVal); // 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); // Evaluate the function ApplyFunc(stOpt, stVal, iArgc); // Apply an infix operator, if present if (stOpt.size() && stOpt.top()->GetCode()==cmOPRT_INFIX) ApplyFunc(stOpt, stVal, 1); } } break; case cmELSE: ApplyRemainingOprt(stOpt, stVal); m_rpn.Add(pTok); stOpt.push(pTok); break; case cmSCRIPT_NEWLINE: { ApplyRemainingOprt(stOpt, stVal); // Value stack plätten // Stack der RPN um die Anzahl im stack enthaltener Werte zurück setzen int n = stVal.size(); m_rpn.AddNewline(pTok, n); stVal.clear(); stOpt.clear(); } break; case cmARG_SEP: if (stArgCount.empty()) Error(ecUNEXPECTED_COMMA, m_pTokenReader->GetPos()); ++stArgCount.top(); //if (stVal.size()) // increase argument counter // stArgCount.top()++; ApplyRemainingOprt(stOpt, stVal); break; case cmEOE: ApplyRemainingOprt(stOpt, stVal); m_rpn.Finalize(); break; case cmIF: case cmOPRT_BIN: { while ( stOpt.size() && stOpt.top()->GetCode() != cmBO && stOpt.top()->GetCode() != cmIO && stOpt.top()->GetCode() != cmELSE && stOpt.top()->GetCode() != cmIF) { IToken *pOprt1 = stOpt.top().Get(); IToken *pOprt2 = pTok.Get(); MUP_ASSERT(pOprt1 && pOprt2); MUP_ASSERT(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, stVal, 2); } // while ( ... ) if (pTok->GetCode()==cmIF) m_rpn.Add(pTok); stOpt.push(pTok); } break; // // Postfix Operators // case cmOPRT_POSTFIX: { MUP_ASSERT(stVal.size()); ptr_val_type &pVal(stVal.top()); try { // place a dummy return value into the value stack, do not // evaluate pOprt (this is important for lazy evaluation!) // The only place where evaluation takes place is the RPN // engine! pVal = ptr_val_type(new Value()); m_rpn.Add(pTok); } catch(ParserError &) { if (!m_bIsQueryingExprVar) throw; } } break; case cmIO: case cmBO: stOpt.push(pTok); stArgCount.push(1); break; // // Functions // case cmOPRT_INFIX: case cmFUNC: { ICallback *pFunc = pTok->AsICallback(); MUP_ASSERT(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_ASSERT(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_ASSERT(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( stVal, stOpt ); } if ( pTok->GetCode() == cmEOE ) bLoop = false; } // for (all tokens) if (ParserXBase::s_bDumpRPN) { m_rpn.AsciiDump(); } m_nFinalResultIdx = stArgCount.top()-1; MUP_ASSERT(stVal.size()); }