fpspreadsheet: Improved reading of rpn formulas: replace "monster case instruction" for function parameter count by lookup table.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3088 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2014-05-24 17:11:05 +00:00
parent 5f2609c39b
commit 81093f647f
3 changed files with 336 additions and 190 deletions

View File

@@ -61,19 +61,24 @@ type
See http://www.techonthenet.com/excel/formulas/ for an explanation of See http://www.techonthenet.com/excel/formulas/ for an explanation of
meaning and parameters of each formula meaning and parameters of each formula
NOTE: When adding or rearranging items make sure to keep the TokenID table NOTE: When adding or rearranging items:
in TsSpreadBIFFWriter.FormulaElementKindToExcelTokenID, unit xlscommon, - make sure that the subtypes TOperandTokens, TBasicOperationTokens and TFuncTokens
in sync !!! are complete
- make sure to keep the FEProps table in sync
- make sure to keep the TokenID table
in TsSpreadBIFFWriter.FormulaElementKindToExcelTokenID, unit xlscommon,
in sync
} }
TFEKind = ( TFEKind = (
{ Basic operands } { Basic operands }
fekCell, fekCellRef, fekCellRange, fekNum, fekInteger, fekString, fekBool, fekCell, fekCellRef, fekCellRange, fekNum, fekInteger, fekString, fekBool,
fekErr, fekMissingArg, fekParen, fekErr, fekMissingArg,
{ Basic operations } { Basic operations }
fekAdd, fekSub, fekDiv, fekMul, fekPercent, fekPower, fekUMinus, fekUPlus, fekAdd, fekSub, fekDiv, fekMul, fekPercent, fekPower, fekUMinus, fekUPlus,
fekConcat, // string concatenation fekConcat, // string concatenation
fekEqual, fekGreater, fekGreaterEqual, fekLess, fekLessEqual, fekNotEqual, fekEqual, fekGreater, fekGreaterEqual, fekLess, fekLessEqual, fekNotEqual,
fekParen,
{ Built-in/Worksheet Functions} { Built-in/Worksheet Functions}
// math // math
fekABS, fekACOS, fekACOSH, fekASIN, fekASINH, fekATAN, fekATANH, fekABS, fekACOS, fekACOSH, fekASIN, fekASINH, fekATAN, fekATANH,
@@ -90,7 +95,7 @@ type
fekMAX, fekMEDIAN, fekMIN, fekPERMUT, fekPOISSON, fekPRODUCT, fekMAX, fekMEDIAN, fekMIN, fekPERMUT, fekPOISSON, fekPRODUCT,
fekSTDEV, fekSTDEVP, fekSUM, fekSUMIF, fekSUMSQ, fekVAR, fekVARP, fekSTDEV, fekSTDEVP, fekSUM, fekSUMIF, fekSUMSQ, fekVAR, fekVARP,
// financial // financial
fekFV, fekNPER, fekPV, fekPMT, fekRATE, fekFV, fekNPER, fekPMT, fekPV, fekRATE,
// logical // logical
fekAND, fekFALSE, fekIF, fekNOT, fekOR, fekTRUE, fekAND, fekFALSE, fekIF, fekNOT, fekOR, fekTRUE,
// string // string
@@ -106,6 +111,10 @@ type
fekOpSUM {Unary sum operation. Note: CANNOT be used for summing sell contents; use fekSUM} fekOpSUM {Unary sum operation. Note: CANNOT be used for summing sell contents; use fekSUM}
); );
TOperandTokens = fekCell..fekMissingArg;
TBasicOperationTokens = fekAdd..fekParen;
TFuncTokens = fekAbs..fekOpSum;
TsRelFlag = (rfRelRow, rfRelCol, rfRelRow2, rfRelCol2); TsRelFlag = (rfRelRow, rfRelCol, rfRelRow2, rfRelCol2);
TsRelFlags = set of TsRelFlag; TsRelFlags = set of TsRelFlag;
@@ -746,6 +755,7 @@ type
function RPNFunc(AToken: TFEKind; ANext: PRPNItem): PRPNItem; overload; function RPNFunc(AToken: TFEKind; ANext: PRPNItem): PRPNItem; overload;
function RPNFunc(AToken: TFEKind; ANumParams: Byte; ANext: PRPNItem): PRPNItem; overload; function RPNFunc(AToken: TFEKind; ANumParams: Byte; ANext: PRPNItem): PRPNItem; overload;
function FixedParamCount(AElementKind: TFEKind): Boolean;
var var
GsSpreadFormats: array of TsSpreadFormatData; GsSpreadFormats: array of TsSpreadFormatData;
@@ -775,6 +785,8 @@ resourcestring
lpNoValidNumberFormatString = 'No valid number format string.'; lpNoValidNumberFormatString = 'No valid number format string.';
lpNoValidDateTimeFormatString = 'No valid date/time format string.'; lpNoValidDateTimeFormatString = 'No valid date/time format string.';
lpIllegalNumberFormat = 'Illegal number format.'; lpIllegalNumberFormat = 'Illegal number format.';
lpSpecifyNumberOfParams = 'Specify number of parameters for function %s';
lpIncorrectParamCount = 'Funtion %s requires at least %d and at most %d parameters.';
lpTRUE = 'TRUE'; lpTRUE = 'TRUE';
lpFALSE = 'FALSE'; lpFALSE = 'FALSE';
lpErrEmptyIntersection = '#NULL!'; lpErrEmptyIntersection = '#NULL!';
@@ -844,6 +856,154 @@ var
'wheat' // $16 'wheat' // $16
); );
{ Properties of formula elements }
type
TFEProp = record Symbol: String; MinParams, MaxParams: Byte; end;
const
FEProps: array[TFEKind] of TFEProp = (
{ Operands }
(Symbol:''; MinParams:-1; MaxParams:-1), // fekCell
(Symbol:''; MinParams:-1; MaxParams:-1), // fekCellRef
(Symbol:''; MinParams:-1; MaxParams:-1), // fekCellRange
(Symbol:''; MinParams:-1; MaxParams:-1), // fekCellNum
(Symbol:''; MinParams:-1; MaxParams:-1), // fekCellInteger
(Symbol:''; MinParams:-1; MaxParams:-1), // fekCellString
(Symbol:''; MinParams:-1; MaxParams:-1), // fekCellBool
(Symbol:''; MinParams:-1; MaxParams:-1), // fekCellErr
(Symbol:''; MinParams:-1; MaxParams:-1), // fekCellMissingArg
{ Basic operations }
(Symbol:'+'; MinParams:2; MaxParams:2), // fekAdd
(Symbol:'-'; MinParams:2; MaxParams:2), // fekSub
(Symbol:'*'; MinParams:2; MaxParams:2), // fekDiv
(Symbol:'/'; MinParams:2; MaxParams:2), // fekMul
(Symbol:'%'; MinParams:1; MaxParams:1), // fekPercent
(Symbol:'^'; MinParams:2; MaxParams:2), // fekPower
(Symbol:'-'; MinParams:1; MaxParams:1), // fekUMinus
(Symbol:'+'; MinParams:1; MaxParams:1), // fekUPlus
(Symbol:'&'; MinParams:2; MaxParams:2), // fekConcat (string concatenation)
(Symbol:'='; MinParams:2; MaxParams:2), // fekEqual
(Symbol:'>'; MinParams:2; MaxParams:2), // fekGreater
(Symbol:'>='; MinParams:2; MaxParams:2), // fekGreaterEqual
(Symbol:'<'; MinParams:2; MaxParams:2), // fekLess
(Symbol:'<='; MinParams:2; MaxParams:2), // fekLessEqual
(Symbol:'<>'; MinParams:2; MaxParams:2), // fekNotEqual
(Symbol:''; MinParams:1; MaxParams:1), // fekParen
{ math }
(Symbol:'ABS'; MinParams:1; MaxParams:1), // fekABS
(Symbol:'ACOS'; MinParams:1; MaxParams:1), // fekACOS
(Symbol:'ACOSH'; MinParams:1; MaxParams:1), // fekACOSH
(Symbol:'ASIN'; MinParams:1; MaxParams:1), // fekASIN
(Symbol:'ASINH'; MinParams:1; MaxParams:1), // fekASINH
(Symbol:'ATAN'; MinParams:1; MaxParams:1), // fekATAN
(Symbol:'ATANH'; MinParams:1; MaxParams:1), // fekATANH,
(Symbol:'COS'; MinParams:1; MaxParams:1), // fekCOS
(Symbol:'COSH'; MinParams:1; MaxParams:1), // fekCOSH
(Symbol:'DEGREES'; MinParams:1; MaxParams:1), // fekDEGREES
(Symbol:'EXP'; MinParams:1; MaxParams:1), // fekEXP
(Symbol:'INT'; MinParams:1; MaxParams:1), // fekINT
(Symbol:'LN'; MinParams:1; MaxParams:1), // fekLN
(Symbol:'LOG'; MinParams:1; MaxParams:2), // fekLOG,
(Symbol:'LOG10'; MinParams:1; MaxParams:1), // fekLOG10
(Symbol:'PI'; MinParams:0; MaxParams:0), // fekPI
(Symbol:'RADIANS'; MinParams:1; MaxParams:1), // fekRADIANS
(Symbol:'RAND'; MinParams:0; MaxParams:0), // fekRAND
(Symbol:'ROUND'; MinParams:2; MaxParams:2), // fekROUND,
(Symbol:'SIGN'; MinParams:1; MaxParams:1), // fekSIGN
(Symbol:'SIN'; MinParams:1; MaxParams:1), // fekSIN
(Symbol:'SINH'; MinParams:1; MaxParams:1), // fekSINH
(Symbol:'SQRT'; MinParams:1; MaxParams:1), // fekSQRT,
(Symbol:'TAN'; MinParams:1; MaxParams:1), // fekTAN
(Symbol:'TANH'; MinParams:1; MaxParams:1), // fekTANH,
{ date/time }
(Symbol:'DATE'; MinParams:3; MaxParams:3), // fekDATE
(Symbol:'DATEDIF'; MinParams:3; MaxParams:3), // fekDATEDIF
(Symbol:'DATEVALUE'; MinParams:1; MaxParams:1), // fekDATEVALUE
(Symbol:'DAY'; MinParams:1; MaxParams:1), // fekDAY
(Symbol:'HOUR'; MinParams:1; MaxParams:1), // fekHOUR
(Symbol:'MINUTE'; MinParams:1; MaxParams:1), // fekMINUTE
(Symbol:'MONTH'; MinParams:1; MaxParams:1), // fekMONTH
(Symbol:'NOW'; MinParams:0; MaxParams:0), // fekNOW
(Symbol:'SECOND'; MinParams:1; MaxParams:1), // fekSECOND
(Symbol:'TIME'; MinParams:3; MaxParams:3), // fekTIME
(Symbol:'TIMEVALUE'; MinParams:1; MaxParams:1), // fekTIMEVALUE
(Symbol:'TODAY'; MinParams:0; MaxParams:0), // fekTODAY
(Symbol:'WEEKDAY'; MinParams:1; MaxParams:2), // fekWEEKDAY
(Symbol:'YEAR'; MinParams:1; MaxParams:1), // fekYEAR
{ statistical }
(Symbol:'AVEDEV'; MinParams:1; MaxParams:30), // fekAVEDEV
(Symbol:'AVERAGE'; MinParams:1; MaxParams:30), // fekAVERAGE
(Symbol:'BETADIST'; MinParams:3; MaxParams:5), // fekBETADIST
(Symbol:'BETAINV'; MinParams:3; MaxParams:5), // fekBETAINV
(Symbol:'BINOMDIST'; MinParams:4; MaxParams:4), // fekBINOMDIST
(Symbol:'CHIDIST'; MinParams:2; MaxParams:2), // fekCHIDIST
(Symbol:'CHIINV'; MinParams:2; MaxParams:2), // fekCHIINV
(Symbol:'COUNT'; MinParams:0; MaxParams:30), // fekCOUNT
(Symbol:'COUNTA'; MinParams:0; MaxParams:30), // fekCOUNTA
(Symbol:'COUNTBLANK';MinParams:1; MaxParams:1), // fekCOUNTBLANK
(Symbol:'COUNTIF'; MinParams:2; MaxParams:2), // fekCOUNTIF
(Symbol:'MAX'; MinParams:1; MaxParams:30), // fekMAX
(Symbol:'MEDIAN'; MinParams:1; MaxParams:30), // fekMEDIAN
(Symbol:'MIN'; MinParams:1; MaxParams:30), // fekMIN
(Symbol:'PERMUT'; MinParams:2; MaxParams:2), // fekPERMUT
(Symbol:'POISSON'; MinParams:3; MaxParams:3), // fekPOISSON
(Symbol:'PRODUCT'; MinParams:0; MaxParams:30), // fekPRODUCT
(Symbol:'STDEV'; MinParams:1; MaxParams:30), // fekSTDEV
(Symbol:'STDEVP'; MinParams:1; MaxParams:30), // fekSTDEVP
(Symbol:'SUM'; MinParams:0; MaxParams:30), // fekSUM
(Symbol:'SUMIF'; MinParams:2; MaxParams:3), // fekSUMIF
(Symbol:'SUMSQ'; MinParams:0; MaxParams:30), // fekSUMSQ
(Symbol:'VAR'; MinParams:1; MaxParams:30), // fekVAR
(Symbol:'VARP'; MinParams:1; MaxParams:30), // fekVARP
{ financial }
(Symbol:'FV'; MinParams:3; MaxParams:5), // fekFV
(Symbol:'NPER'; MinParams:3; MaxParams:5), // fekNPER
(Symbol:'PMT'; MinParams:3; MaxParams:5), // fekPMT
(Symbol:'PV'; MinParams:3; MaxParams:5), // fekPV
(Symbol:'RATE'; MinParams:3; MaxParams:6), // fekRATE
{ logical }
(Symbol:'AND'; MinParams:0; MaxParams:30), // fekAND
(Symbol:'FALSE'; MinParams:0; MaxParams:0), // fekFALSE
(Symbol:'IF'; MinParams:2; MaxParams:3), // fekIF
(Symbol:'NOT'; MinParams:1; MaxParams:1), // fekNOT
(Symbol:'OR'; MinParams:1; MaxParams:30), // fekOR
(Symbol:'TRUE'; MinParams:0; MaxParams:0), // fekTRUE
{ string }
(Symbol:'CHAR'; MinParams:1; MaxParams:1), // fekCHAR
(Symbol:'CODE'; MinParams:1; MaxParams:1), // fekCODE
(Symbol:'LEFT'; MinParams:1; MaxParams:2), // fekLEFT
(Symbol:'LOWER'; MinParams:1; MaxParams:1), // fekLOWER
(Symbol:'MID'; MinParams:3; MaxParams:3), // fekMID
(Symbol:'PROPER'; MinParams:1; MaxParams:1), // fekPROPER
(Symbol:'REPLACE'; MinParams:4; MaxParams:4), // fekREPLACE
(Symbol:'RIGHT'; MinParams:1; MaxParams:2), // fekRIGHT
(Symbol:'SUBSTITUTE';MinParams:3; MaxParams:4), // fekSUBSTITUTE
(Symbol:'TRIM'; MinParams:1; MaxParams:1), // fekTRIM
(Symbol:'UPPER'; MinParams:1; MaxParams:1), // fekUPPER
{ lookup/reference }
(Symbol:'COLUMN'; MinParams:0; MaxParams:1), // fekCOLUMN
(Symbol:'COLUMNS'; MinParams:1; MaxParams:1), // fekCOLUMNS
(Symbol:'ROW'; MinParams:0; MaxParams:1), // fekROW
(Symbol:'ROWS'; MinParams:1; MaxParams:1), // fekROWS
{ info }
(Symbol:'CELL'; MinParams:1; MaxParams:2), // fekCELLINFO
(Symbol:'INFO'; MinParams:1; MaxParams:1), // fekINFO
(Symbol:'ISBLANK'; MinParams:1; MaxParams:1), // fekIsBLANK
(Symbol:'ISERR'; MinParams:1; MaxParams:1), // fekIsERR
(Symbol:'ISERROR'; MinParams:1; MaxParams:1), // fekIsERROR
(Symbol:'ISLOGICAL'; MinParams:1; MaxParams:1), // fekIsLOGICAL
(Symbol:'ISNA'; MinParams:1; MaxParams:1), // fekIsNA
(Symbol:'ISNONTEXT'; MinParams:1; MaxParams:1), // fekIsNONTEXT
(Symbol:'ISNUMBER'; MinParams:1; MaxParams:1), // fekIsNUMBER
(Symbol:'ISREF'; MinParams:1; MaxParams:1), // fekIsRef
(Symbol:'ISTEXT'; MinParams:1; MaxParams:1), // fekIsTEXT
(Symbol:'VALUE'; MinParams:1; MaxParams:1), // fekValue
{ Other operations }
(Symbol:'SUM'; MinParams:1; MaxParams:1) // fekOpSUM (Unary sum operation). Note: CANNOT be used for summing sell contents; use fekSUM}
);
{@@ {@@
Registers a new reader/writer pair for a format Registers a new reader/writer pair for a format
} }
@@ -3761,38 +3921,10 @@ end;
} }
function RPNFunc(AToken: TFEKind; ANext: PRPNItem): PRPNItem; function RPNFunc(AToken: TFEKind; ANext: PRPNItem): PRPNItem;
begin begin
if ord(AToken) < ord(fekAdd) then if FEProps[AToken].MinParams <> FEProps[AToken].MaxParams then
raise Exception.Create('No basic tokens allowed here.'); raise Exception.CreateFmt(lpSpecifyNumberOfParams, [FEProps[AToken].Symbol]);
Result := NewRPNItem;
Result^.FE.ElementKind := AToken;
case AToken of
fekFALSE, fekNOW, fekPI, fekRAND, fekTODAY, fekTRUE:
Result^.FE.ParamsNum := 0;
fekABS, fekACOS, fekACOSH, fekASIN, fekASINH, fekATAN, fekATANH,
fekCHAR, fekCODE, fekCOLUMNS, fekCOUNTBLANK, fekCOS, fekCOSH,
fekDATEVALUE, fekDAY, fekDEGREES, fekEXP, fekHOUR, fekINFO, fekINT,
fekIsBLANK, fekIsERR, fekIsERROR, fekIsLOGICAL, fekIsNA, fekIsNONTEXT,
fekIsTEXT, fekIsNUMBER, fekIsRef, fekLN, fekLOG10, fekLOWER, fekMINUTE,
fekMONTH, fekNOT, fekOpSUM, fekPercent, fekPROPER, fekRADIANS, fekROWS,
fekSECOND, fekSIGN, fekSIN, fekSINH, fekSQRT, fekTAN, fekTANH,
fekTIMEVALUE, fekTRIM, fekUMinus, fekUPlus, fekUPPER, fekValue,
fekWEEKDAY, fekYEAR:
Result^.FE.ParamsNum := 1;
fekAdd, fekCHIDIST, fekCHIINV, fekConcat, fekCOUNTIF, fekDiv,
fekEqual, fekGreater, fekGreaterEqual, fekLess, fekLessEqual,
fekMul, fekNotEqual, fekPERMUT, fekPower, fekSub, fekROUND:
Result^.FE.ParamsNum := 2;
fekDATE, fekDATEDIF, fekMID, fekPOISSON, fekTIME:
Result^.FE.ParamsNum := 3;
fekBINOMDIST, fekREPLACE:
Result^.FE.ParamsNum := 4;
end;
Result := RPNFunc(AToken, FEProps[AToken].MinParams, ANext);
Result^.Next := ANext; Result^.Next := ANext;
end; end;
@@ -3803,8 +3935,27 @@ end;
} }
function RPNFunc(AToken: TFEKind; ANumParams: Byte; ANext: PRPNItem): PRPNItem; function RPNFunc(AToken: TFEKind; ANumParams: Byte; ANext: PRPNItem): PRPNItem;
begin begin
Result := RPNFunc(AToken, ANext); if ord(AToken) < ord(fekAdd) then
raise Exception.Create('No basic tokens allowed here.');
if (ANumParams < FEProps[AToken].MinParams) or (ANumParams > FEProps[AToken].MaxParams) then
raise Exception.CreateFmt(lpIncorrectParamCount, [
FEProps[AToken].Symbol, FEProps[AToken].MinParams, FEProps[AToken].MaxParams
]);
Result := NewRPNItem;
Result^.FE.ElementKind := AToken;
Result^.FE.ParamsNum := ANumParams; Result^.FE.ParamsNum := ANumParams;
Result^.Next := ANext;
end;
{@@
Returns if the function defined by the token requires a fixed number of parameter.
}
function FixedParamCount(AElementKind: TFEKind): Boolean;
begin
Result := (FEProps[AElementKind].MinParams = FEProps[AElementKind].MaxParams)
and (FEProps[AElementKind].MinParams >= 0);
end; end;
{@@ {@@
@@ -3850,6 +4001,7 @@ begin
end; end;
end; end;
initialization initialization
MakeLEPalette(@DEFAULT_PALETTE, Length(DEFAULT_PALETTE)); MakeLEPalette(@DEFAULT_PALETTE, Length(DEFAULT_PALETTE));

View File

@@ -875,7 +875,7 @@ begin
Worksheet.WriteRPNFormula(Row, 1, CreateRPNFormula( Worksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(value, RPNNumber(value,
RPNNumber(2, RPNNumber(2,
RPNFunc(fekLOG, RPNFunc(fekLOG, 2,
nil))))); nil)))));
Worksheet.WriteNumber(Row, 2, logn(2.0, value)); Worksheet.WriteNumber(Row, 2, logn(2.0, value));
end; end;

