fpspreadsheet: Modify expression parser to accept decimal and list separators different from the default point and comma.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3509 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2014-09-01 08:17:35 +00:00
parent f632abb89f
commit c3becffe34
4 changed files with 232 additions and 148 deletions

View File

@ -41,7 +41,7 @@ begin
//cell := Worksheet.WriteFormula(1, 0, 'Day(Date(2014, 1, 12))'); //cell := Worksheet.WriteFormula(1, 0, 'Day(Date(2014, 1, 12))');
//cell := Worksheet.WriteFormula(1, 0, 'SUM(1,2,3)'); //cell := Worksheet.WriteFormula(1, 0, 'SUM(1,2,3)');
//cell := Worksheet.WriteFormula(1, 0, 'CELL("address",A1)'); //cell := Worksheet.WriteFormula(1, 0, 'CELL("address",A1)');
cell := Worksheet.WriteFormula(1, 0, 'ISBLANK(A1)'); cell := Worksheet.WriteFormula(1, 0, 'SUM(A1, 1.2, 1.3)');
WriteLn('A1: ', worksheet.ReadAsUTF8Text(0, 0)); WriteLn('A1: ', worksheet.ReadAsUTF8Text(0, 0));
WriteLn('B1: ', worksheet.ReadAsUTF8Text(0, 1)); WriteLn('B1: ', worksheet.ReadAsUTF8Text(0, 1));
@ -64,7 +64,8 @@ begin
rtError : WriteLn(GetErrorValueStr(res.ResError)); rtError : WriteLn(GetErrorValueStr(res.ResError));
end; end;
WriteLn('Reconstructed string formula: ', parser.BuildStringFormula); WriteLn('Reconstructed string formula: ', parser.Expression);
WriteLn('Reconstructed localized formula: ', parser.LocalizedExpression[DefaultFormatSettings]);
formula := parser.RPNFormula; formula := parser.RPNFormula;
for i:=0 to Length(formula)-1 do begin for i:=0 to Length(formula)-1 do begin
@ -93,7 +94,7 @@ begin
try try
try try
parser.RPNFormula := formula; parser.RPNFormula := formula;
s := parser.BuildStringFormula; s := parser.Expression;
WriteLn('String formula, reconstructed from RPN formula: ', s); WriteLn('String formula, reconstructed from RPN formula: ', s);
except on E:Exception do except on E:Exception do
begin begin

View File

