[Libreoffice-commits] core.git: 6 commits - formula/source include/formula sc/source

Eike Rathke erack at redhat.com
Sat Apr 23 13:53:01 UTC 2016


 formula/source/core/api/FormulaCompiler.cxx    |  167 +++++++++++++++++++++----
 formula/source/core/api/token.cxx              |    5 
 formula/source/core/resource/core_resource.src |    2 
 include/formula/grammar.hxx                    |   15 ++
 include/formula/tokenarray.hxx                 |   26 +--
 sc/source/core/tool/compiler.cxx               |    4 
 sc/source/core/tool/token.cxx                  |    4 
 7 files changed, 176 insertions(+), 47 deletions(-)

New commits:
commit 26adceb098134d918f6d57c8687ab057e24adc39
Author: Eike Rathke <erack at redhat.com>
Date:   Sat Apr 23 15:44:13 2016 +0200

    Resolves: tdf#96426 significant whitespace as intersection in Excel syntax
    
    Also when reading/writing OOXML, so change SC_OPCODE_INTERSECT of
    RID_STRLIST_FUNCTION_NAMES_ENGLISH_OOXML accordingly to " ", where
    previously "!" was expected and written, which was plain wrong.
    
    Change-Id: Ic0cfd7afc657f07bfd8e37de61b3621cc68685ff

diff --git a/formula/source/core/api/FormulaCompiler.cxx b/formula/source/core/api/FormulaCompiler.cxx
index fdf21e0..303e00e 100644
--- a/formula/source/core/api/FormulaCompiler.cxx
+++ b/formula/source/core/api/FormulaCompiler.cxx
@@ -1061,6 +1061,7 @@ bool FormulaCompiler::GetToken()
         bStop = true;
     else
     {
+        FormulaTokenRef pSpacesToken;
         short nWasColRowName;
         if ( pArr->nIndex > 0 && pArr->pCode[ pArr->nIndex-1 ]->GetOpCode() == ocColRowName )
              nWasColRowName = 1;
@@ -1069,6 +1070,9 @@ bool FormulaCompiler::GetToken()
         mpToken = pArr->Next();
         while( mpToken && mpToken->GetOpCode() == ocSpaces )
         {
+            // For significant whitespace remember last ocSpaces token. Usually
+            // there's only one even for multiple spaces.
+            pSpacesToken = mpToken;
             if ( nWasColRowName )
                 nWasColRowName++;
             if ( bAutoCorrect && !pStack )
@@ -1094,6 +1098,14 @@ bool FormulaCompiler::GetToken()
                 mpToken = new FormulaByteToken( ocIntersect );
                 pArr->nIndex--;     // we advanced to the second ocColRowName, step back
             }
+            else if (pSpacesToken && FormulaGrammar::isExcelSyntax( meGrammar))
+            {
+                // Let IntersectionLine() <- Factor() decide how to treat this,
+                // once the actual arguments are determined in RPN.
+                mpToken = pSpacesToken;
+                pArr->nIndex--;     // step back from next non-spaces token
+                return true;
+            }
         }
     }
     if( bStop )
@@ -1562,15 +1574,98 @@ void FormulaCompiler::RangeLine()
     }
 }
 
