Get rid of the index inside FormulaTokenArray

Instead, use FormulaTokenArrrayPlainIterator everywhere, especially in
the FormulaCompiler.

This is the final step of a long chain of commits. (Split up into many
"uncontroversial" bits, and then this, to make potential bisecting
easier.)

Also added a logging operator<< for FormulaTokenArray, for SAL_DEBUG,
SAL_INFO etc goodness.

Change-Id: I02fe29f3f1e0dc33e5cba69e594223b4178a12bc
Reviewed-on: https://gerrit.libreoffice.org/38851
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Tor Lillqvist <tml@collabora.com>
diff --git a/formula/source/core/api/FormulaCompiler.cxx b/formula/source/core/api/FormulaCompiler.cxx
index 7da7587..310ddb2 100644
--- a/formula/source/core/api/FormulaCompiler.cxx
+++ b/formula/source/core/api/FormulaCompiler.cxx
@@ -700,6 +700,7 @@ FormulaCompiler::FormulaCompiler( FormulaTokenArray& rArr )
        :
        nCurrentFactorParam(0),
        pArr( &rArr ),
        maArrIterator( rArr ),
        pCode( nullptr ),
        pStack( nullptr ),
        eLastOp( ocPush ),
@@ -715,10 +716,13 @@ FormulaCompiler::FormulaCompiler( FormulaTokenArray& rArr )
{
}

FormulaTokenArray FormulaCompiler::smDummyTokenArray;

FormulaCompiler::FormulaCompiler()
        :
        nCurrentFactorParam(0),
        pArr( nullptr ),
        maArrIterator( smDummyTokenArray ),
        pCode( nullptr ),
        pStack( nullptr ),
        eLastOp( ocPush ),
@@ -1260,11 +1264,11 @@ bool FormulaCompiler::GetToken()
    {
        FormulaTokenRef pSpacesToken;
        short nWasColRowName;
        if ( pArr->nIndex > 0 && pArr->pCode[ pArr->nIndex-1 ]->GetOpCode() == ocColRowName )
        if ( maArrIterator.mnIndex > 0 && pArr->pCode[ maArrIterator.mnIndex-1 ]->GetOpCode() == ocColRowName )
             nWasColRowName = 1;
        else
             nWasColRowName = 0;
        mpToken = pArr->Next();
        mpToken = maArrIterator.Next();
        while( mpToken && mpToken->GetOpCode() == ocSpaces )
        {
            // For significant whitespace remember last ocSpaces token. Usually
@@ -1274,7 +1278,7 @@ bool FormulaCompiler::GetToken()
                nWasColRowName++;
            if ( bAutoCorrect && !pStack )
                CreateStringFromToken( aCorrectedFormula, mpToken.get() );
            mpToken = pArr->Next();
            mpToken = maArrIterator.Next();
        }
        if ( bAutoCorrect && !pStack && mpToken )
            CreateStringFromToken( aCorrectedSymbol, mpToken.get() );
@@ -1296,7 +1300,7 @@ bool FormulaCompiler::GetToken()
            if ( nWasColRowName >= 2 && mpToken->GetOpCode() == ocColRowName )
            {   // convert an ocSpaces to ocIntersect in RPN
                mpLastToken = mpToken = new FormulaByteToken( ocIntersect );
                pArr->nIndex--;     // we advanced to the second ocColRowName, step back
                maArrIterator.mnIndex--;     // we advanced to the second ocColRowName, step back
            }
            else if (pSpacesToken && FormulaGrammar::isExcelSyntax( meGrammar) &&
                    mpLastToken && mpToken &&
@@ -1306,7 +1310,7 @@ bool FormulaCompiler::GetToken()
                // Let IntersectionLine() <- Factor() decide how to treat this,
                // once the actual arguments are determined in RPN.
                mpLastToken = mpToken = pSpacesToken;
                pArr->nIndex--;     // step back from next non-spaces token
                maArrIterator.mnIndex--;     // step back from next non-spaces token
                return true;
            }
        }
