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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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() ) { _______________________________________________ Libreoffice-commits mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
