Recent

Author Topic: TFPExpressionParser: Way to understand what variables will be needed for expr  (Read 4509 times)

zamtmn

  • Sr. Member
  • ****
  • Posts: 447
Hi All!

I have a large set of variables and I need to perform some action with them. TFPExpressionParser requires defining the variables before of the expression assignment. But there are a lot of my variables and they will definitely not be needed for calculation. I would like to define only the necessary ones. Is there a way to do this implemented in TFPExpressionParser

wp

  • Hero Member
  • *****
  • Posts: 9171
Not sure whether I fully understand the question: You have many possible variables. The user can create an expression based on some of these variables, but he is free to use only a subset of them, and you do not know which ones you should declare in the expression parser. Right?

I think there is no simple way to prepare this.

You could start with no variable at all; put the expression into a try-except block and catch the exception for "Unknown identifier" and ask the user to define the missing variable and to specify a value for it. Then start a-new and repeat until no more error appears. But the problem is that there may be other issues in the expression than just unknown variables, and it is not easy to distinguish between them because the unit only exposes two exception types, EExprScanner and EExprParser.

Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. uses
  4.   SysUtils, fpexprpars;
  5.  
  6. var
  7.   parser: TFpExpressionparser;
  8.   OK: Boolean;
  9.   res: TFpExpressionResult;
  10.   a: double;
  11.   expr: String;
  12. begin
  13.   expr := 'a + 1.0';
  14.   parser := TFpExpressionParser.Create(nil);
  15.   try
  16.     repeat
  17.       try
  18.         OK := true;
  19.         parser.Expression := '';
  20.         parser.Expression := expr;
  21.       except
  22.         on E:EExprParser do
  23.         begin
  24.           WriteLn(E.Message);
  25.           Write('Please enter value for missing variable: ');
  26.           ReadLn(a);
  27.           parser.Identifiers.AddFloatVariable('a', a);
  28.           OK := false;
  29.         end;
  30.       end;
  31.     until OK;  
  32.     res := parser.Evaluate;
  33.     WriteLn(expr, ' = ', ArgToFloat(res));
  34.   finally
  35.     parser.Free;
  36.   end;
  37.  
  38.   ReadLn;
  39.    
  40. end.

I personally would go the safe way and declare all possible variables. A problem may be their initial values; a zero, for example, for variable "A" will be ok when "sqrt(A)" is to be calculated, but be fatal when the expression is "1/A" .
Mainly Lazarus trunk / fpc 3.2.0 / all 32-bit on Win-10, but many more...

zamtmn

  • Sr. Member
  • ****
  • Posts: 447
Yes, you got it right.

But I don't like this solutions.
Handling exceptions is slow.
Declare all variables - there are a lot of them, I don't know them all in advance. I can check whether this identifier is a variable, but not get a list of all variable names.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 9778
  • FPC developer.
Expression parser Symbolic has (from fpc/packages/symbolic/examples/evaltest.pas)


Code: Pascal  [Select][+][-]
  1.  SymVars:=Expr.SymbolicValueNames;
  2.  

to get a list of variables. No type inference though

wp

  • Hero Member
  • *****
  • Posts: 9171
Declare all variables - there are a lot of them, I don't know them all in advance. I can check whether this identifier is a variable, but not get a list of all variable names.
But when you don't know anything about the variables, there must be something where the user defines them... I'd put a ValueListEditor on a form in which the user enters the variables and their values. Then you can create the identifieres for the parser from it.

Or do you mean symbolic calculations? Then fpexpressionparser would not be what you need, Marco's "symbolic" would be much better then.

Or maybe you should think of PascalScript.
« Last Edit: November 27, 2021, 06:15:24 pm by wp »
Mainly Lazarus trunk / fpc 3.2.0 / all 32-bit on Win-10, but many more...

zamtmn

  • Sr. Member
  • ****
  • Posts: 447
marcov
Symbolic in this case it is more good, but has other problems

wp
Scripts are overkill. I need simple calculations with logical and floating point operations. Pre-parsing an expression to get a list of variables would greatly facilitate many tasks. I'll try to add this


zamtmn

  • Sr. Member
  • ****
  • Posts: 447
Added patch and test program, please review

wp

  • Hero Member
  • *****
  • Posts: 9171
Please send this to the bug tracker. I can not commit to fpc, and Michael Van Canneyt (who wrote and maintains the parser) only very rarely reads the forum.

How will you approach the related problem that these auto-detected variables do not have a value?
« Last Edit: November 27, 2021, 09:47:06 pm by wp »
Mainly Lazarus trunk / fpc 3.2.0 / all 32-bit on Win-10, but many more...

zamtmn

  • Sr. Member
  • ****
  • Posts: 447
On the first pass, I just find the variables, then I set their types and values and re-run the parser with typed and valued variables

Issue: https://gitlab.com/freepascal.org/fpc/source/-/issues/39454
« Last Edit: November 28, 2021, 06:13:43 am by zamtmn »

 

TinyPortal © 2005-2018