B4J Library [B4X] Eval (expressions evaluator)

The attached class allows you to evaluate mathematical expressions with support for custom functions.
It is compatible with B4A, B4J and B4i.

Example:
B4X:
Sub AppStart (Args() As String)
   Dim e As B4XEval
   e.Initialize(Me, "Eval")
   Log(e.Eval("1 + Min(2, Max(-4, 1), 6)"))
   Log(e.Eval("-(2+5)*(7-3) + Sin(15 + 15) + Cos(30)"))
   Log("Error? " & e.Error)
   Log(e.Eval("-(2+5)*-(7-3)"))
   Log(e.Eval("-((-7-3))"))
   Log(1.321/-2/3.123 + (2 * 2 + 3) + 4)
   Log(e.Eval("1.321/-2/3.123 + (2 * 2 + 3) + 4"))
End Sub

'custom functions implementation
Sub Eval_Function (Name As String, Values As List) As Double
   Select Name 'it will be lower case
     Case "min"
       Dim d As Double = Values.Get(0)
       For Each n As Double In Values
         If n < d Then d = n
       Next
       Return d
     Case "max"
       Dim d As Double = Values.Get(0)
       For Each n As Double In Values
         If n > d Then d = n
       Next
       Return d
     Case "sin"
       Return SinD(Values.Get(0))
     Case Else
       Log("Invalid function: " & Name)
       Dim e As B4XEval = Sender
       e.Error = True
       Return 0
   End Select
End Sub

Note that if you are using it with B4A then call Eval after Activity_Create completes (you can add Sleep(0) instead). Otherwise the Function event will not be raised.

Updates

V2.01 - Fixes an issue with sub-expressions converted to scientific notation (which is not supported).
V2.00 - adds support for custom functions.
 

Attachments

  • B4XEval.zip
    2.9 KB · Views: 826
Last edited:

imbault

Well-Known Member
Licensed User
Longtime User
One more thing, if I may, would it be complicated to include variables in expressions like (or something to instantiate variables which can be used in this class):
B4X:
Log(e.Eval(" Max(-4, a)"))
or
B4X:
dim a as int = 10
e.SetVar("VA", a )
Log(e.Eval(" Max(-4, "VA")"))

It would be more than great
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
You can create a "get" function that returns values from an array:
B4X:
Sub Process_Globals
   Private vars(1000) As Double
End Sub

Sub AppStart (Args() As String)
   Dim e As B4XEval
   e.Initialize(Me, "Eval")
   vars(10) = 100
   Log(e.Eval("1 + Min(2, Max(-4, 1), 6)"))
   Log(e.Eval("-(2+5)*(7-3) + Sin(15 + 15) + Cos(30)"))
   Log("Error? " & e.Error)
   Log(e.Eval("-(2+5)*-(7-3)"))
   Log(e.Eval("-((-7-3))"))
   Log(1.321/-2/3.123 + (2 * 2 + 3) + 4)
   Log(e.Eval("1.321/-2/3.123 + (2 * 2 + 3) + 4"))
   Log(e.Eval("get(10) * 3")) '<-----
End Sub

Sub Eval_Function (Name As String, Values As List) As Double
   Select Name 'it will be lower case
     Case "min"
       Dim d As Double = Values.Get(0)
       For Each n As Double In Values
         If n < d Then d = n
       Next
       Return d
     Case "max"
       Dim d As Double = Values.Get(0)
       For Each n As Double In Values
         If n > d Then d = n
       Next
       Return d
     Case "sin"
       Return SinD(Values.Get(0))
     Case "get"
       Return vars(Values.Get(0)) '<-----
     Case Else
       Log("Invalid function: " & Name)
       Dim e As B4XEval = Sender
       e.Error = True
       Return 0
   End Select
End Sub
 

imbault

Well-Known Member
Licensed User
Longtime User
You can create a "get" function that returns values from an array:
B4X:
Sub Process_Globals
   Private vars(1000) As Double
End Sub

Sub AppStart (Args() As String)
   Dim e As B4XEval
   e.Initialize(Me, "Eval")
   vars(10) = 100
   Log(e.Eval("1 + Min(2, Max(-4, 1), 6)"))
   Log(e.Eval("-(2+5)*(7-3) + Sin(15 + 15) + Cos(30)"))
   Log("Error? " & e.Error)
   Log(e.Eval("-(2+5)*-(7-3)"))
   Log(e.Eval("-((-7-3))"))
   Log(1.321/-2/3.123 + (2 * 2 + 3) + 4)
   Log(e.Eval("1.321/-2/3.123 + (2 * 2 + 3) + 4"))
   Log(e.Eval("get(10) * 3")) '<-----
End Sub

Sub Eval_Function (Name As String, Values As List) As Double
   Select Name 'it will be lower case
     Case "min"
       Dim d As Double = Values.Get(0)
       For Each n As Double In Values
         If n < d Then d = n
       Next
       Return d
     Case "max"
       Dim d As Double = Values.Get(0)
       For Each n As Double In Values
         If n > d Then d = n
       Next
       Return d
     Case "sin"
       Return SinD(Values.Get(0))
     Case "get"
       Return vars(Values.Get(0)) '<-----
     Case Else
       Log("Invalid function: " & Name)
       Dim e As B4XEval = Sender
       e.Error = True
       Return 0
   End Select
End Sub

That's a beginning, what about a set function?

Thanks a lot
 

Gabino A. de la Gala

Active Member
Licensed User
Longtime User
Would it be very difficult to adapt it so that it would also work with functions that returned other types of data such as strings or dates?
 

agraham

Expert
Licensed User
Longtime User
Do calculations with these values, is it a problem??
No, this is normal and expected. The results are Double values which are binary values that cannot represent accurately every decimal value. If you need exact decimal results you need to use a special library designed to handle decimals like my
 
Top