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
meaning and parameters of each formula
NOTE: When adding or rearranging items make sure to keep the TokenID table
in TsSpreadBIFFWriter.FormulaElementKindToExcelTokenID, unit xlscommon,
in sync !!!
NOTE: When adding or rearranging items:
- make sure that the subtypes TOperandTokens, TBasicOperationTokens and TFuncTokens
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 = (
{ Basic operands }
fekCell, fekCellRef, fekCellRange, fekNum, fekInteger, fekString, fekBool,
fekErr, fekMissingArg, fekParen,
fekErr, fekMissingArg,
{ Basic operations }
fekAdd, fekSub, fekDiv, fekMul, fekPercent, fekPower, fekUMinus, fekUPlus,
fekConcat, // string concatenation
fekEqual, fekGreater, fekGreaterEqual, fekLess, fekLessEqual, fekNotEqual,
fekParen,
{ Built-in/Worksheet Functions}
// math
fekABS, fekACOS, fekACOSH, fekASIN, fekASINH, fekATAN, fekATANH,
@ -90,7 +95,7 @@ type
fekMAX, fekMEDIAN, fekMIN, fekPERMUT, fekPOISSON, fekPRODUCT,
fekSTDEV, fekSTDEVP, fekSUM, fekSUMIF, fekSUMSQ, fekVAR, fekVARP,
// financial
fekFV, fekNPER, fekPV, fekPMT, fekRATE,
fekFV, fekNPER, fekPMT, fekPV, fekRATE,
// logical
fekAND, fekFALSE, fekIF, fekNOT, fekOR, fekTRUE,
// string
@ -106,6 +111,10 @@ type
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);
TsRelFlags = set of TsRelFlag;
@ -746,6 +755,7 @@ type
function RPNFunc(AToken: TFEKind; ANext: PRPNItem): PRPNItem; overload;
function RPNFunc(AToken: TFEKind; ANumParams: Byte; ANext: PRPNItem): PRPNItem; overload;
function FixedParamCount(AElementKind: TFEKind): Boolean;
var
GsSpreadFormats: array of TsSpreadFormatData;
@ -775,6 +785,8 @@ resourcestring
lpNoValidNumberFormatString = 'No valid number format string.';
lpNoValidDateTimeFormatString = 'No valid date/time format string.';
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';
lpFALSE = 'FALSE';
lpErrEmptyIntersection = '#NULL!';
@ -844,6 +856,154 @@ var
'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
}
@ -3761,38 +3921,10 @@ end;
}
function RPNFunc(AToken: TFEKind; ANext: PRPNItem): PRPNItem;
begin
if ord(AToken) < ord(fekAdd) then
raise Exception.Create('No basic tokens allowed here.');
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;
if FEProps[AToken].MinParams <> FEProps[AToken].MaxParams then
raise Exception.CreateFmt(lpSpecifyNumberOfParams, [FEProps[AToken].Symbol]);
Result := RPNFunc(AToken, FEProps[AToken].MinParams, ANext);
Result^.Next := ANext;
end;
@ -3803,8 +3935,27 @@ end;
}
function RPNFunc(AToken: TFEKind; ANumParams: Byte; ANext: PRPNItem): PRPNItem;
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^.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;
{@@
@ -3850,6 +4001,7 @@ begin
end;
end;
initialization
MakeLEPalette(@DEFAULT_PALETTE, Length(DEFAULT_PALETTE));

View File

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

View File

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