From cee350a78901893b62ed0692b3bf7fcaf03ed878 Mon Sep 17 00:00:00 2001 From: Blake-Madden Date: Sat, 18 Nov 2023 10:04:51 -0500 Subject: [PATCH] Simplify Readme --- Embedded.md | 107 -------------------------------------------- README.md | 109 +-------------------------------------------- TinyExprChanges.md | 108 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 215 deletions(-) delete mode 100644 Embedded.md create mode 100644 TinyExprChanges.md diff --git a/Embedded.md b/Embedded.md deleted file mode 100644 index 446dc79..0000000 --- a/Embedded.md +++ /dev/null @@ -1,107 +0,0 @@ -# Embedded Programming - -## Volatility - -If needing to use a `te_parser` object as `volatile` -(e.g., accessing it in a system interrupt), then you will need -to do the following. - -First, declare your `te_parser` as a non-`volatile` object outside -of the interrupt function (e.g., globally): - -```cpp -te_parser tep; -``` -Then, in your interrupt function, create a `volatile` reference to it: - -```cpp -void OnInterrupt() - { - volatile te_parser& vTep = tep; - } -``` -Functions in `te_parser` which have `volatile` overloads can then be -called directly: - -```cpp -void OnInterrupt() - { - volatile te_parser& vTep = tep; - vTep.set_list_separator(','); - vTep.set_decimal_separator('.'); - } -``` -The following functions in the `te_parser` class have `volatile` overloads: - -- `get_result()` -- `success()` -- `get_last_error_position()` -- `get_decimal_separator()` -- `set_decimal_separator()` -- `get_list_separator()` -- `set_list_separator()` - -For any other functions, use `const_cast<>` to remove the parser -reference's volatility: - -```cpp -void OnInterrupt() - { - volatile te_parser& vTep = tep; - - // Use 'const_cast(vTep)' to access - // non-volatile functions. - const_cast(vTep).set_variables_and_functions( - { {"STRESS_L", 10.1}, - {"P_LEVEL", .5} }); - const_cast(vTep).compile(("STRESS_L*P_LEVEL")); - - if (vTep.success()) - { - auto res = vTep.get_result(); - // Do something else... - } - } -``` - -Note that it is required to make the initial declaration of your -`te_parser` non-`volatile`; otherwise, the `const_cast<>` to the -`volatile` reference will cause undefined behavior. - -## Exception Handling - -TinyExpr++ requires exception handling, although it does attempt to -minimize the use of exceptions (e.g., `noexcept` is used extensively). -Syntax errors will be reported without the use of exceptions; -issues such as division by zero or arithmetic overflows, however, -will internally use exceptions. The parser will trap these -exceptions and return NaN (not a number) as the result. - -Exceptions can also be thrown when defining custom functions or variables -which do not follow the proper naming convention. -(Function and variable names must only contain the characters -`a`-`z`, `A`-`Z`, `0`-`9`, and `_`, and must begin with a letter.) - -Finally, specifying an illegal character for a list or decimal separator -can also throw. - -The following functions in `te_parser` can throw and should be wrapped -in `try`/`catch` blocks: - -- `compile()` -- `evaluate()` -- `set_variables_and_functions()` -- `add_variable_or_function()` -- `set_decimal_separator()` -- `set_list_separator()` - -The caught `std::runtime_error` exception will provide a description -of the error in its `what()` method. - -## Virtual Functions - -TinyExpr++ does not use virtual functions or derived classes, -unless you create a custom class derived from `te_expr` yourself -(refer to [Example 5](Examples.md)). -(`te_expr` defines a virtual destructor that may be implicitly optimized to -`final` if no derived classes are defined.) diff --git a/README.md b/README.md index 0325c84..a9cc18d 100644 --- a/README.md +++ b/README.md @@ -61,114 +61,7 @@ For notes on embedded programming, please refer to the [embedded programming](Em ## Changes from TinyExpr -The following are changes from the original TinyExpr C library: - -- Compiles as C++17 code. -- `te_*` functions are now wrapped in a `te_parser` class. -- `te_interp()`, `te_compile()`, and `te_eval()` have been replaced with `te_parser::compile()`, `te_parser::evaluate()`, and `te_parser::set_variables_and_functions()`. - `set_variables_and_functions()` sets your list of custom functions and variables. `compile()` compiles and optimizes an expression. - Finally, `evaluate()` will use the already compiled expression and return its result. - `evaluate()` also has an overload that compiles and evaluates an expression in one call. -- Variable/function types (e.g., `TE_FUNCTION0`) have been removed; types are now deduced by the compiler. The available flags - for variables and functions are now just combinations of `TE_DEFAULT`, `TE_PURE`, and `TE_VARIADIC`. -- Formula parsing is now case insensitive. -- Added support for variadic functions (can accept 1-7 arguments); enabled through the `TE_VARIADIC` flag. - (Refer to the `AVERAGE()` function in `tinyexp.cpp` for an example.) -- Added support for parsing formulas in non-US format (e.g., `pow(2,2; 2)` instead of `pow(2.2, 2)`). Useful for when the program's locale is non-English. - (Refer to [Example 4](Examples.md) for a demonstration.) -- `te_expr` is now a derivable base class. This means that you can derive from `te_expr`, add new fields to that derived class (e.g., arrays, strings, even other classes) - and then use a custom class as an argument to the various function types that accept a `te_expr*` parameter. The function that you connect can then `dynamic_cast<>` - this argument and use its custom fields, thus greatly enhancing the functionality for these types of functions. - (See below for example.) -- Added exception support, where exceptions are thrown for situations like providing invalid separators. Calls to `compile` and `evaluate` should be wrapped in `try`...`catch` blocks. -- Memory management is handled by the `te_parser` class (you no longer need to call `te_free`). Also, replaced `malloc/free` with `new/delete`. -- Stricter type safety; uses `std::variant` (instead of unions) that support `double`, `const double*`, - and 16 specific function signatures (that will work with lambdas or function pointers). - Also uses `std::initializer` lists (instead of various pointer operations). -- Separate enums are now used between `te_expr` and `state`'s types and are more strongly typed. -- Added support for C and C++ style comments (`//` and `/**/`). -- `compile()` and `evaluate()` now accept `std::string_view`s, meaning that these functions can accept either `char*` or `std::string` arguments. -- Added support for `volatile` (refer to [embedded programming](Embedded.md) for details). -- Custom functions and variables can now contain periods in their names. -- Custom functions and variables can now start with an underscore. -- Custom functions and variables can now be removed. -- Added support for custom handlers to resolve unknown variables. -- Added new built-in functions: - - `and`: returns true (i.e., non-zero) if all conditions are true (accepts 1-7 arguments). - - `average`: returns the mean for a range of values (accepts 1-7 arguments). - - `bitlshift`: left shift operator. - Negative shift amount arguments (similar to *Excel*) is supported. - - `bitrshift`: right shift operator. - Negative shift amount arguments (similar to *Excel*) is supported. - - `cot`: returns the cotangent of an angle. - - `combin`: alias for `ncr()`, like the *Excel* function. - - `clamp`: constrains a value to a range. - - `fact`: alias for `fac()`, like the *Excel* function. - - `false`: returns `false` (i.e., `0`) in a boolean expression. - - `if`: if a value is true (i.e., non-zero), then returns the second argument; otherwise, returns the third argument. - - `ifs`: checks up to three conditions, returning the value corresponding to the first met condition. - - `max`: returns the maximum of a range of values (accepts 1-7 arguments). - - `min`: returns the minimum of a range of values (accepts 1-7 arguments). - - `mod`: returns remainder from a division. - - `nan`: returns `NaN` (i.e., Not-a-Number) in a boolean expression. - - `or`: returns true (i.e., non-zero) if any condition is true (accepts 1-7 arguments). - - `not`: returns logical negation of value. - - `permut`: alias for `npr()`, like the *Excel* function. - - `power`: alias for `pow()`, like the *Excel* function. - - `rand`: returns random number between `0` and `1`. - Note that this implementation uses the Mersenne Twister (`mt19937`) to generate random numbers. - - `round`: returns a number, rounded to a given decimal point. - (Decimal point is optional and defaults to `0`.) - Negative number-of-digits arguments (similar to *Excel*) is supported. - - `sign`: returns the sign of a number: `1` if positive, `-1` if negative, `0` if zero. - - `sum`: returns the sum of a list of values (accepts 1-7 arguments). - - `sqr`: returns a number squared. - - `tgamma`: returns gamma function of a specified value. - - `trunc`: returns the integer part of a number. - - `true`: returns `true` (i.e., `1`) in a boolean expression. -- Added new operators: - - `&` logical AND. - - `|` logical OR. - - `=` equal to. - - `==` equal to. - - `<>` not equal to. - - `!=` not equal to. - - `<` less than. - - `<=` less than or equal to. - - `>` greater than. - - `>=` greater than or equal to. - - `<<` left shift operator. - - `>>` right shift operator. - - `**` exponentiation (alias for `^`). -- `round` now supports negative number of digit arguments, similar to *Excel*. - For example, `ROUND(-50.55,-2)` will yield `-100`. -- Custom variables and functions are now stored in a `std::set` - (which can be easily accessed and updated via the new `get_variables_and_functions()/set_variables_and_functions()` functions). -- Added `is_function_used()` and `is_variable_used()` functions to see if a specific function or variable was used in the last parsed formula. -- Added `set_constant()` function to find and update the value of a constant (custom) variable by name. - (In this context, a constant is a variable mapped to a double value in the parser, rather than mapped to a runtime variable.) -- Added `get_constant()` function to return the value of a constant (custom) variable by name. -- Added `TE_FLOAT` preprocessor flag to use `float` instead of `double` for the parser's data type. -- Binary search (i.e., `std::set`) is now used to look up custom variables and functions (small optimization). -- You no longer need to specify the number of arguments for custom functions; it will deduce that for you. -- The position of an error when evaluating an expression is now managed by the `te_parser` class and accessible via `get_last_error_position()`. -- Some parsing errors can provide error messages available via `get_last_error_message()`. -- The position of aforementioned error is now 0-indexed (not 1-indexed); `te_parser::npos` indicates that there was no error. -- Added `success()` function to indicate if the last parse succeeded or not. -- Added `get_result()` function to get result from the last call to `evaluate` or `compile`. -- Now uses `std::numeric_limits` for math constants (instead of macro constants). -- Replaced C-style casts with `static_cast<>`. -- Replaced all macros with `constexpr`s and lambdas. -- Replaced custom binary search used for built-in function searching; `std::set` is used now. -- Now uses `nullptr` (instead of `0`). -- All data fields are now initialized. -- Added [Doxygen](https://github.com/doxygen/doxygen) comments. -- Removed `te_print()` debug function. -- Added `list_available_functions_and_variables()` function to display all available built-in and custom - functions and variables. -- Added `get_expression()` function to get the last formula used. -- Added `[[nodiscard]]` attributes to improve compile-time warnings. -- Added `constexpr` and `noexcept` for C++ optimization. +Please refer [here](TinyExprChanges.md) for a list of changes from the original TinyExpr C library. ## Building diff --git a/TinyExprChanges.md b/TinyExprChanges.md new file mode 100644 index 0000000..8ae9b9b --- /dev/null +++ b/TinyExprChanges.md @@ -0,0 +1,108 @@ +The following are changes from the original TinyExpr C library: + +- Compiles as C++17 code. +- `te_*` functions are now wrapped in a `te_parser` class. +- `te_interp()`, `te_compile()`, and `te_eval()` have been replaced with `te_parser::compile()`, `te_parser::evaluate()`, and `te_parser::set_variables_and_functions()`. + `set_variables_and_functions()` sets your list of custom functions and variables. `compile()` compiles and optimizes an expression. + Finally, `evaluate()` will use the already compiled expression and return its result. + `evaluate()` also has an overload that compiles and evaluates an expression in one call. +- Variable/function types (e.g., `TE_FUNCTION0`) have been removed; types are now deduced by the compiler. The available flags + for variables and functions are now just combinations of `TE_DEFAULT`, `TE_PURE`, and `TE_VARIADIC`. +- Formula parsing is now case insensitive. +- Added support for variadic functions (can accept 1-7 arguments); enabled through the `TE_VARIADIC` flag. + (Refer to the `AVERAGE()` function in `tinyexp.cpp` for an example.) +- Added support for parsing formulas in non-US format (e.g., `pow(2,2; 2)` instead of `pow(2.2, 2)`). Useful for when the program's locale is non-English. + (Refer to [Example 4](Examples.md) for a demonstration.) +- `te_expr` is now a derivable base class. This means that you can derive from `te_expr`, add new fields to that derived class (e.g., arrays, strings, even other classes) + and then use a custom class as an argument to the various function types that accept a `te_expr*` parameter. The function that you connect can then `dynamic_cast<>` + this argument and use its custom fields, thus greatly enhancing the functionality for these types of functions. + (See below for example.) +- Added exception support, where exceptions are thrown for situations like providing invalid separators. Calls to `compile` and `evaluate` should be wrapped in `try`...`catch` blocks. +- Memory management is handled by the `te_parser` class (you no longer need to call `te_free`). Also, replaced `malloc/free` with `new/delete`. +- Stricter type safety; uses `std::variant` (instead of unions) that support `double`, `const double*`, + and 16 specific function signatures (that will work with lambdas or function pointers). + Also uses `std::initializer` lists (instead of various pointer operations). +- Separate enums are now used between `te_expr` and `state`'s types and are more strongly typed. +- Added support for C and C++ style comments (`//` and `/**/`). +- `compile()` and `evaluate()` now accept `std::string_view`s, meaning that these functions can accept either `char*` or `std::string` arguments. +- Added support for `volatile`. +- Custom functions and variables can now contain periods in their names. +- Custom functions and variables can now start with an underscore. +- Custom functions and variables can now be removed. +- Added support for custom handlers to resolve unknown variables. +- Added new built-in functions: + - `and`: returns true (i.e., non-zero) if all conditions are true (accepts 1-7 arguments). + - `average`: returns the mean for a range of values (accepts 1-7 arguments). + - `bitlshift`: left shift operator. + Negative shift amount arguments (similar to *Excel*) is supported. + - `bitrshift`: right shift operator. + Negative shift amount arguments (similar to *Excel*) is supported. + - `cot`: returns the cotangent of an angle. + - `combin`: alias for `ncr()`, like the *Excel* function. + - `clamp`: constrains a value to a range. + - `fact`: alias for `fac()`, like the *Excel* function. + - `false`: returns `false` (i.e., `0`) in a boolean expression. + - `if`: if a value is true (i.e., non-zero), then returns the second argument; otherwise, returns the third argument. + - `ifs`: checks up to three conditions, returning the value corresponding to the first met condition. + - `max`: returns the maximum of a range of values (accepts 1-7 arguments). + - `min`: returns the minimum of a range of values (accepts 1-7 arguments). + - `mod`: returns remainder from a division. + - `nan`: returns `NaN` (i.e., Not-a-Number) in a boolean expression. + - `or`: returns true (i.e., non-zero) if any condition is true (accepts 1-7 arguments). + - `not`: returns logical negation of value. + - `permut`: alias for `npr()`, like the *Excel* function. + - `power`: alias for `pow()`, like the *Excel* function. + - `rand`: returns random number between `0` and `1`. + Note that this implementation uses the Mersenne Twister (`mt19937`) to generate random numbers. + - `round`: returns a number, rounded to a given decimal point. + (Decimal point is optional and defaults to `0`.) + Negative number-of-digits arguments (similar to *Excel*) is supported. + - `sign`: returns the sign of a number: `1` if positive, `-1` if negative, `0` if zero. + - `sum`: returns the sum of a list of values (accepts 1-7 arguments). + - `sqr`: returns a number squared. + - `tgamma`: returns gamma function of a specified value. + - `trunc`: returns the integer part of a number. + - `true`: returns `true` (i.e., `1`) in a boolean expression. +- Added new operators: + - `&` logical AND. + - `|` logical OR. + - `=` equal to. + - `==` equal to. + - `<>` not equal to. + - `!=` not equal to. + - `<` less than. + - `<=` less than or equal to. + - `>` greater than. + - `>=` greater than or equal to. + - `<<` left shift operator. + - `>>` right shift operator. + - `**` exponentiation (alias for `^`). +- `round` now supports negative number of digit arguments, similar to *Excel*. + For example, `ROUND(-50.55,-2)` will yield `-100`. +- Custom variables and functions are now stored in a `std::set` + (which can be easily accessed and updated via the new `get_variables_and_functions()/set_variables_and_functions()` functions). +- Added `is_function_used()` and `is_variable_used()` functions to see if a specific function or variable was used in the last parsed formula. +- Added `set_constant()` function to find and update the value of a constant (custom) variable by name. + (In this context, a constant is a variable mapped to a double value in the parser, rather than mapped to a runtime variable.) +- Added `get_constant()` function to return the value of a constant (custom) variable by name. +- Added `TE_FLOAT` preprocessor flag to use `float` instead of `double` for the parser's data type. +- Binary search (i.e., `std::set`) is now used to look up custom variables and functions (small optimization). +- You no longer need to specify the number of arguments for custom functions; it will deduce that for you. +- The position of an error when evaluating an expression is now managed by the `te_parser` class and accessible via `get_last_error_position()`. +- Some parsing errors can provide error messages available via `get_last_error_message()`. +- The position of aforementioned error is now 0-indexed (not 1-indexed); `te_parser::npos` indicates that there was no error. +- Added `success()` function to indicate if the last parse succeeded or not. +- Added `get_result()` function to get result from the last call to `evaluate` or `compile`. +- Now uses `std::numeric_limits` for math constants (instead of macro constants). +- Replaced C-style casts with `static_cast<>`. +- Replaced all macros with `constexpr`s and lambdas. +- Replaced custom binary search used for built-in function searching; `std::set` is used now. +- Now uses `nullptr` (instead of `0`). +- All data fields are now initialized. +- Added [Doxygen](https://github.com/doxygen/doxygen) comments. +- Removed `te_print()` debug function. +- Added `list_available_functions_and_variables()` function to display all available built-in and custom + functions and variables. +- Added `get_expression()` function to get the last formula used. +- Added `[[nodiscard]]` attributes to improve compile-time warnings. +- Added `constexpr` and `noexcept` for C++ optimization.