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