void FormulaCompiler::Factor()

in main/formula/source/core/api/FormulaCompiler.cxx [873:1158]


void FormulaCompiler::Factor()
{
    if ( pArr->GetCodeError() && !bIgnoreErrors )
        return;

    CurrentFactor pFacToken( this );

    OpCode eOp = pToken->GetOpCode();
    if( eOp == ocPush || eOp == ocColRowNameAuto || eOp == ocMatRef ||
            eOp == ocDBArea
            || (bCompileForFAP && ((eOp == ocName) || (eOp == ocDBArea)
            || (eOp == ocColRowName) || (eOp == ocBad)))
        )
    {
        PutCode( pToken );
        eOp = NextToken();
        if( eOp == ocOpen )
        {
            // PUSH( is an error that may be caused by an unknown function.
            SetError(
                ( pToken->GetType() == svString
               || pToken->GetType() == svSingleRef )
               ? errNoName : errOperatorExpected );
            if ( bAutoCorrect && !pStack )
            {   // assume multiplication
                aCorrectedFormula += mxSymbols->getSymbol(ocMul);
                bCorrected = sal_True;
                NextToken();
                eOp = Expression();
                if( eOp != ocClose )
                    SetError(errPairExpected);
                else
                    eOp = NextToken();
            }
        }
    }
    else if( eOp == ocOpen )
    {
        NextToken();
        eOp = Expression();
        while ((eOp == ocSep) && (!pArr->GetCodeError() || bIgnoreErrors))
        {   // range list  (A1;A2)  converted to  (A1~A2)
            pFacToken = pToken;
            NextToken();
            eOp = Expression();
            // Do not ignore error here, regardless of bIgnoreErrors, otherwise
            // errors like =(1;) would also result in display of =(1~)
            if (!pArr->GetCodeError())
            {
                pFacToken->NewOpCode( ocUnion,FormulaToken::PrivateAccess());
                PutCode( pFacToken);
            }
        }
        if (eOp != ocClose)
            SetError(errPairExpected);
        else
            eOp = NextToken();
    }
    else
    {
        if( nNumFmt == NUMBERFORMAT_UNDEFINED )
            nNumFmt = lcl_GetRetFormat( eOp );
        // Functions that have to be always recalculated
        switch( eOp )
        {
            // no parameters:
            case ocRandom:
            case ocGetActDate:
            case ocGetActTime:
            // one parameter:
            case ocFormula:
            case ocInfo:
            // more than one parameters:
                // ocIndirect/ocIndirectXL otherwise would have to do
                // StopListening and StartListening on a reference for every
                // interpreted value.
            case ocIndirect:
            case ocIndirectXL:
                // ocOffset results in indirect references.
            case ocOffset:
                pArr->SetRecalcModeAlways();
            break;
                // Functions recalculated on every document load.
                // Don't use SetRecalcModeOnLoad() which would override
                // ModeAlways.
            case ocConvert :
                pArr->AddRecalcMode( RECALCMODE_ONLOAD );
            break;
                // If the referred cell is moved the value changes.
            case ocColumn :
            case ocRow :
                // ocCell needs recalc on move for some possible type values.
            case ocCell :
                pArr->SetRecalcModeOnRefMove();
            break;
            case ocHyperLink :
                pArr->SetHyperLink(sal_True);
            break;
            default:
                ;   // nothing
        }
        if (SC_OPCODE_START_NO_PAR <= eOp && eOp < SC_OPCODE_STOP_NO_PAR)
        {
            pFacToken = pToken;
            eOp = NextToken();
            if (eOp != ocOpen)
            {
                SetError(errPairExpected);
                PutCode( pFacToken );
            }
            else
            {
                eOp = NextToken();
                if (eOp != ocClose)
                    SetError(errPairExpected);
                PutCode(pFacToken);
                eOp = NextToken();
            }
        }
        // special cases NOT() and NEG()
        else if( eOp == ocNot || eOp == ocNeg
              || (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR) )
        {
            pFacToken = pToken;
            eOp = NextToken();
            if( nNumFmt == NUMBERFORMAT_UNDEFINED && eOp == ocNot )
                nNumFmt = NUMBERFORMAT_LOGICAL;
            if (eOp == ocOpen)
            {
                NextToken();
                eOp = Expression();
            }
            else
                SetError(errPairExpected);
            if (eOp != ocClose)
                SetError(errPairExpected);
            else if ( !pArr->GetCodeError() )
                pFacToken->SetByte( 1 );
            PutCode( pFacToken );
            eOp = NextToken();
        }
        else if ((SC_OPCODE_START_2_PAR <= eOp && eOp < SC_OPCODE_STOP_2_PAR)
                || eOp == ocExternal
                || eOp == ocMacro
                || eOp == ocAnd
                || eOp == ocOr
                || eOp == ocBad
                || ( eOp >= ocInternalBegin && eOp <= ocInternalEnd )
                || (bCompileForFAP && ((eOp == ocIf) || (eOp == ocChose)))
            )
        {
            pFacToken = pToken;
            OpCode eMyLastOp = eOp;
            eOp = NextToken();
            bool bNoParam = false;
            bool bBadName = false;
            if (eOp == ocOpen)
            {
                eOp = NextToken();
                if (eOp == ocClose)
                    bNoParam = true;
                else
                    eOp = Expression();
            }
            else if (eMyLastOp == ocBad)
            {
                // Just a bad name, not an unknown function, no parameters, no
                // closing expected.
                bBadName = true;
                bNoParam = true;
            }
            else
                SetError(errPairExpected);
            sal_uInt8 nSepCount = 0;
            if( !bNoParam )
            {
                nSepCount++;
                while ( (eOp == ocSep) && (!pArr->GetCodeError() || bIgnoreErrors) )
                {
                    nSepCount++;
                    NextToken();
                    eOp = Expression();
                }
            }
            if (bBadName)
                ;   // nothing, keep current token for return
            else if (eOp != ocClose)
                SetError(errPairExpected);
            else
                eOp = NextToken();
            // Jumps are just normal functions for the FunctionAutoPilot tree view
            if ( bCompileForFAP && pFacToken->GetType() == svJump )
                pFacToken = new FormulaFAPToken( pFacToken->GetOpCode(), nSepCount, pFacToken );
            else
                pFacToken->SetByte( nSepCount );
            PutCode( pFacToken );
        }
        else if (eOp == ocIf || eOp == ocChose)
        {
            // the PC counters are -1
            pFacToken = pToken;
            if ( eOp == ocIf )
                pFacToken->GetJump()[ 0 ] = 3;  // if, else, behind
            else
                pFacToken->GetJump()[ 0 ] = MAXJUMPCOUNT+1;
            eOp = NextToken();
            if (eOp == ocOpen)
            {
                NextToken();
                eOp = Expression();
            }
            else
                SetError(errPairExpected);
            short nJumpCount = 0;
            PutCode( pFacToken );
            // #36253# during AutoCorrect (since pArr->GetCodeError() is
            // ignored) an unlimited ocIf would crash because
            // ScRawToken::Clone() allocates the JumpBuffer according to
            // nJump[0]*2+2, which is 3*2+2 on ocIf.
            const short nJumpMax =
                (pFacToken->GetOpCode() == ocIf ? 3 : MAXJUMPCOUNT);
            while ( (nJumpCount < (MAXJUMPCOUNT - 1)) && (eOp == ocSep)
                    && (!pArr->GetCodeError() || bIgnoreErrors) )
            {
                if ( ++nJumpCount <= nJumpMax )
                    pFacToken->GetJump()[nJumpCount] = pc-1;
                NextToken();
                eOp = Expression();
                // ocSep or ocClose terminate the subexpression
                PutCode( pToken );
            }
            if (eOp != ocClose)
                SetError(errPairExpected);
            else
            {
                eOp = NextToken();
                // always limit to nJumpMax, no arbitrary overwrites
                if ( ++nJumpCount <= nJumpMax )
                    pFacToken->GetJump()[ nJumpCount ] = pc-1;
                if ((pFacToken->GetOpCode() == ocIf && (nJumpCount > 3)) ||
                                 (nJumpCount >= MAXJUMPCOUNT))
                    SetError(errIllegalParameter);
                else
                    pFacToken->GetJump()[ 0 ] = nJumpCount;
            }
        }
        else if ( eOp == ocMissing )
        {
            PutCode( pToken );
            eOp = NextToken();
        }
        else if ( eOp == ocClose )
        {
            SetError( errParameterExpected );
        }
        else if ( eOp == ocSep )
        {   // Subsequent ocSep
            SetError( errParameterExpected );
            if ( bAutoCorrect && !pStack )
            {
                aCorrectedSymbol.Erase();
                bCorrected = sal_True;
            }
        }
        else if ( eOp == ocExternalRef )
        {
            PutCode(pToken);
            eOp = NextToken();
        }
        else
        {
            SetError( errUnknownToken );
            if ( bAutoCorrect && !pStack )
            {
                if ( eOp == ocStop )
                {   // trailing operator w/o operand
                    xub_StrLen nLen = aCorrectedFormula.Len();
                    if ( nLen )
                        aCorrectedFormula.Erase( nLen - 1 );
                    aCorrectedSymbol.Erase();
                    bCorrected = sal_True;
                }
            }
        }
    }
}