summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDennis Francis <dennis.francis@collabora.co.uk>2018-05-02 14:22:09 +0530
committerEike Rathke <erack@redhat.com>2018-06-26 15:41:54 +0200
commit60c5ca1b874ead7251653d01b0d50fdd42482e09 (patch)
tree0de305ced26b3d65f4419df6282562456c377fb5
parent6d22d02c321bc9f8f539865fd0fd3046e3ef3c6f (diff)
More Implicit intersection computation
Do implicit intersection computation for for single parameter functions while generating RPN token array when the argument is a doubleref with relative row references. This optimization is not done when under forced array mode or matrix formula mode. The computation logic was already present in ScInterpreter, so factored it out and reused. This also adds unit tests to ensure correctness of II computation for various cases. Change-Id: I509c3f6f811aa036b1dc3296e8f68904b26c3c49 Reviewed-on: https://gerrit.libreoffice.org/53885 Tested-by: Jenkins Reviewed-by: Eike Rathke <erack@redhat.com>
-rw-r--r--formula/source/core/api/FormulaCompiler.cxx24
-rw-r--r--formula/source/ui/dlg/formula.cxx2
-rw-r--r--include/formula/FormulaCompiler.hxx16
-rw-r--r--sc/inc/compiler.hxx16
-rw-r--r--sc/qa/unit/ucalc.hxx10
-rw-r--r--sc/qa/unit/ucalc_formula.cxx197
-rw-r--r--sc/source/core/data/column.cxx3
-rw-r--r--sc/source/core/data/column4.cxx3
-rw-r--r--sc/source/core/data/formulacell.cxx60
-rw-r--r--sc/source/core/data/simpleformulacalc.cxx2
-rw-r--r--sc/source/core/tool/compiler.cxx178
-rw-r--r--sc/source/core/tool/interpr4.cxx53
-rw-r--r--sc/source/filter/oox/formulabuffer.cxx4
-rw-r--r--sc/source/ui/view/viewfunc.cxx2
14 files changed, 449 insertions, 121 deletions
diff --git a/formula/source/core/api/FormulaCompiler.cxx b/formula/source/core/api/FormulaCompiler.cxx
index f5e06e77deba..671d2c2b9f62 100644
--- a/formula/source/core/api/FormulaCompiler.cxx
+++ b/formula/source/core/api/FormulaCompiler.cxx
@@ -697,7 +697,7 @@ void FormulaCompiler::OpCodeMap::putOpCode( const OUString & rStr, const OpCode
// class FormulaCompiler
-FormulaCompiler::FormulaCompiler( FormulaTokenArray& rArr )
+FormulaCompiler::FormulaCompiler( FormulaTokenArray& rArr, bool bComputeII, bool bMatrixFlag )
:
nCurrentFactorParam(0),
pArr( &rArr ),
@@ -714,13 +714,15 @@ FormulaCompiler::FormulaCompiler( FormulaTokenArray& rArr )
glSubTotal( false ),
needsRPNTokenCheck( false ),
mbJumpCommandReorder(true),
- mbStopOnError(true)
+ mbStopOnError(true),
+ mbComputeII(bComputeII),
+ mbMatrixFlag(bMatrixFlag)
{
}
FormulaTokenArray FormulaCompiler::smDummyTokenArray;
-FormulaCompiler::FormulaCompiler()
+FormulaCompiler::FormulaCompiler(bool bComputeII, bool bMatrixFlag)
:
nCurrentFactorParam(0),
pArr( nullptr ),
@@ -737,7 +739,9 @@ FormulaCompiler::FormulaCompiler()
glSubTotal( false ),
needsRPNTokenCheck( false ),
mbJumpCommandReorder(true),
- mbStopOnError(true)
+ mbStopOnError(true),
+ mbComputeII(bComputeII),
+ mbMatrixFlag(bMatrixFlag)
{
}
@@ -1549,6 +1553,7 @@ void FormulaCompiler::Factor()
else
{
// standard handling of 1-parameter opcodes
+ OpCode eMyLastOp = eOp;
pFacToken = mpToken;
eOp = NextToken();
if( nNumFmt == SvNumFormatType::UNDEFINED && eOp == ocNot )
@@ -1564,7 +1569,14 @@ void FormulaCompiler::Factor()
if (eOp != ocClose)
SetError( FormulaError::PairExpected);
else if ( pArr->GetCodeError() == FormulaError::NONE )
+ {
pFacToken->SetByte( 1 );
+ if (mbComputeII && IsIIOpCode(eMyLastOp))
+ {
+ FormulaToken** pArg = pCode - 1;
+ HandleIIOpCode(eMyLastOp, pFacToken->GetInForceArray(), &pArg, 1);
+ }
+ }
PutCode( pFacToken );
NextToken();
}
@@ -1606,7 +1618,7 @@ void FormulaCompiler::Factor()
sal_uInt32 nSepCount = 0;
if( !bNoParam )
{
- bool bDoIICompute = IsIIOpCode(eMyLastOp);
+ bool bDoIICompute = mbComputeII && IsIIOpCode(eMyLastOp);
// Array of FormulaToken double pointers to collect the parameters of II opcodes.
FormulaToken*** pArgArray = nullptr;
if (bDoIICompute)
@@ -1633,7 +1645,7 @@ void FormulaCompiler::Factor()
pArgArray[nSepCount - 1] = pCode - 1; // Add rest of the arguments
}
if (bDoIICompute)
- HandleIIOpCode(eMyLastOp, pArgArray,
+ HandleIIOpCode(eMyLastOp, pFacToken->GetInForceArray(), pArgArray,
std::min(nSepCount, static_cast<sal_uInt32>(FORMULA_MAXPARAMSII)));
}
if (bBadName)
diff --git a/formula/source/ui/dlg/formula.cxx b/formula/source/ui/dlg/formula.cxx
index e5b07260915a..5abc04622e15 100644
--- a/formula/source/ui/dlg/formula.cxx
+++ b/formula/source/ui/dlg/formula.cxx
@@ -831,6 +831,8 @@ void FormulaDlg_Impl::UpdateTokenArray( const OUString& rStrExp)
// #i101512# Disable special handling of jump commands.
pCompiler->EnableJumpCommandReorder(false);
pCompiler->EnableStopOnError(false);
+ pCompiler->SetComputeIIFlag(true);
+ pCompiler->SetMatrixFlag(m_bUserMatrixFlag);
pCompiler->CompileTokenArray();
}
diff --git a/include/formula/FormulaCompiler.hxx b/include/formula/FormulaCompiler.hxx
index 321e288fcc55..1f0bb0d95c5b 100644
--- a/include/formula/FormulaCompiler.hxx
+++ b/include/formula/FormulaCompiler.hxx
@@ -76,8 +76,8 @@ private:
FormulaCompiler(const FormulaCompiler&) = delete;
FormulaCompiler& operator=(const FormulaCompiler&) = delete;
public:
- FormulaCompiler();
- FormulaCompiler(FormulaTokenArray& _rArr);
+ FormulaCompiler(bool bComputeII = false, bool bMatrixFlag = false);
+ FormulaCompiler(FormulaTokenArray& _rArr, bool bComputeII = false, bool bMatrixFlag = false);
virtual ~FormulaCompiler();
/** Mappings from strings to OpCodes and vice versa. */
@@ -269,6 +269,12 @@ public:
static void ResetNativeSymbols();
static void SetNativeSymbols( const OpCodeMapPtr& xMap );
+ /** Sets the implicit intersection compute flag */
+ void SetComputeIIFlag(bool bSet) { mbComputeII = bSet; }
+
+ /** Sets the matrix flag for the formula*/
+ void SetMatrixFlag(bool bSet) { mbMatrixFlag = bSet; }
+
/** Separators mapped when loading opcodes from the resource, values other
than RESOURCE_BASE may override the resource strings. Used by OpCodeList
implementation via loadSymbols().
@@ -327,7 +333,8 @@ protected:
// This is no-op for this class.
virtual bool IsIIOpCode(OpCode /*nOpCode*/) const { return false; }
// Handles II opcode and passes the parameter array and number of parameters.
- virtual void HandleIIOpCode(OpCode /*nOpCode*/, FormulaToken*** /*pppToken*/, sal_uInt8 /*nNumParams*/) {}
+ virtual void HandleIIOpCode(OpCode /*nOpCode*/, formula::ParamClass /*eClass*/,
+ FormulaToken*** /*pppToken*/, sal_uInt8 /*nNumParams*/) {}
OUString aCorrectedFormula; // autocorrected Formula
OUString aCorrectedSymbol; // autocorrected Symbol
@@ -359,6 +366,9 @@ protected:
bool mbJumpCommandReorder; /// Whether or not to reorder RPN for jump commands.
bool mbStopOnError; /// Whether to stop compilation on first encountered error.
+ bool mbComputeII; // whether to attempt computing implicit intersection ranges while building the RPN array.
+ bool mbMatrixFlag; // whether the formula is a matrix formula (needed for II computation)
+
private:
void InitSymbolsNative() const; /// only SymbolsNative, on first document creation
void InitSymbolsEnglish() const; /// only SymbolsEnglish, maybe later
diff --git a/sc/inc/compiler.hxx b/sc/inc/compiler.hxx
index ffd783a32506..767d08b36e62 100644
--- a/sc/inc/compiler.hxx
+++ b/sc/inc/compiler.hxx
@@ -335,24 +335,25 @@ private:
static void InitCharClassEnglish();
public:
- ScCompiler( sc::CompileFormulaContext& rCxt, const ScAddress& rPos, const ScInterpreterContext* pContext = nullptr );
+ ScCompiler( sc::CompileFormulaContext& rCxt, const ScAddress& rPos,
+ bool bComputeII = false, bool bMatrixFlag = false, const ScInterpreterContext* pContext = nullptr );
/** If eGrammar == GRAM_UNSPECIFIED then the grammar of pDocument is used,
if pDocument==nullptr then GRAM_DEFAULT.
*/
ScCompiler( ScDocument* pDocument, const ScAddress&,
formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_UNSPECIFIED,
- const ScInterpreterContext* pContext = nullptr );
+ bool bComputeII = false, bool bMatrixFlag = false, const ScInterpreterContext* pContext = nullptr );
ScCompiler( sc::CompileFormulaContext& rCxt, const ScAddress& rPos, ScTokenArray& rArr,
- const ScInterpreterContext* pContext = nullptr );
+ bool bComputeII = false, bool bMatrixFlag = false, const ScInterpreterContext* pContext = nullptr );
/** If eGrammar == GRAM_UNSPECIFIED then the grammar of pDocument is used,
if pDocument==nullptr then GRAM_DEFAULT.
*/
ScCompiler( ScDocument* pDocument, const ScAddress&, ScTokenArray& rArr,
formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_UNSPECIFIED,
- const ScInterpreterContext* pContext = nullptr );
+ bool bComputeII = false, bool bMatrixFlag = false, const ScInterpreterContext* pContext = nullptr );
virtual ~ScCompiler() override;
@@ -451,6 +452,10 @@ public:
static bool IsCharFlagAllConventions(
OUString const & rStr, sal_Int32 nPos, ScCharFlags nFlags );
+ /** TODO : Move this to somewhere appropriate. */
+ static bool DoubleRefToPosSingleRefScalarCase(const ScRange& rRange, ScAddress& rAdr,
+ const ScAddress& rFormulaPos);
+
private:
// FormulaCompiler
virtual OUString FindAddInFunction( const OUString& rUpperName, bool bLocalFirst ) const override;
@@ -480,7 +485,8 @@ private:
{ return c < 128 ? pConv->getCharTableFlags(c, cLast) : ScCharFlags::NONE; }
bool IsIIOpCode(OpCode nOpCode) const override;
- void HandleIIOpCode(OpCode nOpCode, formula::FormulaToken*** pppToken, sal_uInt8 nNumParams) override;
+ void HandleIIOpCode(OpCode nOpCode, formula::ParamClass eClass, formula::FormulaToken*** pppToken, sal_uInt8 nNumParams) override;
+ void ReplaceDoubleRefII(formula::FormulaToken** ppDoubleRefTok);
bool AdjustSumRangeShape(const ScComplexRefData& rBaseRange, ScComplexRefData& rSumRange);
void CorrectSumRange(const ScComplexRefData& rBaseRange, ScComplexRefData& rSumRange, formula::FormulaToken** ppSumRangeToken);
};
diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index f1d6acb476eb..03305a8ad74e 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -143,7 +143,10 @@ public:
void testFormulaRefData();
void testFormulaCompiler();
void testFormulaCompilerJumpReordering();
- void testFormulaCompilerImplicitIntersection();
+ void testFormulaCompilerImplicitIntersection2Param();
+ void testFormulaCompilerImplicitIntersection1ParamNoChange();
+ void testFormulaCompilerImplicitIntersection1ParamWithChange();
+ void testFormulaCompilerImplicitIntersection1NoGroup();
void testFormulaRefUpdate();
void testFormulaRefUpdateRange();
void testFormulaRefUpdateSheets();
@@ -568,7 +571,10 @@ public:
CPPUNIT_TEST(testFormulaRefData);
CPPUNIT_TEST(testFormulaCompiler);
CPPUNIT_TEST(testFormulaCompilerJumpReordering);
- CPPUNIT_TEST(testFormulaCompilerImplicitIntersection);
+ CPPUNIT_TEST(testFormulaCompilerImplicitIntersection2Param);
+ CPPUNIT_TEST(testFormulaCompilerImplicitIntersection1ParamNoChange);
+ CPPUNIT_TEST(testFormulaCompilerImplicitIntersection1ParamWithChange);
+ CPPUNIT_TEST(testFormulaCompilerImplicitIntersection1NoGroup);
CPPUNIT_TEST(testFormulaRefUpdate);
CPPUNIT_TEST(testFormulaRefUpdateRange);
CPPUNIT_TEST(testFormulaRefUpdateSheets);
diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx
index 126bed6c9289..5900e3555ada 100644
--- a/sc/qa/unit/ucalc_formula.cxx
+++ b/sc/qa/unit/ucalc_formula.cxx
@@ -1105,7 +1105,7 @@ void Test::testFormulaCompilerJumpReordering()
}
}
-void Test::testFormulaCompilerImplicitIntersection()
+void Test::testFormulaCompilerImplicitIntersection2Param()
{
struct TestCaseFormula
{
@@ -1231,6 +1231,201 @@ void Test::testFormulaCompilerImplicitIntersection()
}
}
+void Test::testFormulaCompilerImplicitIntersection1ParamNoChange()
+{
+ struct TestCaseFormulaNoChange
+ {
+ OUString aFormula;
+ ScAddress aCellAddress;
+ bool bMatrixFormula;
+ bool bForcedArray;
+ };
+
+ m_pDoc->InsertTab(0, "Formula");
+ sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
+
+ {
+ ScAddress aStartAddr(4, 5, 0);
+ TestCaseFormulaNoChange aCasesNoChange[] =
+ {
+ {
+ OUString("=COS(A$2:A$100)"), // No change because of abs col ref.
+ aStartAddr,
+ false,
+ false
+ },
+ {
+ OUString("=COS($A7:$A100)"), // No intersection
+ aStartAddr,
+ false,
+ false
+ },
+ {
+ OUString("=COS($A5:$C7)"), // No intersection 2-D range
+ aStartAddr,
+ false,
+ false
+ },
+ {
+ OUString("=SUMPRODUCT(COS(A6:A10))"), // COS() in forced array mode
+ aStartAddr,
+ false,
+ true
+ },
+ {
+ OUString("=COS(A6:A10)"), // Matrix formula
+ aStartAddr,
+ true,
+ false
+ }
+ };
+
+ for (auto& rCase : aCasesNoChange)
+ {
+ if (rCase.bMatrixFormula)
+ {
+ ScMarkData aMark;
+ aMark.SelectOneTable(0);
+ SCCOL nColStart = rCase.aCellAddress.Col();
+ SCROW nRowStart = rCase.aCellAddress.Row();
+ m_pDoc->InsertMatrixFormula(nColStart, nRowStart, nColStart, nRowStart + 4,
+ aMark, rCase.aFormula);
+ }
+ else
+ m_pDoc->SetString(rCase.aCellAddress, rCase.aFormula);
+
+ const ScFormulaCell* pCell = m_pDoc->GetFormulaCell(rCase.aCellAddress);
+ const ScTokenArray* pCode = pCell->GetCode();
+ CPPUNIT_ASSERT(pCode);
+
+ sal_uInt16 nRPNLen = pCode->GetCodeLen();
+ sal_uInt16 nRawLen = pCode->GetLen();
+ sal_uInt16 nRawArgPos;
+ if (rCase.bForcedArray)
+ {
+ nRawArgPos = 4;
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong raw token count.", static_cast<sal_uInt16>(7), nRawLen);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong RPN token count.", static_cast<sal_uInt16>(3), nRPNLen);
+ }
+ else
+ {
+ nRawArgPos = 2;
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong raw token count.", static_cast<sal_uInt16>(4), nRawLen);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong RPN token count.", static_cast<sal_uInt16>(2), nRPNLen);
+ }
+
+ FormulaToken** ppRawTokens = pCode->GetArray();
+ FormulaToken** ppRPNTokens = pCode->GetCode();
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong type of raw token(argument to COS)", svDoubleRef, ppRawTokens[nRawArgPos]->GetType());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong type of RPN token(argument to COS)", svDoubleRef, ppRPNTokens[0]->GetType());
+
+ ScComplexRefData aArgRangeRaw = *ppRawTokens[nRawArgPos]->GetDoubleRef();
+ ScComplexRefData aArgRangeRPN = *ppRPNTokens[0]->GetDoubleRef();
+ bool bRawMatchRPNToken(aArgRangeRaw == aArgRangeRPN);
+ CPPUNIT_ASSERT_MESSAGE("raw arg token and RPN arg token contents do not match", bRawMatchRPNToken);
+ }
+ }
+}
+
+void Test::testFormulaCompilerImplicitIntersection1ParamWithChange()
+{
+ struct TestCaseFormula
+ {
+ OUString aFormula;
+ ScAddress aCellAddress;
+ ScAddress aArgAddr;
+ };
+
+ m_pDoc->InsertTab(0, "Formula");
+ m_pDoc->InsertTab(1, "Formula1");
+ sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
+
+ {
+ ScAddress aStartAddr(10, 5, 0);
+ TestCaseFormula aCasesWithChange[] =
+ {
+ {
+ OUString("=COS($A6:$A100)"), // Corner case with intersection
+ aStartAddr,
+ ScAddress(0, 5, 0)
+ },
+ {
+ OUString("=COS($A2:$A6)"), // Corner case with intersection
+ aStartAddr,
+ ScAddress(0, 5, 0)
+ },
+ {
+ OUString("=COS($A2:$A100)"), // Typical 1D case
+ aStartAddr,
+ ScAddress(0, 5, 0)
+ },
+ {
+ OUString("=COS($Formula.$A1:$C3)"), // 2D corner case
+ ScAddress(0, 0, 1), // Formula in sheet 1
+ ScAddress(0, 0, 0)
+ },
+ {
+ OUString("=COS($Formula.$A1:$C3)"), // 2D corner case
+ ScAddress(0, 2, 1), // Formula in sheet 1
+ ScAddress(0, 2, 0)
+ },
+ {
+ OUString("=COS($Formula.$A1:$C3)"), // 2D corner case
+ ScAddress(2, 0, 1), // Formula in sheet 1
+ ScAddress(2, 0, 0)
+ },
+ {
+ OUString("=COS($Formula.$A1:$C3)"), // 2D corner case
+ ScAddress(2, 2, 1), // Formula in sheet 1
+ ScAddress(2, 2, 0)
+ },
+ {
+ OUString("=COS($Formula.$A1:$C3)"), // Typical 2D case
+ ScAddress(1, 1, 1), // Formula in sheet 1
+ ScAddress(1, 1, 0)
+ }
+ };
+
+ for (auto& rCase : aCasesWithChange)
+ {
+ m_pDoc->SetString(rCase.aCellAddress, rCase.aFormula);
+
+ const ScFormulaCell* pCell = m_pDoc->GetFormulaCell(rCase.aCellAddress);
+ const ScTokenArray* pCode = pCell->GetCode();
+ CPPUNIT_ASSERT(pCode);
+
+ sal_uInt16 nRPNLen = pCode->GetCodeLen();
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong RPN token count.", static_cast<sal_uInt16>(2), nRPNLen);
+
+ FormulaToken** ppRPNTokens = pCode->GetCode();
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong type of RPN token(argument to COS)", svSingleRef, ppRPNTokens[0]->GetType());
+
+ ScSingleRefData aArgAddrRPN = *ppRPNTokens[0]->GetSingleRef();
+ ScAddress aArgAddrActual = aArgAddrRPN.toAbs(rCase.aCellAddress);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Computed implicit intersection singleref is wrong", rCase.aArgAddr, aArgAddrActual);
+ }
+ }
+}
+
+void Test::testFormulaCompilerImplicitIntersection1NoGroup()
+{
+ m_pDoc->InsertTab(0, "Formula");
+ sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
+
+ m_pDoc->SetString(ScAddress(1,2,0), "=COS(A1:A5)"); // B3
+ m_pDoc->SetString(ScAddress(1,3,0), "=COS(A1:A5)"); // B4
+
+ // Implicit intersection optimization in ScCompiler::HandleIIOpCode() internally changes
+ // these to "=COS(A3)" and "=COS(A4)", but these shouldn't be merged into a formula group,
+ // otherwise B4's formula would then be "=COS(A2:A6)".
+ ASSERT_FORMULA_EQUAL(*m_pDoc, ScAddress(1,2,0), "COS(A1:A5)", "Formula in B3 has changed.");
+ ASSERT_FORMULA_EQUAL(*m_pDoc, ScAddress(1,3,0), "COS(A1:A5)", "Formula in B4 has changed.");
+
+ m_pDoc->DeleteTab(0);
+}
+
void Test::testFormulaRefUpdate()
{
m_pDoc->InsertTab(0, "Formula");
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index d8f164e0c916..268ec1b7793c 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -2112,7 +2112,8 @@ class UpdateRefOnNonCopy
// We need to re-compile the token array when a range name is
// modified, to correctly reflect the new references in the
// name.
- ScCompiler aComp(&mpCxt->mrDoc, rTopCell.aPos, *rTopCell.GetCode(), mpCxt->mrDoc.GetGrammar());
+ ScCompiler aComp(&mpCxt->mrDoc, rTopCell.aPos, *rTopCell.GetCode(), mpCxt->mrDoc.GetGrammar(),
+ true, rTopCell.GetMatrixFlag() != ScMatrixMode::NONE);
aComp.CompileTokenArray();
}
diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx
index 832351d275a7..34566ac15bb1 100644
--- a/sc/source/core/data/column4.cxx
+++ b/sc/source/core/data/column4.cxx
@@ -928,7 +928,8 @@ public:
ScTokenArray* pNewCode = aComp.CompileString(aFormula);
// Generate RPN tokens.
- ScCompiler aComp2(mpDoc, pCell->aPos, *pNewCode);
+ ScCompiler aComp2(mpDoc, pCell->aPos, *pNewCode, formula::FormulaGrammar::GRAM_UNSPECIFIED,
+ true, pCell->GetMatrixFlag() != ScMatrixMode::NONE);
aComp2.CompileTokenArray();
pCell->SetCode(pNewCode);
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index e489f60936b7..3800397a9ca7 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -562,7 +562,8 @@ void ScFormulaCellGroup::compileCode(
if (mpCode->GetLen() && mpCode->GetCodeError() == FormulaError::NONE && !mpCode->GetCodeLen())
{
- ScCompiler aComp(&rDoc, rPos, *mpCode, eGram);
+ bool bMatrixFormula = mpTopCell->GetMatrixFlag() != ScMatrixMode::NONE;
+ ScCompiler aComp(&rDoc, rPos, *mpCode, eGram, true, bMatrixFormula);
mbSubTotal = aComp.CompileTokenArray();
mnFormatType = aComp.GetNumFormatType();
}
@@ -700,7 +701,7 @@ ScFormulaCell::ScFormulaCell(
// Generate RPN token array.
if (pCode->GetLen() && pCode->GetCodeError() == FormulaError::NONE && !pCode->GetCodeLen())
{
- ScCompiler aComp( pDocument, aPos, *pCode, eTempGrammar);
+ ScCompiler aComp( pDocument, aPos, *pCode, eTempGrammar, true, cMatrixFlag != ScMatrixMode::NONE );
bSubTotal = aComp.CompileTokenArray();
nFormatType = aComp.GetNumFormatType();
}
@@ -747,7 +748,7 @@ ScFormulaCell::ScFormulaCell(
// RPN array generation
if( pCode->GetLen() && pCode->GetCodeError() == FormulaError::NONE && !pCode->GetCodeLen() )
{
- ScCompiler aComp( pDocument, aPos, *pCode, eTempGrammar);
+ ScCompiler aComp( pDocument, aPos, *pCode, eTempGrammar, true, cMatrixFlag != ScMatrixMode::NONE );
bSubTotal = aComp.CompileTokenArray();
nFormatType = aComp.GetNumFormatType();
}
@@ -993,7 +994,7 @@ void ScFormulaCell::GetFormula( OUStringBuffer& rBuffer,
}
else
{
- ScCompiler aComp( pDocument, aPos, *pCode, eGrammar, pContext );
+ ScCompiler aComp( pDocument, aPos, *pCode, eGrammar, false, false, pContext );
aComp.CreateStringFromTokenArray( rBuffer );
}
}
@@ -1004,7 +1005,7 @@ void ScFormulaCell::GetFormula( OUStringBuffer& rBuffer,
}
else
{
- ScCompiler aComp( pDocument, aPos, *pCode, eGrammar, pContext );
+ ScCompiler aComp( pDocument, aPos, *pCode, eGrammar, false, false, pContext );
aComp.CreateStringFromTokenArray( rBuffer );
}
@@ -1031,7 +1032,7 @@ OUString ScFormulaCell::GetFormula( sc::CompileFormulaContext& rCxt, const ScInt
{
ScTokenArray aCode;
aCode.AddToken( FormulaErrorToken( pCode->GetCodeError()));
- ScCompiler aComp(rCxt, aPos, aCode, pContext);
+ ScCompiler aComp(rCxt, aPos, aCode, false, false, pContext);
aComp.CreateStringFromTokenArray(aBuf);
return aBuf.makeStringAndClear();
}
@@ -1058,7 +1059,7 @@ OUString ScFormulaCell::GetFormula( sc::CompileFormulaContext& rCxt, const ScInt
}
else
{
- ScCompiler aComp(rCxt, aPos, *pCode, pContext);
+ ScCompiler aComp(rCxt, aPos, *pCode, false, false, pContext);
aComp.CreateStringFromTokenArray(aBuf);
}
}
@@ -1069,7 +1070,7 @@ OUString ScFormulaCell::GetFormula( sc::CompileFormulaContext& rCxt, const ScInt
}
else
{
- ScCompiler aComp(rCxt, aPos, *pCode, pContext);
+ ScCompiler aComp(rCxt, aPos, *pCode, false, false, pContext);
aComp.CreateStringFromTokenArray(aBuf);
}
@@ -1199,7 +1200,7 @@ void ScFormulaCell::CompileTokenArray( bool bNoListening )
if( !bNoListening && pCode->GetCodeLen() )
EndListeningTo( pDocument );
- ScCompiler aComp(pDocument, aPos, *pCode, pDocument->GetGrammar());
+ ScCompiler aComp(pDocument, aPos, *pCode, pDocument->GetGrammar(), true, cMatrixFlag != ScMatrixMode::NONE);
bSubTotal = aComp.CompileTokenArray();
if( pCode->GetCodeError() == FormulaError::NONE )
{
@@ -1239,7 +1240,7 @@ void ScFormulaCell::CompileTokenArray( sc::CompileFormulaContext& rCxt, bool bNo
if( !bNoListening && pCode->GetCodeLen() )
EndListeningTo( pDocument );
- ScCompiler aComp(rCxt, aPos, *pCode);
+ ScCompiler aComp(rCxt, aPos, *pCode, true, cMatrixFlag != ScMatrixMode::NONE);
bSubTotal = aComp.CompileTokenArray();
if( pCode->GetCodeError() == FormulaError::NONE )
{
@@ -1277,7 +1278,7 @@ void ScFormulaCell::CompileXML( sc::CompileFormulaContext& rCxt, ScProgress& rPr
if (bWasInFormulaTree)
pDocument->RemoveFromFormulaTree( this);
rCxt.setGrammar(eTempGrammar);
- ScCompiler aComp(rCxt, aPos, *pCode);
+ ScCompiler aComp(rCxt, aPos, *pCode, true, cMatrixFlag != ScMatrixMode::NONE);
OUString aFormula, aFormulaNmsp;
aComp.CreateStringFromXMLTokenArray( aFormula, aFormulaNmsp );
pDocument->DecXMLImportedFormulaCount( aFormula.getLength() );
@@ -1395,7 +1396,7 @@ void ScFormulaCell::CalcAfterLoad( sc::CompileFormulaContext& rCxt, bool bStartL
// The RPN array is not created when a Calc 3.0-Doc has been read as the Range Names exist until now.
if( pCode->GetLen() && !pCode->GetCodeLen() && pCode->GetCodeError() == FormulaError::NONE )
{
- ScCompiler aComp(rCxt, aPos, *pCode);
+ ScCompiler aComp(rCxt, aPos, *pCode, true, cMatrixFlag != ScMatrixMode::NONE);
bSubTotal = aComp.CompileTokenArray();
nFormatType = aComp.GetNumFormatType();
bDirty = true;
@@ -4110,6 +4111,39 @@ ScFormulaCell::CompareState ScFormulaCell::CompareByTokenArray( const ScFormulaC
switch (pThisTok->GetType())
{
+ // ScCompiler::HandleIIOpCode() may optimize some refs only in RPN code,
+ // resulting in identical RPN references that could lead to creating
+ // a formula group from formulas that should not be merged into a group,
+ // so check also the formula itself.
+ case formula::svSingleRef:
+ {
+ // Single cell reference.
+ const ScSingleRefData& rRef = *pThisTok->GetSingleRef();
+ if (rRef != *pOtherTok->GetSingleRef())
+ return NotEqual;
+
+ if (rRef.IsRowRel())
+ bInvariant = false;
+ }
+ break;
+ case formula::svDoubleRef:
+ {
+ // Range reference.
+ const ScSingleRefData& rRef1 = *pThisTok->GetSingleRef();
+ const ScSingleRefData& rRef2 = *pThisTok->GetSingleRef2();
+ if (rRef1 != *pOtherTok->GetSingleRef())
+ return NotEqual;
+
+ if (rRef2 != *pOtherTok->GetSingleRef2())
+ return NotEqual;
+
+ if (rRef1.IsRowRel())
+ bInvariant = false;
+
+ if (rRef2.IsRowRel())
+ bInvariant = false;
+ }
+ break;
// All index tokens are names. Different categories already had
// different OpCode values.
case formula::svIndex:
@@ -4802,7 +4836,7 @@ bool ScFormulaCell::InterpretInvariantFormulaGroup()
}
}
- ScCompiler aComp(pDocument, aPos, aCode, pDocument->GetGrammar());
+ ScCompiler aComp(pDocument, aPos, aCode, pDocument->GetGrammar(), true, cMatrixFlag != ScMatrixMode::NONE);
aComp.CompileTokenArray(); // Create RPN token array.
ScInterpreter aInterpreter(this, pDocument, pDocument->GetNonThreadedContext(), aPos, aCode);
aInterpreter.Interpret();
diff --git a/sc/source/core/data/simpleformulacalc.cxx b/sc/source/core/data/simpleformulacalc.cxx
index a710d8a34cbf..9882fd7a352f 100644
--- a/sc/source/core/data/simpleformulacalc.cxx
+++ b/sc/source/core/data/simpleformulacalc.cxx
@@ -28,7 +28,7 @@ ScSimpleFormulaCalculator::ScSimpleFormulaCalculator( ScDocument* pDoc, const Sc
, mbMatrixFormula(bMatrixFormula)
{
// compile already here
- ScCompiler aComp(mpDoc, maAddr, eGram);
+ ScCompiler aComp(mpDoc, maAddr, eGram, true, bMatrixFormula);
mpCode.reset(aComp.CompileString(rFormula));
if(mpCode->GetCodeError() == FormulaError::NONE && mpCode->GetLen())
aComp.CompileTokenArray();
diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx
index 4ec04d968042..d8a68b50fb43 100644
--- a/sc/source/core/tool/compiler.cxx
+++ b/sc/source/core/tool/compiler.cxx
@@ -1733,8 +1733,8 @@ struct ConventionXL_R1C1 : public ScCompiler::Convention, public ConventionXL
};
ScCompiler::ScCompiler( sc::CompileFormulaContext& rCxt, const ScAddress& rPos, ScTokenArray& rArr,
- const ScInterpreterContext* pContext )
- : FormulaCompiler(rArr),
+ bool bComputeII, bool bMatrixFlag, const ScInterpreterContext* pContext )
+ : FormulaCompiler(rArr, bComputeII, bMatrixFlag),
pDoc(rCxt.getDoc()),
aPos(rPos),
mpFormatter(pContext? pContext->GetFormatTable() : pDoc->GetFormatTable()),
@@ -1753,8 +1753,9 @@ ScCompiler::ScCompiler( sc::CompileFormulaContext& rCxt, const ScAddress& rPos,
}
ScCompiler::ScCompiler( ScDocument* pDocument, const ScAddress& rPos, ScTokenArray& rArr,
- formula::FormulaGrammar::Grammar eGrammar, const ScInterpreterContext* pContext )
- : FormulaCompiler(rArr),
+ formula::FormulaGrammar::Grammar eGrammar,
+ bool bComputeII, bool bMatrixFlag, const ScInterpreterContext* pContext )
+ : FormulaCompiler(rArr, bComputeII, bMatrixFlag),
pDoc( pDocument ),
aPos( rPos ),
mpFormatter(pContext ? pContext->GetFormatTable() : pDoc->GetFormatTable()),
@@ -1774,8 +1775,10 @@ ScCompiler::ScCompiler( ScDocument* pDocument, const ScAddress& rPos, ScTokenArr
eGrammar );
}
-ScCompiler::ScCompiler( sc::CompileFormulaContext& rCxt, const ScAddress& rPos, const ScInterpreterContext* pContext )
- : pDoc(rCxt.getDoc()),
+ScCompiler::ScCompiler( sc::CompileFormulaContext& rCxt, const ScAddress& rPos,
+ bool bComputeII, bool bMatrixFlag, const ScInterpreterContext* pContext )
+ : FormulaCompiler(bComputeII, bMatrixFlag),
+ pDoc(rCxt.getDoc()),
aPos(rPos),
mpFormatter(pContext ? pContext->GetFormatTable() : pDoc ? pDoc->GetFormatTable() : nullptr),
mnCurrentSheetTab(-1),
@@ -1793,8 +1796,9 @@ ScCompiler::ScCompiler( sc::CompileFormulaContext& rCxt, const ScAddress& rPos,
}
ScCompiler::ScCompiler( ScDocument* pDocument, const ScAddress& rPos,
- formula::FormulaGrammar::Grammar eGrammar, const ScInterpreterContext* pContext )
- :
+ formula::FormulaGrammar::Grammar eGrammar,
+ bool bComputeII, bool bMatrixFlag, const ScInterpreterContext* pContext )
+ : FormulaCompiler(bComputeII, bMatrixFlag),
pDoc( pDocument ),
aPos( rPos ),
mpFormatter(pContext ? pContext->GetFormatTable() : pDoc ? pDoc->GetFormatTable() : nullptr),
@@ -5791,50 +5795,154 @@ formula::ParamClass ScCompiler::GetForceArrayParameter( const formula::FormulaTo
bool ScCompiler::IsIIOpCode(OpCode nOpCode) const
{
- if (nOpCode == ocSumIf || nOpCode == ocAverageIf)
+ if (nOpCode == ocSumIf || nOpCode == ocAverageIf || (nOpCode >= SC_OPCODE_START_1_PAR && nOpCode < SC_OPCODE_STOP_1_PAR))
return true;
return false;
}
-void ScCompiler::HandleIIOpCode(OpCode nOpCode, FormulaToken*** pppToken, sal_uInt8 nNumParams)
+void ScCompiler::HandleIIOpCode(OpCode nOpCode, formula::ParamClass eClass, FormulaToken*** pppToken, sal_uInt8 nNumParams)
{
- switch (nOpCode)
+ if (!mbComputeII)
+ return;
+
+ if (nOpCode == ocSumIf || nOpCode == ocAverageIf)
{
- case ocSumIf:
- case ocAverageIf:
+ if (nNumParams != 3)
+ return;
+
+ if (!(pppToken[0] && pppToken[2] && *pppToken[0] && *pppToken[2]))
+ return;
+
+ if ((*pppToken[0])->GetType() != svDoubleRef)
+ return;
+
+ const StackVar eSumRangeType = (*pppToken[2])->GetType();
+
+ if ( eSumRangeType != svSingleRef && eSumRangeType != svDoubleRef )
+ return;
+
+ const ScComplexRefData& rBaseRange = *(*pppToken[0])->GetDoubleRef();
+
+ ScComplexRefData aSumRange;
+ if (eSumRangeType == svSingleRef)
{
- if (nNumParams != 3)
- return;
+ aSumRange.Ref1 = *(*pppToken[2])->GetSingleRef();
+ aSumRange.Ref2 = aSumRange.Ref1;
+ }
+ else
+ aSumRange = *(*pppToken[2])->GetDoubleRef();
- if (!(pppToken[0] && pppToken[2] && *pppToken[0] && *pppToken[2]))
- return;
+ CorrectSumRange(rBaseRange, aSumRange, pppToken[2]);
+ }
+ else if (nOpCode >= SC_OPCODE_START_1_PAR && nOpCode < SC_OPCODE_STOP_1_PAR)
+ {
+ if (nNumParams != 1)
+ return;
- if ((*pppToken[0])->GetType() != svDoubleRef)
- return;
+ if (eClass == formula::ForceArray || mbMatrixFlag)
+ return;
- const StackVar eSumRangeType = (*pppToken[2])->GetType();
+ if ((*pppToken[0])->GetType() != svDoubleRef)
+ return;
- if ( eSumRangeType != svSingleRef && eSumRangeType != svDoubleRef )
- return;
+ ReplaceDoubleRefII(pppToken[0]);
+ }
+}
- const ScComplexRefData& rBaseRange = *(*pppToken[0])->GetDoubleRef();
+void ScCompiler::ReplaceDoubleRefII(FormulaToken** ppDoubleRefTok)
+{
+ const ScComplexRefData& rRange = *(*ppDoubleRefTok)->GetDoubleRef();
+
+ // Can't do optimization reliably in this case (when row references are absolute).
+ // Example : =SIN(A$1:A$10) filled in a formula group starting at B5 and of length 100.
+ // If we just optimize the argument $A$1:$A$10 to singleref "A5" for the top cell in the fg, then
+ // the results in cells B11:B104 will be incorrect (sin(0) = 0, assuming empty cells in A11:A104)
+ // instead of the #VALUE! errors we would expect. We need to know the formula-group length to
+ // fix this, but that is unknown at this stage, so skip such cases.
+ if (!rRange.Ref1.IsRowRel() && !rRange.Ref2.IsRowRel())
+ return;
- ScComplexRefData aSumRange;
- if (eSumRangeType == svSingleRef)
- {
- aSumRange.Ref1 = *(*pppToken[2])->GetSingleRef();
- aSumRange.Ref2 = aSumRange.Ref1;
- }
- else
- aSumRange = *(*pppToken[2])->GetDoubleRef();
+ ScRange aAbsRange = rRange.toAbs(aPos);
+ if (aAbsRange.aStart == aAbsRange.aEnd)
+ return; // Nothing to do (trivial case).
+
+ ScAddress aAddr;
+
+ if (!DoubleRefToPosSingleRefScalarCase(aAbsRange, aAddr, aPos))
+ return;
- CorrectSumRange(rBaseRange, aSumRange, pppToken[2]);
+ ScSingleRefData aSingleRef;
+ aSingleRef.InitFlags();
+ aSingleRef.SetColRel(rRange.Ref1.IsColRel());
+ aSingleRef.SetRowRel(true);
+ aSingleRef.SetTabRel(rRange.Ref1.IsTabRel());
+ aSingleRef.SetAddress(aAddr, aPos);
+
+ // Replace the original doubleref token with computed singleref token
+ FormulaToken* pNewSingleRefTok = new ScSingleRefToken(aSingleRef);
+ (*ppDoubleRefTok)->DecRef();
+ *ppDoubleRefTok = pNewSingleRefTok;
+ pNewSingleRefTok->IncRef();
+}
+
+bool ScCompiler::DoubleRefToPosSingleRefScalarCase(const ScRange& rRange, ScAddress& rAdr, const ScAddress& rFormulaPos)
+{
+ assert(rRange.aStart != rRange.aEnd);
+
+ bool bOk = false;
+ SCCOL nMyCol = rFormulaPos.Col();
+ SCROW nMyRow = rFormulaPos.Row();
+ SCTAB nMyTab = rFormulaPos.Tab();
+ SCCOL nCol = 0;
+ SCROW nRow = 0;
+ SCTAB nTab;
+ nTab = rRange.aStart.Tab();
+ if ( rRange.aStart.Col() <= nMyCol && nMyCol <= rRange.aEnd.Col() )
+ {
+ nRow = rRange.aStart.Row();
+ if ( nRow == rRange.aEnd.Row() )
+ {
+ bOk = true;
+ nCol = nMyCol;
+ }
+ else if ( nTab != nMyTab && nTab == rRange.aEnd.Tab()
+ && rRange.aStart.Row() <= nMyRow && nMyRow <= rRange.aEnd.Row() )
+ {
+ bOk = true;
+ nCol = nMyCol;
+ nRow = nMyRow;
+ }
+ }
+ else if ( rRange.aStart.Row() <= nMyRow && nMyRow <= rRange.aEnd.Row() )
+ {
+ nCol = rRange.aStart.Col();
+ if ( nCol == rRange.aEnd.Col() )
+ {
+ bOk = true;
+ nRow = nMyRow;
+ }
+ else if ( nTab != nMyTab && nTab == rRange.aEnd.Tab()
+ && rRange.aStart.Col() <= nMyCol && nMyCol <= rRange.aEnd.Col() )
+ {
+ bOk = true;
+ nCol = nMyCol;
+ nRow = nMyRow;
}
- break;
- default:
- ;
}
+ if ( bOk )
+ {
+ if ( nTab == rRange.aEnd.Tab() )
+ ; // all done
+ else if ( nTab <= nMyTab && nMyTab <= rRange.aEnd.Tab() )
+ nTab = nMyTab;
+ else
+ bOk = false;
+ if ( bOk )
+ rAdr.Set( nCol, nRow, nTab );
+ }
+
+ return bOk;
}
static void lcl_GetColRowDeltas(const ScRange& rRange, SCCOL& rXDelta, SCROW& rYDelta)
diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx
index c600cdca34b1..6194fa5abe02 100644
--- a/sc/source/core/tool/interpr4.cxx
+++ b/sc/source/core/tool/interpr4.cxx
@@ -65,6 +65,7 @@
#include <doubleref.hxx>
#include <queryparam.hxx>
#include <tokenarray.hxx>
+#include <compiler.hxx>
#include <math.h>
#include <float.h>
@@ -2004,56 +2005,8 @@ bool ScInterpreter::DoubleRefToPosSingleRef( const ScRange& rRange, ScAddress& r
return bOk;
}
- SCCOL nMyCol = aPos.Col();
- SCROW nMyRow = aPos.Row();
- SCTAB nMyTab = aPos.Tab();
- SCCOL nCol = 0;
- SCROW nRow = 0;
- SCTAB nTab;
- nTab = rRange.aStart.Tab();
- if ( rRange.aStart.Col() <= nMyCol && nMyCol <= rRange.aEnd.Col() )
- {
- nRow = rRange.aStart.Row();
- if ( nRow == rRange.aEnd.Row() )
- {
- bOk = true;
- nCol = nMyCol;
- }
- else if ( nTab != nMyTab && nTab == rRange.aEnd.Tab()
- && rRange.aStart.Row() <= nMyRow && nMyRow <= rRange.aEnd.Row() )
- {
- bOk = true;
- nCol = nMyCol;
- nRow = nMyRow;
- }
- }
- else if ( rRange.aStart.Row() <= nMyRow && nMyRow <= rRange.aEnd.Row() )
- {
- nCol = rRange.aStart.Col();
- if ( nCol == rRange.aEnd.Col() )
- {
- bOk = true;
- nRow = nMyRow;
- }
- else if ( nTab != nMyTab && nTab == rRange.aEnd.Tab()
- && rRange.aStart.Col() <= nMyCol && nMyCol <= rRange.aEnd.Col() )
- {
- bOk = true;
- nCol = nMyCol;
- nRow = nMyRow;
- }
- }
- if ( bOk )
- {
- if ( nTab == rRange.aEnd.Tab() )
- ; // all done
- else if ( nTab <= nMyTab && nMyTab <= rRange.aEnd.Tab() )
- nTab = nMyTab;
- else
- bOk = false;
- if ( bOk )
- rAdr.Set( nCol, nRow, nTab );
- }
+ bOk = ScCompiler::DoubleRefToPosSingleRefScalarCase(rRange, rAdr, aPos);
+
if ( !bOk )
SetError( FormulaError::NoValue );
return bOk;
diff --git a/sc/source/filter/oox/formulabuffer.cxx b/sc/source/filter/oox/formulabuffer.cxx
index 87529dcad0d0..9f7977b5ddb2 100644
--- a/sc/source/filter/oox/formulabuffer.cxx
+++ b/sc/source/filter/oox/formulabuffer.cxx
@@ -121,7 +121,7 @@ void applySharedFormulas(
sal_Int32 nId = rEntry.mnSharedId;
const OUString& rTokenStr = rEntry.maTokenStr;
- ScCompiler aComp(&rDoc.getDoc(), aPos, formula::FormulaGrammar::GRAM_OOXML);
+ ScCompiler aComp(&rDoc.getDoc(), aPos, formula::FormulaGrammar::GRAM_OOXML, true, false);
aComp.SetNumberFormatter(&rFormatter);
ScTokenArray* pArray = aComp.CompileString(rTokenStr);
if (pArray)
@@ -206,7 +206,7 @@ void applyCellFormulas(
continue;
}
- ScCompiler aCompiler(&rDoc.getDoc(), aPos, formula::FormulaGrammar::GRAM_OOXML);
+ ScCompiler aCompiler(&rDoc.getDoc(), aPos, formula::FormulaGrammar::GRAM_OOXML, true, false);
aCompiler.SetNumberFormatter(&rFormatter);
aCompiler.SetExternalLinks(rExternalLinks);
ScTokenArray* pCode = aCompiler.CompileString(rItem.maTokenStr);
diff --git a/sc/source/ui/view/viewfunc.cxx b/sc/source/ui/view/viewfunc.cxx
index 306d020ec947..9e29d72da734 100644
--- a/sc/source/ui/view/viewfunc.cxx
+++ b/sc/source/ui/view/viewfunc.cxx
@@ -400,7 +400,7 @@ void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab,
{ // formula, compile with autoCorrection
i = rMark.GetFirstSelected();
ScAddress aPos( nCol, nRow, i );
- ScCompiler aComp( pDoc, aPos, pDoc->GetGrammar());
+ ScCompiler aComp( pDoc, aPos, pDoc->GetGrammar(), true, false );
//2do: enable/disable autoCorrection via calcoptions
aComp.SetAutoCorrection( true );
if ( rString[0] == '+' || rString[0] == '-' )