Released "Exevalator": A Multilingual & Copyright-Free Expression Evaluator Library

We have released a new library "Exevalator" (an abbreviation for Expression-Evaluator) which enables you to calculate values of numerical expressions stored in string variables, on Java/C#/C++/Rust programs.

In the former part of this article, we will explain details of Exevalator. In addition, in the latter part, we will actually use Exevalator in Java/C#/C++/Rust.

- List of Contents -

What is Exevalator ?

First of all, we should clarify target users/readers of Exevalator and this article.

Exevalator is a "library", which is a component of software, available for developing your software/apps. Hence, target users of Exevalator (and target readers of this article) are people who developing some softwere/apps as a hobby or jobs.

Purpose of Exevalator

Let's get into details. When you are developing software, don't you want to calculate (evaluate) the value of a numerical expression stored in a string-type variable easily?

Where typical examples of expressions are as follows:

1 + 2
(1.2 + 3.4) * 5.6
x + f(y)

Calculating these expressions are required for: developing some kind of calculator apps, applying user-defined conversions to data, drawing graphs of numeric expressions/functions, and so on.

On such apps, internally, gets an inputted expression from an user, as a string-type value. So the situation "an expression is stored in a string-type variable, and you want to calculate the value of it" occurs practically.

However, most of compiled (not scripting) languages don't support such feature by default, so you are required to implement a calculation routine by yourself, or use a library providing such feature.

Exevalator is a very compact library to provide such feature on Java/Rust/C#/C++ programs.

Multilingual

