Fluxins is a lightweight expression parser and evaluator written in modern C++. It has no dependencies*, simple integration, and is highly customizable.
Fluxins provides a flexible way to parse and evaluate expressions from strings. It is designed to be easily integrated into multiple systems, including user-facing applications, which allows them to input an expression that can be automatically evaluated. This allows users to perform quick operation directly in a text field, without having to pull up a calculator.
Fluxins can be useful in scenarios where flexible value evaluation is needed, but a simple lambda won't cut it. A prime example for this is in a GUI framework, where programmer can enter an expression that queries related data (e.g., parent container's width) within the expression, and apply transformations (like calculating a child container's max width).
The integration possibilities are endless, basically. You can also customize it to include your own operators too! You can create a REPL-like expression parsing prompt, or build another calculator, because you feel like that's what the world needs right now.
*: it does have a dependency for testing, but it is not enabled by default when Fluxins is added as a subdirectory.
- Clone the repository
git clone https://github.com/anstropleuton/fluxins.git
- Create a build directory
mkdir build cd build - Build the project
cmake .. cmake --build . --config Release - Install the project (optional; UNIX-like systems)
sudo cmake --install . --config Release
If you are looking to experiment with just the expressions and features of this parser, check out the REPL example.
If you are ready to dive into the APIs, add your project as a subdirectory in your CMakeLists.txt:
add_subdirectory(fluxins)If your project does not use CMake for your project, you can use CMake to build Fluxins as a static library, set up include paths, and link the library to your project.
#include <print>
#include <memory>
#include <string>
#include "fluxins/fluxins.hpp"
int main()
{
// This is just a quick-start example. Also see the other examples from the
// example directory to learn more.
// Create a configuration for parser and evaluator
auto cfg = std::make_shared<fluxins::config>();
// Create an expression
fluxins::expression expr("a + 2", cfg);
// Add variable to the expression's context
expr.set_variable("a", 3);
try
{
// Parse and evaluate the expression
expr.parse();
expr.evaluate();
}
catch (const fluxins::code_error &e)
{
// Report error
std::println("Error when parsing expression: {}", e.what());
return 1;
}
// Get the result
float result = expr;
std::println("Result of {}: {}", (std::string)expr, result); // 5
}Or check out this micro-example if you want ultra-quick expression parsing.
#include "fluxins/fluxins.hpp"
int main()
{
float value = fluxins::express("1 + 1"); // Since v1.0.1
std::println("Result of 1 + 1: {}", value);
}For other usage examples, including customizing functions or operators, see the examples in the example directory.
Expression features:
- Numbers (duh)
- Both integers and floating-point numbers are interpreted as float type.
- Separate digits using
'or_character. - Don't use the 'f' suffix for floats, as you would do in C++.
- Conversion to integral value in specific contexts is done by flooring, not truncating.
- Parenthesis:
(and) - Operators:
- Basic operators:
+,-,*,/,%(modulo/remainder),%%(wrapping modulo),**(exponent/power),//(flooring division) - Relational operators:
==,!=,<,>,<=,>= - Boolean conditional operators:
&&,||,! - Integral bitwise operators:
&,|,^,~,<<,>> - Absolute difference operator:
!! - Min and Max operator:
<?and>?. - Zero-coalescing operator:
value ?? value_if_zero - Conditional operator:
condition ? true_value : false_value
- Basic operators:
- Variables:
var* - Functions:
fn(args)
*: Technically, an expression cannot modify a variable, and the term "constant" may have made more sense. But the term "variable" is chosen due to the common use of identifiers as a variable in the code.
Customizations:
- Custom variables: Append your custom variable in list of variables.
- Custom functions: Append your custom function in list of functions.
- Multiple contexts for storing global symbols.
- Inherit symbols from other contexts.
- Custom operators: Append your custom operator in the parser config.
Other features:
- Thread Safety: Fluxins is thread safe, as long as you do not mutate configurations or contexts from multiple threads at the same time. Thread safety is on your hand.
- Error Reporting: Parsing and evaluating can throw
code_errorexception which contains information about the error, along with location of the error within the expression, such as syntax error or missing function. - Caching: Expression's AST and evaluated value is cached. If you change the expression, you would need to re-parse and re-evaluate the expression. If you change the context (symbols), you would only need to re-evaluat the expression.
- Built-in Variables and Functions: There are several built-in variables and functions that expressions can access. Variables include
e,pi,phi,sqrt2,inv_sqrt3,inv_pi, etc. while Functions includeabs(x),sin(x),pow(x, y),min(...),clamp(x,min,max),avg(...), etc. See Symbols List.
- A programming language: It's not.
- Variables or function calls outside the ones defined: It cannot.
- Automatic vulnerability checks to prevent unauthorized defined function call: It does not have it.
You can technically turn this into a programming language if you add basic control structure as function, and function that only return 0.
print_hello() + print_number(if(value) + equals(0) + then(10) + else(-10))
Here,
print_hello(),print_number(),if()andequals()always returns 0.if(),then()andelse()act as basic control structure.then()andelse()return if condition matched, otherwise 0. Note: none of these function are part of the fluxins.
- Comments support in the expression (?).
- Perhaps the comments start with
#?
- Perhaps the comments start with
- Allow the tokenizer to validly tokenize additional symbolic characters:
- Punctuations:
`@#$(){}\;,. - Operators:
~!%^&*-+=[]|:<>/?
- Punctuations:
- Tokenize strings too for easier extendability.
- Combine
fluxins::configandfluxins::context. - Rename token type
identifierto a more general term that can include keywords or commands for expressive extendability. - Rephrase "symbol" to mean only "operator" and find another term collective of both "variable" and "function".
- Currently "symbol" refers to operator, variable and/or function, and even keyboard symbol characters. Yikes!
- Perhaps the term "identifier" referring to variable and function collectively.
- Instead of throwing when an exception immediately when the first error in the expression is seen, maybe return a list of all the errors within the expression.
- Remove
codedata type completely. - Rename
code_locationtotext_rangeand inherit text formatting features from Optrone, which are inspired by Fluxin's REPL example so it's a full cycle...
Fluxins uses context to obtain list of variables or functions (collectively: symbols). This allows flexibility of providing symbols only to specific expressions or allowing them to inherit from other contexts. This allows global sharing of symbols.
The expression consists of tokens, i.e., identifiers, numbers, operators and punctuations. The whitespace is ignored by the parser, so feel free to use it to make your expression readable.
The grammar is similar to that of most programming language. Operators have precedence and parentheses override operator precedence and are evaluated first. They can be also nested.
Unary prefix operators:
+- Unary addition operator, one operand (at the right), has no effect (same as 0 + x).-- Unary subtraction operator, one operand (at the right), negates the value (same as 0 - x).*- Unary multiplication operator, one operand (at the right), has no effect (same as 1 * x)./- Unary division operator, one operand (at the right), inverts the value (same as 1 / x).!- NOT operator, one operand (at the right).~- Bitwise NOT operator, one operand (at the right).
Unary suffix operators:
!- Factorial operator, one operand (at the left, not to be confused with!NOT operator which requires operand at the right).
Binary operators:
+- Addition operator.-- Subtraction operator.*- Multiplication operator./- Division operator.%- Modulo operator.%%- Wrapping modulo operator.-2 %% 5yields 3 (Wraps negative remainder into [0,5) range).**- Exponent operator.//- Flooring division operator.7 // 2yields 3 (3.5 floored down).==- Equality comparison.2 == 2yields 1 (true is 1 and false is 0).!=- Opposite of equality comparison.<- Less-than operator.>- More-than operator (greater-than operator).<=- Less-than or equal to operator.>=- More-than or equal to operator.&&- AND operator. Considers operands to be true if they are non-zero.||- OR operator.&- Bitwise AND operator.|- Bitwise OR operator.^- Bitwise XOR operator.<<- Bitwise left-shift operator.>>- Bitwise right-shift operator.!!- Absolute difference operator.3 !! 5yields 2 (same asabs(3 - 5)).??- Zero-coalescing operator.4 ?? 5yields 4 and0 ?? 5yields 5 (if the first operand is non-zero, it is yielded, otherwise the second operand is yielded)<?- Min operator.>?- Max operator.?and:- Conditional operator.1 ? 2 : 3yields 2 and0 ? 2 : 3yields 3 (syntax iscondition ? true_value : false_value).
This is the default precedence table for binary operator.
Note that the lower precedence value means higher precedence, i.e., operators with precedence 0 is the most precedent operator.
| Precedence | Operator |
|---|---|
| 0 | <<, >> |
| 1 | ^ |
| 2 | &, | |
| 3 | !! |
| 4 | <?, >? |
| 5 | ?? |
| 6 | ** |
| 7 | // |
| 8 | %, %% |
| 9 | *, / |
| 10 | +, - |
| 11 | ==, !=, <, >, <=, >= |
| 12 | &&, || |
There are 17 variables and 70 functions defined as of release 1.0.0. For the full list of all the variables and functions, see the full list of built-in functions and variables.
More functions are to be added when C++26 is released and compilers support are ready (namely saturated arithmetic such as add_sat, sub_sat).
There are a few examples that I have created to demonstrate Fluxins.
- usage.cpp: Demonstrates general usage of Fluxins. This is a larger example and covers wider areas compared to the Quick-Start Example.
- customize.cpp: Showcases customizability of Fluxins by creating custom variables, functions and several operators (prefix, suffix, binary).
- repl.cpp: Implements a REPL console that allows users to parse and evaluate expressions. It even supports expression evaluation from the command-line arguments, and more features for ease of demo.
Feel free to contribute to this project by code (see contributing.md), by suggesting your ideas, or even by reporting a bug.
Thanks to jothepro for the stylesheet Doxygen Awesome for Doxygen.
Thanks to Nuno Pinheiro (can't find link) for the background Elarun. But I did find a KDE store link to the background image. I think you could consider that. If KDE developers are here, I would appreciate your help to find a proper link to the author.
Thanks to patorjk for Text to ASCII Art Generator.
Copyright (c) 2025 Anstro Pleuton.
This project is licensed under the terms of MIT License. See license.md for more info.