https://github.com/alessandro-salerno/forflex
Flexible expression evaluation library
https://github.com/alessandro-salerno/forflex
algebra expression-parser expressions flexible flexible-library flexible-parsers java java-library lexer library math math-parser parser
Last synced: 11 months ago
JSON representation
Flexible expression evaluation library
- Host: GitHub
- URL: https://github.com/alessandro-salerno/forflex
- Owner: Alessandro-Salerno
- License: apache-2.0
- Created: 2025-02-25T22:11:07.000Z (11 months ago)
- Default Branch: main
- Last Pushed: 2025-02-27T00:34:51.000Z (11 months ago)
- Last Synced: 2025-02-27T01:33:00.715Z (11 months ago)
- Topics: algebra, expression-parser, expressions, flexible, flexible-library, flexible-parsers, java, java-library, lexer, library, math, math-parser, parser
- Language: Java
- Homepage:
- Size: 76.2 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
Forflex
Simple, flexible, and extensible expression parseing and evaluation library for Java
[contributors-shield]: https://img.shields.io/github/contributors/Alessandro-Salerno/Forflex.svg?style=flat-square
[contributors-url]: https://github.com/Alessandro-Salerno/Forflex/graphs/contributors
[forks-shield]: https://img.shields.io/github/forks/Alessandro-Salerno/Forflex.svg?style=flat-square
[forks-url]: https://github.com/Alessandro-Salerno/Forflex/network/members
[stars-shield]: https://img.shields.io/github/stars/Alessandro-Salerno/Forflex.svg?style=flat-square
[stars-url]: https://github.com/Alessandro-Salerno/Forflex/stargazers
[issues-shield]: https://img.shields.io/github/issues/Alessandro-Salerno/Forflex.svg?style=flat-square
[issues-url]: https://github.com/Alessandro-Salerno/Forflex/issues
[license-shield]: https://img.shields.io/github/license/Alessandro-Salerno/Forflex.svg?style=flat-square
[license-url]: https://github.com/Alessandro-Salerno/Forflex/blob/master/LICENSE.txt
[![Contributors][contributors-shield]][contributors-url]
[![Forks][forks-shield]][forks-url]
[![Stargazers][stars-shield]][stars-url]
[![Issues][issues-shield]][issues-url]
[![MIT License][license-shield]][license-url]

## Features
- Java function invocation inside expressions
- Strings in function parameters (used to retreive data from the host program)
- Expression parameters
- Custom algebric structures other than real numbers
- Parse tree caching
- Error handling
- Can be used in both FOSS and proprietary software
## Syntax and grammar
The grammar is defined in pseudo-BNF as follows:
```
Grammar:
:= anything in UTF-8
:= 0|1|2|3|4|5|6|7|8|9
:= {}*
:= [.]
:= a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z
:= A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z
:= |
:= "{}*"
:= |_{||_}*
:= [{+|-}]
:= |
:= [{, }*]
:= ()
:= [{*|/}]
:= -|()|||
```
For example, this is a valid statement:
```
round((a + b + c - d) / (5.47 * sin(1)) + priceof("AAPL", "2025-02-26"))
```
However, the round functions and the other symbols must be defied by the Java program, otherwise an exception is thrown:
```
1:1 ERROR: Undeclared identifier "round"
1 | round((a + b + c - d) / (5.47 * sin(1)) + priceof("AAPL", "2025-02-26"))
| ~~~~~
```
## Structure
Forflex has six main concepts:
- Algebric structures
- Evaluables
- Expressions
- Functions
- Parameters
- Parser
### Algebric structures
Algebric structures in Forflex define what operations can be applied to a number and how these operations behave. Algebric structures are classes that implement `ForflexAlgebra` and define methods for addition, subtraction, multiplication, and division. If a given algebric structure does not support one or more of these operations, it can throw a `ForflexUnsupportedOperationError`. The default algebric structure is `ForflexRealNumber`.
### Evaluables
Evaluables in Forflex are essentially nodes in the parse tree. Evaluables implement the `ForflexEvaluable` interface and its method `evaluate` which returns an instance of a `ForflexAlgebra` when called.
Forflex ships with four main evaluables:
- Identity (`ForflexIdentityNode` - returns the same instance of `ForflexAlgebra` that was passed)
- Binary (`ForflexBinaryNode` - holds two other evaluables on the left and right in order to make the binary tree)
- Function call (`ForflexFunctionCallNode` - used to represent a function call in the tree)
- Parameter (`ForflexParameterNode` - used to store references to parameters)
### Expressions
Expressions in Forflex are a special type of evaluable which stands outside the tree and is used to cahce the tree itself in order to reuse it. This removes the need to reparse the expression every time it has to be evaluated with a given set of parameters.
### Functions
Functions in Forflex are implementations of the `ForflexFunction` interface which, once added to a Parser, can be invoked from within an expression.
### Parameters
Parameters in Forflex are named values that reside in the host Java program but can be access in read-only mode within expressions.
### Parser
The Parser (`ForflexParser`) is the component responsible for constructing the tree. It first tokenizes the expression using the Lexer and then recursively scrolls the token list to build the tree.
## Example
```java
package alessandrosalerno.forflex;
import alessandrosalerno.forflex.errors.preprocessor.ForflexPreprocessorError;
import alessandrosalerno.forflex.errors.runtime.ForflexParameterCountError;
import alessandrosalerno.forflex.errors.runtime.ForflexParameterTypeError;
import alessandrosalerno.forflex.algebra.ForflexAlgebra;
import alessandrosalerno.forflex.algebra.ForflexRealNumber;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
try {
String formula = "round((a + b + c - d) / (5.47 * sin(1)) + priceof(\"AAPL\", \"2025-02-26\"))";
Map parameters = new HashMap<>();
parameters.put("a", new ForflexRealNumber(1));
parameters.put("b", new ForflexRealNumber(2));
parameters.put("c", new ForflexRealNumber(3));
parameters.put("d", new ForflexRealNumber(4));
ForflexParser parser = new ForflexParser().addFunctions(ForflexUtils.DEFAULT_FUNCTIONS)
.addFunction("priceof", new ForflexFunction() {
@Override
public ForflexAlgebra run(Object[] params) {
String symbol = ForflexUtils.requireParameterType(params, 0, String.class);
String date = ForflexUtils.requireParameterType(params, 1, String.class);
// Do some magic stock market stuff
return new ForflexRealNumber(200.5);
}
});
ForflexExpression expr = parser.parse(formula, parameters);
// Now the expression has been parsed, parameters can be changed at any time
// NOTE: this means that parameters are NOT thread-safe!
ForflexRealNumber result = (ForflexRealNumber) expr.evaluate();
System.out.println(result.getDouble());
} catch (ForflexPreprocessorError e) {
e.printErrorMessage();
} catch (ForflexParameterCountError
| ForflexParameterTypeError e) {
e.printStackTrace();
}
}
}
```
## Installing Forflex with Maven
After downloading the JAR and placing it in some project directory (e.g., resources), use the following dependency structure in your pom.xml file:
```xml
alessandrosalerno.forflex
forflex
1.0.0
system
${project.basedir}/src/main/resources/forflex-1.0.0.jar
```
Alternatively, you can install the package from GitHub Packages:
```xml
alessandrosalerno.forflex
forflex
1.0.0
```
## License
Forflex is distributed under the Apache License 2.0.
## Credits
- https://github.com/javalc6/Simple-Expression-Parser