+namespace {
+
+bool isRangeResultFunction( OpCode eOp )
+{
+    switch (eOp)
+    {
+        case ocIndirect:
+        case ocOffset:
+            return true;
+        default:
+            return false;
+    }
+}
+
+bool isRangeResultOpCode( OpCode eOp )
+{
+    switch (eOp)
+    {
+        case ocRange:
+        case ocUnion:
+        case ocIntersect:
+        case ocIndirect:
+        case ocOffset:
+            return true;
+        default:
+            return false;
+    }
+}
+
+bool isPotentialRangeType( FormulaToken* pToken, bool bRPN )
+{
+    switch (pToken->GetType())
+    {
+        case svByte:                // could be range result, but only a few
+            if (bRPN)
+                return isRangeResultOpCode( pToken->GetOpCode());
+            else
+                return isRangeResultFunction( pToken->GetOpCode());
+        case svSingleRef:
+        case svDoubleRef:
+        case svIndex:               // could be range
+        //case svRefList:           // um..what?
+        case svExternalSingleRef:
+        case svExternalDoubleRef:
+        case svExternalName:        // could be range
+            return true;
+        default:
+            return false;
+    }
+}
+
+bool isIntersectable( FormulaToken** pCode1, FormulaToken** pCode2 )
+{
+    FormulaToken* pToken1 = *pCode1;
+    FormulaToken* pToken2 = *pCode2;
+    if (pToken1 && pToken2)
+        return isPotentialRangeType( pToken1, true) && isPotentialRangeType( pToken2, true);
+    return false;
+}
+
+}
+
 void FormulaCompiler::IntersectionLine()
 {
     RangeLine();
-    while (mpToken->GetOpCode() == ocIntersect)
+    while (mpToken->GetOpCode() == ocIntersect || mpToken->GetOpCode() == ocSpaces)
     {
+        sal_uInt16 nCodeIndex = pArr->nIndex - 1;
+        FormulaToken** pCode1 = pCode - 1;
         FormulaTokenRef p = mpToken;
         NextToken();
         RangeLine();
-        PutCode(p);
+        FormulaToken** pCode2 = pCode - 1;
+        if (p->GetOpCode() == ocSpaces)
+        {
+            // Convert to intersection if both left and right are references or
+            // functions (potentially returning references, if not then a space
+            // or no space would be a syntax error anyway), not other operators
+            // or operands. Else discard.
+            if (isIntersectable( pCode1, pCode2))
+            {
+                FormulaTokenRef pIntersect( new FormulaByteToken( ocIntersect));
+                // Replace ocSpaces with ocIntersect so that when switching
+                // formula syntax the correct operator string is created.
+                pArr->ReplaceToken( nCodeIndex, pIntersect.get(), FormulaTokenArray::ReplaceMode::CODE_ONLY);
+                PutCode( pIntersect);
+            }
+        }
+        else
+        {
+            PutCode(p);
+        }
     }
 }
 
@@ -1920,6 +2015,14 @@ const FormulaToken* FormulaCompiler::CreateStringFromToken( OUStringBuffer& rBuf
     }
     else if( eOp >= ocInternalBegin && eOp <= ocInternalEnd )
         rBuffer.appendAscii( pInternal[ eOp - ocInternalBegin ] );
+    else if (eOp == ocIntersect)
+    {
+        // Nasty, ugly, horrific, terrifying..
+        if (FormulaGrammar::isExcelSyntax( meGrammar))
+            rBuffer.append(' ');
+        else
+            rBuffer.append( mxSymbols->getSymbol( eOp));
+    }
     else if( (sal_uInt16) eOp < mxSymbols->getSymbolCount())        // Keyword:
         rBuffer.append( mxSymbols->getSymbol( eOp));
     else
@@ -2208,7 +2311,24 @@ OpCode FormulaCompiler::NextToken()
                 }
             }
         }
-        eLastOp = eOp;
+        // Nasty, ugly, horrific, terrifying.. significant whitespace..
+        if (eOp == ocSpaces && FormulaGrammar::isExcelSyntax( meGrammar))
+        {
+            // Fake an intersection op as last op for the next round, but at
+            // least roughly check if it could make sense at all.
+            if (eLastOp == ocPush || eLastOp == ocClose)
+            {
+                FormulaToken* pNext = pArr->PeekNextNoSpaces();
+                if (pNext && isPotentialRangeType( pNext, false))
+                    eLastOp = ocIntersect;
+                else
+                    eLastOp = eOp;
+            }
+            else
+                eLastOp = eOp;
+        }
+        else
+            eLastOp = eOp;
     }
     return eOp;
 }
diff --git a/formula/source/core/resource/core_resource.src b/formula/source/core/resource/core_resource.src
index 0fb5a63..bf49624 100644
--- a/formula/source/core/resource/core_resource.src
+++ b/formula/source/core/resource/core_resource.src
@@ -486,7 +486,7 @@ Resource RID_STRLIST_FUNCTION_NAMES_ENGLISH_OOXML
     String SC_OPCODE_AND { Text = "AND" ; };
     String SC_OPCODE_OR { Text = "OR" ; };
     String SC_OPCODE_XOR { Text = "_xlfn.XOR" ; };