@ -67,7 +67,7 @@ type
ttCell, ttCellRange, ttNumber, ttString, ttIdentifier, ttCell, ttCellRange, ttNumber, ttString, ttIdentifier,
ttPlus, ttMinus, ttMul, ttDiv, ttConcat, ttPercent, ttPower, ttLeft, ttRight, ttPlus, ttMinus, ttMul, ttDiv, ttConcat, ttPercent, ttPower, ttLeft, ttRight,
ttLessThan, ttLargerThan, ttEqual, ttNotEqual, ttLessThanEqual, ttLargerThanEqual, ttLessThan, ttLargerThan, ttEqual, ttNotEqual, ttLessThanEqual, ttLargerThanEqual,
ttComma, ttTrue, ttFalse, ttEOF ttListSep, ttTrue, ttFalse, ttEOF
); );
TsExprFloat = Double; TsExprFloat = Double;
@ -110,6 +110,8 @@ type
{ TsExprNode } { TsExprNode }
TsExprNode = class(TObject) TsExprNode = class(TObject)
private
FParser: TsExpressionParser;
protected protected
procedure CheckNodeType(ANode: TsExprNode; Allowed: TsResultTypes); procedure CheckNodeType(ANode: TsExprNode; Allowed: TsResultTypes);
// A procedure with var saves an implicit try/finally in each node // A procedure with var saves an implicit try/finally in each node
@ -121,6 +123,7 @@ type
procedure Check; virtual; abstract; procedure Check; virtual; abstract;
function NodeType: TsResultType; virtual; abstract; function NodeType: TsResultType; virtual; abstract;
function NodeValue: TsExpressionResult; function NodeValue: TsExpressionResult;
property Parser: TsExpressionParser read FParser;
end; end;
TsExprArgumentArray = array of TsExprNode; TsExprArgumentArray = array of TsExprNode;
@ -133,7 +136,7 @@ type
protected protected
procedure CheckSameNodeTypes; virtual; procedure CheckSameNodeTypes; virtual;
public public
constructor Create(ALeft, ARight: TsExprNode); constructor Create(AParser: TsExpressionParser; ALeft, ARight: TsExprNode);
destructor Destroy; override; destructor Destroy; override;
procedure Check; override; procedure Check; override;
property Left: TsExprNode read FLeft; property Left: TsExprNode read FLeft;
@ -295,7 +298,7 @@ type
protected protected
procedure Check; override; procedure Check; override;
public public
constructor Create(AOperand: TsExprNode); constructor Create(AParser: TsExpressionParser; AOperand: TsExprNode);
destructor Destroy; override; destructor Destroy; override;
property Operand: TsExprNode read FOperand; property Operand: TsExprNode read FOperand;
end; end;
@ -399,12 +402,12 @@ type
procedure Check; override; procedure Check; override;
procedure GetNodeValue(var Result: TsExpressionResult); override; procedure GetNodeValue(var Result: TsExpressionResult); override;
public public
constructor CreateString(AValue: String); constructor CreateString(AParser: TsExpressionParser; AValue: String);
constructor CreateInteger(AValue: Int64); constructor CreateInteger(AParser: TsExpressionParser; AValue: Int64);
constructor CreateDateTime(AValue: TDateTime); constructor CreateDateTime(AParser: TsExpressionParser; AValue: TDateTime);
constructor CreateFloat(AValue: TsExprFloat); constructor CreateFloat(AParser: TsExpressionParser; AValue: TsExprFloat);
constructor CreateBoolean(AValue: Boolean); constructor CreateBoolean(AParser: TsExpressionParser; AValue: Boolean);
constructor CreateError(AValue: TsErrorValue); constructor CreateError(AParser: TsExpressionParser; AValue: TsErrorValue);
function AsString: string; override; function AsString: string; override;
function AsRPNItem(ANext: PRPNItem): PRPNItem; override; function AsRPNItem(ANext: PRPNItem): PRPNItem; override;
function NodeType : TsResultType; override; function NodeType : TsResultType; override;
@ -451,6 +454,7 @@ type
protected protected
procedure CheckResultType(const AType: TsResultType); procedure CheckResultType(const AType: TsResultType);
procedure CheckVariable; procedure CheckVariable;
function GetFormatSettings: TFormatSettings;
public public
function ArgumentCount: Integer; function ArgumentCount: Integer;
procedure Assign(Source: TPersistent); override; procedure Assign(Source: TPersistent); override;
@ -533,7 +537,7 @@ type
protected protected
procedure GetNodeValue(var Result: TsExpressionResult); override; procedure GetNodeValue(var Result: TsExpressionResult); override;
public public
constructor CreateIdentifier(AID: TsExprIdentifierDef); constructor CreateIdentifier(AParser: TsExpressionParser; AID: TsExprIdentifierDef);
function NodeType: TsResultType; override; function NodeType: TsResultType; override;
property Identifier: TsExprIdentifierDef read FID; property Identifier: TsExprIdentifierDef read FID;
end; end;
@ -553,8 +557,8 @@ type
protected protected
procedure CalcParams; procedure CalcParams;
public public
constructor CreateFunction(AID: TsExprIdentifierDef; constructor CreateFunction(AParser: TsExpressionParser;
const Args: TsExprArgumentArray); virtual; AID: TsExprIdentifierDef; const Args: TsExprArgumentArray); virtual;
destructor Destroy; override; destructor Destroy; override;
function AsRPNItem(ANext: PRPNItem): PRPNItem; override; function AsRPNItem(ANext: PRPNItem): PRPNItem; override;
function AsString: String; override; function AsString: String; override;
@ -570,8 +574,8 @@ type
protected protected
procedure GetNodeValue(var Result: TsExpressionResult); override; procedure GetNodeValue(var Result: TsExpressionResult); override;
public public
constructor CreateFunction(AID: TsExprIdentifierDef; constructor CreateFunction(AParser: TsExpressionParser;
const Args: TsExprArgumentArray); override; AID: TsExprIdentifierDef; const Args: TsExprArgumentArray); override;
property CallBack: TsExprFunctionCallBack read FCallBack; property CallBack: TsExprFunctionCallBack read FCallBack;
end; end;
@ -582,8 +586,8 @@ type
protected protected
procedure GetNodeValue(var Result: TsExpressionResult); override; procedure GetNodeValue(var Result: TsExpressionResult); override;
public public
constructor CreateFunction(AID: TsExprIdentifierDef; constructor CreateFunction(AParser: TsExpressionParser;
const Args: TsExprArgumentArray); override; AID: TsExprIdentifierDef; const Args: TsExprArgumentArray); override;
property CallBack: TsExprFunctionEvent read FCallBack; property CallBack: TsExprFunctionEvent read FCallBack;
end; end;
@ -599,9 +603,10 @@ type
procedure Check; override; procedure Check; override;
procedure GetNodeValue(var Result: TsExpressionResult); override; procedure GetNodeValue(var Result: TsExpressionResult); override;
public public
constructor Create(AWorksheet: TsWorksheet; ACellString: String); overload; constructor Create(AParser: TsExpressionParser; AWorksheet: TsWorksheet;
constructor Create(AWorksheet: TsWorksheet; ARow, ACol: Cardinal; ACellString: String); overload;
AFlags: TsRelFlags); overload; constructor Create(AParser: TsExpressionParser; AWorksheet: TsWorksheet;
ARow, ACol: Cardinal; AFlags: TsRelFlags); overload;
function AsRPNItem(ANext: PRPNItem): PRPNItem; override; function AsRPNItem(ANext: PRPNItem): PRPNItem; override;
function AsString: string; override; function AsString: string; override;
function NodeType: TsResultType; override; function NodeType: TsResultType; override;
@ -619,9 +624,10 @@ type
procedure Check; override; procedure Check; override;
procedure GetNodeValue(var Result: TsExpressionResult); override; procedure GetNodeValue(var Result: TsExpressionResult); override;
public public
constructor Create(AWorksheet: TsWorksheet; ACellRangeString: String); overload; constructor Create(AParser: TsExpressionParser; AWorksheet: TsWorksheet;
constructor Create(AWorksheet: TsWorksheet; ARow1,ACol1, ARow2,ACol2: Cardinal; ACellRangeString: String); overload;
AFlags: TsRelFlags); overload; constructor Create(AParser: TsExpressionParser; AWorksheet: TsWorksheet;
ARow1,ACol1, ARow2,ACol2: Cardinal; AFlags: TsRelFlags); overload;
function AsRPNItem(ANext: PRPNItem): PRPNItem; override; function AsRPNItem(ANext: PRPNItem): PRPNItem; override;
function AsString: String; override; function AsString: String; override;
function NodeType: TsResultType; override; function NodeType: TsResultType; override;
@ -637,6 +643,7 @@ type
FToken: String; FToken: String;
FTokenType: TsTokenType; FTokenType: TsTokenType;
private private
FParser: TsExpressionParser;
function GetCurrentChar: Char; function GetCurrentChar: Char;
procedure ScanError(Msg: String); procedure ScanError(Msg: String);
protected protected
@ -652,7 +659,7 @@ type
function IsDigit(C: Char): Boolean; // inline; function IsDigit(C: Char): Boolean; // inline;
function IsAlpha(C: Char): Boolean; // inline; function IsAlpha(C: Char): Boolean; // inline;
public public
constructor Create; constructor Create(AParser: TsExpressionParser);
function GetToken: TsTokenType; function GetToken: TsTokenType;
property Token: String read FToken; property Token: String read FToken;
property TokenType: TsTokenType read FTokenType; property TokenType: TsTokenType read FTokenType;
@ -689,9 +696,15 @@ type
procedure SetRPNFormula(const AFormula: TsRPNFormula); procedure SetRPNFormula(const AFormula: TsRPNFormula);
protected protected
FFormatSettings: TFormatSettings;
class function BuiltinExpressionManager: TsBuiltInExpressionManager; class function BuiltinExpressionManager: TsBuiltInExpressionManager;
function BuildStringFormula(AFormatSettings: TFormatSettings): String;
procedure ParserError(Msg: String); procedure ParserError(Msg: String);
procedure SetExpression(const AValue: String); virtual; function GetExpression: String;
function GetLocalizedExpression(const AFormatSettings: TFormatSettings): String; virtual;
procedure SetExpression(const AValue: String);
procedure SetLocalizedExpression(const AFormatSettings: TFormatSettings;
const AValue: String); virtual;
procedure CheckResultType(const Res: TsExpressionResult; procedure CheckResultType(const Res: TsExpressionResult;
AType: TsResultType); inline; AType: TsResultType); inline;
function CurrentToken: String; function CurrentToken: String;
@ -714,7 +727,6 @@ type
destructor Destroy; override; destructor Destroy; override;
function IdentifierByName(AName: ShortString): TsExprIdentifierDef; virtual; function IdentifierByName(AName: ShortString): TsExprIdentifierDef; virtual;
procedure Clear; procedure Clear;
function BuildStringFormula: String;
function Evaluate: TsExpressionResult; function Evaluate: TsExpressionResult;
procedure EvaluateExpression(var Result: TsExpressionResult); procedure EvaluateExpression(var Result: TsExpressionResult);
function ResultType: TsResultType; function ResultType: TsResultType;
@ -724,7 +736,9 @@ type
property AsBoolean: Boolean read GetAsBoolean; property AsBoolean: Boolean read GetAsBoolean;
property AsDateTime: TDateTime read GetAsDateTime; property AsDateTime: TDateTime read GetAsDateTime;
// The expression to parse // The expression to parse
property Expression: String read FExpression write SetExpression; property Expression: String read GetExpression write SetExpression;
property LocalizedExpression[AFormatSettings: TFormatSettings]: String
read GetLocalizedExpression write SetLocalizedExpression;
property RPNFormula: TsRPNFormula read GetRPNFormula write SetRPNFormula; property RPNFormula: TsRPNFormula read GetRPNFormula write SetRPNFormula;
property Identifiers: TsExprIdentifierDefs read FIdentifiers write SetIdentifiers; property Identifiers: TsExprIdentifierDefs read FIdentifiers write SetIdentifiers;
property BuiltIns: TsBuiltInExprCategories read FBuiltIns write SetBuiltIns; property BuiltIns: TsBuiltInExprCategories read FBuiltIns write SetBuiltIns;
@ -805,7 +819,8 @@ const
bcInfo, bcUser]; bcInfo, bcUser];
var var
ExprFormatSettings: TFormatSettings; ExprFormatSettings: TFormatSettings; // MUST BE REMOVED
implementation implementation
@ -816,10 +831,10 @@ const
cNull = #0; cNull = #0;
cDoubleQuote = '"'; cDoubleQuote = '"';
Digits = ['0'..'9', '.']; Digits = ['0'..'9']; // + decimalseparator
WhiteSpace = [' ', #13, #10, #9]; WhiteSpace = [' ', #13, #10, #9];
Operators = ['+', '-', '<', '>', '=', '/', '*', '&', '%', '^']; Operators = ['+', '-', '<', '>', '=', '/', '*', '&', '%', '^'];
Delimiters = Operators + [',', '(', ')']; Delimiters = Operators + ['(', ')']; // + listseparator
Symbols = Delimiters; Symbols = Delimiters;
WordDelimiters = WhiteSpace + Symbols; WordDelimiters = WhiteSpace + Symbols;
@ -921,9 +936,10 @@ end;
{ TsExpressionScanner } { TsExpressionScanner }
{------------------------------------------------------------------------------} {------------------------------------------------------------------------------}
constructor TsExpressionScanner.Create; constructor TsExpressionScanner.Create(AParser: TsExpressionParser);
begin begin
Source := ''; Source := '';
FParser := AParser;
end; end;
function TsExpressionScanner.DoDelimiter: TsTokenType; function TsExpressionScanner.DoDelimiter: TsTokenType;
@ -948,6 +964,9 @@ begin
else else
Result := ttLessThanEqual; Result := ttLessThanEqual;
end end
else
if D = FParser.FFormatSettings.ListSeparator then
Result := ttListSep
else else
case D of case D of
'+' : Result := ttPlus; '+' : Result := ttPlus;
@ -962,7 +981,7 @@ begin
'=' : Result := ttEqual; '=' : Result := ttEqual;
'(' : Result := ttLeft; '(' : Result := ttLeft;
')' : Result := ttRight; ')' : Result := ttRight;
',' : Result := ttComma; // ',' : Result := ttComma;
else else
ScanError(Format(SUnknownDelimiter, [D])); ScanError(Format(SUnknownDelimiter, [D]));
end; end;
@ -1015,7 +1034,7 @@ begin
prevC := Upcase(C); prevC := Upcase(C);
C := NextPos; C := NextPos;
end; end;
if not TryStrToFloat(FToken, X, ExprFormatSettings) then if not TryStrToFloat(FToken, X, FParser.FFormatSettings) then
ScanError(Format(SErrInvalidNumber, [FToken])); ScanError(Format(SErrInvalidNumber, [FToken]));
Result := ttNumber; Result := ttNumber;
end; end;
@ -1085,17 +1104,17 @@ end;
function TsExpressionScanner.IsDelim(C: Char): Boolean; function TsExpressionScanner.IsDelim(C: Char): Boolean;
begin begin
Result := C in Delimiters; Result := (C in Delimiters) or (C = FParser.FFormatSettings.ListSeparator);
end; end;
function TsExpressionScanner.IsDigit(C: Char): Boolean; function TsExpressionScanner.IsDigit(C: Char): Boolean;
begin begin
Result := C in Digits; Result := (C in Digits) or (C = FParser.FFormatSettings.DecimalSeparator);
end; end;
function TsExpressionScanner.IsWordDelim(C: Char): Boolean; function TsExpressionScanner.IsWordDelim(C: Char): Boolean;
begin begin
Result := C in WordDelimiters; Result := (C in WordDelimiters) or (C = FParser.FFormatSettings.ListSeparator);
end; end;
function TsExpressionScanner.NextPos: Char; function TsExpressionScanner.NextPos: Char;
@ -1140,7 +1159,7 @@ begin
FWorksheet := AWorksheet; FWorksheet := AWorksheet;
FIdentifiers := TsExprIdentifierDefs.Create(TsExprIdentifierDef); FIdentifiers := TsExprIdentifierDefs.Create(TsExprIdentifierDef);
FIdentifiers.FParser := Self; FIdentifiers.FParser := Self;
FScanner := TsExpressionScanner.Create; FScanner := TsExpressionScanner.Create(self);
FHashList := TFPHashObjectList.Create(False); FHashList := TFPHashObjectList.Create(False);
end; end;
@ -1153,12 +1172,17 @@ begin
inherited Destroy; inherited Destroy;
end; end;
function TsExpressionParser.BuildStringFormula: String; { Constructs the string formula from the tree of expression nodes. Gets the
decimal and list separator from the formatsettings provided. }
function TsExpressionParser.BuildStringFormula(AFormatSettings: TFormatSettings): String;
begin begin
if FExprNode = nil then if FExprNode = nil then
Result := '' Result := ''
else else
begin
FFormatSettings := AFormatSettings;
Result := FExprNode.AsString; Result := FExprNode.AsString;
end;
end; end;
class function TsExpressionParser.BuiltinExpressionManager: TsBuiltInExpressionManager; class function TsExpressionParser.BuiltinExpressionManager: TsBuiltInExpressionManager;
@ -1200,12 +1224,12 @@ begin
case ToDo.NodeType of case ToDo.NodeType of
rtInteger : rtInteger :
case ToType of case ToType of
rtFloat : Result := TsIntToFloatExprNode.Create(Result); rtFloat : Result := TsIntToFloatExprNode.Create(self, Result);
rtDateTime : Result := TsIntToDateTimeExprNode.Create(Result); rtDateTime : Result := TsIntToDateTimeExprNode.Create(self, Result);
end; end;
rtFloat : rtFloat :
case ToType of case ToType of
rtDateTime : Result := TsFloatToDateTimeExprNode.Create(Result); rtDateTime : Result := TsFloatToDateTimeExprNode.Create(self, Result);
end; end;
end; end;
end; end;
@ -1404,7 +1428,7 @@ begin
else else
ParserError(SErrUnknownComparison) ParserError(SErrUnknownComparison)
end; end;
Result := C.Create(Result, right); Result := C.Create(self, Result, right);
end; end;
except except
Result.Free; Result.Free;
@ -1427,9 +1451,9 @@ begin
right := Level4; right := Level4;
CheckNodes(Result, right); CheckNodes(Result, right);
case tt of case tt of
ttPlus : Result := TsAddExprNode.Create(Result, right); ttPlus : Result := TsAddExprNode.Create(self, Result, right);
ttMinus : Result := TsSubtractExprNode.Create(Result, right); ttMinus : Result := TsSubtractExprNode.Create(self, Result, right);
ttConcat: Result := TsConcatExprNode.Create(Result, right); ttConcat: Result := TsConcatExprNode.Create(self, Result, right);
end; end;
end; end;
except except
@ -1453,8 +1477,8 @@ begin
right := Level5; right := Level5;
CheckNodes(Result, right); CheckNodes(Result, right);
case tt of case tt of
ttMul : Result := TsMultiplyExprNode.Create(Result, right); ttMul : Result := TsMultiplyExprNode.Create(self, Result, right);
ttDiv : Result := TsDivideExprNode.Create(Result, right); ttDiv : Result := TsDivideExprNode.Create(self, Result, right);
end; end;
end; end;
except except
@ -1479,9 +1503,9 @@ begin
end; end;
Result := Level6; Result := Level6;
if isPlus then if isPlus then
Result := TsUPlusExprNode.Create(Result); Result := TsUPlusExprNode.Create(self, Result);
if isMinus then if isMinus then
Result := TsUMinusExprNode.Create(Result); Result := TsUMinusExprNode.Create(self, Result);
end; end;
function TsExpressionParser.Level6: TsExprNode; function TsExpressionParser.Level6: TsExprNode;
@ -1493,7 +1517,7 @@ begin
if (TokenType = ttLeft) then if (TokenType = ttLeft) then
begin begin
GetToken; GetToken;
Result := TsParenthesisExprNode.Create(Level1); Result := TsParenthesisExprNode.Create(self, Level1);
try try
if (TokenType <> ttRight) then if (TokenType <> ttRight) then
ParserError(Format(SErrBracketExpected, [SCanner.Pos, CurrentToken])); ParserError(Format(SErrBracketExpected, [SCanner.Pos, CurrentToken]));
@ -1514,7 +1538,7 @@ begin
GetToken; GetToken;
Right := Primitive; Right := Primitive;
CheckNodes(Result, right); CheckNodes(Result, right);
Result := TsPowerExprNode.Create(Result, Right); Result := TsPowerExprNode.Create(self, Result, Right);
//GetToken; //GetToken;
except except
Result.Free; Result.Free;
@ -1570,26 +1594,26 @@ begin
if (TokenType = ttNumber) then if (TokenType = ttNumber) then
begin begin
if TryStrToInt64(CurrentToken, I) then if TryStrToInt64(CurrentToken, I) then
Result := TsConstExprNode.CreateInteger(I) Result := TsConstExprNode.CreateInteger(self, I)
else else
begin begin
if TryStrToFloat(CurrentToken, X, ExprFormatSettings) then if TryStrToFloat(CurrentToken, X, FFormatSettings) then
Result := TsConstExprNode.CreateFloat(X) Result := TsConstExprNode.CreateFloat(self, X)
else else
ParserError(Format(SErrInvalidFloat, [CurrentToken])); ParserError(Format(SErrInvalidFloat, [CurrentToken]));
end; end;
end end
else if (TokenType = ttTrue) then else if (TokenType = ttTrue) then
Result := TsConstExprNode.CreateBoolean(true) Result := TsConstExprNode.CreateBoolean(self, true)
else if (TokenType = ttFalse) then else if (TokenType = ttFalse) then
Result := TsConstExprNode.CreateBoolean(false) Result := TsConstExprNode.CreateBoolean(self, false)
else if (TokenType = ttString) then else if (TokenType = ttString) then
Result := TsConstExprNode.CreateString(CurrentToken) Result := TsConstExprNode.CreateString(self, CurrentToken)
else if (TokenType = ttCell) then else if (TokenType = ttCell) then
Result := TsCellExprNode.Create(FWorksheet, CurrentToken) Result := TsCellExprNode.Create(self, FWorksheet, CurrentToken)
else if (TokenType = ttCellRange) then else if (TokenType = ttCellRange) then
Result := TsCellRangeExprNode.Create(FWorksheet, CurrentToken) Result := TsCellRangeExprNode.Create(self, FWorksheet, CurrentToken)
else if not (TokenType in [ttIdentifier{, ttIf}]) then else if not (TokenType in [ttIdentifier]) then
ParserError(Format(SerrUnknownTokenAtPos, [Scanner.Pos, CurrentToken])) ParserError(Format(SerrUnknownTokenAtPos, [Scanner.Pos, CurrentToken]))
else else
begin begin
@ -1637,7 +1661,7 @@ begin
optional := ID.IsOptionalArgument(AI+1); optional := ID.IsOptionalArgument(AI+1);
if not optional then if not optional then
begin begin
if (TokenType <> ttComma) then if (TokenType <> ttListSep) then
if (AI < abs(lCount)) then if (AI < abs(lCount)) then
ParserError(Format(SErrCommaExpected, [Scanner.Pos, CurrentToken])) ParserError(Format(SErrCommaExpected, [Scanner.Pos, CurrentToken]))
end; end;
@ -1660,14 +1684,17 @@ begin
end; end;
end; end;
case ID.IdentifierType of case ID.IdentifierType of
itVariable : Result := TsVariableExprNode.CreateIdentifier(ID); itVariable:
itFunctionCallBack : Result := TsFunctionCallBackExprNode.CreateFunction(ID, Args); Result := TsVariableExprNode.CreateIdentifier(self, ID);
itFunctionHandler : Result := TFPFunctionEventHandlerExprNode.CreateFunction(ID, Args); itFunctionCallBack:
Result := TsFunctionCallBackExprNode.CreateFunction(self, ID, Args);
itFunctionHandler:
Result := TFPFunctionEventHandlerExprNode.CreateFunction(self, ID, Args);
end; end;
end; end;
GetToken; GetToken;
if TokenType = ttPercent then begin if TokenType = ttPercent then begin
Result := TsPercentExprNode.Create(Result); Result := TsPercentExprNode.Create(self, Result);
GetToken; GetToken;
end; end;
end; end;
@ -1687,10 +1714,37 @@ begin
FDirty := true; FDirty := true;
end; end;
function TsExpressionParser.GetExpression: String;
var
fs: TFormatsettings;
begin
fs := DefaultFormatSettings;
fs.DecimalSeparator := '.';
fs.ListSeparator := ',';
Result := BuildStringFormula(fs);
end;
function TsExpressionParser.GetLocalizedExpression(const AFormatSettings: TFormatSettings): String;
begin
Result := BuildStringFormula(AFormatSettings);
end;
procedure TsExpressionParser.SetExpression(const AValue: String); procedure TsExpressionParser.SetExpression(const AValue: String);
var
fs: TFormatSettings;
begin
fs := DefaultFormatSettings;
fs.DecimalSeparator := '.';
fs.ListSeparator := ',';
SetLocalizedExpression(fs, AValue);
end;
procedure TsExpressionParser.SetLocalizedExpression(const AFormatSettings: TFormatSettings;
const AValue: String);
begin begin
if FExpression = AValue then if FExpression = AValue then
exit; exit;
FFormatSettings := AFormatSettings;
FExpression := AValue; FExpression := AValue;
if (AValue <> '') and (AValue[1] = '=') then if (AValue <> '') and (AValue[1] = '=') then
FScanner.Source := Copy(AValue, 2, Length(AValue)) FScanner.Source := Copy(AValue, 2, Length(AValue))
@ -1738,7 +1792,7 @@ procedure TsExpressionParser.SetRPNFormula(const AFormula: TsRPNFormula);
r := AFormula[AIndex].Row; r := AFormula[AIndex].Row;
c := AFormula[AIndex].Col; c := AFormula[AIndex].Col;
flags := AFormula[AIndex].RelFlags; flags := AFormula[AIndex].RelFlags;
ANode := TsCellExprNode.Create(FWorksheet, r, c, flags); ANode := TsCellExprNode.Create(self, FWorksheet, r, c, flags);
dec(AIndex); dec(AIndex);
end; end;
fekCellRange: fekCellRange:
@ -1748,32 +1802,32 @@ procedure TsExpressionParser.SetRPNFormula(const AFormula: TsRPNFormula);
r2 := AFormula[AIndex].Row2; r2 := AFormula[AIndex].Row2;
c2 := AFormula[AIndex].Col2; c2 := AFormula[AIndex].Col2;
flags := AFormula[AIndex].RelFlags; flags := AFormula[AIndex].RelFlags;
ANode := TsCellRangeExprNode.Create(FWorksheet, r, c, r2, c2, flags); ANode := TsCellRangeExprNode.Create(self, FWorksheet, r, c, r2, c2, flags);
dec(AIndex); dec(AIndex);
end; end;
fekNum: fekNum:
begin begin
ANode := TsConstExprNode.CreateFloat(AFormula[AIndex].DoubleValue); ANode := TsConstExprNode.CreateFloat(self, AFormula[AIndex].DoubleValue);
dec(AIndex); dec(AIndex);
end; end;
fekInteger: fekInteger:
begin begin
ANode := TsConstExprNode.CreateInteger(AFormula[AIndex].IntValue); ANode := TsConstExprNode.CreateInteger(self, AFormula[AIndex].IntValue);
dec(AIndex); dec(AIndex);
end; end;
fekString: fekString:
begin begin
ANode := TsConstExprNode.CreateString(AFormula[AIndex].StringValue); ANode := TsConstExprNode.CreateString(self, AFormula[AIndex].StringValue);
dec(AIndex); dec(AIndex);
end; end;
fekBool: fekBool:
begin begin
ANode := TsConstExprNode.CreateBoolean(AFormula[AIndex].DoubleValue <> 0.0); ANode := TsConstExprNode.CreateBoolean(self, AFormula[AIndex].DoubleValue <> 0.0);
dec(AIndex); dec(AIndex);
end; end;
fekErr: fekErr:
begin begin
ANode := TsConstExprNode.CreateError(TsErrorValue(AFormula[AIndex].IntValue)); ANode := TsConstExprNode.CreateError(self, TsErrorValue(AFormula[AIndex].IntValue));
dec(AIndex); dec(AIndex);
end; end;
@ -1783,10 +1837,10 @@ procedure TsExpressionParser.SetRPNFormula(const AFormula: TsRPNFormula);
dec(AIndex); dec(AIndex);
CreateNodeFromRPN(operand, AIndex); CreateNodeFromRPN(operand, AIndex);
case fek of case fek of
fekPercent : ANode := TsPercentExprNode.Create(operand); fekPercent : ANode := TsPercentExprNode.Create(self, operand);
fekUMinus : ANode := TsUMinusExprNode.Create(operand); fekUMinus : ANode := TsUMinusExprNode.Create(self, operand);
fekUPlus : ANode := TsUPlusExprNode.Create(operand); fekUPlus : ANode := TsUPlusExprNode.Create(self, operand);
fekParen : ANode := TsParenthesisExprNode.Create(operand); fekParen : ANode := TsParenthesisExprNode.Create(self, operand);
end; end;
end; end;
@ -1802,18 +1856,18 @@ procedure TsExpressionParser.SetRPNFormula(const AFormula: TsRPNFormula);
CreateNodeFromRPN(left, AIndex); CreateNodeFromRPN(left, AIndex);
CheckNodes(left, right); CheckNodes(left, right);
case fek of case fek of
fekAdd : ANode := TsAddExprNode.Create(left, right); fekAdd : ANode := TsAddExprNode.Create(self, left, right);
fekSub : ANode := TsSubtractExprNode.Create(left, right); fekSub : ANode := TsSubtractExprNode.Create(self, left, right);
fekMul : ANode := TsMultiplyExprNode.Create(left, right); fekMul : ANode := TsMultiplyExprNode.Create(self, left, right);
fekDiv : ANode := TsDivideExprNode.Create(left, right); fekDiv : ANode := TsDivideExprNode.Create(self, left, right);
fekPower : ANode := TsPowerExprNode.Create(left, right); fekPower : ANode := TsPowerExprNode.Create(self, left, right);
fekConcat : ANode := tsConcatExprNode.Create(left, right); fekConcat : ANode := tsConcatExprNode.Create(self, left, right);
fekEqual : ANode := TsEqualExprNode.Create(left, right); fekEqual : ANode := TsEqualExprNode.Create(self, left, right);
fekNotEqual : ANode := TsNotEqualExprNode.Create(left, right); fekNotEqual : ANode := TsNotEqualExprNode.Create(self, left, right);
fekGreater : ANode := TsGreaterExprNode.Create(left, right); fekGreater : ANode := TsGreaterExprNode.Create(self, left, right);
fekGreaterEqual: ANode := TsGreaterEqualExprNode.Create(left, right); fekGreaterEqual: ANode := TsGreaterEqualExprNode.Create(self, left, right);
fekLess : ANode := TsLessExprNode.Create(left, right); fekLess : ANode := TsLessExprNode.Create(self, left, right);
fekLessEqual : ANode := tsLessEqualExprNode.Create(left, right); fekLessEqual : ANode := tsLessEqualExprNode.Create(self, left, right);
end; end;
end; end;
@ -1836,9 +1890,12 @@ procedure TsExpressionParser.SetRPNFormula(const AFormula: TsRPNFormula);
for i:=n-1 downto 0 do for i:=n-1 downto 0 do
CreateNodeFromRPN(args[i], AIndex); CreateNodeFromRPN(args[i], AIndex);
case ID.IdentifierType of case ID.IdentifierType of
itVariable : ANode := TsVariableExprNode.CreateIdentifier(ID); itVariable:
itFunctionCallBack : ANode := TsFunctionCallBackExprNode.CreateFunction(ID, args); ANode := TsVariableExprNode.CreateIdentifier(self, ID);
itFunctionHandler : ANode := TFPFunctionEventHandlerExprNode.CreateFunction(ID, args); itFunctionCallBack:
ANode := TsFunctionCallBackExprNode.CreateFunction(self, ID, args);
itFunctionHandler:
ANode := TFPFunctionEventHandlerExprNode.CreateFunction(self, ID, args);
end; end;
end; end;
end; end;
@ -2127,6 +2184,11 @@ begin
Result := FValue.ResString; Result := FValue.ResString;
end; end;
function TsExprIdentifierDef.GetFormatSettings: TFormatSettings;
begin
Result := TsExprIdentifierDefs(Collection).Parser.FFormatSettings;
end;
function TsExprIdentifierDef.GetResultType: TsResultType; function TsExprIdentifierDef.GetResultType: TsResultType;
begin begin
Result := FValue.ResultType; Result := FValue.ResultType;
@ -2136,12 +2198,12 @@ function TsExprIdentifierDef.GetValue: String;
begin begin
case FValue.ResultType of case FValue.ResultType of
rtBoolean : if FValue.ResBoolean then rtBoolean : if FValue.ResBoolean then
Result := 'True' Result := 'TRUE'
else else
Result := 'False'; Result := 'FALSE';
rtInteger : Result := IntToStr(FValue.ResInteger); rtInteger : Result := IntToStr(FValue.ResInteger);
rtFloat : Result := FloatToStr(FValue.ResFloat, ExprFormatSettings); rtFloat : Result := FloatToStr(FValue.ResFloat, GetFormatSettings);
rtDateTime : Result := FormatDateTime('cccc', FValue.ResDateTime); rtDateTime : Result := FormatDateTime('cccc', FValue.ResDateTime, GetFormatSettings);
rtString : Result := FValue.ResString; rtString : Result := FValue.ResString;
end; end;
end; end;
@ -2216,7 +2278,7 @@ procedure TsExprIdentifierDef.SetAsString(const AValue: String);
begin begin
CheckVariable; CheckVariable;
CheckResultType(rtString); CheckResultType(rtString);
FValue.resString := AValue; FValue.ResString := AValue;
end; end;
procedure TsExprIdentifierDef.SetName(const AValue: ShortString); procedure TsExprIdentifierDef.SetName(const AValue: ShortString);
@ -2243,10 +2305,10 @@ begin
FStringValue := AValue; FStringValue := AValue;
if (AValue <> '') then if (AValue <> '') then
case FValue.ResultType of case FValue.ResultType of
rtBoolean : FValue.ResBoolean := FStringValue='True'; rtBoolean : FValue.ResBoolean := (FStringValue='True');
rtInteger : FValue.ResInteger := StrToInt(AValue); rtInteger : FValue.ResInteger := StrToInt(AValue);
rtFloat : FValue.ResFloat := StrToFloat(AValue); rtFloat : FValue.ResFloat := StrToFloat(AValue, GetFormatSettings);
rtDateTime : FValue.ResDateTime := StrToDateTime(AValue); rtDateTime : FValue.ResDateTime := StrToDateTime(AValue, GetFormatSettings);
rtString : FValue.ResString := AValue; rtString : FValue.ResString := AValue;
end end
else else
@ -2411,8 +2473,10 @@ end;
{ TsUnaryOperationExprNode } { TsUnaryOperationExprNode }
constructor TsUnaryOperationExprNode.Create(AOperand: TsExprNode); constructor TsUnaryOperationExprNode.Create(AParser: TsExpressionParser;
AOperand: TsExprNode);
begin begin
FParser := AParser;
FOperand := AOperand; FOperand := AOperand;
end; end;
@ -2431,8 +2495,10 @@ end;
{ TsBinaryOperationExprNode } { TsBinaryOperationExprNode }
constructor TsBinaryOperationExprNode.Create(ALeft, ARight: TsExprNode); constructor TsBinaryOperationExprNode.Create(AParser: TsExpressionParser;
ALeft, ARight: TsExprNode);
begin begin
FParser := AParser;
FLeft := ALeft; FLeft := ALeft;
FRight := ARight; FRight := ARight;
end; end;
@ -2481,39 +2547,50 @@ end;
{ TsConstExprNode } { TsConstExprNode }
constructor TsConstExprNode.CreateString(AValue: String); constructor TsConstExprNode.CreateString(AParser: TsExpressionParser;
AValue: String);
begin begin
FParser := AParser;
FValue.ResultType := rtString; FValue.ResultType := rtString;
FValue.ResString := AValue; FValue.ResString := AValue;
end; end;
constructor TsConstExprNode.CreateInteger(AValue: Int64); constructor TsConstExprNode.CreateInteger(AParser: TsExpressionParser;
AValue: Int64);
begin begin
FParser := AParser;
FValue.ResultType := rtInteger; FValue.ResultType := rtInteger;
FValue.ResInteger := AValue; FValue.ResInteger := AValue;
end; end;
constructor TsConstExprNode.CreateDateTime(AValue: TDateTime); constructor TsConstExprNode.CreateDateTime(AParser: TsExpressionParser;
AValue: TDateTime);
begin begin
FParser := AParser;
FValue.ResultType := rtDateTime; FValue.ResultType := rtDateTime;
FValue.ResDateTime := AValue; FValue.ResDateTime := AValue;
end; end;
constructor TsConstExprNode.CreateFloat(AValue: TsExprFloat); constructor TsConstExprNode.CreateFloat(AParser: TsExpressionParser;
AValue: TsExprFloat);
begin begin
Inherited Create; FParser := AParser;
FValue.ResultType := rtFloat; FValue.ResultType := rtFloat;
FValue.ResFloat := AValue; FValue.ResFloat := AValue;
end; end;
constructor TsConstExprNode.CreateBoolean(AValue: Boolean); constructor TsConstExprNode.CreateBoolean(AParser: TsExpressionParser;
AValue: Boolean);
begin begin
FParser := AParser;
FValue.ResultType := rtBoolean; FValue.ResultType := rtBoolean;
FValue.ResBoolean := AValue; FValue.ResBoolean := AValue;
end; end;
constructor TsConstExprNode.CreateError(AValue: TsErrorValue); constructor TsConstExprNode.CreateError(AParser: TsExpressionParser;
AValue: TsErrorValue);
begin begin
FParser := AParser;
FValue.ResultType := rtError; FValue.ResultType := rtError;
FValue.ResError := AValue; FValue.ResError := AValue;
end; end;
@ -2538,9 +2615,9 @@ begin
case NodeType of case NodeType of
rtString : Result := cDoubleQuote + FValue.ResString + cDoubleQuote; rtString : Result := cDoubleQuote + FValue.ResString + cDoubleQuote;
rtInteger : Result := IntToStr(FValue.ResInteger); rtInteger : Result := IntToStr(FValue.ResInteger);
rtDateTime : Result := '''' + FormatDateTime('cccc', FValue.ResDateTime) + ''''; // Probably wrong !!! rtDateTime : Result := '''' + FormatDateTime('cccc', FValue.ResDateTime, Parser.FFormatSettings) + ''''; // Probably wrong !!!
rtBoolean : if FValue.ResBoolean then Result := 'TRUE' else Result := 'FALSE'; rtBoolean : if FValue.ResBoolean then Result := 'TRUE' else Result := 'FALSE';
rtFloat : Result := FloatToStr(FValue.ResFloat, ExprFormatSettings); rtFloat : Result := FloatToStr(FValue.ResFloat, Parser.FFormatSettings);
end; end;
end; end;
@ -3419,9 +3496,10 @@ end;
{ TsIdentifierExprNode } { TsIdentifierExprNode }
constructor TsIdentifierExprNode.CreateIdentifier(AID: TsExprIdentifierDef); constructor TsIdentifierExprNode.CreateIdentifier(AParser: TsExpressionParser;
AID: TsExprIdentifierDef);
begin begin
inherited Create; FParser := AParser;
FID := AID; FID := AID;
PResult := @FID.FValue; PResult := @FID.FValue;
FResultType := FID.ResultType; FResultType := FID.ResultType;
@ -3459,10 +3537,10 @@ end;
{ TsFunctionExprNode } { TsFunctionExprNode }
constructor TsFunctionExprNode.CreateFunction(AID: TsExprIdentifierDef; constructor TsFunctionExprNode.CreateFunction(AParser: TsExpressionParser;
const Args: TsExprArgumentArray); AID: TsExprIdentifierDef; const Args: TsExprArgumentArray);
begin begin
inherited CreateIdentifier(AID); inherited CreateIdentifier(AParser, AID);
FArgumentNodes := Args; FArgumentNodes := Args;
SetLength(FArgumentParams, Length(Args)); SetLength(FArgumentParams, Length(Args));
end; end;
@ -3500,7 +3578,7 @@ begin
for i := 0 to Length(FArgumentNodes)-1 do for i := 0 to Length(FArgumentNodes)-1 do
begin begin
if (S <> '') then if (S <> '') then
S := S + ','; S := S + Parser.FFormatSettings.ListSeparator;
S := S + FArgumentNodes[i].AsString; S := S + FArgumentNodes[i].AsString;
end; end;
S := '(' + S + ')'; S := '(' + S + ')';
@ -3544,18 +3622,20 @@ begin
begin begin
rta := FArgumentNodes[i].NodeType; rta := FArgumentNodes[i].NodeType;
// A "cell" can return any type --> no type conversion required here.
if rta = rtCell then
Continue;
if i+1 <= Length(FID.ParameterTypes) then if i+1 <= Length(FID.ParameterTypes) then
begin begin
rtp := CharToResultType(FID.ParameterTypes[i+1]); rtp := CharToResultType(FID.ParameterTypes[i+1]);
lastrtp := rtp; lastrtp := rtp;
end else end else
rtp := lastrtp; rtp := lastrtp;
if rtp = rtAny then if rtp = rtAny then
Continue; Continue;
// A "cell" can return any type --> no type conversion required here.
if rta = rtCell then
Continue;
if (rtp <> rta) and not (rta in [rtCellRange, rtError, rtEmpty]) then if (rtp <> rta) and not (rta in [rtCellRange, rtError, rtEmpty]) then
begin begin
// Automatically convert integers to floats in functions that return a float // Automatically convert integers to floats in functions that return a float
@ -3575,8 +3655,8 @@ end;
{ TsFunctionCallBackExprNode } { TsFunctionCallBackExprNode }
constructor TsFunctionCallBackExprNode.CreateFunction(AID: TsExprIdentifierDef; constructor TsFunctionCallBackExprNode.CreateFunction(AParser: TsExpressionParser;
const Args: TsExprArgumentArray); AID: TsExprIdentifierDef; const Args: TsExprArgumentArray);
begin begin
inherited; inherited;
FCallBack := AID.OnGetFunctionValueCallBack; FCallBack := AID.OnGetFunctionValueCallBack;
@ -3593,8 +3673,8 @@ end;
{ TFPFunctionEventHandlerExprNode } { TFPFunctionEventHandlerExprNode }
constructor TFPFunctionEventHandlerExprNode.CreateFunction(AID: TsExprIdentifierDef; constructor TFPFunctionEventHandlerExprNode.CreateFunction(AParser: TsExpressionParser;
const Args: TsExprArgumentArray); AID: TsExprIdentifierDef; const Args: TsExprArgumentArray);
begin begin
inherited; inherited;
FCallBack := AID.OnGetFunctionValue; FCallBack := AID.OnGetFunctionValue;
@ -3611,18 +3691,20 @@ end;
{ TsCellExprNode } { TsCellExprNode }
constructor TsCellExprNode.Create(AWorksheet: TsWorksheet; ACellString: String); constructor TsCellExprNode.Create(AParser: TsExpressionParser;
AWorksheet: TsWorksheet; ACellString: String);
var var
r, c: Cardinal; r, c: Cardinal;
flags: TsRelFlags; flags: TsRelFlags;
begin begin
ParseCellString(ACellString, r, c, flags); ParseCellString(ACellString, r, c, flags);
Create(AWorksheet, r, c, flags); Create(AParser, AWorksheet, r, c, flags);
end; end;
constructor TsCellExprNode.Create(AWorksheet: TsWorksheet; ARow,ACol: Cardinal; constructor TsCellExprNode.Create(AParser: TsExpressionParser;
AFlags: TsRelFlags); AWorksheet: TsWorksheet; ARow,ACol: Cardinal; AFlags: TsRelFlags);
begin begin
FParser := AParser;
FWorksheet := AWorksheet; FWorksheet := AWorksheet;
FRow := ARow; FRow := ARow;
FCol := ACol; FCol := ACol;
@ -3696,7 +3778,8 @@ end;
{ TsCellRangeExprNode } { TsCellRangeExprNode }
constructor TsCellRangeExprNode.Create(AWorksheet: TsWorksheet; ACellRangeString: String); constructor TsCellRangeExprNode.Create(AParser: TsExpressionParser;
AWorksheet: TsWorksheet; ACellRangeString: String);
var var
r1, c1, r2, c2: Cardinal; r1, c1, r2, c2: Cardinal;
flags: TsRelFlags; flags: TsRelFlags;
@ -3706,17 +3789,18 @@ begin
ParseCellString(ACellRangeString, r1, c1, flags); ParseCellString(ACellRangeString, r1, c1, flags);
if rfRelRow in flags then Include(flags, rfRelRow2); if rfRelRow in flags then Include(flags, rfRelRow2);
if rfRelCol in flags then Include(flags, rfRelCol2); if rfRelCol in flags then Include(flags, rfRelCol2);
Create(AWorksheet, r1, c1, r1, c1, flags); Create(AParser, AWorksheet, r1, c1, r1, c1, flags);
end else end else
begin begin
ParseCellRangeString(ACellRangeString, r1, c1, r2, c2, flags); ParseCellRangeString(ACellRangeString, r1, c1, r2, c2, flags);
Create(AWorksheet, r1, c1, r2, c2, flags); Create(AParser, AWorksheet, r1, c1, r2, c2, flags);
end; end;
end; end;
constructor TsCellRangeExprNode.Create(AWorksheet: TsWorksheet; constructor TsCellRangeExprNode.Create(AParser: TsExpressionParser;
ARow1,ACol1,ARow2,ACol2: Cardinal; AFlags: TsRelFlags); AWorksheet: TsWorksheet; ARow1,ACol1,ARow2,ACol2: Cardinal; AFlags: TsRelFlags);
begin begin
FParser := AParser;
FWorksheet := AWorksheet; FWorksheet := AWorksheet;
FRow1 := ARow1; FRow1 := ARow1;
FCol1 := ACol1; FCol1 := ACol1;

View File

@ -1463,20 +1463,20 @@ begin
// Statistical // Statistical
cat := bcStatistics; cat := bcStatistics;
AddFunction(cat, 'AVEDEV', 'F', '?+', INT_EXCEL_SHEET_FUNC_AVEDEV, @fpsAVEDEV); AddFunction(cat, 'AVEDEV', 'F', 'F+', INT_EXCEL_SHEET_FUNC_AVEDEV, @fpsAVEDEV);
AddFunction(cat, 'AVERAGE', 'F', '?+', INT_EXCEL_SHEET_FUNC_AVERAGE, @fpsAVERAGE); AddFunction(cat, 'AVERAGE', 'F', 'F+', INT_EXCEL_SHEET_FUNC_AVERAGE, @fpsAVERAGE);
AddFunction(cat, 'COUNT', 'I', '?+', INT_EXCEL_SHEET_FUNC_COUNT, @fpsCOUNT); AddFunction(cat, 'COUNT', 'I', '?+', INT_EXCEL_SHEET_FUNC_COUNT, @fpsCOUNT);
AddFunction(cat, 'COUNTA', 'I', '?+', INT_EXCEL_SHEET_FUNC_COUNTA, @fpsCOUNTA); AddFunction(cat, 'COUNTA', 'I', '?+', INT_EXCEL_SHEET_FUNC_COUNTA, @fpsCOUNTA);
AddFunction(cat, 'COUNTBLANK','I', 'R', INT_EXCEL_SHEET_FUNC_COUNTBLANK, @fpsCOUNTBLANK); AddFunction(cat, 'COUNTBLANK','I', 'R', INT_EXCEL_SHEET_FUNC_COUNTBLANK, @fpsCOUNTBLANK);
AddFunction(cat, 'MAX', 'F', '?+', INT_EXCEL_SHEET_FUNC_MAX, @fpsMAX); AddFunction(cat, 'MAX', 'F', 'F+', INT_EXCEL_SHEET_FUNC_MAX, @fpsMAX);
AddFunction(cat, 'MIN', 'F', '?+', INT_EXCEL_SHEET_FUNC_MIN, @fpsMIN); AddFunction(cat, 'MIN', 'F', 'F+', INT_EXCEL_SHEET_FUNC_MIN, @fpsMIN);
AddFunction(cat, 'PRODUCT', 'F', '?+', INT_EXCEL_SHEET_FUNC_PRODUCT, @fpsPRODUCT); AddFunction(cat, 'PRODUCT', 'F', 'F+', INT_EXCEL_SHEET_FUNC_PRODUCT, @fpsPRODUCT);
AddFunction(cat, 'STDEV', 'F', '?+', INT_EXCEL_SHEET_FUNC_STDEV, @fpsSTDEV); AddFunction(cat, 'STDEV', 'F', 'F+', INT_EXCEL_SHEET_FUNC_STDEV, @fpsSTDEV);
AddFunction(cat, 'STDEVP', 'F', '?+', INT_EXCEL_SHEET_FUNC_STDEVP, @fpsSTDEVP); AddFunction(cat, 'STDEVP', 'F', 'F+', INT_EXCEL_SHEET_FUNC_STDEVP, @fpsSTDEVP);
AddFunction(cat, 'SUM', 'F', '?+', INT_EXCEL_SHEET_FUNC_SUM, @fpsSUM); AddFunction(cat, 'SUM', 'F', 'F+', INT_EXCEL_SHEET_FUNC_SUM, @fpsSUM);
AddFunction(cat, 'SUMSQ', 'F', '?+', INT_EXCEL_SHEET_FUNC_SUMSQ, @fpsSUMSQ); AddFunction(cat, 'SUMSQ', 'F', 'F+', INT_EXCEL_SHEET_FUNC_SUMSQ, @fpsSUMSQ);
AddFunction(cat, 'VAR', 'F', '?+', INT_EXCEL_SHEET_FUNC_VAR, @fpsVAR); AddFunction(cat, 'VAR', 'F', 'F+', INT_EXCEL_SHEET_FUNC_VAR, @fpsVAR);
AddFunction(cat, 'VARP', 'F', '?+', INT_EXCEL_SHEET_FUNC_VARP, @fpsVARP); AddFunction(cat, 'VARP', 'F', 'F+', INT_EXCEL_SHEET_FUNC_VARP, @fpsVARP);
// to do: CountIF, SUMIF // to do: CountIF, SUMIF
// Info functions // Info functions

View File

@ -2668,7 +2668,6 @@ begin
Result := False; Result := False;
end; end;
{@@ {@@
Converts an RPN formula (as read from an xls biff file, for example) to a Converts an RPN formula (as read from an xls biff file, for example) to a
string formula. string formula.
@ -2685,7 +2684,7 @@ begin
parser := TsSpreadsheetParser.Create(self); parser := TsSpreadsheetParser.Create(self);
try try
parser.RPNFormula := AFormula; parser.RPNFormula := AFormula;
Result := parser.BuildStringFormula; Result := parser.Expression;
finally finally
parser.Free; parser.Free;
end; end;