@@ -1494,7 +1498,7 @@ void FormulaCompiler::Factor()
                else
                    SetError( FormulaError::PairExpected);
                sal_uInt8 nSepCount = 0;
                const sal_uInt16 nSepPos = pArr->nIndex - 1;    // separator position, if any
                const sal_uInt16 nSepPos = maArrIterator.mnIndex - 1;    // separator position, if any
                if( !bNoParam )
                {
                    nSepCount++;
@@ -1521,12 +1525,13 @@ void FormulaCompiler::Factor()
                    // Current index is nSepPos+3 if expression stops, or
                    // nSepPos+4 if expression continues after the call because
                    // we just called NextToken() to move away from it.
                    if (pc >= 2 && (pArr->nIndex == nSepPos + 3 || pArr->nIndex == nSepPos + 4) &&
                    if (pc >= 2 && (maArrIterator.mnIndex == nSepPos + 3 || maArrIterator.mnIndex == nSepPos + 4) &&
                            pArr->pCode[nSepPos+1]->GetType() == svDouble &&
                            pArr->pCode[nSepPos+1]->GetDouble() != 1.0 &&
                            pArr->pCode[nSepPos+2]->GetOpCode() == ocClose &&
                            pArr->RemoveToken( nSepPos, 2) == 2)
                    {
                        maArrIterator.AfterRemoveToken( nSepPos, 2);
                        // Remove the ocPush/svDouble just removed also from
                        // the compiler local RPN array.
                        --pCode; --pc;
@@ -1783,7 +1788,7 @@ void FormulaCompiler::IntersectionLine()
    RangeLine();
    while (mpToken->GetOpCode() == ocIntersect || mpToken->GetOpCode() == ocSpaces)
    {
        sal_uInt16 nCodeIndex = pArr->nIndex - 1;
        sal_uInt16 nCodeIndex = maArrIterator.mnIndex - 1;
        FormulaToken** pCode1 = pCode - 1;
        FormulaTokenRef p = mpToken;
        NextToken();
@@ -1984,6 +1989,7 @@ bool FormulaCompiler::CompileTokenArray()
            aCorrectedSymbol.clear();
        }
        pArr->DelRPN();
        maArrIterator.Reset();
        pStack = nullptr;
        FormulaToken* pData[ FORMULA_MAXTOKENS ];
        pCode = pData;
@@ -1994,7 +2000,7 @@ bool FormulaCompiler::CompileTokenArray()
                aCorrectedFormula = "=";
        }
        pArr->ClearRecalcMode();
        pArr->Reset();
        maArrIterator.Reset();
        eLastOp = ocOpen;
        pc = 0;
        NextToken();
@@ -2021,6 +2027,7 @@ bool FormulaCompiler::CompileTokenArray()
        if (pArr->GetCodeError() != FormulaError::NONE && mbStopOnError)
        {
            pArr->DelRPN();
            maArrIterator.Reset();
            pArr->SetHyperLink( false);
        }

@@ -2049,6 +2056,8 @@ void FormulaCompiler::PopTokenArray()
        if( p->bTemp )
            delete pArr;
        pArr = p->pArr;
        maArrIterator = FormulaTokenArrayPlainIterator(*pArr);
        maArrIterator.Jump(p->nIndex);
        mpLastToken = p->mpLastToken;
        delete p;
    }
@@ -2068,20 +2077,27 @@ void FormulaCompiler::CreateStringFromTokenArray( OUStringBuffer& rBuffer )
        return;

    FormulaTokenArray* pSaveArr = pArr;
    int nSaveIndex = maArrIterator.GetIndex();
    bool bODFF = FormulaGrammar::isODFF( meGrammar);
    if (bODFF || FormulaGrammar::isPODF( meGrammar) )
    {
        // Scan token array for missing args and re-write if present.
        MissingConventionODF aConv( bODFF);
        if (pArr->NeedsPodfRewrite( aConv))
        {
            pArr = pArr->RewriteMissing( aConv );
            maArrIterator = FormulaTokenArrayPlainIterator( *pArr );
        }
    }
    else if ( FormulaGrammar::isOOXML( meGrammar ) )
    {
        // Scan token array for missing args and rewrite if present.
        MissingConventionOOXML aConv;
        if (pArr->NeedsOoxmlRewrite())
        {
            pArr = pArr->RewriteMissing( aConv );
            maArrIterator = FormulaTokenArrayPlainIterator( *pArr );
        }
    }

    // At least one character per token, plus some are references, some are
@@ -2090,7 +2106,7 @@ void FormulaCompiler::CreateStringFromTokenArray( OUStringBuffer& rBuffer )

    if ( pArr->IsRecalcModeForced() )
        rBuffer.append( '=');
    const FormulaToken* t = pArr->First();
    const FormulaToken* t = maArrIterator.First();
    while( t )
        t = CreateStringFromToken( rBuffer, t, true );

@@ -2098,6 +2114,8 @@ void FormulaCompiler::CreateStringFromTokenArray( OUStringBuffer& rBuffer )
    {
        delete pArr;
        pArr = pSaveArr;
        maArrIterator = FormulaTokenArrayPlainIterator( *pArr );
        maArrIterator.Jump(nSaveIndex);
    }
}