-    String SC_OPCODE_INTERSECT { Text = "!" ; };
+    String SC_OPCODE_INTERSECT { Text = " " ; };
     String SC_OPCODE_UNION { Text = "~" ; };
     String SC_OPCODE_RANGE { Text = ":" ; };
     String SC_OPCODE_NOT { Text = "NOT" ; };
diff --git a/include/formula/grammar.hxx b/include/formula/grammar.hxx
index 91ca7ae11..6500d68 100644
--- a/include/formula/grammar.hxx
+++ b/include/formula/grammar.hxx
@@ -203,6 +203,21 @@ public:
             css::sheet::FormulaLanguage::OOXML;
     }
 
+    /// If grammar has an Excel syntax, determined by address convention.
+    static inline bool isExcelSyntax( const Grammar eGrammar )
+    {
+        AddressConvention eConv = extractRefConvention( eGrammar );
+        switch (eConv)
+        {
+            case FormulaGrammar::AddressConvention::CONV_XL_A1:
+            case FormulaGrammar::AddressConvention::CONV_XL_R1C1:
+            case FormulaGrammar::AddressConvention::CONV_XL_OOX:
+                return true;
+            default:
+                return false;
+        }
+    }
+
 };
 
 } // formula
commit f41257dc9913cd6020a3a37bf425c20b51e18ece
Author: Eike Rathke <erack at redhat.com>
Date:   Sat Apr 23 14:33:50 2016 +0200

    simplify the ReplaceToken() offset logic to absolute offsets
    
    Change-Id: I8d02fb63bc0c5cb48aabaf7a8800f5f9ac95cbf5

diff --git a/formula/source/core/api/token.cxx b/formula/source/core/api/token.cxx
index 7009d94..ac5e339 100644
--- a/formula/source/core/api/token.cxx
+++ b/formula/source/core/api/token.cxx
@@ -867,16 +867,13 @@ FormulaToken* FormulaTokenArray::MergeArray( )
 FormulaToken* FormulaTokenArray::ReplaceToken( sal_uInt16 nOffset, FormulaToken* t,
         FormulaTokenArray::ReplaceMode eMode )
 {
-    if (eMode == BACKWARD_CODE_ONLY)
-        nOffset = nLen - nOffset - 1;
-
     if (nOffset < nLen)
     {
         CheckToken(*t);
         t->IncRef();
         FormulaToken* p = pCode[nOffset];
         pCode[nOffset] = t;
-        if (eMode == FORWARD_CODE_AND_RPN && p->GetRef() > 1)
+        if (eMode == CODE_AND_RPN && p->GetRef() > 1)
         {
             for (sal_uInt16 i=0; i < nRPN; ++i)
             {
diff --git a/include/formula/tokenarray.hxx b/include/formula/tokenarray.hxx
index e890c3a..cd0f430 100644
--- a/include/formula/tokenarray.hxx
+++ b/include/formula/tokenarray.hxx
@@ -127,23 +127,19 @@ protected:
 public:
     enum ReplaceMode
     {
-        BACKWARD_CODE_ONLY,     ///< offset goes backward, replacement only in pCode
-        FORWARD_CODE_AND_RPN    ///< offset goes forward, replacement in pCode and RPN
+        CODE_ONLY,      ///< replacement only in pCode
+        CODE_AND_RPN    ///< replacement in pCode and pRPN
     };
 
 protected:
     /** Also used by the compiler. The token MUST had been allocated with new!
         @param  nOffset
-                If eMode==BACKWARD_CODE_ONLY negative offset of token, 0==last,
-                1==previous, ...
-                If eMode==FORWARD_CODE_AND_RPN positive offset of token, 0==first,
-                1==second, ...
+                Absolute offset in pCode of the token to be replaced.
         @param  eMode
-                If BACKWARD_CODE_ONLY only the token in pCode at nLen-nOffset-1
-                is replaced.
-                If FORWARD_CODE_AND_RPN the token in pCode at nOffset is
-                replaced; if the original token was also referenced in the RPN
-                array then that reference is replaced with a reference to the new
+                If CODE_ONLY only the token in pCode at nOffset is replaced.
+                If CODE_AND_RPN the token in pCode at nOffset is replaced;
+                if the original token was also referenced in the pRPN array
+                then that reference is replaced with a reference to the new
                 token as well.
      */
     FormulaToken*           ReplaceToken( sal_uInt16 nOffset, FormulaToken*, ReplaceMode eMode );
diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx
index e16446a..f647286 100644
--- a/sc/source/core/tool/compiler.cxx
+++ b/sc/source/core/tool/compiler.cxx
@@ -4325,8 +4325,8 @@ ScTokenArray* ScCompiler::CompileString( const OUString& rFormula )
                 FormulaToken* pTableRefToken = new ScTableRefToken( pPrev->GetIndex(), ScTableRefToken::TABLE);
                 maTableRefs.push_back( TableRefEntry( pTableRefToken));
                 // pPrev may be dead hereafter.
-                static_cast<ScTokenArray*>(pArr)->ReplaceToken( 1, pTableRefToken,
-                        FormulaTokenArray::ReplaceMode::BACKWARD_CODE_ONLY);
+                static_cast<ScTokenArray*>(pArr)->ReplaceToken( nIdx, pTableRefToken,
+                        FormulaTokenArray::ReplaceMode::CODE_ONLY);
             }
         }
         switch (eOp)
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index 154868e..00203e0 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -2397,7 +2397,7 @@ void ScTokenArray::ReadjustAbsolute3DReferences( const ScDocument* pOldDoc, cons
                     OUString aTabName;
                     sal_uInt16 nFileId;
                     GetExternalTableData(pOldDoc, pNewDoc, rRef1.Tab(), aTabName, nFileId);
-                    ReplaceToken( j, new ScExternalDoubleRefToken(nFileId, aTabName, rRef), FORWARD_CODE_AND_RPN);
+                    ReplaceToken( j, new ScExternalDoubleRefToken(nFileId, aTabName, rRef), CODE_AND_RPN);
                     // ATTENTION: rRef can't be used after this point
                 }
             }
@@ -2414,7 +2414,7 @@ void ScTokenArray::ReadjustAbsolute3DReferences( const ScDocument* pOldDoc, cons
                     OUString aTabName;
                     sal_uInt16 nFileId;
                     GetExternalTableData(pOldDoc, pNewDoc, rRef.Tab(), aTabName, nFileId);
-                    ReplaceToken( j, new ScExternalSingleRefToken(nFileId, aTabName, rRef), FORWARD_CODE_AND_RPN);
+                    ReplaceToken( j, new ScExternalSingleRefToken(nFileId, aTabName, rRef), CODE_AND_RPN);
                     // ATTENTION: rRef can't be used after this point
                 }
             }
