diff -rcP sc/inc/compiler.hrc sc/inc/compiler.hrc *** sc/inc/compiler.hrc Fri Jan 19 15:54:41 2007 --- sc/inc/compiler.hrc Wed Jan 24 15:26:13 2007 *************** *** 58,101 **** #define SC_OPCODE_MACRO 15 #define SC_OPCODE_COL_ROW_NAME 16 #define SC_OPCODE_COL_ROW_NAME_AUTO 17 ! #define SC_OPCODE_PERCENT_SIGN 18 /* operator _follows_ value */ ! #define SC_OPCODE_END_DIV 20 /*** Binaere Operatoren ***/ ! #define SC_OPCODE_ADD 21 ! #define SC_OPCODE_SUB 22 ! #define SC_OPCODE_MUL 23 ! #define SC_OPCODE_DIV 24 ! #define SC_OPCODE_AMPERSAND 25 ! #define SC_OPCODE_POW 26 ! #define SC_OPCODE_EQUAL 27 ! #define SC_OPCODE_NOT_EQUAL 28 ! #define SC_OPCODE_LESS 29 ! #define SC_OPCODE_GREATER 30 ! #define SC_OPCODE_LESS_EQUAL 31 ! #define SC_OPCODE_GREATER_EQUAL 32 ! #define SC_OPCODE_AND 33 ! #define SC_OPCODE_OR 34 ! #define SC_OPCODE_INTERSECT 35 ! #define SC_OPCODE_UNION 36 ! #define SC_OPCODE_RANGE 37 ! #define SC_OPCODE_END_BIN_OP 40 /*** Unaere Operatoren ***/ ! #define SC_OPCODE_NOT 41 ! #define SC_OPCODE_NEG 42 ! #define SC_OPCODE_NEG_SUB 43 ! #define SC_OPCODE_END_UN_OP 45 /*** Funktionen ohne Parameter ***/ ! #define SC_OPCODE_PI 46 ! #define SC_OPCODE_RANDOM 47 ! #define SC_OPCODE_TRUE 48 ! #define SC_OPCODE_FALSE 49 ! #define SC_OPCODE_GET_ACT_DATE 50 ! #define SC_OPCODE_GET_ACT_TIME 51 ! #define SC_OPCODE_NO_VALUE 52 ! #define SC_OPCODE_CURRENT 53 #define SC_OPCODE_END_NO_PAR 60 /*** Funktionen mit einem Parameter ***/ --- 58,104 ---- #define SC_OPCODE_MACRO 15 #define SC_OPCODE_COL_ROW_NAME 16 #define SC_OPCODE_COL_ROW_NAME_AUTO 17 ! #define SC_OPCODE_PERCENT_SIGN 18 /* operator _follows_ value */ ! #define SC_OPCODE_ARRAY_OPEN 19 ! #define SC_OPCODE_ARRAY_CLOSE 20 ! #define SC_OPCODE_ARRAY_ROW_SEP 21 ! #define SC_OPCODE_END_DIV 22 /*** Binaere Operatoren ***/ ! #define SC_OPCODE_ADD 25 ! #define SC_OPCODE_SUB 26 ! #define SC_OPCODE_MUL 27 ! #define SC_OPCODE_DIV 28 ! #define SC_OPCODE_AMPERSAND 29 ! #define SC_OPCODE_POW 30 ! #define SC_OPCODE_EQUAL 31 ! #define SC_OPCODE_NOT_EQUAL 32 ! #define SC_OPCODE_LESS 33 ! #define SC_OPCODE_GREATER 34 ! #define SC_OPCODE_LESS_EQUAL 35 ! #define SC_OPCODE_GREATER_EQUAL 36 ! #define SC_OPCODE_AND 37 ! #define SC_OPCODE_OR 38 ! #define SC_OPCODE_INTERSECT 39 ! #define SC_OPCODE_UNION 40 ! #define SC_OPCODE_RANGE 41 ! #define SC_OPCODE_END_BIN_OP 44 /*** Unaere Operatoren ***/ ! #define SC_OPCODE_NOT 45 ! #define SC_OPCODE_NEG 46 ! #define SC_OPCODE_NEG_SUB 47 ! #define SC_OPCODE_END_UN_OP 48 /*** Funktionen ohne Parameter ***/ ! #define SC_OPCODE_PI 50 ! #define SC_OPCODE_RANDOM 51 ! #define SC_OPCODE_TRUE 52 ! #define SC_OPCODE_FALSE 53 ! #define SC_OPCODE_GET_ACT_DATE 54 ! #define SC_OPCODE_GET_ACT_TIME 55 ! #define SC_OPCODE_NO_VALUE 56 ! #define SC_OPCODE_CURRENT 57 #define SC_OPCODE_END_NO_PAR 60 /*** Funktionen mit einem Parameter ***/ diff -rcP sc/inc/compiler.hxx sc/inc/compiler.hxx *** sc/inc/compiler.hxx Fri Jan 19 15:54:41 2007 --- sc/inc/compiler.hxx Wed Feb 28 17:39:04 2007 *************** *** 319,324 **** --- 319,325 ---- void PushTokenArray( ScTokenArray*, BOOL = FALSE ); void PopTokenArray(); void SetRelNameReference(); + void CreateStringFromScMatrix( rtl::OUStringBuffer& rBuffer, const ScMatrix* pMatrix ); public: ScCompiler(ScDocument* pDocument, const ScAddress& ); diff -rcP sc/inc/errorcodes.hxx sc/inc/errorcodes.hxx *** sc/inc/errorcodes.hxx Fri Jan 19 15:54:41 2007 --- sc/inc/errorcodes.hxx Fri Jan 26 13:35:03 2007 *************** *** 83,88 **** --- 83,89 ---- // Interpreter: needed Macro not found const USHORT errNoMacro = 531; const USHORT errDivisionByZero = 532; // #DIV/0! + const USHORT errNestedArray = 533; // Interpreter: NA() not available condition, not a real error const USHORT NOVALUE = 0x7fff; diff -rcP sc/inc/globstr.hrc sc/inc/globstr.hrc *** sc/inc/globstr.hrc Fri Jan 19 15:54:42 2007 --- sc/inc/globstr.hrc Fri Jan 26 13:34:06 2007 *************** *** 561,567 **** #define STR_UNDO_TAB_R1C1 418 #define STR_DELETE_DID_NOT_COPY 419 ! #define STR_COUNT 420 #endif --- 561,569 ---- #define STR_UNDO_TAB_R1C1 418 #define STR_DELETE_DID_NOT_COPY 419 ! #define STR_ERR_NESTED_ARRAY 420 ! ! #define STR_COUNT 421 #endif diff -rcP sc/inc/opcode.hxx sc/inc/opcode.hxx *** sc/inc/opcode.hxx Fri Jan 19 15:54:41 2007 --- sc/inc/opcode.hxx Wed Jan 24 16:15:13 2007 *************** *** 58,63 **** --- 58,67 ---- ocOpen = SC_OPCODE_OPEN, ocClose = SC_OPCODE_CLOSE, ocSep = SC_OPCODE_SEP, + ocArrayOpen = SC_OPCODE_ARRAY_OPEN, + ocArrayClose = SC_OPCODE_ARRAY_CLOSE, + ocArrayRowSep = SC_OPCODE_ARRAY_ROW_SEP, + // Spezial-Opcodes ocMissing = SC_OPCODE_MISSING, ocBad = SC_OPCODE_BAD, diff -rcP sc/inc/tokenarray.hxx sc/inc/tokenarray.hxx *** sc/inc/tokenarray.hxx Thu Sep 8 14:01:25 2005 --- sc/inc/tokenarray.hxx Wed Feb 14 09:38:59 2007 *************** *** 224,229 **** --- 224,230 ---- ScToken* AddColRowName( const SingleRefData& rRef ); ScToken* AddBad( const sal_Unicode* pStr ); /// ocBad with String ScToken* AddBad( const String& rStr ); /// ocBad with String + ScToken* MergeArray( ); /// Assignment with references to ScToken entries (not copied!) ScTokenArray& operator=( const ScTokenArray& ); diff -rcP sc/source/core/data/global.cxx sc/source/core/data/global.cxx *** sc/source/core/data/global.cxx Fri Jan 19 15:54:41 2007 --- sc/source/core/data/global.cxx Fri Jan 26 13:34:58 2007 *************** *** 487,492 **** --- 487,495 ---- case errDivisionByZero: nErrNumber = STR_LONG_ERR_DIV_ZERO; break; + case errNestedArray: + nErrNumber = STR_ERR_NESTED_ARRAY; + break; case errNoValue: nErrNumber = STR_LONG_ERR_NO_VALUE; break; diff -rcP sc/source/core/src/compiler.src sc/source/core/src/compiler.src *** sc/source/core/src/compiler.src Fri Jan 19 15:54:42 2007 --- sc/source/core/src/compiler.src Thu Jan 25 12:11:31 2007 *************** *** 51,56 **** --- 51,59 ---- }; String SC_OPCODE_OPEN { Text = "(" ; }; String SC_OPCODE_CLOSE { Text = ")" ; }; + String SC_OPCODE_ARRAY_OPEN { Text = "{" ; }; + String SC_OPCODE_ARRAY_CLOSE { Text = "}" ; }; + String SC_OPCODE_ARRAY_ROW_SEP { Text = "|" ; }; String SC_OPCODE_SEP { Text = ";" ; }; String SC_OPCODE_PERCENT_SIGN { Text = "%" ; }; String SC_OPCODE_ADD { Text = "+" ; }; *************** *** 1700,1705 **** --- 1703,1711 ---- String SC_OPCODE_CHOSE { Text = "CHOOSE" ; }; String SC_OPCODE_OPEN { Text = "(" ; }; String SC_OPCODE_CLOSE { Text = ")" ; }; + String SC_OPCODE_ARRAY_OPEN { Text = "{" ; }; + String SC_OPCODE_ARRAY_CLOSE { Text = "}" ; }; + String SC_OPCODE_ARRAY_ROW_SEP { Text = "|" ; }; String SC_OPCODE_SEP { Text = ";" ; }; String SC_OPCODE_PERCENT_SIGN { Text = "%" ; }; String SC_OPCODE_ADD { Text = "+" ; }; diff -rcP sc/source/core/tool/compiler.cxx sc/source/core/tool/compiler.cxx *** sc/source/core/tool/compiler.cxx Fri Jan 19 15:54:42 2007 --- sc/source/core/tool/compiler.cxx Wed Feb 28 21:32:10 2007 *************** *** 351,359 **** /* ` */ // FREI for (i = 97; i < 123; i++) /* a-z */ t[i] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT; ! /* { */ // FREI ! /* | */ // FREI ! /* } */ // FREI /* ~ */ // FREI /* 127 */ // FREI if( ScAddress::CONV_XL_A1 == meConv || ScAddress::CONV_XL_R1C1 == meConv ) --- 351,359 ---- /* ` */ // FREI for (i = 97; i < 123; i++) /* a-z */ t[i] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT; ! /* { */ t[123] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array open ! /* | */ t[124] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array row sep (Should be OOo specific) ! /* } */ t[125] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array close /* ~ */ // FREI /* 127 */ // FREI if( ScAddress::CONV_XL_A1 == meConv || ScAddress::CONV_XL_R1C1 == meConv ) *************** *** 1368,1374 **** } } if ( bFound && pRawToken->GetOpCode() == ocSub && ! (eLastOp == ocOpen || eLastOp == ocSep || eLastOp == ocNegSub || (eLastOp > ocEndDiv && eLastOp < ocEndBinOp))) pRawToken->NewOpCode( ocNegSub ); //! if ocNegSub had ForceArray we'd have to set it here --- 1368,1375 ---- } } if ( bFound && pRawToken->GetOpCode() == ocSub && ! (eLastOp == ocOpen || eLastOp == ocArrayOpen || ! eLastOp == ocSep || eLastOp == ocNegSub || (eLastOp > ocEndDiv && eLastOp < ocEndBinOp))) pRawToken->NewOpCode( ocNegSub ); //! if ocNegSub had ForceArray we'd have to set it here *************** *** 2097,2104 **** { xub_StrLen nSpaces = NextSymbol(); ! // fprintf( stderr, "NextNewToken '%s' (?) ", ! // rtl::OUStringToOString( cSymbol, RTL_TEXTENCODING_UTF8 ).getStr() ); ScRawToken aToken; if( cSymbol[0] ) --- 2098,2107 ---- { xub_StrLen nSpaces = NextSymbol(); ! #if 0 ! fprintf( stderr, "NextNewToken '%s' (spaces = %d)\n", ! rtl::OUStringToOString( cSymbol, RTL_TEXTENCODING_UTF8 ).getStr(), nSpaces ); ! #endif ScRawToken aToken; if( cSymbol[0] ) *************** *** 2180,2187 **** ScTokenArray* ScCompiler::CompileString( const String& rFormula, ScAddress::Convention eConv ) { ! // fprintf( stderr, "CompileString '%s'\n", ! // rtl::OUStringToOString( rFormula, RTL_TEXTENCODING_UTF8 ).getStr() ); ScTokenArray aArr; pArr = &aArr; aFormula = rFormula; --- 2183,2193 ---- ScTokenArray* ScCompiler::CompileString( const String& rFormula, ScAddress::Convention eConv ) { ! #if 0 ! fprintf( stderr, "CompileString '%s'\n", ! rtl::OUStringToOString( rFormula, RTL_TEXTENCODING_UTF8 ).getStr() ); ! #endif ! ScTokenArray aArr; pArr = &aArr; aFormula = rFormula; *************** *** 2213,2218 **** --- 2219,2225 ---- aCorrectedFormula += '='; } short nBrackets = 0; + bool bInArray = false; eLastOp = ocOpen; while( NextNewToken() ) { *************** *** 2232,2237 **** --- 2239,2268 ---- else nBrackets--; } + else if( pRawToken->GetOpCode() == ocArrayOpen ) + { + if( bInArray ) + SetError( errNestedArray ); + else + bInArray = true; + } + else if( pRawToken->GetOpCode() == ocArrayClose ) + { + if( bInArray ) + { + bInArray = false; + } + else + { + SetError( errPairExpected ); + if ( bAutoCorrect ) + { + bCorrected = TRUE; + aCorrectedSymbol.Erase(); + } + } + } + if( eLastOp == ocSep && pRawToken->GetOpCode() == ocSep ) { *************** *** 2254,2259 **** --- 2285,2299 ---- } if ( eLastOp != ocBad ) { + if (bInArray) { + ScByteToken aToken( ocArrayClose ); + if( !pArr->AddToken( aToken ) ) + { + SetError(errCodeOverflow); + } else if ( bAutoCorrect ) + aCorrectedFormula += pSymbolTable[ocArrayClose]; + } + // With ocBad the remaining formula is a string, too many parentheses // would be shown. ScByteToken aToken( ocClose ); *************** *** 4396,4401 **** --- 4436,4445 ---- case svDoubleRef: pConv->MakeRefStr( rBuffer, *this, t->GetDoubleRef(), FALSE ); break; + case svMatrix: + CreateStringFromScMatrix( rBuffer, t->GetMatrix() ); + break; + case svIndex: { rtl::OUStringBuffer aBuffer; *************** *** 4459,4464 **** --- 4503,4578 ---- return pTokenP; } + void ScCompiler::CreateStringFromScMatrix( rtl::OUStringBuffer& rBuffer, + const ScMatrix* pMatrix ) + { + SCSIZE nC, nMaxC, nR, nMaxR; + + pMatrix->GetDimensions( nMaxC, nMaxR); + + rBuffer.append( pSymbolTable[ocArrayOpen] ); + for( nC = 0 ; nC < nMaxC ; nC++) + { + if( nC > 0) + { + rBuffer.append( pSymbolTable[ocSep] ); + } + + for( nR = 0 ; nR < nMaxR ; nR++) + { + if( nR > 0) + { + rBuffer.append( pSymbolTable[ocArrayRowSep] ); + } + + if( pMatrix->IsValue( nC, nR ) ) + { + const double v = pMatrix->GetDouble( nC, nR ); + if ( pSymbolTable == pSymbolTableEnglish ) + { + ::rtl::math::doubleToUStringBuffer( rBuffer, v, + rtl_math_StringFormat_Automatic, + rtl_math_DecimalPlaces_Max, '.', TRUE ); + } + else + { + ::rtl::math::doubleToUStringBuffer( rBuffer, v, + rtl_math_StringFormat_Automatic, + rtl_math_DecimalPlaces_Max, + ScGlobal::pLocaleData->getNumDecimalSep().GetChar(0), + TRUE ); + } + } + else if( pMatrix->IsString( nC, nR ) ) + { + const String & v = pMatrix->GetString( nC, nR ); + if (bImportXML) + rBuffer.append( v ); + else + { + rBuffer.append(sal_Unicode('"')); + if ( ScGlobal::UnicodeStrChr( v.GetBuffer(), '"' ) == NULL ) + rBuffer.append( v ); + else + { + String aStr( v ); + xub_StrLen nPos = 0; + while ( (nPos = aStr.Search( '"', nPos)) != STRING_NOTFOUND ) + { + aStr.Insert( '"', nPos ); + nPos += 2; + } + rBuffer.append(aStr); + } + rBuffer.append(sal_Unicode('"')); + } + } + // else if( pMatrix->IsEmpty( nC, nR ) ) { } + } + } + rBuffer.append( pSymbolTable[ocArrayClose] ); + } + void ScCompiler::CreateStringFromTokenArray( String& rFormula ) { rtl::OUStringBuffer aBuffer( pArr->GetLen() * 2 ); diff -rcP sc/source/core/tool/token.cxx sc/source/core/tool/token.cxx *** sc/source/core/tool/token.cxx Fri Jul 21 07:45:36 2006 --- sc/source/core/tool/token.cxx Wed Feb 28 21:32:52 2007 *************** *** 1411,1416 **** --- 1411,1560 ---- return Add( r.Clone() ); } + // Utility function to ensure that there is strict alternation of values and + // seperators. + static bool + checkArraySep( bool & bPrevWasSep, bool bNewVal ) + { + bool bResult = (bPrevWasSep == bNewVal); + bPrevWasSep = bNewVal; + return bResult; + } + + ScToken* ScTokenArray::MergeArray( ) + { + int nCol = -1, nRow = 0; + int i, nPrevRowSep = -1, nStart = 0; + bool bPrevWasSep = false; // top of stack is ocArrayClose + ScToken* t; + + // (1) Iterate from the end to the start to find matrix dims + // and do basic validation. + for ( i = nLen ; i-- > nStart ; ) + { + t = pCode[i]; + switch ( t->GetOpCode() ) + { + case ocPush : + if( checkArraySep( bPrevWasSep, false ) ) + { + return NULL; + } + + // no references or nested arrays + if ( t->GetType() != svDouble && t->GetType() != svString ) + { + return NULL; + } + break; + + case ocSep : + if( checkArraySep( bPrevWasSep, true ) ) + { + return NULL; + } + break; + + case ocArrayClose : + // not possible with the current code, but check just in case + // something changes in the future + if( i != (nLen-1)) + { + return NULL; + } + + if( checkArraySep( bPrevWasSep, true ) ) + { + return NULL; + } + + nPrevRowSep = i; + break; + + case ocArrayOpen : + nStart = i; // stop iteration + // fall through to ArrayRowSep + + case ocArrayRowSep : + if( checkArraySep( bPrevWasSep, true ) ) + { + return NULL; + } + + if( nPrevRowSep < 0 || // missing ocArrayClose + ((nPrevRowSep - i) % 2) == 1) // no complex elements + { + return NULL; + } + + if( nCol < 0 ) + { + nCol = (nPrevRowSep - i) / 2; + } + else if( (nPrevRowSep - i)/2 != nCol) // irregular array + { + return NULL; + } + + nPrevRowSep = i; + nRow++; + break; + + case ocMissing : + // Talk to ER : Do we want to expand past XL to support + // missing/null values in arrays ? + break; + + default : + // no functions or operators + return NULL; + } + } + if( nCol <= 0 || nRow <= 0 ) + return NULL; + + // fprintf (stderr, "Array (cols = %d, rows = %d)\n", nCol, nRow ); + + ScMatrix* pArray = new ScMatrix( nCol, nRow ); + for ( i = nStart, nCol = 0, nRow = 0 ; i < nLen ; i++ ) + { + t = pCode[i]; + + switch ( t->GetOpCode() ) + { + case ocMissing : + pArray->PutEmpty( nCol, nRow); + break; + + case ocPush : + if ( t->GetType() == svDouble ) + { + pArray->PutDouble( t->GetDouble(), nCol, nRow); + } + else if ( t->GetType() == svString ) + { + pArray->PutString( t->GetString(), nCol, nRow); + } + break; + + case ocSep : + nCol++; + break; + + case ocArrayRowSep : + nRow++; + break; + + default : + break; + } + pCode[i] = NULL; + t->DecRef(); + } + nLen = nStart; + return AddMatrix( pArray ); + } + // Wird auch vom Compiler genutzt. Das Token ist per new angelegt! ScToken* ScTokenArray::Add( ScToken* t ) *************** *** 1424,1429 **** --- 1568,1575 ---- && ( t->GetType() == svSingleRef || t->GetType() == svDoubleRef ) ) nRefs++; t->IncRef(); + if( t->GetOpCode() == ocArrayClose ) + return MergeArray(); return t; } else diff -rcP sc/source/ui/src/globstr.src sc/source/ui/src/globstr.src *** sc/source/ui/src/globstr.src Fri Jan 19 15:54:42 2007 --- sc/source/ui/src/globstr.src Fri Jan 26 13:32:38 2007 *************** *** 2605,2610 **** --- 2605,2616 ---- Text [ en-US ] = "#NULL!" ; Text [ x-comment ] = " "; }; + String STR_ERR_NESTED_ARRAY + { + Text [ de ] = "Nested arrays are not supported." ; + Text [ en-US ] = "Nested arrays are not supported." ; + Text [ x-comment ] = " "; + }; String STR_RECALC_MANUAL { Text [ de ] = "Manuell";