@@ -2120,9 +2138,9 @@ const FormulaToken* FormulaCompiler::CreateStringFromToken( OUStringBuffer& rBuf
    {
        // AND, OR infix?
        if ( bAllowArrAdvance )
            t = pArr->Next();
            t = maArrIterator.Next();
        else
            t = pArr->PeekNext();
            t = maArrIterator.PeekNext();
        bNext = false;
        bSpaces = ( !t || t->GetOpCode() != ocOpen );
    }
@@ -2134,11 +2152,11 @@ const FormulaToken* FormulaCompiler::CreateStringFromToken( OUStringBuffer& rBuf
        bool bIntersectionOp = mxSymbols->isODFF();
        if (bIntersectionOp)
        {
            const FormulaToken* p = pArr->PeekPrevNoSpaces();
            const FormulaToken* p = maArrIterator.PeekPrevNoSpaces();
            bIntersectionOp = (p && p->GetOpCode() == ocColRowName);
            if (bIntersectionOp)
            {
                p = pArr->PeekNextNoSpaces();
                p = maArrIterator.PeekNextNoSpaces();
                bIntersectionOp = (p && p->GetOpCode() == ocColRowName);
            }
        }
@@ -2208,13 +2226,13 @@ const FormulaToken* FormulaCompiler::CreateStringFromToken( OUStringBuffer& rBuf
                {
                    // Suppress all TableRef related tokens, the resulting
                    // range was written by CreateStringFromIndex().
                    const FormulaToken* const p = pArr->PeekNext();
                    const FormulaToken* const p = maArrIterator.PeekNext();
                    if (p && p->GetOpCode() == ocTableRefOpen)
                    {
                        int nLevel = 0;
                        do
                        {
                            t = pArr->Next();
                            t = maArrIterator.Next();
                            if (!t)
                                break;

@@ -2284,7 +2302,7 @@ const FormulaToken* FormulaCompiler::CreateStringFromToken( OUStringBuffer& rBuf
    if ( bAllowArrAdvance )
    {
        if( bNext )
            t = pArr->Next();
            t = maArrIterator.Next();
        return t;
    }
    return pTokenP;
@@ -2457,10 +2475,10 @@ OpCode FormulaCompiler::NextToken()
        {
            // Fake an intersection op as last op for the next round, but at
            // least roughly check if it could make sense at all.
            FormulaToken* pPrev = pArr->PeekPrevNoSpaces();
            FormulaToken* pPrev = maArrIterator.PeekPrevNoSpaces();
            if (pPrev && isPotentialRangeType( pPrev, false, false))
            {
                FormulaToken* pNext = pArr->PeekNextNoSpaces();
                FormulaToken* pNext = maArrIterator.PeekNextNoSpaces();
                if (pNext && isPotentialRangeType( pNext, false, true))
                    eLastOp = ocIntersect;
                else
@@ -2610,10 +2628,12 @@ void FormulaCompiler::PushTokenArray( FormulaTokenArray* pa, bool bTemp )
    FormulaArrayStack* p = new FormulaArrayStack;
    p->pNext      = pStack;
    p->pArr       = pArr;
    p->nIndex     = maArrIterator.GetIndex();
    p->mpLastToken = mpLastToken;
    p->bTemp      = bTemp;
    pStack        = p;
    pArr          = pa;
    maArrIterator = FormulaTokenArrayPlainIterator( *pArr );
}

} // namespace formula
diff --git a/formula/source/core/api/token.cxx b/formula/source/core/api/token.cxx
index 1e966f1..78c69ea 100644
--- a/formula/source/core/api/token.cxx
+++ b/formula/source/core/api/token.cxx
@@ -456,134 +456,6 @@ bool FormulaTokenArray::Fill(
    }
    return bError;
}
FormulaToken* FormulaTokenArray::GetNextReference()
{
    while( nIndex < nLen )
    {
        FormulaToken* t = pCode[ nIndex++ ];
        switch( t->GetType() )
        {
            case svSingleRef:
            case svDoubleRef:
            case svExternalSingleRef:
            case svExternalDoubleRef:
                return t;
            default:
            {
                // added to avoid warnings
            }
        }
    }
    return nullptr;
}

FormulaToken* FormulaTokenArray::GetNextColRowName()
{
    while( nIndex < nLen )
    {
        FormulaToken* t = pCode[ nIndex++ ];
        if ( t->GetOpCode() == ocColRowName )
            return t;
    }
    return nullptr;
}

FormulaToken* FormulaTokenArray::GetNextReferenceRPN()
{
    while( nIndex < nRPN )
    {
        FormulaToken* t = pRPN[ nIndex++ ];
        switch( t->GetType() )
        {
            case svSingleRef:
            case svDoubleRef:
            case svExternalSingleRef:
            case svExternalDoubleRef:
                return t;
            default:
            {
                // added to avoid warnings
            }
        }
    }
    return nullptr;
}

FormulaToken* FormulaTokenArray::GetNextReferenceOrName()
{
    if( pCode )
    {
        while ( nIndex < nLen )
        {
            FormulaToken* t = pCode[ nIndex++ ];
            switch( t->GetType() )
            {
                case svSingleRef:
                case svDoubleRef:
                case svIndex:
                case svExternalSingleRef:
                case svExternalDoubleRef:
                case svExternalName:
                    return t;
                default:
                {
                    // added to avoid warnings
                }
             }
         }
     }
    return nullptr;
}

FormulaToken* FormulaTokenArray::GetNextName()
{
    if( pCode )
    {
        while ( nIndex < nLen )
        {
            FormulaToken* t = pCode[ nIndex++ ];
            if( t->GetType() == svIndex )
                return t;
        }
    } // if( pCode )
    return nullptr;
}

FormulaToken* FormulaTokenArray::Next()
{
    if( pCode && nIndex < nLen )
        return pCode[ nIndex++ ];
    else
        return nullptr;
}

FormulaToken* FormulaTokenArray::NextNoSpaces()
{
    if( pCode )
    {
        while( (nIndex < nLen) && (pCode[ nIndex ]->GetOpCode() == ocSpaces) )
            ++nIndex;
        if( nIndex < nLen )
            return pCode[ nIndex++ ];
    }
    return nullptr;
}

FormulaToken* FormulaTokenArray::NextRPN()
{
    if( pRPN && nIndex < nRPN )
        return pRPN[ nIndex++ ];
    else
        return nullptr;
}

FormulaToken* FormulaTokenArray::PrevRPN()
{
    if( pRPN && nIndex )
        return pRPN[ --nIndex ];
    else
        return nullptr;
}

void FormulaTokenArray::DelRPN()
{
@@ -597,7 +469,7 @@ void FormulaTokenArray::DelRPN()
        delete [] pRPN;
    }
    pRPN = nullptr;
    nRPN = nIndex = 0;
    nRPN = 0;
}

FormulaToken* FormulaTokenArray::FirstToken() const
@@ -614,46 +486,6 @@ FormulaToken* FormulaTokenArray::PeekPrev( sal_uInt16 & nIdx )
    return nullptr;
}

FormulaToken* FormulaTokenArray::PeekNext()
{
    if( pCode && nIndex < nLen )
        return pCode[ nIndex ];
    else
        return nullptr;
}

FormulaToken* FormulaTokenArray::PeekNextNoSpaces()
{
    if( pCode && nIndex < nLen )
    {
        sal_uInt16 j = nIndex;
        while ( j < nLen && pCode[j]->GetOpCode() == ocSpaces )
            j++;
        if ( j < nLen )
            return pCode[ j ];
        else
            return nullptr;
    }
    else
        return nullptr;
}

FormulaToken* FormulaTokenArray::PeekPrevNoSpaces()
{
    if( pCode && nIndex > 1 )
    {
        sal_uInt16 j = nIndex - 2;
        while ( pCode[j]->GetOpCode() == ocSpaces && j > 0 )
            j--;
        if ( j > 0 || pCode[j]->GetOpCode() != ocSpaces )
            return pCode[ j ];
        else
            return nullptr;
    }
    else
        return nullptr;
}

FormulaToken* FormulaTokenArray::FirstRPNToken() const
{
    if (!pRPN || nRPN == 0)
@@ -737,7 +569,6 @@ FormulaTokenArray::FormulaTokenArray() :
    pRPN(nullptr),
    nLen(0),
    nRPN(0),
    nIndex(0),
    nError(FormulaError::NONE),
    nMode(ScRecalcMode::NORMAL),
    bHyperLink(false),
@@ -761,7 +592,6 @@ void FormulaTokenArray::Assign( const FormulaTokenArray& r )
{
    nLen   = r.nLen;
    nRPN   = r.nRPN;
    nIndex = r.nIndex;
    nError = r.nError;
    nMode  = r.nMode;
    bHyperLink = r.bHyperLink;
@@ -828,7 +658,7 @@ void FormulaTokenArray::Clear()
    }
    pCode = nullptr; pRPN = nullptr;
    nError = FormulaError::NONE;
    nLen = nIndex = nRPN = 0;
    nLen = nRPN = 0;
    bHyperLink = false;
    mbFromRangeName = false;
    mbShareable = true;
@@ -924,13 +754,6 @@ sal_uInt16 FormulaTokenArray::RemoveToken( sal_uInt16 nOffset, sal_uInt16 nCount
        }
        nLen -= nCount;

        if (nIndex >= nOffset)
        {
            if (nIndex < nStop)
                nIndex = nOffset + 1;
            else
                nIndex -= nStop - nOffset;
        }
        return nCount;
    }
    else
diff --git a/include/formula/FormulaCompiler.hxx b/include/formula/FormulaCompiler.hxx
index f665020..a9b6567 100644
--- a/include/formula/FormulaCompiler.hxx
+++ b/include/formula/FormulaCompiler.hxx
@@ -29,6 +29,7 @@
#include <formula/grammar.hxx>
#include <formula/opcode.hxx>
#include <formula/token.hxx>
#include <formula/tokenarray.hxx>
#include <formula/types.hxx>
#include <formula/paramclass.hxx>
#include <rtl/ustrbuf.hxx>
@@ -53,12 +54,12 @@ enum class FormulaError : sal_uInt16;

namespace formula
{
    class FormulaTokenArray;

struct FormulaArrayStack
{
    FormulaArrayStack*  pNext;
    FormulaTokenArray*  pArr;
    sal_uInt16          nIndex;
    FormulaTokenRef     mpLastToken;
    bool bTemp;
};
@@ -331,6 +332,7 @@ protected:
    FormulaTokenRef     pCurrentFactorToken;    // current factor token (of Factor() method)
    sal_uInt16          nCurrentFactorParam;    // current factor token's parameter, 1-based
    FormulaTokenArray*  pArr;
    FormulaTokenArrayPlainIterator maArrIterator;
    FormulaTokenRef     mpLastToken;            // last token

    FormulaToken**      pCode;
@@ -416,6 +418,8 @@ private:
    mutable NonConstOpCodeMapPtr  mxSymbolsEnglish;   // English symbols
    mutable NonConstOpCodeMapPtr  mxSymbolsEnglishXL; // English Excel symbols (for VBA formula parsing)
    mutable NonConstOpCodeMapPtr  mxSymbolsOOXML;     // Excel OOXML symbols

    static FormulaTokenArray smDummyTokenArray;
};

} // formula
diff --git a/include/formula/tokenarray.hxx b/include/formula/tokenarray.hxx
index 72cb0e5..8a00c02 100644
--- a/include/formula/tokenarray.hxx
+++ b/include/formula/tokenarray.hxx
@@ -22,6 +22,7 @@

#include <climits>
#include <memory>
#include <ostream>
#include <type_traits>
#include <unordered_set>
#include <unordered_map>
@@ -123,7 +124,6 @@ protected:
    FormulaToken**  pRPN;                   // RPN array
    sal_uInt16      nLen;                   // Length of token array
    sal_uInt16      nRPN;                   // Length of RPN array
    sal_uInt16      nIndex;                 // Current step index
    FormulaError    nError;                 // Error code
    ScRecalcMode    nMode;                  // Flags to indicate when to recalc this code
    bool            bHyperLink      :1;     // If HYPERLINK() occurs in the formula.
@@ -161,9 +161,7 @@ protected:
    /** Remove a sequence of tokens from pCode array, and pRPN array if the
        tokens are referenced there.

        This' nLen and nRPN are adapted, as is nIndex if it points behind
        nOffset. If nIndex points into the to be removed range
        (nOffset < nIndex < nOffset+nCount) it is set to nOffset+1.
        nLen and nRPN are adapted.

        @param  nOffset
                Start offset into pCode.
@@ -205,24 +203,10 @@ public:

    void Clear();
    void DelRPN();
    FormulaToken* First() { nIndex = 0; return Next(); }
    FormulaToken* FirstToken() const;
    FormulaToken* Next();
    FormulaToken* NextNoSpaces();
    FormulaToken* GetNextName();
    FormulaToken* GetNextReference();
    FormulaToken* GetNextReferenceRPN();
    FormulaToken* GetNextReferenceOrName();
    FormulaToken* GetNextColRowName();
    /// Peek at nIdx-1 if not out of bounds, decrements nIdx if successful. Returns NULL if not.
    FormulaToken* PeekPrev( sal_uInt16 & nIdx );
    FormulaToken* PeekNext();
    FormulaToken* PeekPrevNoSpaces();    /// Only after Reset/First/Next/Last/Prev!
    FormulaToken* PeekNextNoSpaces();    /// Only after Reset/First/Next/Last/Prev!
    FormulaToken* FirstRPNToken() const;
    FormulaToken* NextRPN();
    FormulaToken* LastRPN() { nIndex = nRPN; return PrevRPN(); }
    FormulaToken* PrevRPN();

    bool HasReferences() const;

@@ -246,7 +230,6 @@ public:
    FormulaToken** GetCode()  const  { return pRPN; }
    sal_uInt16     GetLen() const     { return nLen; }
    sal_uInt16     GetCodeLen() const { return nRPN; }
    void           Reset()            { nIndex = 0; }
    FormulaError   GetCodeError() const      { return nError; }
    void      SetCodeError( FormulaError n )  { nError = n; }
    void      SetHyperLink( bool bVal ) { bHyperLink = bVal; }
@@ -407,6 +390,22 @@ private:
    const FormulaToken* GetNonEndOfPathToken( short nIdx ) const;
};

// For use in SAL_INFO, SAL_WARN etc

template<typename charT, typename traits>
inline std::basic_ostream<charT, traits> & operator <<(std::basic_ostream<charT, traits> & stream, const FormulaTokenArray& point)
{
    stream <<
        static_cast<const void*>(&point) <<
        ":{nLen=" << point.GetLen() <<
        ",nRPN=" << point.GetCodeLen() <<
        ",pCode=" << static_cast<void*>(point.GetArray()) <<
        ",pRPN=" << static_cast<void*>(point.GetCode()) <<
        "}";

    return stream;
}

class FORMULA_DLLPUBLIC FormulaTokenArrayPlainIterator
{
    friend class FormulaCompiler;
diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx
index 943c89d..50775af 100644
--- a/sc/source/core/tool/compiler.cxx
+++ b/sc/source/core/tool/compiler.cxx
@@ -4361,6 +4361,7 @@ ScTokenArray* ScCompiler::CompileString( const OUString& rFormula )

    ScTokenArray aArr;
    pArr = &aArr;
    maArrIterator = FormulaTokenArrayPlainIterator(*pArr);
    aFormula = comphelper::string::strip(rFormula, ' ');

    nSrcPos = 0;
@@ -4645,6 +4646,7 @@ ScTokenArray* ScCompiler::CompileString( const OUString& rFormula )
    ScTokenArray* pNew = new ScTokenArray( aArr );
    pNew->GenHash();
    pArr = pNew;
    maArrIterator = FormulaTokenArrayPlainIterator(*pArr);

    if (!maExternalFiles.empty())
    {
@@ -4675,6 +4677,7 @@ ScTokenArray* ScCompiler::CompileString( const OUString& rFormula, const OUStrin
            // remember pArr, in case a subsequent CompileTokenArray() is executed.
            ScTokenArray* pNew = new ScTokenArray( aTokenArray );
            pArr = pNew;
            maArrIterator = FormulaTokenArrayPlainIterator(*pArr);
            return pNew;
        }
    }
@@ -4707,8 +4710,8 @@ bool ScCompiler::HandleRange()
            // or if not directly between ocSep/parenthesis,
            // e.g. SUM(...;(...;...)) no, SUM(...;(...)*3) yes,
            // in short: if it isn't a self-contained expression.
            FormulaToken* p1 = pArr->PeekPrevNoSpaces();
            FormulaToken* p2 = pArr->PeekNextNoSpaces();
            FormulaToken* p1 = maArrIterator.PeekPrevNoSpaces();
            FormulaToken* p2 = maArrIterator.PeekNextNoSpaces();
            OpCode eOp1 = (p1 ? p1->GetOpCode() : ocSep);
            OpCode eOp2 = (p2 ? p2->GetOpCode() : ocSep);
            bool bBorder1 = (eOp1 == ocSep || eOp1 == ocOpen);
@@ -4719,7 +4722,6 @@ bool ScCompiler::HandleRange()
                pNew = new ScTokenArray();
                pNew->AddOpCode( ocClose );
                PushTokenArray( pNew, true );
                pNew->Reset();
            }
            pNew = pRangeData->GetCode()->Clone();
            pNew->SetFromRangeName( true );
@@ -4737,13 +4739,12 @@ bool ScCompiler::HandleRange()
                SetRelNameReference();
                MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
            }
            pNew->Reset();
            maArrIterator.Reset();
            if ( bAddPair )
            {
                pNew = new ScTokenArray();
                pNew->AddOpCode( ocOpen );
                PushTokenArray( pNew, true );
                pNew->Reset();
            }
            return GetToken();
        }
@@ -4755,7 +4756,6 @@ bool ScCompiler::HandleRange()
        pNew = new ScTokenArray;
        pNew->Add( new FormulaErrorToken( FormulaError::NoName));
        PushTokenArray( pNew, true );
        pNew->Reset();
        return GetToken();
    }
    return true;
@@ -4791,12 +4791,12 @@ bool ScCompiler::HandleExternalReference(const FormulaToken& _aToken)

            ScTokenArray* pNew = xNew->Clone();
            PushTokenArray( pNew, true);
            if (pNew->GetNextReference() != nullptr)
            if (FormulaTokenArrayPlainIterator(*pNew).GetNextReference() != nullptr)
            {
                SetRelNameReference();
                MoveRelWrap(MAXCOL, MAXROW);
            }
            pNew->Reset();
            maArrIterator.Reset();
            return GetToken();
        }
        default:
@@ -4808,8 +4808,8 @@ bool ScCompiler::HandleExternalReference(const FormulaToken& _aToken)

void ScCompiler::AdjustSheetLocalNameRelReferences( SCTAB nDelta )
{
    pArr->Reset();
    for (formula::FormulaToken* t = pArr->GetNextReference(); t; t = pArr->GetNextReference())
    maArrIterator.Reset();
    for (formula::FormulaToken* t = maArrIterator.GetNextReference(); t; t = maArrIterator.GetNextReference())
    {
        ScSingleRefData& rRef1 = *t->GetSingleRef();
        if (rRef1.IsTabRel())
@@ -4827,9 +4827,9 @@ void ScCompiler::AdjustSheetLocalNameRelReferences( SCTAB nDelta )

void ScCompiler::SetRelNameReference()
{
    pArr->Reset();
    for( formula::FormulaToken* t = pArr->GetNextReference(); t;
                  t = pArr->GetNextReference() )
    maArrIterator.Reset();
    for( formula::FormulaToken* t = maArrIterator.GetNextReference(); t;
                  t = maArrIterator.GetNextReference() )
    {
        ScSingleRefData& rRef1 = *t->GetSingleRef();
        if ( rRef1.IsColRel() || rRef1.IsRowRel() || rRef1.IsTabRel() )
@@ -4847,9 +4847,9 @@ void ScCompiler::SetRelNameReference()
// don't call for other token arrays!
void ScCompiler::MoveRelWrap( SCCOL nMaxCol, SCROW nMaxRow )
{
    pArr->Reset();
    for( formula::FormulaToken* t = pArr->GetNextReference(); t;
                  t = pArr->GetNextReference() )
    maArrIterator.Reset();
    for( formula::FormulaToken* t = maArrIterator.GetNextReference(); t;
                  t = maArrIterator.GetNextReference() )
    {
        if ( t->GetType() == svSingleRef || t->GetType() == svExternalSingleRef )
            ScRefUpdate::MoveRelWrap( pDoc, aPos, nMaxCol, nMaxRow, SingleDoubleRefModifier( *t->GetSingleRef() ).Ref() );
@@ -4863,9 +4863,9 @@ void ScCompiler::MoveRelWrap( SCCOL nMaxCol, SCROW nMaxRow )
void ScCompiler::MoveRelWrap( ScTokenArray& rArr, ScDocument* pDoc, const ScAddress& rPos,
                              SCCOL nMaxCol, SCROW nMaxRow )
{
    rArr.Reset();
    for( formula::FormulaToken* t = rArr.GetNextReference(); t;
                  t = rArr.GetNextReference() )
    formula::FormulaTokenArrayPlainIterator aIter(rArr);
    for( formula::FormulaToken* t = aIter.GetNextReference(); t;
                  t = aIter.GetNextReference() )
    {
        if ( t->GetType() == svSingleRef || t->GetType() == svExternalSingleRef )
            ScRefUpdate::MoveRelWrap( pDoc, rPos, nMaxCol, nMaxRow, SingleDoubleRefModifier( *t->GetSingleRef() ).Ref() );
@@ -5031,7 +5031,7 @@ void ScCompiler::CreateStringFromSingleRef( OUStringBuffer& rBuffer, const Formu
                              GetSetupTabNames(), aRef, true, (pArr && pArr->IsFromRangeName()));
        }
    }
    else if (pArr && (p = pArr->PeekPrevNoSpaces()) && p->GetOpCode() == ocTableRefOpen)
    else if (pArr && (p = maArrIterator.PeekPrevNoSpaces()) && p->GetOpCode() == ocTableRefOpen)
    {
        OUString aStr;
        ScAddress aAbs = rRef.toAbs(aPos);
@@ -5351,8 +5351,8 @@ bool ScCompiler::HandleColRowName()
            bFound = true;
        else
        {
            FormulaToken* p1 = pArr->PeekPrevNoSpaces();
            FormulaToken* p2 = pArr->PeekNextNoSpaces();
            FormulaToken* p1 = maArrIterator.PeekPrevNoSpaces();
            FormulaToken* p2 = maArrIterator.PeekNextNoSpaces();
            // begin/end of a formula => single
            OpCode eOp1 = p1 ? p1->GetOpCode() : ocAdd;
            OpCode eOp2 = p2 ? p2->GetOpCode() : ocAdd;
@@ -5422,7 +5422,6 @@ bool ScCompiler::HandleColRowName()
                }
            }
            PushTokenArray( pNew, true );
            pNew->Reset();
            return GetToken();
        }
    }
@@ -5447,7 +5446,6 @@ bool ScCompiler::HandleDbData()
        ScTokenArray* pNew = new ScTokenArray();
        pNew->AddDoubleReference( aRefData );
        PushTokenArray( pNew, true );
        pNew->Reset();
        return GetToken();
    }
    return true;
@@ -5455,7 +5453,7 @@ bool ScCompiler::HandleDbData()

bool ScCompiler::GetTokenIfOpCode( OpCode eOp )
{
    const formula::FormulaToken* p = pArr->PeekNextNoSpaces();
    const formula::FormulaToken* p = maArrIterator.PeekNextNoSpaces();
    if (p && p->GetOpCode() == eOp)
        return GetToken();
    return false;
@@ -5590,7 +5588,7 @@ bool ScCompiler::HandleTableRef()
            } eState = sOpen;
            do
            {
                const formula::FormulaToken* p = pArr->PeekNextNoSpaces();
                const formula::FormulaToken* p = maArrIterator.PeekNextNoSpaces();
                if (!p)
                    eState = sStop;
                else
@@ -5762,7 +5760,6 @@ bool ScCompiler::HandleTableRef()
                SetError( FormulaError::Pair);
        }
        PushTokenArray( pNew, true );
        pNew->Reset();
        return GetToken();
    }
    return true;
diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx
index 37c9db9..6b5247b 100644
--- a/sc/source/core/tool/interpr4.cxx
+++ b/sc/source/core/tool/interpr4.cxx
@@ -1296,7 +1296,8 @@ void ScInterpreter::GetExternalDoubleRef(
        return;
    }

    formula::FormulaToken* pToken = pArray->First();
    formula::FormulaTokenArrayPlainIterator aIter(*pArray);
    formula::FormulaToken* pToken = aIter.First();
    if (pToken->GetType() == svError)
    {
        SetError( pToken->GetError());
@@ -1308,7 +1309,7 @@ void ScInterpreter::GetExternalDoubleRef(
        return;
    }

    if (pArray->Next())
    if (aIter.Next())
    {
        // Can't handle more than one matrix per parameter.
        SetError( FormulaError::IllegalArgument);