Exevalator is available in multiple programming languages. The lis of currently supported languages are as follows:

  • Java  (Java 8 or later is required. The latest version Java 18 is already available.)
  • C#    (C# 8.0 or later is recommended)
  • C++  (C++17 or later is required)
  • Rust  (rustc 1.57.0 or later is recommended)
  • Also, in future, we may port Exevalator to other languages too. Source code structure of Exevalator is relatively simple (as explained later), so it is easy to port. Indeed, we had developed Exevalator in Java at first, and then we ported it to C#, Rust, and C++.

    Compact, Easy to Use

    Exevalator is very compact libary implemented as single-file, for each language. (Only for C++, a header file is also provided, so it consists of two-files.)

    Copyright-Free

    This library is released under the "Unlicense" license, which is almost the same as the so-called "copyright-free" (public domain).

    Also, you can choose the CC0 license instead, if you want. The Unlicense and the CC0 is similar in that they are licenses to release something into the public domain, but their details are little different. Choose the one you want.

    Hence, no need to pay any attention to license terms, for using Exevalator. It is the same for distributing/selling your apps which are using Exevalator. It is even the same for customizing/diverting source code of Exevalator.

    Can Define Functions/Variables

    Sometimes you may want to calculate the value of an expression like "x + 2", where "x" is an variable, of which value can be modified in/by your app or its users.

    Exevalator supports defining such variables. You can define variables as many as you want. You also can decide their names freely.

    Also, as many as you want, you can create functions available in expressions, e.g.: "x + f(y)". You can implement internal process of such functions freely, and decide its name freely.

    High-Speed

    Exevalator performs calculations at high-speed.

    For example, as the score measured by a benchmark program (containd in the repository of Exevalaor) on the general mid-range PC, Exevalator can performs hundreds of millions times of numerical operations per each second (= hundreds MFLOGS).

    Based on our experience, we consider that the above calculation speed is enough for performing a conversion for large data, for sampling coordinates (x,y) of a expression in dense points, and so on.

    Compared with Vnano

    By the way, as same as Exevalator, we are developing/distributing a script engine "Vnano" for embedded use in apps.

    The above "Vnano" can also calculates numerical expressions. So, features of Exevalator and Vnano are duplicate in some extent. However, it does NOT mean that one is "overall better" than the other. It depends on the purpose that which one is better.

    For Exevalator, we give priority to make the implementation compact, and to ease steps to embed it in apps, than to support various features.

    On the other hand, Vnano supports more features than Exevalator, though its implementation is more complex and larger. In addition, the maximum processing speed of Vnano is faster than it of Exevalator.

    Details of differences between Exevalator and Vnano are as follows:

    Aspect_Library Exevalator Vnano
    Calculating a Numerical Expression Supported Supported
    Defining Variables/Functions by Developpes ofApps Supported Supported
    Defining Variables/Functions by User of Apps Unsupported Supported
    Running Complex Procedure (Script) Containing Branching and Loops Unsupported Supported
    Available Data-types 64-bit Floating Point Number 64-bit Floating Point Number,
    64-bit Signed Integer,
    String,
    Boolean
    Defining/Accessing to Arrays Unsupported Supported
    Maximum Calculation Speed
    About 400 MFLOPS
    iOn Java Version, CPU: Core i7-1165G7j
    Scalar: Abuot 700 MFLOPS,
    Array: About 16 GFLOPS
    iCPU: Core i7-1165G7j
    Supported Programming Language Java, C#, C++, Rust Java
    (May be ported to some other lanugases in future)
    Components of the Library Single source file, for each language version Many source files
    Lines of Source Code (LOC) One thousand and hundreds of lines, for each language version Tens of thousands of lines
    Steps to be Embedded in Apps Put a source file into source code folder of an app. Create a JAR file from source files by doing build-steps, and specify class-path to it from an app, for loading it dynamically.
    Software Architecture AST Interpreter Intermediate Code Compiler+VM
    License Choose either Unlicense or CC0 MIT License

    Rughly summarized as follows: If you want to develop an highly customizable app, we recommend to try to use Vnano. On the other hand, what you want to do is only to calculate a value of a numerical expression, we recommend to use Exevalator.
    (Please note that, Exevalator is available in Java/C#/C++/Rust, but Vnano is currently available in only Java.)

    Let's Use Exevalator Actually

    That's all about introduction of Exevalator. From here, Let's try to use Exevalator actually.

    Download

    At first, download the source code of Exevalator. You can get it from the following webpage on GitHub:

    Download Page of Released Versions, in Source Code Repository of Exevalator on GitHub
    https://github.com/RINEARN/exevalator/releases

    On the above page, go to the section of a released version you want to use (the latest version is recommended), and click the hyperlink "Source code (zip)" in there.

    Then, a ZIP file "exevalator-1.0.0.zip" (the actual name depends on the selected version) will be download, so right-click it and select "Extract All" to extract contents.

    A folder "exevalator-..." will be created as the result of the above. In the folder, there are various files (e.g.: README, example files, and so on), but only following files are necessary to embed Exevalator into your apps.

    For Java Apps
    "Exevalator.java" in "java" folder
    For C# Apps
    "Exevalator.cs" in "csharp" folder
    For C++ Apps
    "exevalator.cpp" (implementation) and "exevalator.hpp" (header file) in "cpp" folder
    For Rust Apps
    "exevalator.rs" in "rust" folder

    Let's use in each language.

    For Java Apps

    For using in Java, put "Exevalator.java" into the same folder with the source file of a class in which you want to calculate expressions. If necessary, the same as when you create a new class, update build-settings to include "Exevalator.java" in compilation target.

    In addition, append a package-declaration line "package ..." at the top of code of "Exevalator.java". The content of line depends where the file is locating, but it is the same as it of source files in the same folder. As an example, here we assume that the package is declared as follows:

    (At the top in "Exevalator.java")
    package myapp;
    ...

    Then, you can "import" Exevalator from other classes, and perform calculations as follows:

    (Code of your source file, in which you want to calculate expressions)
    ...
    import myapp.Exevalator;
    ...

    ...
    Exevalator exevalator = new Exevalator();   // Create an interpreter of Exevalator
    double result = exevalator.eval("1.2 + 3.4");   // Calculate the value of an expression
    System.out.println("result: " + result);   // Display the result
    ...
    Note: "Exevalator.Exception" will be thrown when incorrect expressions are inputted, so catch and handle it if you want.

    For more detailed explanation, and how to compile/run example code, see README for Java in repository.

    For C# Apps

    For using in C#, put "Exevalator.cs" into source code folder of your project to develop an app. If necessary, the same as when you create a new class, update build-settings to include "Exevalator.cs" in compilation target.

    Then, you can "using" Exevalator from other source files, and perform calculations as follows:

    (Code of your source file, in which you want to calculate expressions)
    ...
    using Rinearn.ExevalatorCS;
    ...

    ...
    Exevalator exevalator = new Exevalator();   // Create an interpreter of Exevalator
    double result = exevalator.Eval("1.2 + 3.4");   // Calculate the value of an expression
    Console.WriteLine("result: " + result);   // Display the result
    ...
    Note: "Exevalator.Exception" will be thrown when incorrect expressions are inputted, so catch and handle it if you want.

    For more detailed explanation, and how to compile/run example code, see README for C# in repository.

    For C++ Apps

    For using in C++, put "exevalator.cpp" and "exevalator.hpp" into the same folder with the source file in which you want to calculate expressions.

    If you want to do "separate compilation", put "exevalator.cpp" into the folder of implementation files, and put "exevalator.hpp" into the foler of header files, and modify build-settings to them in compilation target.

    Then, you can "include" them from other source files, and perform calculations as follows:

    (Code of your source file, in which you want to calculate expressions)
    ...
    #include "exevalator.hpp"
    #include "exevalator.cpp"
    ...

    ...
    exevalator::Exevalator exevalator; // Create an interpreter of Exevalator
    try {
        double result = exevalator.eval("1.2 + 3.4"); // Calculate the value of an expression
        std::cout << "result: " << result << std::endl; // Display the result

    // When any error occurred
    } catch (exevalator::ExevalatorException &e) {
        std::cout << "Error occurred: " << e.what() << std::endl;
    }
    ...

    For more detailed explanation, and how to compile/run example code, see README for C++ in repository.

    For Rust Apps

    For using in Rust, put "exevalator.rs" at the root-hierarchy of source code folder. (If you want to put it at other hierarchy, you are required to modify "mod" declarations appropriately.)

    In addition, append the follosing "mod" declaration in the code of the root file (e.g.: main.rs):

    ...
    mod exevalator;
    ...

    Then, you can "use" Exevalator in other source files, and perform calculations as follows:

    (Code of your source file, in which you want to calculate expressions)
    ...
    use exevalator::Exevalator;
    ...

    ...
    // Create an interpreter of Exevalator
    let mut exevalator = Exevalator::new();

    // Calculate the value of an expression
    let result: f64 = match exevalator.eval("1.2 + 3.4") {
        Ok(eval_value) => eval_value,
        Err(eval_error) => panic!("{}", eval_error),
    };

    // Display the result
    println!("result: {}", result);

    For more detailed explanation, and how to compile/run example code, see README for Rust in repository.

    ---

    That's all. When there is additional information about Exevalator, we will report it in this "RINEARN News" category. Exevalator is an open source library, so we will probably publish an article explaining details of software architecture of it, at a later date.