View File

@@ -499,161 +499,157 @@ uses
StrUtils, fpsNumFormatParser; StrUtils, fpsNumFormatParser;
{ Helper table for rpn formulas: { Helper table for rpn formulas:
Assignment of FormulaElementKinds (fekXXXX) to EXCEL_TOKEN IDs. The table Assignment of FormulaElementKinds (fekXXXX) to EXCEL_TOKEN IDs. }
contains additional inforation in the first column:
0 --> primary token (basic operands and operations)
1 --> secondary token of a function with a fixed parameter count
2 --> secondary token of a function with a variable parameter count }
const const
TokenIDs: array[fekCell..fekOpSum, 0..1] of Word = ( TokenIDs: array[TFEKind] of Word = (
// Basic operands // Basic operands
(0, INT_EXCEL_TOKEN_TREFV), {fekCell} INT_EXCEL_TOKEN_TREFV, {fekCell}
(0, INT_EXCEL_TOKEN_TREFR), {fekCellRef} INT_EXCEL_TOKEN_TREFR, {fekCellRef}
(0, INT_EXCEL_TOKEN_TAREA_R), {fekCellRange} INT_EXCEL_TOKEN_TAREA_R, {fekCellRange}
(0, INT_EXCEL_TOKEN_TNUM), {fekNum} INT_EXCEL_TOKEN_TNUM, {fekNum}
(0, INT_EXCEL_TOKEN_TINT), {fekInteger} INT_EXCEL_TOKEN_TINT, {fekInteger}
(0, INT_EXCEL_TOKEN_TSTR), {fekString} INT_EXCEL_TOKEN_TSTR, {fekString}
(0, INT_EXCEL_TOKEN_TBOOL), {fekBool} INT_EXCEL_TOKEN_TBOOL, {fekBool}
(0, INT_EXCEL_TOKEN_TERR), {fekErr} INT_EXCEL_TOKEN_TERR, {fekErr}
(0, INT_EXCEL_TOKEN_TMISSARG), {fekMissArg, missing argument} INT_EXCEL_TOKEN_TMISSARG, {fekMissArg, missing argument}
(0, INT_EXCEL_TOKEN_TPAREN), {Operator in parenthesis}
// Basic operations // Basic operations
(0, INT_EXCEL_TOKEN_TADD), {fekAdd, +} INT_EXCEL_TOKEN_TADD, {fekAdd, +}
(0, INT_EXCEL_TOKEN_TSUB), {fekSub, -} INT_EXCEL_TOKEN_TSUB, {fekSub, -}
(0, INT_EXCEL_TOKEN_TDIV), {fekDiv, /} INT_EXCEL_TOKEN_TDIV, {fekDiv, /}
(0, INT_EXCEL_TOKEN_TMUL), {fekMul, *} INT_EXCEL_TOKEN_TMUL, {fekMul, *}
(0, INT_EXCEL_TOKEN_TPERCENT), {fekPercent, %} INT_EXCEL_TOKEN_TPERCENT, {fekPercent, %}
(0, INT_EXCEL_TOKEN_TPOWER), {fekPower, ^} INT_EXCEL_TOKEN_TPOWER, {fekPower, ^}
(0, INT_EXCEL_TOKEN_TUMINUS), {fekUMinus, -} INT_EXCEL_TOKEN_TUMINUS, {fekUMinus, -}
(0, INT_EXCEL_TOKEN_TUPLUS), {fekUPlus, +} INT_EXCEL_TOKEN_TUPLUS, {fekUPlus, +}
(0, INT_EXCEL_TOKEN_TCONCAT), {fekConcat, &, for strings} INT_EXCEL_TOKEN_TCONCAT, {fekConcat, &, for strings}
(0, INT_EXCEL_TOKEN_TEQ), {fekEqual, =} INT_EXCEL_TOKEN_TEQ, {fekEqual, =}
(0, INT_EXCEL_TOKEN_TGT), {fekGreater, >} INT_EXCEL_TOKEN_TGT, {fekGreater, >}
(0, INT_EXCEL_TOKEN_TGE), {fekGreaterEqual, >=} INT_EXCEL_TOKEN_TGE, {fekGreaterEqual, >=}
(0, INT_EXCEL_TOKEN_TLT), {fekLess <} INT_EXCEL_TOKEN_TLT, {fekLess <}
(0, INT_EXCEL_TOKEN_TLE), {fekLessEqual, <=} INT_EXCEL_TOKEN_TLE, {fekLessEqual, <=}
(0, INT_EXCEL_TOKEN_TNE), {fekNotEqual, <>} INT_EXCEL_TOKEN_TNE, {fekNotEqual, <>}
INT_EXCEL_TOKEN_TPAREN, {Operator in parenthesis}
// Math functions // Math functions
(1, INT_EXCEL_SHEET_FUNC_ABS), {fekABS} INT_EXCEL_SHEET_FUNC_ABS, {fekABS}
(1, INT_EXCEL_SHEET_FUNC_ACOS), {fekACOS} INT_EXCEL_SHEET_FUNC_ACOS, {fekACOS}
(1, INT_EXCEL_SHEET_FUNC_ACOSH), {fekACOSH} INT_EXCEL_SHEET_FUNC_ACOSH, {fekACOSH}
(1, INT_EXCEL_SHEET_FUNC_ASIN), {fekASIN} INT_EXCEL_SHEET_FUNC_ASIN, {fekASIN}
(1, INT_EXCEL_SHEET_FUNC_ASINH), {fekASINH} INT_EXCEL_SHEET_FUNC_ASINH, {fekASINH}
(1, INT_EXCEL_SHEET_FUNC_ATAN), {fekATAN} INT_EXCEL_SHEET_FUNC_ATAN, {fekATAN}
(1, INT_EXCEL_SHEET_FUNC_ATANH), {fekATANH} INT_EXCEL_SHEET_FUNC_ATANH, {fekATANH}
(1, INT_EXCEL_SHEET_FUNC_COS), {fekCOS} INT_EXCEL_SHEET_FUNC_COS, {fekCOS}
(1, INT_EXCEL_SHEET_FUNC_COSH), {fekCOSH} INT_EXCEL_SHEET_FUNC_COSH, {fekCOSH}
(1, INT_EXCEL_SHEET_FUNC_DEGREES), {fekDEGREES} INT_EXCEL_SHEET_FUNC_DEGREES, {fekDEGREES}
(1, INT_EXCEL_SHEET_FUNC_EXP), {fekEXP} INT_EXCEL_SHEET_FUNC_EXP, {fekEXP}
(1, INT_EXCEL_SHEET_FUNC_INT), {fekINT} INT_EXCEL_SHEET_FUNC_INT, {fekINT}
(1, INT_EXCEL_SHEET_FUNC_LN), {fekLN} INT_EXCEL_SHEET_FUNC_LN, {fekLN}
(1, INT_EXCEL_SHEET_FUNC_LOG), {fekLOG} INT_EXCEL_SHEET_FUNC_LOG, {fekLOG}
(1, INT_EXCEL_SHEET_FUNC_LOG10), {fekLOG10} INT_EXCEL_SHEET_FUNC_LOG10, {fekLOG10}
(1, INT_EXCEL_SHEET_FUNC_PI), {fekPI} INT_EXCEL_SHEET_FUNC_PI, {fekPI}
(1, INT_EXCEL_SHEET_FUNC_RADIANS), {fekRADIANS} INT_EXCEL_SHEET_FUNC_RADIANS, {fekRADIANS}
(1, INT_EXCEL_SHEET_FUNC_RAND), {fekRAND} INT_EXCEL_SHEET_FUNC_RAND, {fekRAND}
(1, INT_EXCEL_SHEET_FUNC_ROUND), {fekROUND} INT_EXCEL_SHEET_FUNC_ROUND, {fekROUND}
(1, INT_EXCEL_SHEET_FUNC_SIGN), {fekSIGN} INT_EXCEL_SHEET_FUNC_SIGN, {fekSIGN}
(1, INT_EXCEL_SHEET_FUNC_SIN), {fekSIN} INT_EXCEL_SHEET_FUNC_SIN, {fekSIN}
(1, INT_EXCEL_SHEET_FUNC_SINH), {fekSINH} INT_EXCEL_SHEET_FUNC_SINH, {fekSINH}
(1, INT_EXCEL_SHEET_FUNC_SQRT), {fekSQRT} INT_EXCEL_SHEET_FUNC_SQRT, {fekSQRT}
(1, INT_EXCEL_SHEET_FUNC_TAN), {fekTAN} INT_EXCEL_SHEET_FUNC_TAN, {fekTAN}
(1, INT_EXCEL_SHEET_FUNC_TANH), {fekTANH} INT_EXCEL_SHEET_FUNC_TANH, {fekTANH}
// Date/time functions // Date/time functions
(1, INT_EXCEL_SHEET_FUNC_DATE), {fekDATE} INT_EXCEL_SHEET_FUNC_DATE, {fekDATE}
(1, INT_EXCEL_SHEET_FUNC_DATEDIF), {fekDATEDIF} INT_EXCEL_SHEET_FUNC_DATEDIF, {fekDATEDIF}
(1, INT_EXCEL_SHEET_FUNC_DATEVALUE), {fekDATEVALUE} INT_EXCEL_SHEET_FUNC_DATEVALUE, {fekDATEVALUE}
(1, INT_EXCEL_SHEET_FUNC_DAY), {fekDAY} INT_EXCEL_SHEET_FUNC_DAY, {fekDAY}
(1, INT_EXCEL_SHEET_FUNC_HOUR), {fekHOUR} INT_EXCEL_SHEET_FUNC_HOUR, {fekHOUR}
(1, INT_EXCEL_SHEET_FUNC_MINUTE), {fekMINUTE} INT_EXCEL_SHEET_FUNC_MINUTE, {fekMINUTE}
(1, INT_EXCEL_SHEET_FUNC_MONTH), {fekMONTH} INT_EXCEL_SHEET_FUNC_MONTH, {fekMONTH}
(1, INT_EXCEL_SHEET_FUNC_NOW), {fekNOW} INT_EXCEL_SHEET_FUNC_NOW, {fekNOW}
(1, INT_EXCEL_SHEET_FUNC_SECOND), {fekSECOND} INT_EXCEL_SHEET_FUNC_SECOND, {fekSECOND}
(1, INT_EXCEL_SHEET_FUNC_TIME), {fekTIME} INT_EXCEL_SHEET_FUNC_TIME, {fekTIME}
(1, INT_EXCEL_SHEET_FUNC_TIMEVALUE), {fekTIMEVALUE} INT_EXCEL_SHEET_FUNC_TIMEVALUE, {fekTIMEVALUE}
(1, INT_EXCEL_SHEET_FUNC_TODAY), {fekTODAY} INT_EXCEL_SHEET_FUNC_TODAY, {fekTODAY}
(2, INT_EXCEL_SHEET_FUNC_WEEKDAY), {fekWEEKDAY} INT_EXCEL_SHEET_FUNC_WEEKDAY, {fekWEEKDAY}
(1, INT_EXCEL_SHEET_FUNC_YEAR), {fekYEAR} INT_EXCEL_SHEET_FUNC_YEAR, {fekYEAR}
// Statistical functions // Statistical functions
(2, INT_EXCEL_SHEET_FUNC_AVEDEV), {fekAVEDEV} INT_EXCEL_SHEET_FUNC_AVEDEV, {fekAVEDEV}
(2, INT_EXCEL_SHEET_FUNC_AVERAGE), {fekAVERAGE} INT_EXCEL_SHEET_FUNC_AVERAGE, {fekAVERAGE}
(2, INT_EXCEL_SHEET_FUNC_BETADIST), {fekBETADIST} INT_EXCEL_SHEET_FUNC_BETADIST, {fekBETADIST}
(2, INT_EXCEL_SHEET_FUNC_BETAINV), {fekBETAINV} INT_EXCEL_SHEET_FUNC_BETAINV, {fekBETAINV}
(1, INT_EXCEL_SHEET_FUNC_BINOMDIST), {fekBINOMDIST} INT_EXCEL_SHEET_FUNC_BINOMDIST, {fekBINOMDIST}
(1, INT_EXCEL_SHEET_FUNC_CHIDIST), {fekCHIDIST} INT_EXCEL_SHEET_FUNC_CHIDIST, {fekCHIDIST}
(1, INT_EXCEL_SHEET_FUNC_CHIINV), {fekCHIINV} INT_EXCEL_SHEET_FUNC_CHIINV, {fekCHIINV}
(2, INT_EXCEL_SHEET_FUNC_COUNT), {fekCOUNT} INT_EXCEL_SHEET_FUNC_COUNT, {fekCOUNT}
(2, INT_EXCEL_SHEET_FUNC_COUNTA), {fekCOUNTA} INT_EXCEL_SHEET_FUNC_COUNTA, {fekCOUNTA}
(1, INT_EXCEL_SHEET_FUNC_COUNTBLANK),{fekCOUNTBLANK} INT_EXCEL_SHEET_FUNC_COUNTBLANK,{fekCOUNTBLANK}
(2, INT_EXCEL_SHEET_FUNC_COUNTIF), {fekCOUNTIF} INT_EXCEL_SHEET_FUNC_COUNTIF, {fekCOUNTIF}
(2, INT_EXCEL_SHEET_FUNC_MAX), {fekMAX} INT_EXCEL_SHEET_FUNC_MAX, {fekMAX}
(2, INT_EXCEL_SHEET_FUNC_MEDIAN), {fekMEDIAN} INT_EXCEL_SHEET_FUNC_MEDIAN, {fekMEDIAN}
(2, INT_EXCEL_SHEET_FUNC_MIN), {fekMIN} INT_EXCEL_SHEET_FUNC_MIN, {fekMIN}
(1, INT_EXCEL_SHEET_FUNC_PERMUT), {fekPERMUT} INT_EXCEL_SHEET_FUNC_PERMUT, {fekPERMUT}
(1, INT_EXCEL_SHEET_FUNC_POISSON), {fekPOISSON} INT_EXCEL_SHEET_FUNC_POISSON, {fekPOISSON}
(2, INT_EXCEL_SHEET_FUNC_PRODUCT), {fekPRODUCT} INT_EXCEL_SHEET_FUNC_PRODUCT, {fekPRODUCT}
(2, INT_EXCEL_SHEET_FUNC_STDEV), {fekSTDEV} INT_EXCEL_SHEET_FUNC_STDEV, {fekSTDEV}
(2, INT_EXCEL_SHEET_FUNC_STDEVP), {fekSTDEVP} INT_EXCEL_SHEET_FUNC_STDEVP, {fekSTDEVP}
(2, INT_EXCEL_SHEET_FUNC_SUM), {fekSUM} INT_EXCEL_SHEET_FUNC_SUM, {fekSUM}
(2, INT_EXCEL_SHEET_FUNC_SUMIF), {fekSUMIF} INT_EXCEL_SHEET_FUNC_SUMIF, {fekSUMIF}
(2, INT_EXCEL_SHEET_FUNC_SUMSQ), {fekSUMSQ} INT_EXCEL_SHEET_FUNC_SUMSQ, {fekSUMSQ}
(2, INT_EXCEL_SHEET_FUNC_VAR), {fekVAR} INT_EXCEL_SHEET_FUNC_VAR, {fekVAR}
(2, INT_EXCEL_SHEET_FUNC_VARP), {fekVARP} INT_EXCEL_SHEET_FUNC_VARP, {fekVARP}
// Financial functions // Financial functions
(2, INT_EXCEL_SHEET_FUNC_FV), {fekFV} INT_EXCEL_SHEET_FUNC_FV, {fekFV}
(2, INT_EXCEL_SHEET_FUNC_NPER), {fekNPER} INT_EXCEL_SHEET_FUNC_NPER, {fekNPER}
(2, INT_EXCEL_SHEET_FUNC_PV), {fekPV} INT_EXCEL_SHEET_FUNC_PMT, {fekPMT}
(2, INT_EXCEL_SHEET_FUNC_PMT), {fekPMT} INT_EXCEL_SHEET_FUNC_PV, {fekPV}
(2, INT_EXCEL_SHEET_FUNC_RATE), {fekRATE} INT_EXCEL_SHEET_FUNC_RATE, {fekRATE}
// Logical functions // Logical functions
(2, INT_EXCEL_SHEET_FUNC_AND), {fekAND} INT_EXCEL_SHEET_FUNC_AND, {fekAND}
(1, INT_EXCEL_SHEET_FUNC_FALSE), {fekFALSE} INT_EXCEL_SHEET_FUNC_FALSE, {fekFALSE}
(2, INT_EXCEL_SHEET_FUNC_IF), {fekIF} INT_EXCEL_SHEET_FUNC_IF, {fekIF}
(1, INT_EXCEL_SHEET_FUNC_NOT), {fekNOT} INT_EXCEL_SHEET_FUNC_NOT, {fekNOT}
(2, INT_EXCEL_SHEET_FUNC_OR), {fekOR} INT_EXCEL_SHEET_FUNC_OR, {fekOR}
(1, INT_EXCEL_SHEET_FUNC_TRUE), {fekTRUE} INT_EXCEL_SHEET_FUNC_TRUE, {fekTRUE}
// String functions // String functions
(1, INT_EXCEL_SHEET_FUNC_CHAR), {fekCHAR} INT_EXCEL_SHEET_FUNC_CHAR, {fekCHAR}
(1, INT_EXCEL_SHEET_FUNC_CODE), {fekCODE} INT_EXCEL_SHEET_FUNC_CODE, {fekCODE}
(2, INT_EXCEL_SHEET_FUNC_LEFT), {fekLEFT} INT_EXCEL_SHEET_FUNC_LEFT, {fekLEFT}
(1, INT_EXCEL_SHEET_FUNC_LOWER), {fekLOWER} INT_EXCEL_SHEET_FUNC_LOWER, {fekLOWER}
(1, INT_EXCEL_SHEET_FUNC_MID), {fekMID} INT_EXCEL_SHEET_FUNC_MID, {fekMID}
(1, INT_EXCEL_SHEET_FUNC_PROPER), {fekPROPER} INT_EXCEL_SHEET_FUNC_PROPER, {fekPROPER}
(1, INT_EXCEL_SHEET_FUNC_REPLACE), {fekREPLACE} INT_EXCEL_SHEET_FUNC_REPLACE, {fekREPLACE}
(2, INT_EXCEL_SHEET_FUNC_RIGHT), {fekRIGHT} INT_EXCEL_SHEET_FUNC_RIGHT, {fekRIGHT}
(2, INT_EXCEL_SHEET_FUNC_SUBSTITUTE),{fekSUBSTITUTE} INT_EXCEL_SHEET_FUNC_SUBSTITUTE,{fekSUBSTITUTE}
(1, INT_EXCEL_SHEET_FUNC_TRIM), {fekTRIM} INT_EXCEL_SHEET_FUNC_TRIM, {fekTRIM}
(1, INT_EXCEL_SHEET_FUNC_UPPER), {fekUPPER} INT_EXCEL_SHEET_FUNC_UPPER, {fekUPPER}
// lookup/reference functions // lookup/reference functions
(2, INT_EXCEL_SHEET_FUNC_COLUMN), {fekCOLUMN} INT_EXCEL_SHEET_FUNC_COLUMN, {fekCOLUMN}
(1, INT_EXCEL_SHEET_FUNC_COLUMNS), {fekCOLUMNS} INT_EXCEL_SHEET_FUNC_COLUMNS, {fekCOLUMNS}
(2, INT_EXCEL_SHEET_FUNC_ROW), {fekROW} INT_EXCEL_SHEET_FUNC_ROW, {fekROW}
(1, INT_EXCEL_SHEET_FUNC_ROWS), {fekROWS} INT_EXCEL_SHEET_FUNC_ROWS, {fekROWS}
// Info functions // Info functions
(2, INT_EXCEL_SHEET_FUNC_CELL), {fekCELLINFO} INT_EXCEL_SHEET_FUNC_CELL, {fekCELLINFO}
(1, INT_EXCEL_SHEET_FUNC_INFO), {fekINFO} INT_EXCEL_SHEET_FUNC_INFO, {fekINFO}
(1, INT_EXCEL_SHEET_FUNC_ISBLANK), {fekIsBLANK} INT_EXCEL_SHEET_FUNC_ISBLANK, {fekIsBLANK}
(1, INT_EXCEL_SHEET_FUNC_ISERR), {fekIsERR} INT_EXCEL_SHEET_FUNC_ISERR, {fekIsERR}
(1, INT_EXCEL_SHEET_FUNC_ISERROR), {fekIsERROR} INT_EXCEL_SHEET_FUNC_ISERROR, {fekIsERROR}
(1, INT_EXCEL_SHEET_FUNC_ISLOGICAL), {fekIsLOGICAL} INT_EXCEL_SHEET_FUNC_ISLOGICAL, {fekIsLOGICAL}
(1, INT_EXCEL_SHEET_FUNC_ISNA), {fekIsNA} INT_EXCEL_SHEET_FUNC_ISNA, {fekIsNA}
(1, INT_EXCEL_SHEET_FUNC_ISNONTEXT), {fekIsNONTEXT} INT_EXCEL_SHEET_FUNC_ISNONTEXT, {fekIsNONTEXT}
(1, INT_EXCEL_SHEET_FUNC_ISNUMBER), {fekIsNUMBER} INT_EXCEL_SHEET_FUNC_ISNUMBER, {fekIsNUMBER}
(1, INT_EXCEL_SHEET_FUNC_ISREF), {fekIsREF} INT_EXCEL_SHEET_FUNC_ISREF, {fekIsREF}
(1, INT_EXCEL_SHEET_FUNC_ISTEXT), {fekIsTEXT} INT_EXCEL_SHEET_FUNC_ISTEXT, {fekIsTEXT}
(1, INT_EXCEL_SHEET_FUNC_VALUE), {fekValue} INT_EXCEL_SHEET_FUNC_VALUE, {fekValue}
// Other operations // Other operations
(0, INT_EXCEL_TOKEN_TATTR) {fekOpSum} INT_EXCEL_TOKEN_TATTR {fekOpSum}
); );
@@ -1475,8 +1471,8 @@ begin
begin begin
func := ReadRPNFunc(AStream); func := ReadRPNFunc(AStream);
found := false; found := false;
for fek in TFEKind do begin for fek in TFuncTokens do begin
if (TokenIDs[fek, 1] = func) and (TokenIDs[fek, 0] = 1) then begin if (TokenIDs[fek] = func) and FixedParamCount(fek) then begin
rpnItem := RPNFunc(fek, rpnItem); rpnItem := RPNFunc(fek, rpnItem);
found := true; found := true;
break; break;
@@ -1494,8 +1490,8 @@ begin
b := AStream.ReadByte; b := AStream.ReadByte;
func := ReadRPNFunc(AStream); func := ReadRPNFunc(AStream);
found := false; found := false;
for fek in TFEKind do for fek in TFuncTokens do
if (TokenIDs[fek, 1] = func) and (TokenIDs[fek, 0] = 2) then begin if (TokenIDs[fek] = func) and not FixedParamCount(fek) then begin
rpnItem := RPNFunc(fek, b, rpnItem); rpnItem := RPNFunc(fek, b, rpnItem);
found := true; found := true;
break; break;
@@ -1506,8 +1502,8 @@ begin
else else
found := false; found := false;
for fek in TFEKind do for fek in TBasicOperationTokens do
if (TokenIDs[fek, 1] = token) and (TokenIDs[fek, 0] = 0) then begin if (TokenIDs[fek] = token) then begin
rpnItem := RPNFunc(fek, rpnItem); rpnItem := RPNFunc(fek, rpnItem);
found := true; found := true;
break; break;
@@ -1638,19 +1634,17 @@ end;
function TsSpreadBIFFWriter.FormulaElementKindToExcelTokenID( function TsSpreadBIFFWriter.FormulaElementKindToExcelTokenID(
AElementKind: TFEKind; out ASecondaryID: Word): Word; AElementKind: TFEKind; out ASecondaryID: Word): Word;
begin begin
case TokenIDs[AElementKind, 0] of if (AElementKind >= Low(TFuncTokens)) and (AElementKind <= High(TFuncTokens))
0: begin then begin
Result := TokenIDs[AElementKind, 1]; if FixedParamCount(AElementKind) then
ASecondaryID := 0; Result := INT_EXCEL_TOKEN_FUNC_V
end; else
1: begin Result := INT_EXCEL_TOKEN_FUNCVAR_V;
Result := INT_EXCEL_TOKEN_FUNC_V; ASecondaryID := TokenIDs[AElementKind];
ASecondaryID := TokenIDs[AElementKind, 1] end
end; else begin
2: begin Result := TokenIDs[AElementKind];
Result := INT_EXCEL_TOKEN_FUNCVAR_V; ASecondaryID := 0;
ASecondaryID := TokenIDs[AElementKind, 1]
end;
end; end;
end; end;