From 5d6bea6a850963362eedf667bfbe352c673db300 Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Sat, 6 Jun 2015 11:53:47 +0000 Subject: [PATCH] fpspreadsheet: Add support for missing arguments to formula parser. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4179 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- components/fpspreadsheet/fpsexprparser.pas | 58 ++++++++++++++++++++-- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/components/fpspreadsheet/fpsexprparser.pas b/components/fpspreadsheet/fpsexprparser.pas index 61c2d6ba6..384c2154b 100644 --- a/components/fpspreadsheet/fpsexprparser.pas +++ b/components/fpspreadsheet/fpsexprparser.pas @@ -61,7 +61,7 @@ type ttCell, ttCellRange, ttNumber, ttString, ttIdentifier, ttPlus, ttMinus, ttMul, ttDiv, ttConcat, ttPercent, ttPower, ttLeft, ttRight, ttLessThan, ttLargerThan, ttEqual, ttNotEqual, ttLessThanEqual, ttLargerThanEqual, - ttListSep, ttTrue, ttFalse, ttError, ttEOF + ttListSep, ttTrue, ttFalse, ttMissingArg, ttError, ttEOF ); TsExprFloat = Double; @@ -84,7 +84,7 @@ type TsFormulaDialect = (fdExcel, fdOpenDocument); TsResultType = (rtEmpty, rtBoolean, rtInteger, rtFloat, rtDateTime, rtString, - rtCell, rtCellRange, rtHyperlink, rtError, rtAny); + rtCell, rtCellRange, rtHyperlink, rtError, rtMissingArg, rtAny); TsResultTypes = set of TsResultType; TsExpressionResult = record @@ -410,6 +410,15 @@ type property ConstValue: TsExpressionResult read FValue; end; + { TsMissingArgExprNode } + TsMissingArgExprNode = class(TsExprNode) + protected + procedure GetNodeValue(out Result: TsExpressionResult); override; + function AsString: String; override; + function AsRPNItem(ANext: PRPNItem): PRPNItem; override; + function NodeType: TsResultType; override; + end; + TsExprIdentifierType = (itVariable, itFunctionCallBack, itFunctionHandler); TsExprFunctionCallBack = procedure (var Result: TsExpressionResult; @@ -1666,6 +1675,7 @@ var AI: Integer; optional: Boolean; token: String; + prevTokenType: TsTokenType; begin {$ifdef debugexpr} Writeln('Primitive : ',TokenName(TokenType),': ',CurrentToken);{$endif debugexpr} SetLength(Args, 0); @@ -1692,7 +1702,7 @@ begin else if (TokenType = ttCellRange) then Result := TsCellRangeExprNode.Create(self, FWorksheet, CurrentToken) else if (TokenType = ttError) then - Result := tsConstExprNode.CreateError(self, CurrentToken) + Result := TsConstExprNode.CreateError(self, CurrentToken) else if not (TokenType in [ttIdentifier]) then ParserError(Format(SerrUnknownTokenAtPos, [Scanner.Pos, CurrentToken])) else @@ -1729,6 +1739,7 @@ begin AI := 0; try repeat + prevTokenType := TokenType; GetToken; // Check if we must enlarge the argument array if (lCount < 0) and (AI = Length(Args)) then @@ -1736,6 +1747,12 @@ begin SetLength(Args, AI+1); Args[AI] := nil; end; + if (prevTokenType in [ttLeft, ttListSep]) and (TokenType in [ttListSep, ttRight]) then + begin + Args[AI] := TsMissingArgExprNode.Create; + inc(AI); + Continue; + end; Args[AI] := Level1; inc(AI); optional := ID.IsOptionalArgument(AI+1); @@ -1912,6 +1929,11 @@ procedure TsExpressionParser.SetRPNFormula(const AFormula: TsRPNFormula); ANode := TsConstExprNode.CreateError(self, TsErrorValue(AFormula[AIndex].IntValue)); dec(AIndex); end; + fekMissingArg: + begin + ANode := TsMissingArgExprNode.Create; + dec(AIndex); + end; // unary operations fekPercent, fekUMinus, fekUPlus, fekParen: @@ -2699,6 +2721,8 @@ begin err := errIllegalRef else if AVAlue = '#NAME?' then err := errWrongName + else if AValue = '#N/A' then + err := errArgError else if AValue = '#FORMULA?' then err := errFormulaNotSupported else @@ -2746,6 +2770,28 @@ begin end; +{ TsMissingExprNode } + +function TsMissingArgExprNode.AsRPNItem(ANext: PRPNItem): PRPNItem; +begin + Result := RPNMissingARg(ANext); +end; + +function TsMissingArgExprNode.AsString: String; +begin + Result := ''; +end; + +procedure TsMissingArgExprNode.GetNodeValue(out Result: TsExpressionResult); +begin + Result.ResultType := rtMissingArg; +end; + +function TsMissingArgExprNode.NodeType: TsResultType; +begin + Result := rtMissingArg; +end; + { TsUPlusExprNode } function TsUPlusExprNode.AsRPNItem(ANext: PRPNItem): PRPNItem; @@ -3675,7 +3721,8 @@ begin begin if (S <> '') then S := S + Parser.FFormatSettings.ListSeparator; - S := S + FArgumentNodes[i].AsString; + if Assigned(FArgumentNodes[i]) then + S := S + FArgumentNodes[i].AsString; end; S := '(' + S + ')'; Result := FID.Name + S; @@ -3716,6 +3763,9 @@ begin for i := 0 to Length(FArgumentNodes)-1 do begin + if FArgumentNodes[i] = nil then + Continue; + rta := FArgumentNodes[i].NodeType; if i+1 <= Length(FID.ParameterTypes) then