Hi Winfried, *, On Fri, Apr 26, 2019 at 9:04 AM Winfried Donkers <Winfried.Donkers@xxxxxxxxxx> wrote: > > I am working on tdf#124710, which means that I need to convert functions IFS and SWITCH to 'jump functions'. I tried this before, but abandoned my work, which was in gerrit #26348. > > Somehow I cannot retrieve that 'commit'. > > Is there any way to retrieve it (so that I can read the comments and changes), or does it really no longer exist? Not on gerrit anymore, but is available on jenkins mirror... Attached is the change v1 - if there was a second revision, then that is lost. ciao Christian
commit 44ae1f7586d0a038d6f41b5a0c01fc1275009c24 Author: Winfried Donkers <winfrieddonkers@xxxxxxxxxxxxxxx> Date: Thu Jun 16 09:00:58 2016 +0200 Convert ScInterpreter::ScIfs_MS() and ScSwitch_MS() to jump functions. Current situation: All seems to work well, except when any argument (other than the first) contains a function or expression. See comment above ScSwitch_MS() in interpr1.cxx. The 'test code' in ScSwitch_MS() was used to get the results in the comment. How do I recognise that an argument is an expression? I think I need to know that first to be able to handle that argument correctly. I left the trace code in, but renamed SAL_DEBUG to SAL__DEBUG to get the code accepted by git. Change-Id: I879a211dc525502f4730d67215b324e30ed54955 diff --git a/formula/source/core/api/FormulaCompiler.cxx b/formula/source/core/api/FormulaCompiler.cxx index 675da4bb422a..d84d2c5409a0 100644 --- a/formula/source/core/api/FormulaCompiler.cxx +++ b/formula/source/core/api/FormulaCompiler.cxx @@ -930,6 +930,8 @@ bool FormulaCompiler::IsOpCodeJumpCommand( OpCode eOp ) case ocIfError: case ocIfNA: case ocChoose: + case ocIfs_MS: + case ocSwitch_MS: return true; default: ; @@ -1540,6 +1542,8 @@ void FormulaCompiler::Factor() pFacToken->GetJump()[ 0 ] = 3; // if, else, behind break; case ocChoose: + case ocIfs_MS: + case ocSwitch_MS: pFacToken->GetJump()[ 0 ] = FORMULA_MAXJUMPCOUNT + 1; break; case ocIfError: @@ -1572,6 +1576,8 @@ void FormulaCompiler::Factor() nJumpMax = 3; break; case ocChoose: + case ocIfs_MS: + case ocSwitch_MS: nJumpMax = FORMULA_MAXJUMPCOUNT; break; case ocIfError: @@ -1611,6 +1617,8 @@ void FormulaCompiler::Factor() bLimitOk = (nJumpCount <= 3); break; case ocChoose: + case ocIfs_MS: + case ocSwitch_MS: bLimitOk = (nJumpCount < FORMULA_MAXJUMPCOUNT); break; case ocIfError: diff --git a/formula/source/core/api/token.cxx b/formula/source/core/api/token.cxx index 9c16870ea6fa..d49dd01b590a 100644 --- a/formula/source/core/api/token.cxx +++ b/formula/source/core/api/token.cxx @@ -85,7 +85,8 @@ bool FormulaToken::IsFunction() const eOp != ocTableRef && (GetByte() != 0 // x parameters || (SC_OPCODE_START_NO_PAR <= eOp && eOp < SC_OPCODE_STOP_NO_PAR) // no parameter - || (ocIf == eOp || ocIfError == eOp || ocIfNA == eOp || ocChoose == eOp ) // @ jump commands + || (ocIf == eOp || ocIfError == eOp || ocIfNA == eOp || + ocChoose == eOp || ocIfs_MS == eOp || ocSwitch_MS == eOp ) // @ jump commands || (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR) // one parameter || (SC_OPCODE_START_2_PAR <= eOp && eOp < SC_OPCODE_STOP_2_PAR) // x parameters (cByte==0 in // FuncAutoPilot) @@ -101,10 +102,11 @@ sal_uInt8 FormulaToken::GetParamCount() const { if ( eOp < SC_OPCODE_STOP_DIV && eOp != ocExternal && eOp != ocMacro && eOp != ocIf && eOp != ocIfError && eOp != ocIfNA && eOp != ocChoose && - eOp != ocPercentSign ) + eOp != ocIfs_MS && eOp != ocSwitch_MS && eOp != ocPercentSign ) return 0; // parameters and specials - // ocIf, ocIfError, ocIfNA and ocChoose not for FAP, have cByte then -//2do: bool parameter whether FAP or not? + // ocIf, ocIfError, ocIfNA, ocChoose, ocIfs_MS and ocSwitch_MS not for FAP, + // have cByte then +// todo : bool parameter whether FAP or not? else if ( GetByte() ) return GetByte(); // all functions, also ocExternal and ocMacro else if (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP) @@ -116,7 +118,8 @@ sal_uInt8 FormulaToken::GetParamCount() const return 0; // no parameter else if (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR) return 1; // one parameter - else if ( eOp == ocIf || eOp == ocIfError || eOp == ocIfNA || eOp == ocChoose ) + else if ( eOp == ocIf || eOp == ocIfError || eOp == ocIfNA || + eOp == ocChoose || eOp == ocIfs_MS || eOp == ocSwitch_MS ) return 1; // only the condition counts as parameter else return 0; // all the rest, no Parameter, or @@ -976,7 +979,8 @@ bool FormulaTokenArray::HasMatrixDoubleRefOps() } if ( eOp == ocPush || lcl_IsReference( eOp, t->GetType() ) ) pStack[sp++] = t; - else if ( eOp == ocIf || eOp == ocIfError || eOp == ocIfNA || eOp == ocChoose ) + else if ( eOp == ocIf || eOp == ocIfError || eOp == ocIfNA || + eOp == ocChoose || eOp == ocIfs_MS || eOp == ocSwitch_MS ) { // ignore Jumps, pop previous Result (Condition) if ( sp ) --sp; @@ -1529,11 +1533,13 @@ FormulaToken* FormulaTokenArray::AddOpCode( OpCode eOp ) case ocIfError: case ocIfNA: case ocChoose: + case ocIfs_MS: + case ocSwitch_MS: { short nJump[FORMULA_MAXJUMPCOUNT + 1]; if ( eOp == ocIf ) nJump[ 0 ] = 3; - else if ( eOp == ocChoose ) + else if ( eOp == ocChoose || eOp == ocIfs_MS || eOp == ocSwitch_MS ) nJump[ 0 ] = FORMULA_MAXJUMPCOUNT + 1; else nJump[ 0 ] = 2; diff --git a/include/formula/FormulaCompiler.hxx b/include/formula/FormulaCompiler.hxx index fc912fcc9bc3..bfc8f4b0d9d5 100644 --- a/include/formula/FormulaCompiler.hxx +++ b/include/formula/FormulaCompiler.hxx @@ -35,7 +35,7 @@ #include <memory> #include <unordered_map> -#define FORMULA_MAXJUMPCOUNT 32 /* maximum number of jumps (ocChoose) */ +#define FORMULA_MAXJUMPCOUNT 255 /* maximum number of jumps (ocChoose, ocIfs_MS, ocSwitch_MS) */ #define FORMULA_MAXTOKENS 8192 /* maximum number of tokens in formula */ diff --git a/include/formula/compiler.hrc b/include/formula/compiler.hrc index 7a7bfe74ab94..9aad8cdddd71 100644 --- a/include/formula/compiler.hrc +++ b/include/formula/compiler.hrc @@ -33,33 +33,35 @@ #define SC_OPCODE_IF_ERROR 7 #define SC_OPCODE_IF_NA 8 #define SC_OPCODE_CHOOSE 9 -#define SC_OPCODE_OPEN 10 /* parentheses and separators */ -#define SC_OPCODE_CLOSE 11 -#define SC_OPCODE_SEP 12 -#define SC_OPCODE_MISSING 13 /* special OpCodes */ -#define SC_OPCODE_BAD 14 -#define SC_OPCODE_STRINGXML 15 -#define SC_OPCODE_SPACES 16 -#define SC_OPCODE_MAT_REF 17 -#define SC_OPCODE_DB_AREA 18 /* additional access operators */ -#define SC_OPCODE_TABLE_REF 19 -#define SC_OPCODE_MACRO 20 -#define SC_OPCODE_COL_ROW_NAME 21 -#define SC_OPCODE_COL_ROW_NAME_AUTO 22 -#define SC_OPCODE_PERCENT_SIGN 23 /* operator _follows_ value */ -#define SC_OPCODE_ARRAY_OPEN 24 -#define SC_OPCODE_ARRAY_CLOSE 25 -#define SC_OPCODE_ARRAY_ROW_SEP 26 -#define SC_OPCODE_ARRAY_COL_SEP 27 /* some convs use sep != col_sep */ -#define SC_OPCODE_TABLE_REF_OPEN 28 -#define SC_OPCODE_TABLE_REF_CLOSE 29 -#define SC_OPCODE_TABLE_REF_ITEM_ALL 30 -#define SC_OPCODE_TABLE_REF_ITEM_HEADERS 31 -#define SC_OPCODE_TABLE_REF_ITEM_DATA 32 -#define SC_OPCODE_TABLE_REF_ITEM_TOTALS 33 -#define SC_OPCODE_TABLE_REF_ITEM_THIS_ROW 34 -#define SC_OPCODE_STOP_DIV 35 -#define SC_OPCODE_SKIP 36 /* used to skip raw tokens during string compilation */ +#define SC_OPCODE_IFS_MS 10 +#define SC_OPCODE_SWITCH_MS 11 +#define SC_OPCODE_OPEN 12 /* parentheses and separators */ +#define SC_OPCODE_CLOSE 13 +#define SC_OPCODE_SEP 14 +#define SC_OPCODE_MISSING 15 /* special OpCodes */ +#define SC_OPCODE_BAD 16 +#define SC_OPCODE_STRINGXML 17 +#define SC_OPCODE_SPACES 18 +#define SC_OPCODE_MAT_REF 19 +#define SC_OPCODE_DB_AREA 20 /* additional access operators */ +#define SC_OPCODE_TABLE_REF 21 +#define SC_OPCODE_MACRO 22 +#define SC_OPCODE_COL_ROW_NAME 23 +#define SC_OPCODE_COL_ROW_NAME_AUTO 24 +#define SC_OPCODE_PERCENT_SIGN 25 /* operator _follows_ value */ +#define SC_OPCODE_ARRAY_OPEN 26 +#define SC_OPCODE_ARRAY_CLOSE 27 +#define SC_OPCODE_ARRAY_ROW_SEP 28 +#define SC_OPCODE_ARRAY_COL_SEP 29 /* some convs use sep != col_sep */ +#define SC_OPCODE_TABLE_REF_OPEN 30 +#define SC_OPCODE_TABLE_REF_CLOSE 31 +#define SC_OPCODE_TABLE_REF_ITEM_ALL 32 +#define SC_OPCODE_TABLE_REF_ITEM_HEADERS 33 +#define SC_OPCODE_TABLE_REF_ITEM_DATA 34 +#define SC_OPCODE_TABLE_REF_ITEM_TOTALS 35 +#define SC_OPCODE_TABLE_REF_ITEM_THIS_ROW 36 +#define SC_OPCODE_STOP_DIV 37 +#define SC_OPCODE_SKIP 38 /* used to skip raw tokens during string compilation */ /*** error constants #... ***/ #define SC_OPCODE_START_ERRORS 40 @@ -497,11 +499,9 @@ #define SC_OPCODE_FORECAST_LIN 486 #define SC_OPCODE_CONCAT_MS 487 #define SC_OPCODE_TEXTJOIN_MS 488 -#define SC_OPCODE_IFS_MS 489 -#define SC_OPCODE_SWITCH_MS 490 -#define SC_OPCODE_MINIFS_MS 491 -#define SC_OPCODE_MAXIFS_MS 492 -#define SC_OPCODE_STOP_2_PAR 493 /* last function with two or more parameters' OpCode + 1 */ +#define SC_OPCODE_MINIFS_MS 489 +#define SC_OPCODE_MAXIFS_MS 490 +#define SC_OPCODE_STOP_2_PAR 491 /* last function with two or more parameters' OpCode + 1 */ #define SC_OPCODE_STOP_FUNCTION SC_OPCODE_STOP_2_PAR /* last function's OpCode + 1 */ #define SC_OPCODE_LAST_OPCODE_ID (SC_OPCODE_STOP_FUNCTION - 1) /* last OpCode */ diff --git a/include/formula/opcode.hxx b/include/formula/opcode.hxx index 30dc94ff578c..81163165295b 100644 --- a/include/formula/opcode.hxx +++ b/include/formula/opcode.hxx @@ -37,6 +37,8 @@ enum OpCode : sal_uInt16 ocIfError = SC_OPCODE_IF_ERROR, ocIfNA = SC_OPCODE_IF_NA, ocChoose = SC_OPCODE_CHOOSE, + ocIfs_MS = SC_OPCODE_IFS_MS, + ocSwitch_MS = SC_OPCODE_SWITCH_MS, // Parentheses and separators ocOpen = SC_OPCODE_OPEN, ocClose = SC_OPCODE_CLOSE, @@ -282,8 +284,6 @@ enum OpCode : sal_uInt16 ocNominal = SC_OPCODE_NOMINAL, ocSubTotal = SC_OPCODE_SUB_TOTAL, ocRawSubtract = SC_OPCODE_RAWSUBTRACT, - ocIfs_MS = SC_OPCODE_IFS_MS, - ocSwitch_MS = SC_OPCODE_SWITCH_MS, ocMinIfs_MS = SC_OPCODE_MINIFS_MS, ocMaxIfs_MS = SC_OPCODE_MAXIFS_MS, // Database functions diff --git a/include/formula/tokenarray.hxx b/include/formula/tokenarray.hxx index 81b85586f274..27e40a010b08 100644 --- a/include/formula/tokenarray.hxx +++ b/include/formula/tokenarray.hxx @@ -357,8 +357,8 @@ public: @param nStop Stop before reaching code at position nStop. If not specified the default is to either run the entire code, or to stop if an ocSep or - ocClose is encountered, which are only present in ocIf or ocChoose - jumps. + ocClose is encountered, which are only present in ocIf, ocChoose, + ocIfs_MS or ocSwitch_MS jumps. */ void Jump( short nStart, short nNext, short nStop = SHRT_MAX ); void Push( const FormulaTokenArray* ); diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx index 6e78b880c0c3..16d6de3fb83c 100644 --- a/sc/source/core/tool/interpr1.cxx +++ b/sc/source/core/tool/interpr1.cxx @@ -503,6 +503,190 @@ void ScInterpreter::ScChooseJump() aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] ); } +// TODO : when argument is function or expression, problems arise (see ScSwitch_MS) +void ScInterpreter::ScIfs_MS() +{ + const short* pJump = pCur->GetJump(); + short nJumpCount = pJump[ 0 ]; + MatrixDoubleRefToMatrix(); + bool bFinished = false; + short nJumpIndex = 0; + // SAL__DEBUG( "ScIfs_MS(), nJumpIndex = " << nJumpIndex << "(before loop), nJumpCount = " << nJumpCount ); + while ( !bFinished ) + { + if ( GetBool() ) + { // TRUE + // SAL__DEBUG( "ScIfs_MS(), expression is true, nJumpIndex = " << nJumpIndex << + // "(before+1), nJumpCount = " << nJumpCount ); + if( ++nJumpIndex < nJumpCount ) + { // THEN path + // SAL__DEBUG( "ScIfs_MS(), expression is true, jumping to " << nJumpIndex ); + aCode.Jump( pJump[ nJumpIndex ], pJump[ nJumpCount ] ); + } + else + { // no parameter given for THEN + PushNA(); + aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] ); + } + bFinished = true; + } + else + { // FALSE + // SAL__DEBUG( "ScIfs_MS(), expression is false, nJumpIndex = " << nJumpIndex << + // "(before+2), nJumpCount = " << nJumpCount ); + nJumpIndex += 2; + if( nJumpIndex < nJumpCount - 1 ) + { // ELSE path + // SAL__DEBUG( "ScIfs_MS(), expression is false, jumping to " << nJumpIndex ); + aCode.Jump( pJump[ nJumpIndex ], pJump[ nJumpCount ] ); + pCur = aCode.Next(); + if ( pCur != nullptr ) + PushWithoutError( (FormulaToken&) *pCur ); + else + { + PushError( errUnknownState ); + bFinished = true; + } + } + else + { // no parameter given for ELSE + PushNA(); + aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] ); + bFinished = true; + } + } + } +} + +// TODO : when argument is function or expression, problems arise: +// SWITCH(1;2/3;4;IF(5>6;7;8);9;10) produces stack values after jump to +// 0 (no jump) 1 ok +// 1 2 wrong +// 2 4 ok +// 3 5 wrong +// 4 9 ok +// 5 10 ok +void ScInterpreter::ScSwitch_MS() +{ + const short* pJump = pCur->GetJump(); + short nJumpCount = pJump[ 0 ]; + MatrixDoubleRefToMatrix(); + bool bIsValue = false; + double fRefVal = 0; + svl::SharedString aRefStr; + OUString aStackType; + switch ( GetStackType() ) + { + case svDouble: + aStackType = "svDouble"; + bIsValue = true; + fRefVal = GetDouble(); + break; + case svString: + aStackType = "svString"; + bIsValue = false; + aRefStr = GetString(); + break; + case svSingleRef : + case svDoubleRef : + aStackType = "svSingle of DoubleRef"; + { + ScAddress aAdr; + if (!PopDoubleRefOrSingleRef( aAdr )) + break; + ScRefCellValue aCell( *pDok, aAdr ); + bIsValue = !( aCell.hasString() || aCell.hasEmptyValue() || aCell.isEmpty() ); + if ( bIsValue ) + fRefVal = GetCellValue( aAdr, aCell); + else + GetCellString( aRefStr, aCell); + } + break; + case svExternalSingleRef: + case svExternalDoubleRef: + case svMatrix: + { + aStackType = "svExternalSingle of DoubleRef of svMatrix"; + bIsValue = ScMatrix::IsValueType( GetDoubleOrStringFromMatrix( fRefVal, aRefStr ) ); + } + break; + default : + aStackType = "other"; + PushIllegalArgument(); + return; + } + // SAL__DEBUG( "ScSwitch_MS(), argument " << 0 << " : stacktype=" << aStackType << + // ", bIsValue=" << bIsValue << ", fRefVal=" << fRefVal << ", aRefStr=" << + // aRefStr.getString() << ", nGlobalError=" << nGlobalError ); + bool bFinished = false; + short nJumpIndex = 1; + while ( !bFinished ) + { + aCode.Jump( pJump[ nJumpIndex ], pJump[ nJumpCount ] ); + pCur = aCode.Next(); + if ( pCur != nullptr ) + { + PushWithoutError( (FormulaToken&) *pCur ); + double fVal = 0; + svl::SharedString aStr; + if ( bIsValue ) + fVal = GetDouble(); + else + aStr = GetString(); + // SAL__DEBUG( "ScSwitch_MS(), argument " << nJumpIndex << " : fVal=" << fVal << + // ", aStr=" << aStr.getString() << ", nGlobalError=" << nGlobalError << + // ", nJumpCount=" << nJumpCount ); +/* +// start test code + if ( ++nJumpIndex >= nJumpCount ) + { + bFinished = true; + PushNA(); + } + // SAL__DEBUG( "ScSwitch_MS(), argument " << nJumpIndex << ", nJumpCount=" << nJumpCount << + // ", finished=" << bFinished); +// end test code +*/ +// * start original code + if ( nGlobalError || (( bIsValue && rtl::math::approxEqual( fRefVal, fVal ) ) || + ( !bIsValue && ( aRefStr == aStr ) ) ) ) + { + bFinished = true; + nJumpIndex++; + } + else + { + nJumpIndex += 2; + // SAL__DEBUG( "ScSwitch_MS(), argument " << nJumpIndex << ", nJumpCount=" << nJumpCount ); + if ( nJumpIndex >= nJumpCount ) + { + // no match found + // SAL__DEBUG( "ScSwitch_MS(), no match found, return N/A" ); + bFinished = true; + PushNA(); + } + else + { + if ( nJumpIndex == nJumpCount - 1 ) + { + // no more evaluations, jump to default value + // SAL__DEBUG( "ScSwitch_MS(), no match found, return default value" ); + bFinished = true; + } + } + } +// end original code */ + if ( !nGlobalError ) + aCode.Jump( pJump[ nJumpIndex ], pJump[ nJumpCount ] ); + } + else + { + PushError( errUnknownState ); + bFinished = true; + } + } +} + static void lcl_AdjustJumpMatrix( ScJumpMatrix* pJumpM, SCSIZE nParmCols, SCSIZE nParmRows ) { SCSIZE nJumpCols, nJumpRows; diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx index eff287105e86..eb0a0b72ead7 100644 --- a/sc/source/core/tool/interpr4.cxx +++ b/sc/source/core/tool/interpr4.cxx @@ -3695,8 +3695,6 @@ bool IsErrFunc(OpCode oc) case ocIfError : case ocIfNA : case ocErrorType_ODF : - case ocIfs_MS: - case ocSwitch_MS: return true; default: return false; @@ -3743,7 +3741,8 @@ StackVar ScInterpreter::Interpret() PushWithoutError( (FormulaToken&) *pCur ); } else if (pTokenMatrixMap && - !(eOp == ocIf || eOp == ocIfError || eOp == ocIfNA || eOp == ocChoose) && + !(eOp == ocIf || eOp == ocIfError || eOp == ocIfNA || + eOp == ocChoose || eOp == ocIfs_MS || eOp == ocSwitch_MS ) && ((aTokenMatrixMapIter = pTokenMatrixMap->find( pCur)) != pTokenMatrixMap->end()) && (*aTokenMatrixMapIter).second->GetType() != svJumpMatrix) @@ -3764,7 +3763,8 @@ StackVar ScInterpreter::Interpret() nFuncFmtType = css::util::NumberFormat::NUMBER; nFuncFmtIndex = 0; - if ( eOp == ocIf || eOp == ocChoose || eOp == ocIfError || eOp == ocIfNA ) + if ( eOp == ocIf || eOp == ocChoose || eOp == ocIfError || + eOp == ocChoose || eOp == ocIfs_MS || eOp == ocSwitch_MS ) nStackBase = sp; // don't mess around with the jumps else { @@ -3794,6 +3794,8 @@ StackVar ScInterpreter::Interpret() case ocIfError : ScIfError( false ); break; case ocIfNA : ScIfError( true ); break; case ocChoose : ScChooseJump(); break; + case ocIfs_MS : ScIfs_MS(); break; + case ocSwitch_MS : ScSwitch_MS(); break; case ocAdd : ScAdd(); break; case ocSub : ScSub(); break; case ocMul : ScMul(); break; @@ -4036,8 +4038,6 @@ StackVar ScInterpreter::Interpret() case ocConcat : ScConcat(); break; case ocConcat_MS : ScConcat_MS(); break; case ocTextJoin_MS : ScTextJoin_MS(); break; - case ocIfs_MS : ScIfs_MS(); break; - case ocSwitch_MS : ScSwitch_MS(); break; case ocMinIfs_MS : ScMinIfs_MS(); break; case ocMaxIfs_MS : ScMaxIfs_MS(); break; case ocMatValue : ScMatValue(); break; diff --git a/sc/source/core/tool/interpr8.cxx b/sc/source/core/tool/interpr8.cxx index a94cd032ed02..02af2e9e2d8b 100644 --- a/sc/source/core/tool/interpr8.cxx +++ b/sc/source/core/tool/interpr8.cxx @@ -1873,166 +1873,4 @@ void ScInterpreter::ScTextJoin_MS() } } - -void ScInterpreter::ScIfs_MS() -{ - short nParamCount = GetByte(); - - ReverseStack( nParamCount ); - - nGlobalError = 0; // propagate only for condition or active result path - bool bFinished = false; - while ( nParamCount > 0 && !bFinished && !nGlobalError ) - { - bool bVal = GetBool(); - nParamCount--; - if ( bVal ) - { - // TRUE - if ( nParamCount < 1 ) - { - // no parameter given for THEN - PushParameterExpected(); - return; - } - bFinished = true; - } - else - { - // FALSE - if ( nParamCount >= 3 ) - { - // ELSEIF path - Pop(); - nParamCount--; - } - else - { - // no parameter given for ELSE - PushNA(); - return; - } - } - } - - if ( nGlobalError || !bFinished ) - { - if ( !bFinished ) - PushNA(); // no true expression found - if ( nGlobalError ) - PushNoValue(); // expression returned something other than true or false - return; - } - - //push result : - FormulaTokenRef xToken( PopToken() ); - if ( xToken ) - PushTempToken( xToken.get() ); - else - PushError( errUnknownStackVariable ); -} - - -void ScInterpreter::ScSwitch_MS() -{ - short nParamCount = GetByte(); - - if (!MustHaveParamCountMin( nParamCount, 3)) - return; - - ReverseStack( nParamCount ); - - nGlobalError = 0; // propagate only for match or active result path - bool isValue = false; - double fRefVal = 0; - svl::SharedString aRefStr; - switch ( GetStackType() ) - { - case svDouble: - isValue = true; - fRefVal = GetDouble(); - break; - case svString: - isValue = false; - aRefStr = GetString(); - break; - case svSingleRef : - case svDoubleRef : - { - ScAddress aAdr; - if (!PopDoubleRefOrSingleRef( aAdr )) - break; - ScRefCellValue aCell( *pDok, aAdr ); - isValue = !( aCell.hasString() || aCell.hasEmptyValue() || aCell.isEmpty() ); - if ( isValue ) - fRefVal = GetCellValue( aAdr, aCell); - else - GetCellString( aRefStr, aCell); - } - break; - case svExternalSingleRef: - case svExternalDoubleRef: - case svMatrix: - isValue = ScMatrix::IsValueType( GetDoubleOrStringFromMatrix( fRefVal, aRefStr ) ); - break; - default : - PopError(); - PushIllegalArgument(); - return; - } - nParamCount--; - bool bFinished = false; - while ( nParamCount > 1 && !bFinished && !nGlobalError ) - { - double fVal = 0; - svl::SharedString aStr; - if ( isValue ) - fVal = GetDouble(); - else - aStr = GetString(); - nParamCount--; - if ( nGlobalError || (( isValue && rtl::math::approxEqual( fRefVal, fVal ) ) || - ( !isValue && aRefStr.getDataIgnoreCase() == aStr.getDataIgnoreCase() )) ) - { - // TRUE - bFinished = true; - } - else - { - // FALSE - if ( nParamCount >= 2 ) - { - // ELSEIF path - Pop(); - nParamCount--; - // if nParamCount equals 1: default value to be returned - bFinished = ( nParamCount == 1 ); - } - else - { - // no parameter given for ELSE - PushNA(); - return; - } - nGlobalError = 0; - } - } - - if ( nGlobalError || !bFinished ) - { - if ( !bFinished ) - PushNA(); // no true expression found - else - PushError( nGlobalError ); - return; - } - - // push result - FormulaTokenRef xToken( PopToken() ); - if ( xToken ) - PushTempToken( xToken.get() ); - else - PushError( errUnknownStackVariable ); -} - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/tool/parclass.cxx b/sc/source/core/tool/parclass.cxx index bd8ca5544a8d..f7a7abf59c58 100644 --- a/sc/source/core/tool/parclass.cxx +++ b/sc/source/core/tool/parclass.cxx @@ -517,6 +517,8 @@ void ScParameterClassification::GenerateDocumentation() case ocIfError: case ocIfNA: case ocChoose: + case ocIfs_MS: + case ocSwitch_MS: aToken.SetByte(2); break; case ocPercentSign: diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx index c7f03f2b6f56..5bc35fef85d8 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -237,6 +237,8 @@ void ScRawToken::SetOpCode( OpCode e ) nJump[ 0 ] = 2; // If, Behind break; case ocChoose: + case ocIfs_MS: + case ocSwitch_MS: eType = svJump; nJump[ 0 ] = FORMULA_MAXJUMPCOUNT + 1; break; @@ -1347,6 +1349,8 @@ void ScTokenArray::CheckToken( const FormulaToken& r ) case ocIfError: case ocIfNA: case ocChoose: + case ocIfs_MS: + case ocSwitch_MS: // Jump commands are now supported. break; case ocAverage: diff --git a/sc/source/ui/unoobj/tokenuno.cxx b/sc/source/ui/unoobj/tokenuno.cxx index fab7c26e8350..08dba32dc1e0 100644 --- a/sc/source/ui/unoobj/tokenuno.cxx +++ b/sc/source/ui/unoobj/tokenuno.cxx @@ -478,7 +478,7 @@ bool ScTokenConversion::ConvertToTokenSequence( const ScDocument& rDoc, OSL_TRACE( "ScTokenConversion::ConvertToTokenSequence: unhandled token type SvStackVar %d", rToken.GetType()); SAL_FALLTHROUGH; case svSep: // occurs with ocSep, ocOpen, ocClose, ocArray* - case svJump: // occurs with ocIf, ocChoose + case svJump: // occurs with ocIf, ocChoose, ocError, ocNA, ocIfs_MS and ocSwitch_MS case svMissing: // occurs with ocMissing rAPI.Data.clear(); // no data }
_______________________________________________ LibreOffice mailing list LibreOffice@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/libreoffice