summaryrefslogtreecommitdiff
path: root/formula
diff options
context:
space:
mode:
authorWinfried Donkers <osc@dci-electronics.nl>2013-01-07 15:34:32 +0100
committerEike Rathke <erack@redhat.com>2013-01-11 17:01:23 +0100
commit5fd9feafa5d73121636af9397d42e046cc394719 (patch)
tree8e21bfd21fe23e64a9eb3214c9c7ade60ce312a8 /formula
parent0f4afa41ec8e2f438fbea9e4d7a123f668b124ca (diff)
fdo#56124 add functions IFERROR and IFNA to calc as in ODFF1.2
Change-Id: I6403b51ac8c710ad3b8d2625e1482971f50e6b1d
Diffstat (limited to 'formula')
-rw-r--r--formula/inc/formula/compiler.hrc42
-rw-r--r--formula/inc/formula/opcode.hxx2
-rw-r--r--formula/source/core/api/FormulaCompiler.cxx24
-rw-r--r--formula/source/core/api/token.cxx22
-rw-r--r--formula/source/core/resource/core_resource.src12
5 files changed, 66 insertions, 36 deletions
diff --git a/formula/inc/formula/compiler.hrc b/formula/inc/formula/compiler.hrc
index 582e3a589c93..7f976ae3a163 100644
--- a/formula/inc/formula/compiler.hrc
+++ b/formula/inc/formula/compiler.hrc
@@ -29,26 +29,28 @@
#define SC_OPCODE_NAME 4
#define SC_OPCODE_EXTERNAL_REF 5
#define SC_OPCODE_IF 6 /* jump commands */
-#define SC_OPCODE_CHOSE 7
-#define SC_OPCODE_OPEN 8 /* parentheses and separators */
-#define SC_OPCODE_CLOSE 9
-#define SC_OPCODE_SEP 10
-#define SC_OPCODE_MISSING 11 /* special OpCodes */
-#define SC_OPCODE_BAD 12
-#define SC_OPCODE_STRINGXML 13
-#define SC_OPCODE_SPACES 14
-#define SC_OPCODE_MAT_REF 15
-#define SC_OPCODE_DB_AREA 16 /* additional access operators */
-#define SC_OPCODE_MACRO 17
-#define SC_OPCODE_COL_ROW_NAME 18
-#define SC_OPCODE_COL_ROW_NAME_AUTO 19
-#define SC_OPCODE_PERCENT_SIGN 20 /* operator _follows_ value */
-#define SC_OPCODE_ARRAY_OPEN 21
-#define SC_OPCODE_ARRAY_CLOSE 22
-#define SC_OPCODE_ARRAY_ROW_SEP 23
-#define SC_OPCODE_ARRAY_COL_SEP 24 /* some convs use sep != col_sep */
-#define SC_OPCODE_STOP_DIV 25
-#define SC_OPCODE_SKIP 26 /* used to skip raw tokens during string compilation */
+#define SC_OPCODE_IF_ERROR 7
+#define SC_OPCODE_IF_NA 8
+#define SC_OPCODE_CHOSE 9
+#define SC_OPCODE_OPEN 10 /* parentheses and separators */
+#define SC_OPCODE_CLOSE 11
+#define SC_OPCODE_SEP 12
+#define SC_OPCODE_MISSING 13 /* special OpCodes */
+#define SC_OPCODE_BAD 14
+#define SC_OPCODE_STRINGXML 15
+#define SC_OPCODE_SPACES 16
+#define SC_OPCODE_MAT_REF 17
+#define SC_OPCODE_DB_AREA 18 /* additional access operators */
+#define SC_OPCODE_MACRO 19
+#define SC_OPCODE_COL_ROW_NAME 20
+#define SC_OPCODE_COL_ROW_NAME_AUTO 21
+#define SC_OPCODE_PERCENT_SIGN 22 /* operator _follows_ value */
+#define SC_OPCODE_ARRAY_OPEN 23
+#define SC_OPCODE_ARRAY_CLOSE 24
+#define SC_OPCODE_ARRAY_ROW_SEP 25
+#define SC_OPCODE_ARRAY_COL_SEP 26 /* some convs use sep != col_sep */
+#define SC_OPCODE_STOP_DIV 27
+#define SC_OPCODE_SKIP 28 /* used to skip raw tokens during string compilation */
/*** error constants #... ***/
#define SC_OPCODE_START_ERRORS 30
diff --git a/formula/inc/formula/opcode.hxx b/formula/inc/formula/opcode.hxx
index cd1831b89637..e37395ea6e70 100644
--- a/formula/inc/formula/opcode.hxx
+++ b/formula/inc/formula/opcode.hxx
@@ -34,6 +34,8 @@ enum OpCodeEnum
ocExternalRef = SC_OPCODE_EXTERNAL_REF,
// Jump commands
ocIf = SC_OPCODE_IF,
+ ocIfError = SC_OPCODE_IF_ERROR,
+ ocIfNA = SC_OPCODE_IF_NA,
ocChose = SC_OPCODE_CHOSE,
// Parentheses and separators
ocOpen = SC_OPCODE_OPEN,
diff --git a/formula/source/core/api/FormulaCompiler.cxx b/formula/source/core/api/FormulaCompiler.cxx
index f79201b6c673..e91912368a5c 100644
--- a/formula/source/core/api/FormulaCompiler.cxx
+++ b/formula/source/core/api/FormulaCompiler.cxx
@@ -824,7 +824,7 @@ sal_uInt16 FormulaCompiler::GetErrorConstant( const String& rName ) const
{
switch ((*iLook).second)
{
- // Not all may make sense in a formula, but these we know as
+ // Not all may make sense in a formula, but these we know as
// opcodes.
case ocErrNull:
nError = errNoCode;
@@ -1125,7 +1125,8 @@ void FormulaCompiler::Factor()
|| eOp == ocOr
|| eOp == ocBad
|| ( eOp >= ocInternalBegin && eOp <= ocInternalEnd )
- || (bCompileForFAP && ((eOp == ocIf) || (eOp == ocChose)))
+ || ( bCompileForFAP
+ && ( eOp == ocIf || eOp == ocIfError || eOp == ocIfNA || eOp == ocChose ) )
)
{
pFacToken = mpToken;
@@ -1174,14 +1175,16 @@ void FormulaCompiler::Factor()
pFacToken->SetByte( nSepCount );
PutCode( pFacToken );
}
- else if (eOp == ocIf || eOp == ocChose)
+ else if (eOp == ocIf || eOp == ocIfError || eOp == ocIfNA || eOp == ocChose)
{
// the PC counters are -1
pFacToken = mpToken;
if ( eOp == ocIf )
pFacToken->GetJump()[ 0 ] = 3; // if, else, behind
- else
+ else if ( eOp == ocChose )
pFacToken->GetJump()[ 0 ] = MAXJUMPCOUNT+1;
+ else
+ pFacToken->GetJump()[ 0 ] = 2; // if, else
eOp = NextToken();
if (eOp == ocOpen)
{
@@ -1195,9 +1198,10 @@ void FormulaCompiler::Factor()
// 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);
+ // nJump[0]*2+2, which is 3*2+2 on ocIf and 2*2+2 ocIfError and ocIfNA.
+ OpCode eFacOpCode = pFacToken->GetOpCode();
+ const short nJumpMax = ( eFacOpCode == ocIf ? 3 :
+ ( eFacOpCode == ocChose ? MAXJUMPCOUNT : 2 ) );
while ( (nJumpCount < (MAXJUMPCOUNT - 1)) && (eOp == ocSep)
&& (!pArr->GetCodeError() || bIgnoreErrors) )
{
@@ -1216,8 +1220,10 @@ void FormulaCompiler::Factor()
// always limit to nJumpMax, no arbitrary overwrites
if ( ++nJumpCount <= nJumpMax )
pFacToken->GetJump()[ nJumpCount ] = pc-1;
- if ((pFacToken->GetOpCode() == ocIf && (nJumpCount > 3)) ||
- (nJumpCount >= MAXJUMPCOUNT))
+ eFacOpCode = pFacToken->GetOpCode();
+ if ( ( eFacOpCode == ocIf && nJumpCount > 3) ||
+ ( ( eFacOpCode == ocIfError || eFacOpCode == ocIfNA ) && nJumpCount > 2 ) ||
+ ( nJumpCount >= MAXJUMPCOUNT ) )
SetError(errIllegalParameter);
else
pFacToken->GetJump()[ 0 ] = nJumpCount;
diff --git a/formula/source/core/api/token.cxx b/formula/source/core/api/token.cxx
index d187073b2f22..f6110e7ce5b3 100644
--- a/formula/source/core/api/token.cxx
+++ b/formula/source/core/api/token.cxx
@@ -76,7 +76,7 @@ bool FormulaToken::IsFunction() const
eOp != ocColRowNameAuto && eOp != ocName && eOp != ocDBArea &&
(GetByte() != 0 // x parameters
|| (SC_OPCODE_START_NO_PAR <= eOp && eOp < SC_OPCODE_STOP_NO_PAR) // no parameter
- || (ocIf == eOp || ocChose == eOp ) // @ jump commands
+ || (ocIf == eOp || ocIfError == eOp || ocIfNA == eOp || ocChose == eOp ) // @ jump commands
|| (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR) // one parameter
|| (SC_OPCODE_START_2_PAR <= eOp && eOp < SC_OPCODE_STOP_2_PAR) // x parameters (cByte==0 in
// FuncAutoPilot)
@@ -91,9 +91,10 @@ bool FormulaToken::IsFunction() const
sal_uInt8 FormulaToken::GetParamCount() const
{
if ( eOp < SC_OPCODE_STOP_DIV && eOp != ocExternal && eOp != ocMacro &&
- eOp != ocIf && eOp != ocChose && eOp != ocPercentSign )
+ eOp != ocIf && eOp != ocIfError && eOp != ocIfNA && eOp != ocChose &&
+ eOp != ocPercentSign )
return 0; // parameters and specials
- // ocIf and ocChose not for FAP, have cByte then
+ // ocIf, ocIfError, ocIfNA and ocChose not for FAP, have cByte then
//2do: bool parameter whether FAP or not?
else if ( GetByte() )
return GetByte(); // all functions, also ocExternal and ocMacro
@@ -106,7 +107,7 @@ sal_uInt8 FormulaToken::GetParamCount() const
return 0; // no parameter
else if (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR)
return 1; // one parameter
- else if ( eOp == ocIf || eOp == ocChose )
+ else if ( eOp == ocIf || eOp == ocIfError || eOp == ocIfNA || eOp == ocChose )
return 1; // only the condition counts as parameter
else
return 0; // all the rest, no Parameter, or
@@ -842,8 +843,8 @@ bool FormulaTokenArray::HasMatrixDoubleRefOps()
}
if ( eOp == ocPush || lcl_IsReference( eOp, t->GetType() ) )
pStack[sp++] = t;
- else if ( eOp == ocIf || eOp == ocChose )
- { // Jumps ignorieren, vorheriges Result (Condition) poppen
+ else if ( eOp == ocIf || eOp == ocIfError || eOp == ocIfNA || eOp == ocChose )
+ { // ignore Jumps, pop previous Result (Condition)
if ( sp )
--sp;
}
@@ -1178,10 +1179,17 @@ FormulaToken* FormulaTokenArray::AddOpCode( OpCode eOp )
pRet = new FormulaToken( svSep,eOp );
break;
case ocIf:
+ case ocIfError:
+ case ocIfNA:
case ocChose:
{
short nJump[MAXJUMPCOUNT + 1];
- nJump[ 0 ] = ocIf == eOp ? 3 : MAXJUMPCOUNT+1;
+ if ( eOp == ocIf )
+ nJump[ 0 ] = 3;
+ else if ( eOp == ocChose )
+ nJump[ 0 ] = MAXJUMPCOUNT + 1;
+ else
+ nJump[ 0 ] = 2;
pRet = new FormulaJumpToken( eOp, (short*)nJump );
}
break;
diff --git a/formula/source/core/resource/core_resource.src b/formula/source/core/resource/core_resource.src
index 8b0ee14e9a5a..1852d5839ae4 100644
--- a/formula/source/core/resource/core_resource.src
+++ b/formula/source/core/resource/core_resource.src
@@ -24,6 +24,8 @@
Resource RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF
{
String SC_OPCODE_IF { Text = "IF" ; };
+ String SC_OPCODE_IF_NA { Text = "IFERROR" ; };
+ String SC_OPCODE_IF_ERROR { Text = "IFNA" ; };
String SC_OPCODE_CHOSE { Text = "CHOOSE" ; };
String SC_OPCODE_OPEN { Text = "(" ; };
String SC_OPCODE_CLOSE { Text = ")" ; };
@@ -362,6 +364,8 @@ Resource RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF
Resource RID_STRLIST_FUNCTION_NAMES_ENGLISH
{
String SC_OPCODE_IF { Text = "IF" ; };
+ String SC_OPCODE_IF_ERROR { Text = "IFERROR" ; };
+ String SC_OPCODE_IF_NA { Text = "IFNA" ; };
String SC_OPCODE_CHOSE { Text = "CHOOSE" ; };
String SC_OPCODE_OPEN { Text = "(" ; };
String SC_OPCODE_CLOSE { Text = ")" ; };
@@ -700,6 +704,14 @@ Resource RID_STRLIST_FUNCTION_NAMES
{
Text [ en-US ] = "IF" ;
};
+ String SC_OPCODE_IF_ERROR
+ {
+ Text [ en-US ] = "IFERROR" ;
+ };
+ String SC_OPCODE_IF_NA
+ {
+ Text [ en-US ] = "IFNA" ;
+ };
String SC_OPCODE_CHOSE
{
Text [ en-US ] = "CHOOSE" ;