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: 995
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

Well-Known 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
 

Ben10

New Member
This is my first time attempting to use a B4X library with B4A. I've created a program in B4J using this library which I would like to run on an Android device using B4A. When attempting to run in B4A the code execution fails and asks if the B4XEval library is missing. Looking at the library in the "AdditionalLibraries/B4X" folder the file type designations are ".b4j". What do i need to do to have this library run successfully in B4A?
 

Ben10

New Member
Thanks, I just did that but now the follow error comes up: "Cannot find: C:\Program Files\Anywhere Software\B4A\libraries\jcore.jar"

Is this because the B4XEval library is dependent on this B4J library?
 
Top