commit 9185f889ed9da48aad07d6a552224561f38e9b99
Author: Eike Rathke <erack at redhat.com>
Date:   Fri Apr 22 21:12:23 2016 +0200

    newline shortage
    
    Change-Id: Id2487480270bb2be765495bb6d5982c85ae2117f

diff --git a/formula/source/core/api/FormulaCompiler.cxx b/formula/source/core/api/FormulaCompiler.cxx
index 492abb0..fdf21e0 100644
--- a/formula/source/core/api/FormulaCompiler.cxx
+++ b/formula/source/core/api/FormulaCompiler.cxx
@@ -2212,6 +2212,7 @@ OpCode FormulaCompiler::NextToken()
     }
     return eOp;
 }
+
 void FormulaCompiler::PutCode( FormulaTokenRef& p )
 {
     if( pc >= FORMULA_MAXTOKENS - 1 )
commit 7756822206e84669f55cec1e75ede8c09d5693a7
Author: Eike Rathke <erack at redhat.com>
Date:   Fri Apr 22 19:18:13 2016 +0200

    alignment
    
    Change-Id: If7dbdcd93a43d4e14f853b7d3436fa31c0091403

diff --git a/include/formula/tokenarray.hxx b/include/formula/tokenarray.hxx
index 7960591..e890c3a 100644
--- a/include/formula/tokenarray.hxx
+++ b/include/formula/tokenarray.hxx
@@ -109,10 +109,10 @@ class FORMULA_DLLPUBLIC FormulaTokenArray
 protected:
     FormulaToken**  pCode;                  // Token code array
     FormulaToken**  pRPN;                   // RPN array
-    sal_uInt16          nLen;                   // Length of token array
-    sal_uInt16          nRPN;                   // Length of RPN array
-    sal_uInt16          nIndex;                 // Current step index
-    sal_uInt16          nError;                 // Error code
+    sal_uInt16      nLen;                   // Length of token array
+    sal_uInt16      nRPN;                   // Length of RPN array
+    sal_uInt16      nIndex;                 // Current step index
+    sal_uInt16      nError;                 // Error code
     ScRecalcMode    nMode;                  // Flags to indicate when to recalc this code
     bool            bHyperLink;             // If HYPERLINK() occurs in the formula.
     bool            mbFromRangeName;        // If this array originates from a named expression
commit 737040e5db1b74f49d3a075ac4c64e218b1134de
Author: Eike Rathke <erack at redhat.com>
Date:   Fri Apr 22 18:42:05 2016 +0200

    change multiple ifs to switch case
    
    ... obtaining mpToken->GetOpCode() only once.
    
    Change-Id: I909fef97540998a7f09115738fb76a1e963480bf

diff --git a/formula/source/core/api/FormulaCompiler.cxx b/formula/source/core/api/FormulaCompiler.cxx
index 31004d4..492abb0 100644
--- a/formula/source/core/api/FormulaCompiler.cxx
+++ b/formula/source/core/api/FormulaCompiler.cxx
@@ -1101,27 +1101,29 @@ bool FormulaCompiler::GetToken()
         mpToken = new FormulaByteToken( ocStop );
         return false;
     }
