diff --git a/components/fpspreadsheet/examples/other/demo_expression_parser.lpi b/components/fpspreadsheet/examples/other/demo_expression_parser.lpi
index 04d0c00ac..c824526b3 100644
--- a/components/fpspreadsheet/examples/other/demo_expression_parser.lpi
+++ b/components/fpspreadsheet/examples/other/demo_expression_parser.lpi
@@ -36,12 +36,17 @@
-
+
+
+
+
+
+
diff --git a/components/fpspreadsheet/examples/other/demo_expression_parser.pas b/components/fpspreadsheet/examples/other/demo_expression_parser.pas
index 97053732d..87b81fd2f 100644
--- a/components/fpspreadsheet/examples/other/demo_expression_parser.pas
+++ b/components/fpspreadsheet/examples/other/demo_expression_parser.pas
@@ -31,14 +31,15 @@ begin
workbook := TsWorkbook.Create;
try
worksheet := workbook.AddWorksheet('Test');
-
+ {
worksheet.WriteNumber(0, 0, 2); // A1
worksheet.WriteNumber(0, 1, 2.5); // B1
- {
+ }
worksheet.WriteUTF8Text(0, 0, 'Hallo'); // A1
- worksheet.WriteUTF8Text(0, 1, 'Welt'); // B1
- }
- cell := worksheet.WriteFormula(1, 0, '=(A1+2)*3'); // A2
+ worksheet.WriteUTF8Text(0, 1, 'World'); // B1
+
+ //cell := worksheet.WriteFormula(1, 0, '=(A1+2)*3'); // A2
+ cell := worksheet.WriteFormula(1, 0, 'A1&" "&B1');
WriteLn('A1 = ', worksheet.ReadAsUTF8Text(0, 0));
WriteLn('B1 = ', worksheet.ReadAsUTF8Text(0, 1));
diff --git a/components/fpspreadsheet/fpsexprparser.pas b/components/fpspreadsheet/fpsexprparser.pas
index 31f8c4dc4..bf14a27ac 100644
--- a/components/fpspreadsheet/fpsexprparser.pas
+++ b/components/fpspreadsheet/fpsexprparser.pas
@@ -15,7 +15,8 @@
Modified for integration into fpspreadsheet by Werner Pamler:
- Original file name: fpexprpars.pp
- Rename identifiers to avoid naming conflicts with the original
- - TsExpressionParser and TsBuiltinExpressionManager are not components any more
+ - TsExpressionParser and TsBuiltinExpressionManager are not components
+ any more
- TsExpressionParser is created with the worksheet as a parameter.
- add new TExprNode classes:
- TsCellExprNode for references to cells
@@ -26,7 +27,7 @@
- remove and modifiy built-in function such that the parser is compatible
with Excel syntax (and OpenOffice - which is the same).
- **********************************************************************}
+ ******************************************************************************}
{$mode objfpc}
{$h+}
unit fpsExprParser;
@@ -49,7 +50,7 @@ type
fekParen,
*)
TTokenType = (
- ttPlus, ttMinus, ttMul, ttDiv, ttPercent, ttPower, ttLeft, ttRight,
+ ttPlus, ttMinus, ttMul, ttDiv, ttConcat, ttPercent, ttPower, ttLeft, ttRight,
ttLessThan, ttLargerThan, ttEqual, ttNotEqual, ttLessThanEqual, ttLargerThanEqual,
ttNumber, ttString, ttIdentifier, ttCell, ttCellRange,
ttComma, ttAnd, ttOr, ttXor, ttTrue, ttFalse, ttNot, ttIf,
@@ -272,6 +273,17 @@ type
property Condition: TsExprNode read FCondition;
end;
+ { TsConcatExprNode }
+ TsConcatExprNode = class(TsBinaryOperationExprNode)
+ protected
+ procedure Check; override;
+ procedure GetNodeValue(var Result: TsExpressionResult); override;
+ function NodeType: TsResultType; override;
+ public
+ function AsRPNItem(ANext: PRPNItem): PRPNItem; override;
+ function AsString: string ; override;
+ end;
+
{ TsMathOperationExprNode }
TsMathOperationExprNode = class(TsBinaryOperationExprNode)
protected
@@ -914,7 +926,7 @@ begin
'/' : Result := ttDiv;
'^' : Result := ttPower;
'%' : Result := ttPercent;
- '&' : Result := ttPlus;
+ '&' : Result := ttConcat;
'<' : Result := ttLessThan;
'>' : Result := ttLargerThan;
'=' : Result := ttEqual;
@@ -1356,7 +1368,7 @@ begin
{$ifdef debugexpr} Writeln('Level 3 ',TokenName(TokenType),': ',CurrentToken);{$endif debugexpr}
Result := Level4;
try
- while TokenType in [ttPlus, ttMinus] do begin
+ while TokenType in [ttPlus, ttMinus, ttConcat] do begin
tt := TokenType;
GetToken;
CheckEOF;
@@ -1365,6 +1377,7 @@ begin
case tt of
ttPlus : Result := TsAddExprNode.Create(Result, right);
ttMinus : Result := TsSubtractExprNode.Create(Result, right);
+ ttConcat: Result := TsConcatExprNode.Create(Result, right);
end;
end;
except
@@ -1483,10 +1496,6 @@ begin
// Determine number of arguments
if isIF then
ACount := 3
- {
- else if isCASE then
- ACount := -4
- }
else if (ID.IdentifierType in [itFunctionCallBack, itFunctionHandler]) then
ACount := ID.ArgumentCount
else
@@ -2662,11 +2671,49 @@ begin
end;
+{ TsConcatExprNode }
+
+procedure TsConcatExprNode.Check;
+begin
+ inherited Check;
+ CheckNodeType(Left, [rtString]);
+ CheckNodeType(Right, [rtString]);
+end;
+
+procedure TsConcatExprNode.GetNodeValue(var Result: TsExpressionResult);
+var
+ RRes : TsExpressionResult;
+begin
+ Left.GetNodeValue(Result);
+ Right.GetNodeValue(RRes);
+ Result.ResString := Result.ResString + RRes.ResString;
+ Result.ResultType := rtString;
+end;
+
+function TsConcatExprNode.NodeType: TsResultType;
+begin
+ Result := rtString;
+end;
+
+function TsConcatExprNode.AsRPNItem(ANext: PRPNItem): PRPNItem;
+begin
+ Result := RPNFunc(fekConcat,
+ Right.AsRPNItem(
+ Left.AsRPNItem(
+ nil)));
+end;
+
+function TsConcatExprNode.AsString: string;
+begin
+ Result := Left.AsString + '&' + Right.AsString;
+end;
+
+
{ TsMathOperationExprNode }
procedure TsMathOperationExprNode.Check;
const
- AllowedTypes = [rtInteger, rtfloat, rtDateTime, rtString];
+ AllowedTypes = [rtInteger, rtfloat, rtDateTime];
begin
inherited Check;
CheckNodeType(Left, AllowedTypes);
@@ -2704,7 +2751,7 @@ begin
Right.GetNodeValue(RRes);
case Result.ResultType of
rtInteger : Result.ResInteger := Result.ResInteger + RRes.ResInteger;
- rtString : Result.ResString := Result.ResString + RRes.ResString;
+// rtString : Result.ResString := Result.ResString + RRes.ResString;
rtDateTime : Result.ResDateTime := Result.ResDateTime + RRes.ResDateTime;
rtFloat : Result.ResFloat := Result.ResFloat + RRes.ResFloat;
end;