-    if ( mpToken->GetOpCode() == ocSubTotal || mpToken->GetOpCode() == ocAggregate )
-        glSubTotal = true;
-    else if ( mpToken->IsExternalRef() )
+    if ( mpToken->IsExternalRef() )
     {
         return HandleExternalReference(*mpToken);
     }
-    else if( mpToken->GetOpCode() == ocName )
-    {
-        return HandleRange();
-    }
-    else if( mpToken->GetOpCode() == ocColRowName )
-    {
-        return HandleColRowName();
-    }
-    else if( mpToken->GetOpCode() == ocDBArea )
-    {
-        return HandleDbData();
-    }
-    else if( mpToken->GetOpCode() == ocTableRef )
+    else
     {
-        return HandleTableRef();
+        switch (mpToken->GetOpCode())
+        {
+            case ocSubTotal:
+            case ocAggregate:
+                glSubTotal = true;
+                break;
+            case ocName:
+                return HandleRange();
+            case ocColRowName:
+                return HandleColRowName();
+            case ocDBArea:
+                return HandleDbData();
+            case ocTableRef:
+                return HandleTableRef();
+            default:
+                ;   // nothing
+        }
     }
     return true;
 }
commit 4c5932cf06f0434a0df32203d567cab976402011
Author: Eike Rathke <erack at redhat.com>
Date:   Fri Apr 22 18:30:29 2016 +0200

    join two lines that cause an annoying debugger step over experience
    
    Change-Id: I50bf6710f7319f5c2ea18d8a3aa02f5c613de063

diff --git a/formula/source/core/api/FormulaCompiler.cxx b/formula/source/core/api/FormulaCompiler.cxx
index baacb94..31004d4 100644
--- a/formula/source/core/api/FormulaCompiler.cxx
+++ b/formula/source/core/api/FormulaCompiler.cxx
@@ -1062,8 +1062,7 @@ bool FormulaCompiler::GetToken()
     else
     {
         short nWasColRowName;
-        if ( pArr->nIndex
-          && pArr->pCode[ pArr->nIndex-1 ]->GetOpCode() == ocColRowName )
+        if ( pArr->nIndex > 0 && pArr->pCode[ pArr->nIndex-1 ]->GetOpCode() == ocColRowName )
              nWasColRowName = 1;
         else
              nWasColRowName = 0;
@@ -1102,8 +1101,7 @@ bool FormulaCompiler::GetToken()
         mpToken = new FormulaByteToken( ocStop );
         return false;
     }
-    if ( mpToken->GetOpCode() == ocSubTotal ||
-         mpToken->GetOpCode() == ocAggregate )
+    if ( mpToken->GetOpCode() == ocSubTotal || mpToken->GetOpCode() == ocAggregate )
         glSubTotal = true;
     else if ( mpToken->IsExternalRef() )
     {


More information about the Libreoffice-commits mailing list