diff --git a/CMakeLists.txt b/CMakeLists.txt index 20105156..5450146c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,7 +89,7 @@ set(ENABLE_COVERAGE OFF CACHE BOOL "Enable code coverage") set(ENABLE_ARRAY_INDEX_CHECKING OFF CACHE BOOL "Enable Array index checking") set(SV_LOCAL_VTK_PATH "" CACHE STRING "Path to a local build of VTK.") set(ENABLE_UNIT_TEST OFF CACHE BOOL "Enable Unit Test by Google Test") - +set(SV_USE_SYMENGINE OFF CACHE BOOL "Build with the SymEngine symbolic algebra package") #----------------------------------------------------------------------------- # RPATH handling # No objects built directly with project. Not needed! @@ -145,6 +145,7 @@ ExternalProject_Add(svFSI -DSV_EXTERNALS_USE_TOPLEVEL_DIR:BOOL=ON -DSV_EXTERNALS_TOPLEVEL_DIR:PATH=${SV_EXTERNALS_TOPLEVEL_DIR} -DSV_USE_TRILINOS:BOOL=${SV_USE_TRILINOS} + -DSV_USE_SYMENGINE:BOOL=${SV_USE_SYMENGINE} #-DSV_USE_PETSC:BOOL=${SV_USE_PETSC} -DSV_PETSC_DIR:STRING=${SV_PETSC_DIR} -DENABLE_COVERAGE:BOOL=${ENABLE_COVERAGE} diff --git a/Code/CMake/SimVascularInternals.cmake b/Code/CMake/SimVascularInternals.cmake index 430ee65b..21036f4f 100644 --- a/Code/CMake/SimVascularInternals.cmake +++ b/Code/CMake/SimVascularInternals.cmake @@ -4,6 +4,7 @@ set(SV_LIBS THIRDPARTY_GKLIB_SVFSI THIRDPARTY_TETGEN THIRDPARTY_TINYXML + THIRDPARTY_EXPRTK THIRDPARTY_ZLIB SVFSILS SVFSI_CINTERFACE diff --git a/Code/CMake/SimVascularThirdParty.cmake b/Code/CMake/SimVascularThirdParty.cmake index e693acb1..3e287e8e 100644 --- a/Code/CMake/SimVascularThirdParty.cmake +++ b/Code/CMake/SimVascularThirdParty.cmake @@ -47,5 +47,6 @@ endif() simvascular_third_party(tinyxml) set(TINYXML_LIBRARY ${SV_LIB_THIRDPARTY_TINYXML_NAME}) - - +# EXPRTK +simvascular_third_party(exprtk) +set(EXPRTK_LIBRARY ${SV_LIB_THIRDPARTY_EXPRTK_NAME}) diff --git a/Code/Source/svFSI/CMakeLists.txt b/Code/Source/svFSI/CMakeLists.txt index d67a9882..f819c895 100644 --- a/Code/Source/svFSI/CMakeLists.txt +++ b/Code/Source/svFSI/CMakeLists.txt @@ -29,6 +29,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED True) include_directories(${SV_SOURCE_DIR}/ThirdParty/parmetis_svfsi/simvascular_parmetis_svfsi/ParMETISLib) include_directories(${SV_SOURCE_DIR}/ThirdParty/tetgen/simvascular_tetgen) include_directories(${SV_SOURCE_DIR}/ThirdParty/tinyxml/simvascular_tinyxml) +include_directories(${SV_SOURCE_DIR}/ThirdParty/exprtk/simvascular_exprtk) include_directories(${MPI_C_INCLUDE_PATH}) # Find Trilinos package if requested @@ -124,6 +125,30 @@ else() endif() +# Build with the SymEngine library. +if(SV_USE_SYMENGINE) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR "${CMAKE_BINARY_DIR}/ThirdParty/symengine") + FetchContent_Declare( + symengine + GIT_REPOSITORY https://github.com/symengine/symengine.git + GIT_TAG v0.12.0 + GIT_SHALLOW TRUE + GIT_PROGRESS TRUE + ) + set(FETCHCONTENT_QUIET FALSE) + FetchContent_GetProperties(symengine) + if(NOT symengine_POPULATED) + FetchContent_Populate(symengine) + set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build." FORCE) # Set the build type for SymEngine + #add_subdirectory(${symengine_SOURCE_DIR} ${symengine_BINARY_DIR}) + endif() + message(STATUS "SymEngine fetched from source.") + set(USE_SYMENGINE 1) +else() + set(USE_SYMENGINE 0) +endif() + if(ENABLE_ARRAY_INDEX_CHECKING) ADD_DEFINITIONS(-DENABLE_ARRAY_INDEX_CHECKING) endif() @@ -238,6 +263,8 @@ if(USE_TRILINOS) link_directories(${Trilinos_TPL_LIBRARY_DIRS}) endif() + + simvascular_add_executable(${SV_SVFSI_EXE} SRCS ${CSRCS} DEV_SCRIPT_NAME "mysvfsi" @@ -272,6 +299,10 @@ if(USE_PETSC) target_link_libraries(${SV_SVFSI_EXE} ${PETSC_LIBRARY_DIRS}) endif() +if(USE_SYMENGINE) + target_link_libraries(${SV_SVFSI_EXE} symengine) +endif() + # coverage if(ENABLE_COVERAGE) # set compiler flags diff --git a/Code/ThirdParty/README.md b/Code/ThirdParty/README.md index 7c6e0b7e..55f1a06a 100644 --- a/Code/ThirdParty/README.md +++ b/Code/ThirdParty/README.md @@ -6,6 +6,8 @@ Applications eigen - A header-only application for matrix objects. +exprtk - A header-only application for parsing and evaluating mathematical expressions. + gklib_svfsi - A library used by METIS and ParMETIS applications. metis_svfsi - The METIS mesh partitioning application used by ParMETIS. diff --git a/Code/ThirdParty/exprtk/CMakeLists.txt b/Code/ThirdParty/exprtk/CMakeLists.txt new file mode 100644 index 00000000..b33153ff --- /dev/null +++ b/Code/ThirdParty/exprtk/CMakeLists.txt @@ -0,0 +1,31 @@ +# Copyright (c) Stanford University, The Regents of the University of +# California, and others. +# +# All Rights Reserved. +# +# See Copyright-SimVascular.txt for additional details. +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject +# to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +simvascular_third_party(exprtk) diff --git a/Code/ThirdParty/exprtk/simvascular_exprtk.h.in b/Code/ThirdParty/exprtk/simvascular_exprtk.h.in new file mode 100644 index 00000000..44a6522c --- /dev/null +++ b/Code/ThirdParty/exprtk/simvascular_exprtk.h.in @@ -0,0 +1,43 @@ +/* Copyright (c) Stanford University, The Regents of the University of + * California, and others. + * + * All Rights Reserved. + * + * See Copyright-SimVascular.txt for additional details. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject + * to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __simvascular_exprtk_h +#define __simvascular_exprtk_h + +/* Use the exprtk library configured for SimVascular. */ +#cmakedefine SV_USE_SYSTEM_EXPRTK +#ifdef SV_USE_SYSTEM_EXPRTK +# include +#else +# include +#endif + +#endif diff --git a/Code/ThirdParty/exprtk/simvascular_exprtk/CMakeLists.txt b/Code/ThirdParty/exprtk/simvascular_exprtk/CMakeLists.txt new file mode 100644 index 00000000..c95341fc --- /dev/null +++ b/Code/ThirdParty/exprtk/simvascular_exprtk/CMakeLists.txt @@ -0,0 +1,57 @@ +# Copyright (c) Stanford University, The Regents of the University of +# California, and others. +# +# All Rights Reserved. +# +# See Copyright-SimVascular.txt for additional details. +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject +# to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Set the minimum required version of cmake for a project. +cmake_minimum_required(VERSION 3.10) +project(EXPRTK) + +# source files for exprtk +SET(SRCS exprtk.cpp) +SET(HDRS exprtk.h) + +set(lib ${SV_LIB_THIRDPARTY_EXPRTK_NAME}) +if(SV_USE_THIRDPARTY_SHARED_LIBRARIES) + add_library(${lib} SHARED ${SRCS} ${HDRS}) +else() + add_library(${lib} STATIC ${SRCS} ${HDRS}) +endif() + +if(SV_INSTALL_LIBS) + install(TARGETS ${lib} + RUNTIME DESTINATION ${SV_INSTALL_RUNTIME_DIR} COMPONENT ThirdPartyExecutables + LIBRARY DESTINATION ${SV_INSTALL_LIBRARY_DIR} COMPONENT ThirdPartyLibraries + ARCHIVE DESTINATION ${SV_INSTALL_ARCHIVE_DIR} COMPONENT ThirdPartyLibraries + ) +endif() +if(SV_INSTALL_HEADERS) + install(FILES ${HDRS} + DESTINATION ${SV_INSTALL_INCLUDE_DIR}/thirdparty/exprtk COMPONENT ThirdPartyHeaders + ) +endif() diff --git a/Code/ThirdParty/exprtk/simvascular_exprtk/LICENSE b/Code/ThirdParty/exprtk/simvascular_exprtk/LICENSE new file mode 100644 index 00000000..7fc1af82 --- /dev/null +++ b/Code/ThirdParty/exprtk/simvascular_exprtk/LICENSE @@ -0,0 +1,15 @@ +# +# ************************************************************** +# * C++ Mathematical Expression Toolkit Library * +# * * +# * Author: Arash Partow (1999-2023) * +# * URL: https://www.partow.net/programming/exprtk/index.html * +# * * +# * Copyright notice: * +# * Free use of the Mathematical Expression Toolkit Library is * +# * permitted under the guidelines and in accordance with the * +# * most current version of the MIT License. * +# * http://www.opensource.org/licenses/MIT * +# * * +# ************************************************************** +# \ No newline at end of file diff --git a/Code/ThirdParty/exprtk/simvascular_exprtk/exprtk.cpp b/Code/ThirdParty/exprtk/simvascular_exprtk/exprtk.cpp new file mode 100644 index 00000000..6756e4f0 --- /dev/null +++ b/Code/ThirdParty/exprtk/simvascular_exprtk/exprtk.cpp @@ -0,0 +1 @@ +// dummy file \ No newline at end of file diff --git a/Code/ThirdParty/exprtk/simvascular_exprtk/exprtk.h b/Code/ThirdParty/exprtk/simvascular_exprtk/exprtk.h new file mode 100644 index 00000000..aba56abd --- /dev/null +++ b/Code/ThirdParty/exprtk/simvascular_exprtk/exprtk.h @@ -0,0 +1,40983 @@ +/* + ****************************************************************** + * C++ Mathematical Expression Toolkit Library * + * * + * Author: Arash Partow (1999-2023) * + * URL: https://www.partow.net/programming/exprtk/index.html * + * * + * Copyright notice: * + * Free use of the C++ Mathematical Expression Toolkit Library is * + * permitted under the guidelines and in accordance with the most * + * current version of the MIT License. * + * https://www.opensource.org/licenses/MIT * + * * + * Example expressions: * + * (00) (y + x / y) * (x - y / x) * + * (01) (x^2 / sin(2 * pi / y)) - x / 2 * + * (02) sqrt(1 - (x^2)) * + * (03) 1 - sin(2 * x) + cos(pi / y) * + * (04) a * exp(2 * t) + c * + * (05) if(((x + 2) == 3) and ((y + 5) <= 9),1 + w, 2 / z) * + * (06) (avg(x,y) <= x + y ? x - y : x * y) + 2 * pi / x * + * (07) z := x + sin(2 * pi / y) * + * (08) u := 2 * (pi * z) / (w := x + cos(y / pi)) * + * (09) clamp(-1,sin(2 * pi * x) + cos(y / 2 * pi),+1) * + * (10) inrange(-2,m,+2) == if(({-2 <= m} and [m <= +2]),1,0) * + * (11) (2sin(x)cos(2y)7 + 1) == (2 * sin(x) * cos(2*y) * 7 + 1) * + * (12) (x ilike 's*ri?g') and [y < (3 z^7 + w)] * + * * + ****************************************************************** +*/ + + +#ifndef INCLUDE_EXPRTK_HPP +#define INCLUDE_EXPRTK_HPP + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace exprtk +{ +#ifdef exprtk_enable_debugging +#define exprtk_debug(params) printf params +#else +#define exprtk_debug(params) (void)0 +#endif + +#define exprtk_error_location \ + "exprtk.hpp:" + details::to_str(__LINE__) \ + +#if defined(__GNUC__) && (__GNUC__ >= 7) + +#define exprtk_disable_fallthrough_begin \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") \ + +#define exprtk_disable_fallthrough_end \ + _Pragma ("GCC diagnostic pop") \ + +#else +#define exprtk_disable_fallthrough_begin (void)0; +#define exprtk_disable_fallthrough_end (void)0; +#endif + +#if __cplusplus >= 201103L +#define exprtk_override override +#define exprtk_final final +#define exprtk_delete = delete +#else +#define exprtk_override +#define exprtk_final +#define exprtk_delete +#endif + +namespace details +{ +typedef char char_t; +typedef char_t* char_ptr; +typedef char_t const* char_cptr; +typedef unsigned char uchar_t; +typedef uchar_t* uchar_ptr; +typedef uchar_t const* uchar_cptr; +typedef unsigned long long int _uint64_t; +typedef long long int _int64_t; + +inline bool is_whitespace(const char_t c) +{ +return (' ' == c) || ('\n' == c) || +('\r' == c) || ('\t' == c) || +('\b' == c) || ('\v' == c) || +('\f' == c) ; +} + +inline bool is_operator_char(const char_t c) +{ +return ('+' == c) || ('-' == c) || +('*' == c) || ('/' == c) || +('^' == c) || ('<' == c) || +('>' == c) || ('=' == c) || +(',' == c) || ('!' == c) || +('(' == c) || (')' == c) || +('[' == c) || (']' == c) || +('{' == c) || ('}' == c) || +('%' == c) || (':' == c) || +('?' == c) || ('&' == c) || +('|' == c) || (';' == c) ; +} + +inline bool is_letter(const char_t c) +{ +return (('a' <= c) && (c <= 'z')) || +(('A' <= c) && (c <= 'Z')) ; +} + +inline bool is_digit(const char_t c) +{ +return ('0' <= c) && (c <= '9'); +} + +inline bool is_letter_or_digit(const char_t c) +{ +return is_letter(c) || is_digit(c); +} + +inline bool is_left_bracket(const char_t c) +{ +return ('(' == c) || ('[' == c) || ('{' == c); +} + +inline bool is_right_bracket(const char_t c) +{ +return (')' == c) || (']' == c) || ('}' == c); +} + +inline bool is_bracket(const char_t c) +{ +return is_left_bracket(c) || is_right_bracket(c); +} + +inline bool is_sign(const char_t c) +{ +return ('+' == c) || ('-' == c); +} + +inline bool is_invalid(const char_t c) +{ +return !is_whitespace (c) && +!is_operator_char(c) && +!is_letter (c) && +!is_digit (c) && +('.' != c) && +('_' != c) && +('$' != c) && +('~' != c) && +('\'' != c); +} + +inline bool is_valid_string_char(const char_t c) +{ +return std::isprint(static_cast(c)) || +is_whitespace(c); +} + +#ifndef exprtk_disable_caseinsensitivity +inline void case_normalise(std::string& s) +{ +for (std::size_t i = 0; i < s.size(); ++i) +{ +s[i] = static_cast(std::tolower(s[i])); +} +} + +inline bool imatch(const char_t c1, const char_t c2) +{ +return std::tolower(c1) == std::tolower(c2); +} + +inline bool imatch(const std::string& s1, const std::string& s2) +{ +if (s1.size() == s2.size()) +{ +for (std::size_t i = 0; i < s1.size(); ++i) +{ +if (std::tolower(s1[i]) != std::tolower(s2[i])) +{ +return false; +} +} + +return true; +} + +return false; +} + +struct ilesscompare +{ +inline bool operator() (const std::string& s1, const std::string& s2) const +{ +const std::size_t length = std::min(s1.size(),s2.size()); + +for (std::size_t i = 0; i < length; ++i) +{ +const char_t c1 = static_cast(std::tolower(s1[i])); +const char_t c2 = static_cast(std::tolower(s2[i])); + +if (c1 > c2) +return false; +else if (c1 < c2) +return true; +} + +return s1.size() < s2.size(); +} +}; + +#else +inline void case_normalise(std::string&) +{} + +inline bool imatch(const char_t c1, const char_t c2) +{ +return c1 == c2; +} + +inline bool imatch(const std::string& s1, const std::string& s2) +{ +return s1 == s2; +} + +struct ilesscompare +{ +inline bool operator() (const std::string& s1, const std::string& s2) const +{ +return s1 < s2; +} +}; +#endif + +inline bool is_valid_sf_symbol(const std::string& symbol) +{ +// Special function: $f12 or $F34 +return (4 == symbol.size()) && +('$' == symbol[0]) && +imatch('f',symbol[1]) && +is_digit(symbol[2]) && +is_digit(symbol[3]); +} + +inline const char_t& front(const std::string& s) +{ +return s[0]; +} + +inline const char_t& back(const std::string& s) +{ +return s[s.size() - 1]; +} + +inline std::string to_str(int i) +{ +if (0 == i) +return std::string("0"); + +std::string result; + +const int sign = (i < 0) ? -1 : 1; + +for ( ; i; i /= 10) +{ +result += '0' + static_cast(sign * (i % 10)); +} + +if (sign < 0) +{ +result += '-'; +} + +std::reverse(result.begin(), result.end()); + +return result; +} + +inline std::string to_str(std::size_t i) +{ +return to_str(static_cast(i)); +} + +inline bool is_hex_digit(const uchar_t digit) +{ +return (('0' <= digit) && (digit <= '9')) || +(('A' <= digit) && (digit <= 'F')) || +(('a' <= digit) && (digit <= 'f')) ; +} + +inline uchar_t hex_to_bin(uchar_t h) +{ +if (('0' <= h) && (h <= '9')) +return (h - '0'); +else +return static_cast(std::toupper(h) - 'A'); +} + +template +inline bool parse_hex(Iterator& itr, Iterator end, +char_t& result) +{ +if ( +(end == (itr )) || +(end == (itr + 1)) || +(end == (itr + 2)) || +(end == (itr + 3)) || +('0' != *(itr )) || +('X' != std::toupper(*(itr + 1))) || +(!is_hex_digit(*(itr + 2))) || +(!is_hex_digit(*(itr + 3))) +) +{ +return false; +} + +result = hex_to_bin(static_cast(*(itr + 2))) << 4 | +hex_to_bin(static_cast(*(itr + 3))) ; + +return true; +} + +inline bool cleanup_escapes(std::string& s) +{ +typedef std::string::iterator str_itr_t; + +str_itr_t itr1 = s.begin(); +str_itr_t itr2 = s.begin(); +str_itr_t end = s.end (); + +std::size_t removal_count = 0; + +while (end != itr1) +{ +if ('\\' == (*itr1)) +{ +if (end == ++itr1) +{ +return false; +} +else if (parse_hex(itr1, end, *itr2)) +{ +itr1+= 4; +itr2+= 1; +removal_count +=4; +} +else if ('a' == (*itr1)) { (*itr2++) = '\a'; ++itr1; ++removal_count; } +else if ('b' == (*itr1)) { (*itr2++) = '\b'; ++itr1; ++removal_count; } +else if ('f' == (*itr1)) { (*itr2++) = '\f'; ++itr1; ++removal_count; } +else if ('n' == (*itr1)) { (*itr2++) = '\n'; ++itr1; ++removal_count; } +else if ('r' == (*itr1)) { (*itr2++) = '\r'; ++itr1; ++removal_count; } +else if ('t' == (*itr1)) { (*itr2++) = '\t'; ++itr1; ++removal_count; } +else if ('v' == (*itr1)) { (*itr2++) = '\v'; ++itr1; ++removal_count; } +else if ('0' == (*itr1)) { (*itr2++) = '\0'; ++itr1; ++removal_count; } +else +{ +(*itr2++) = (*itr1++); +++removal_count; +} +continue; +} +else +(*itr2++) = (*itr1++); +} + +if ((removal_count > s.size()) || (0 == removal_count)) +return false; + +s.resize(s.size() - removal_count); + +return true; +} + +class build_string +{ +public: + +explicit build_string(const std::size_t& initial_size = 64) +{ +data_.reserve(initial_size); +} + +inline build_string& operator << (const std::string& s) +{ +data_ += s; +return (*this); +} + +inline build_string& operator << (char_cptr s) +{ +data_ += std::string(s); +return (*this); +} + +inline operator std::string () const +{ +return data_; +} + +inline std::string as_string() const +{ +return data_; +} + +private: + +std::string data_; +}; + +static const std::string reserved_words[] = +{ +"break", "case", "continue", "default", "false", "for", +"if", "else", "ilike", "in", "like", "and", "nand", "nor", +"not", "null", "or", "repeat", "return", "shl", "shr", +"swap", "switch", "true", "until", "var", "while", "xnor", +"xor", "&", "|" +}; + +static const std::size_t reserved_words_size = sizeof(reserved_words) / sizeof(std::string); + +static const std::string reserved_symbols[] = +{ +"abs", "acos", "acosh", "and", "asin", "asinh", "atan", +"atanh", "atan2", "avg", "break", "case", "ceil", "clamp", +"continue", "cos", "cosh", "cot", "csc", "default", +"deg2grad", "deg2rad", "equal", "erf", "erfc", "exp", +"expm1", "false", "floor", "for", "frac", "grad2deg", +"hypot", "iclamp", "if", "else", "ilike", "in", "inrange", +"like", "log", "log10", "log2", "logn", "log1p", "mand", +"max", "min", "mod", "mor", "mul", "ncdf", "nand", "nor", +"not", "not_equal", "null", "or", "pow", "rad2deg", +"repeat", "return", "root", "round", "roundn", "sec", "sgn", +"shl", "shr", "sin", "sinc", "sinh", "sqrt", "sum", "swap", +"switch", "tan", "tanh", "true", "trunc", "until", "var", +"while", "xnor", "xor", "&", "|" +}; + +static const std::size_t reserved_symbols_size = sizeof(reserved_symbols) / sizeof(std::string); + +static const std::string base_function_list[] = +{ +"abs", "acos", "acosh", "asin", "asinh", "atan", "atanh", +"atan2", "avg", "ceil", "clamp", "cos", "cosh", "cot", +"csc", "equal", "erf", "erfc", "exp", "expm1", "floor", +"frac", "hypot", "iclamp", "like", "log", "log10", "log2", +"logn", "log1p", "mand", "max", "min", "mod", "mor", "mul", +"ncdf", "pow", "root", "round", "roundn", "sec", "sgn", +"sin", "sinc", "sinh", "sqrt", "sum", "swap", "tan", "tanh", +"trunc", "not_equal", "inrange", "deg2grad", "deg2rad", +"rad2deg", "grad2deg" +}; + +static const std::size_t base_function_list_size = sizeof(base_function_list) / sizeof(std::string); + +static const std::string logic_ops_list[] = +{ +"and", "nand", "nor", "not", "or", "xnor", "xor", "&", "|" +}; + +static const std::size_t logic_ops_list_size = sizeof(logic_ops_list) / sizeof(std::string); + +static const std::string cntrl_struct_list[] = +{ +"if", "switch", "for", "while", "repeat", "return" +}; + +static const std::size_t cntrl_struct_list_size = sizeof(cntrl_struct_list) / sizeof(std::string); + +static const std::string arithmetic_ops_list[] = +{ +"+", "-", "*", "/", "%", "^" +}; + +static const std::size_t arithmetic_ops_list_size = sizeof(arithmetic_ops_list) / sizeof(std::string); + +static const std::string assignment_ops_list[] = +{ +":=", "+=", "-=", +"*=", "/=", "%=" +}; + +static const std::size_t assignment_ops_list_size = sizeof(assignment_ops_list) / sizeof(std::string); + +static const std::string inequality_ops_list[] = +{ +"<", "<=", "==", +"=", "!=", "<>", +">=", ">" +}; + +static const std::size_t inequality_ops_list_size = sizeof(inequality_ops_list) / sizeof(std::string); + +inline bool is_reserved_word(const std::string& symbol) +{ +for (std::size_t i = 0; i < reserved_words_size; ++i) +{ +if (imatch(symbol, reserved_words[i])) +{ +return true; +} +} + +return false; +} + +inline bool is_reserved_symbol(const std::string& symbol) +{ +for (std::size_t i = 0; i < reserved_symbols_size; ++i) +{ +if (imatch(symbol, reserved_symbols[i])) +{ +return true; +} +} + +return false; +} + +inline bool is_base_function(const std::string& function_name) +{ +for (std::size_t i = 0; i < base_function_list_size; ++i) +{ +if (imatch(function_name, base_function_list[i])) +{ +return true; +} +} + +return false; +} + +inline bool is_control_struct(const std::string& cntrl_strct) +{ +for (std::size_t i = 0; i < cntrl_struct_list_size; ++i) +{ +if (imatch(cntrl_strct, cntrl_struct_list[i])) +{ +return true; +} +} + +return false; +} + +inline bool is_logic_opr(const std::string& lgc_opr) +{ +for (std::size_t i = 0; i < logic_ops_list_size; ++i) +{ +if (imatch(lgc_opr, logic_ops_list[i])) +{ +return true; +} +} + +return false; +} + +struct cs_match +{ +static inline bool cmp(const char_t c0, const char_t c1) +{ +return (c0 == c1); +} +}; + +struct cis_match +{ +static inline bool cmp(const char_t c0, const char_t c1) +{ +return (std::tolower(c0) == std::tolower(c1)); +} +}; + +template +inline bool match_impl(const Iterator pattern_begin, +const Iterator pattern_end , +const Iterator data_begin , +const Iterator data_end , +const typename std::iterator_traits::value_type& zero_or_more, +const typename std::iterator_traits::value_type& exactly_one ) +{ +typedef typename std::iterator_traits::value_type type; + +const Iterator null_itr(0); + +Iterator p_itr = pattern_begin; +Iterator d_itr = data_begin; +Iterator np_itr = null_itr; +Iterator nd_itr = null_itr; + +for ( ; ; ) +{ +if (p_itr != pattern_end) +{ +const type c = *(p_itr); + +if ((data_end != d_itr) && (Compare::cmp(c,*(d_itr)) || (exactly_one == c))) +{ +++d_itr; +++p_itr; +continue; +} +else if (zero_or_more == c) +{ +while ((pattern_end != p_itr) && (zero_or_more == *(p_itr))) +{ +++p_itr; +} + +const type d = *(p_itr); + +while ((data_end != d_itr) && !(Compare::cmp(d,*(d_itr)) || (exactly_one == d))) +{ +++d_itr; +} + +// set backtrack iterators +np_itr = p_itr - 1; +nd_itr = d_itr + 1; + +continue; +} +} +else if (data_end == d_itr) +return true; + +if ((data_end == d_itr) || (null_itr == nd_itr)) +return false; + +p_itr = np_itr; +d_itr = nd_itr; +} + +return true; +} + +inline bool wc_match(const std::string& wild_card, +const std::string& str) +{ +return match_impl( +wild_card.data(), +wild_card.data() + wild_card.size(), +str.data(), +str.data() + str.size(), +'*', '?'); +} + +inline bool wc_imatch(const std::string& wild_card, +const std::string& str) +{ +return match_impl( +wild_card.data(), +wild_card.data() + wild_card.size(), +str.data(), +str.data() + str.size(), +'*', '?'); +} + +inline bool sequence_match(const std::string& pattern, +const std::string& str, +std::size_t& diff_index, +char_t& diff_value) +{ +if (str.empty()) +{ +return ("Z" == pattern); +} +else if ('*' == pattern[0]) +return false; + +typedef std::string::const_iterator itr_t; + +itr_t p_itr = pattern.begin(); +itr_t s_itr = str .begin(); + +const itr_t p_end = pattern.end(); +const itr_t s_end = str .end(); + +while ((s_end != s_itr) && (p_end != p_itr)) +{ +if ('*' == (*p_itr)) +{ +const char_t target = static_cast(std::toupper(*(p_itr - 1))); + +if ('*' == target) +{ +diff_index = static_cast(std::distance(str.begin(),s_itr)); +diff_value = static_cast(std::toupper(*p_itr)); + +return false; +} +else +++p_itr; + +while (s_itr != s_end) +{ +if (target != std::toupper(*s_itr)) +break; +else +++s_itr; +} + +continue; +} +else if ( +('?' != *p_itr) && +std::toupper(*p_itr) != std::toupper(*s_itr) +) +{ +diff_index = static_cast(std::distance(str.begin(),s_itr)); +diff_value = static_cast(std::toupper(*p_itr)); + +return false; +} + +++p_itr; +++s_itr; +} + +return ( +(s_end == s_itr) && +( +(p_end == p_itr) || +('*' == *p_itr) +) +); +} + +static const double pow10[] = { +1.0, +1.0E+001, 1.0E+002, 1.0E+003, 1.0E+004, +1.0E+005, 1.0E+006, 1.0E+007, 1.0E+008, +1.0E+009, 1.0E+010, 1.0E+011, 1.0E+012, +1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016 +}; + +static const std::size_t pow10_size = sizeof(pow10) / sizeof(double); + +namespace numeric +{ +namespace constant +{ +static const double e = 2.71828182845904523536028747135266249775724709369996; +static const double pi = 3.14159265358979323846264338327950288419716939937510; +static const double pi_2 = 1.57079632679489661923132169163975144209858469968755; +static const double pi_4 = 0.78539816339744830961566084581987572104929234984378; +static const double pi_180 = 0.01745329251994329576923690768488612713442871888542; +static const double _1_pi = 0.31830988618379067153776752674502872406891929148091; +static const double _2_pi = 0.63661977236758134307553505349005744813783858296183; +static const double _180_pi = 57.29577951308232087679815481410517033240547246656443; +static const double log2 = 0.69314718055994530941723212145817656807550013436026; +static const double sqrt2 = 1.41421356237309504880168872420969807856967187537695; +} + +namespace details +{ +struct unknown_type_tag { unknown_type_tag() {} }; +struct real_type_tag { real_type_tag () {} }; +struct int_type_tag { int_type_tag () {} }; + +template +struct number_type +{ +typedef unknown_type_tag type; +number_type() {} +}; + +#define exprtk_register_real_type_tag(T) \ + template <> struct number_type \ + { typedef real_type_tag type; number_type() {} }; \ + +#define exprtk_register_int_type_tag(T) \ + template <> struct number_type \ + { typedef int_type_tag type; number_type() {} }; \ + +exprtk_register_real_type_tag(double ) +exprtk_register_real_type_tag(long double) +exprtk_register_real_type_tag(float ) + +exprtk_register_int_type_tag(short ) +exprtk_register_int_type_tag(int ) +exprtk_register_int_type_tag(_int64_t ) +exprtk_register_int_type_tag(unsigned short) +exprtk_register_int_type_tag(unsigned int ) +exprtk_register_int_type_tag(_uint64_t ) + +#undef exprtk_register_real_type_tag +#undef exprtk_register_int_type_tag + +template +struct epsilon_type {}; + +#define exprtk_define_epsilon_type(Type, Epsilon) \ + template <> struct epsilon_type \ + { \ + static inline Type value() \ + { \ + const Type epsilon = static_cast(Epsilon); \ + return epsilon; \ + } \ + }; \ + +exprtk_define_epsilon_type(float , 0.00000100000f) +exprtk_define_epsilon_type(double , 0.000000000100) +exprtk_define_epsilon_type(long double, 0.000000000001) + +#undef exprtk_define_epsilon_type + +template +inline bool is_nan_impl(const T v, real_type_tag) +{ +return std::not_equal_to()(v,v); +} + +template +inline int to_int32_impl(const T v, real_type_tag) +{ +return static_cast(v); +} + +template +inline _int64_t to_int64_impl(const T v, real_type_tag) +{ +return static_cast<_int64_t>(v); +} + +template +inline bool is_true_impl(const T v) +{ +return std::not_equal_to()(T(0),v); +} + +template +inline bool is_false_impl(const T v) +{ +return std::equal_to()(T(0),v); +} + +template +inline T abs_impl(const T v, real_type_tag) +{ +return ((v < T(0)) ? -v : v); +} + +template +inline T min_impl(const T v0, const T v1, real_type_tag) +{ +return std::min(v0,v1); +} + +template +inline T max_impl(const T v0, const T v1, real_type_tag) +{ +return std::max(v0,v1); +} + +template +inline T equal_impl(const T v0, const T v1, real_type_tag) +{ +const T epsilon = epsilon_type::value(); +return (abs_impl(v0 - v1,real_type_tag()) <= (std::max(T(1),std::max(abs_impl(v0,real_type_tag()),abs_impl(v1,real_type_tag()))) * epsilon)) ? T(1) : T(0); +} + +inline float equal_impl(const float v0, const float v1, real_type_tag) +{ +const float epsilon = epsilon_type::value(); +return (abs_impl(v0 - v1,real_type_tag()) <= (std::max(1.0f,std::max(abs_impl(v0,real_type_tag()),abs_impl(v1,real_type_tag()))) * epsilon)) ? 1.0f : 0.0f; +} + +template +inline T equal_impl(const T v0, const T v1, int_type_tag) +{ +return (v0 == v1) ? 1 : 0; +} + +template +inline T expm1_impl(const T v, real_type_tag) +{ +// return std::expm1(v); +if (abs_impl(v,real_type_tag()) < T(0.00001)) +return v + (T(0.5) * v * v); +else +return std::exp(v) - T(1); +} + +template +inline T expm1_impl(const T v, int_type_tag) +{ +return T(std::exp(v)) - T(1); +} + +template +inline T nequal_impl(const T v0, const T v1, real_type_tag) +{ +typedef real_type_tag rtg; +const T epsilon = epsilon_type::value(); +return (abs_impl(v0 - v1,rtg()) > (std::max(T(1),std::max(abs_impl(v0,rtg()),abs_impl(v1,rtg()))) * epsilon)) ? T(1) : T(0); +} + +inline float nequal_impl(const float v0, const float v1, real_type_tag) +{ +typedef real_type_tag rtg; +const float epsilon = epsilon_type::value(); +return (abs_impl(v0 - v1,rtg()) > (std::max(1.0f,std::max(abs_impl(v0,rtg()),abs_impl(v1,rtg()))) * epsilon)) ? 1.0f : 0.0f; +} + +template +inline T nequal_impl(const T v0, const T v1, int_type_tag) +{ +return (v0 != v1) ? 1 : 0; +} + +template +inline T modulus_impl(const T v0, const T v1, real_type_tag) +{ +return std::fmod(v0,v1); +} + +template +inline T modulus_impl(const T v0, const T v1, int_type_tag) +{ +return v0 % v1; +} + +template +inline T pow_impl(const T v0, const T v1, real_type_tag) +{ +return std::pow(v0,v1); +} + +template +inline T pow_impl(const T v0, const T v1, int_type_tag) +{ +return std::pow(static_cast(v0),static_cast(v1)); +} + +template +inline T logn_impl(const T v0, const T v1, real_type_tag) +{ +return std::log(v0) / std::log(v1); +} + +template +inline T logn_impl(const T v0, const T v1, int_type_tag) +{ +return static_cast(logn_impl(static_cast(v0),static_cast(v1),real_type_tag())); +} + +template +inline T log1p_impl(const T v, real_type_tag) +{ +if (v > T(-1)) +{ +if (abs_impl(v,real_type_tag()) > T(0.0001)) +{ +return std::log(T(1) + v); +} +else +return (T(-0.5) * v + T(1)) * v; +} +else +return std::numeric_limits::quiet_NaN(); +} + +template +inline T log1p_impl(const T v, int_type_tag) +{ +if (v > T(-1)) +{ +return std::log(T(1) + v); +} +else +return std::numeric_limits::quiet_NaN(); +} + +template +inline T root_impl(const T v0, const T v1, real_type_tag) +{ +if (v1 < T(0)) +return std::numeric_limits::quiet_NaN(); + +const std::size_t n = static_cast(v1); + +if ((v0 < T(0)) && (0 == (n % 2))) +return std::numeric_limits::quiet_NaN(); + +return std::pow(v0, T(1) / n); +} + +template +inline T root_impl(const T v0, const T v1, int_type_tag) +{ +return root_impl(static_cast(v0),static_cast(v1),real_type_tag()); +} + +template +inline T round_impl(const T v, real_type_tag) +{ +return ((v < T(0)) ? std::ceil(v - T(0.5)) : std::floor(v + T(0.5))); +} + +template +inline T roundn_impl(const T v0, const T v1, real_type_tag) +{ +const int index = std::max(0, std::min(pow10_size - 1, static_cast(std::floor(v1)))); +const T p10 = T(pow10[index]); + +if (v0 < T(0)) +return T(std::ceil ((v0 * p10) - T(0.5)) / p10); +else +return T(std::floor((v0 * p10) + T(0.5)) / p10); +} + +template +inline T roundn_impl(const T v0, const T, int_type_tag) +{ +return v0; +} + +template +inline T hypot_impl(const T v0, const T v1, real_type_tag) +{ +return std::sqrt((v0 * v0) + (v1 * v1)); +} + +template +inline T hypot_impl(const T v0, const T v1, int_type_tag) +{ +return static_cast(std::sqrt(static_cast((v0 * v0) + (v1 * v1)))); +} + +template +inline T atan2_impl(const T v0, const T v1, real_type_tag) +{ +return std::atan2(v0,v1); +} + +template +inline T atan2_impl(const T, const T, int_type_tag) +{ +return 0; +} + +template +inline T shr_impl(const T v0, const T v1, real_type_tag) +{ +return v0 * (T(1) / std::pow(T(2),static_cast(static_cast(v1)))); +} + +template +inline T shr_impl(const T v0, const T v1, int_type_tag) +{ +return v0 >> v1; +} + +template +inline T shl_impl(const T v0, const T v1, real_type_tag) +{ +return v0 * std::pow(T(2),static_cast(static_cast(v1))); +} + +template +inline T shl_impl(const T v0, const T v1, int_type_tag) +{ +return v0 << v1; +} + +template +inline T sgn_impl(const T v, real_type_tag) +{ +if (v > T(0)) return T(+1); +else if (v < T(0)) return T(-1); +else return T( 0); +} + +template +inline T sgn_impl(const T v, int_type_tag) +{ +if (v > T(0)) return T(+1); +else if (v < T(0)) return T(-1); +else return T( 0); +} + +template +inline T and_impl(const T v0, const T v1, real_type_tag) +{ +return (is_true_impl(v0) && is_true_impl(v1)) ? T(1) : T(0); +} + +template +inline T and_impl(const T v0, const T v1, int_type_tag) +{ +return v0 && v1; +} + +template +inline T nand_impl(const T v0, const T v1, real_type_tag) +{ +return (is_false_impl(v0) || is_false_impl(v1)) ? T(1) : T(0); +} + +template +inline T nand_impl(const T v0, const T v1, int_type_tag) +{ +return !(v0 && v1); +} + +template +inline T or_impl(const T v0, const T v1, real_type_tag) +{ +return (is_true_impl(v0) || is_true_impl(v1)) ? T(1) : T(0); +} + +template +inline T or_impl(const T v0, const T v1, int_type_tag) +{ +return (v0 || v1); +} + +template +inline T nor_impl(const T v0, const T v1, real_type_tag) +{ +return (is_false_impl(v0) && is_false_impl(v1)) ? T(1) : T(0); +} + +template +inline T nor_impl(const T v0, const T v1, int_type_tag) +{ +return !(v0 || v1); +} + +template +inline T xor_impl(const T v0, const T v1, real_type_tag) +{ +return (is_false_impl(v0) != is_false_impl(v1)) ? T(1) : T(0); +} + +template +inline T xor_impl(const T v0, const T v1, int_type_tag) +{ +return v0 ^ v1; +} + +template +inline T xnor_impl(const T v0, const T v1, real_type_tag) +{ +const bool v0_true = is_true_impl(v0); +const bool v1_true = is_true_impl(v1); + +if ((v0_true && v1_true) || (!v0_true && !v1_true)) +return T(1); +else +return T(0); +} + +template +inline T xnor_impl(const T v0, const T v1, int_type_tag) +{ +const bool v0_true = is_true_impl(v0); +const bool v1_true = is_true_impl(v1); + +if ((v0_true && v1_true) || (!v0_true && !v1_true)) +return T(1); +else +return T(0); +} + +#if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || !defined(_MSC_VER) +#define exprtk_define_erf(TT, impl) \ + inline TT erf_impl(const TT v) { return impl(v); } \ + +exprtk_define_erf( float,::erff) +exprtk_define_erf( double,::erf ) +exprtk_define_erf(long double,::erfl) +#undef exprtk_define_erf +#endif + +template +inline T erf_impl(const T v, real_type_tag) +{ +#if defined(_MSC_VER) && (_MSC_VER < 1900) +// Credits: Abramowitz & Stegun Equations 7.1.25-28 +static const T c[] = { +T( 1.26551223), T(1.00002368), +T( 0.37409196), T(0.09678418), +T(-0.18628806), T(0.27886807), +T(-1.13520398), T(1.48851587), +T(-0.82215223), T(0.17087277) +}; + +const T t = T(1) / (T(1) + T(0.5) * abs_impl(v,real_type_tag())); + +const T result = T(1) - t * std::exp((-v * v) - +c[0] + t * (c[1] + t * +(c[2] + t * (c[3] + t * +(c[4] + t * (c[5] + t * +(c[6] + t * (c[7] + t * +(c[8] + t * (c[9])))))))))); + +return (v >= T(0)) ? result : -result; +#else +return erf_impl(v); +#endif +} + +template +inline T erf_impl(const T v, int_type_tag) +{ +return erf_impl(static_cast(v),real_type_tag()); +} + +#if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || !defined(_MSC_VER) +#define exprtk_define_erfc(TT, impl) \ + inline TT erfc_impl(const TT v) { return impl(v); } \ + +exprtk_define_erfc(float ,::erfcf) +exprtk_define_erfc(double ,::erfc ) +exprtk_define_erfc(long double,::erfcl) +#undef exprtk_define_erfc +#endif + +template +inline T erfc_impl(const T v, real_type_tag) +{ +#if defined(_MSC_VER) && (_MSC_VER < 1900) +return T(1) - erf_impl(v,real_type_tag()); +#else +return erfc_impl(v); +#endif +} + +template +inline T erfc_impl(const T v, int_type_tag) +{ +return erfc_impl(static_cast(v),real_type_tag()); +} + +template +inline T ncdf_impl(const T v, real_type_tag) +{ +const T cnd = T(0.5) * (T(1) + +erf_impl(abs_impl(v,real_type_tag()) / +T(numeric::constant::sqrt2),real_type_tag())); +return (v < T(0)) ? (T(1) - cnd) : cnd; +} + +template +inline T ncdf_impl(const T v, int_type_tag) +{ +return ncdf_impl(static_cast(v),real_type_tag()); +} + +template +inline T sinc_impl(const T v, real_type_tag) +{ +if (std::abs(v) >= std::numeric_limits::epsilon()) +return(std::sin(v) / v); +else +return T(1); +} + +template +inline T sinc_impl(const T v, int_type_tag) +{ +return sinc_impl(static_cast(v),real_type_tag()); +} + +template inline T acos_impl(const T v, real_type_tag) { return std::acos (v); } +template inline T acosh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) - T(1))); } +template inline T asin_impl(const T v, real_type_tag) { return std::asin (v); } +template inline T asinh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) + T(1))); } +template inline T atan_impl(const T v, real_type_tag) { return std::atan (v); } +template inline T atanh_impl(const T v, real_type_tag) { return (std::log(T(1) + v) - std::log(T(1) - v)) / T(2); } +template inline T ceil_impl(const T v, real_type_tag) { return std::ceil (v); } +template inline T cos_impl(const T v, real_type_tag) { return std::cos (v); } +template inline T cosh_impl(const T v, real_type_tag) { return std::cosh (v); } +template inline T exp_impl(const T v, real_type_tag) { return std::exp (v); } +template inline T floor_impl(const T v, real_type_tag) { return std::floor(v); } +template inline T log_impl(const T v, real_type_tag) { return std::log (v); } +template inline T log10_impl(const T v, real_type_tag) { return std::log10(v); } +template inline T log2_impl(const T v, real_type_tag) { return std::log(v)/T(numeric::constant::log2); } +template inline T neg_impl(const T v, real_type_tag) { return -v; } +template inline T pos_impl(const T v, real_type_tag) { return +v; } +template inline T sin_impl(const T v, real_type_tag) { return std::sin (v); } +template inline T sinh_impl(const T v, real_type_tag) { return std::sinh (v); } +template inline T sqrt_impl(const T v, real_type_tag) { return std::sqrt (v); } +template inline T tan_impl(const T v, real_type_tag) { return std::tan (v); } +template inline T tanh_impl(const T v, real_type_tag) { return std::tanh (v); } +template inline T cot_impl(const T v, real_type_tag) { return T(1) / std::tan(v); } +template inline T sec_impl(const T v, real_type_tag) { return T(1) / std::cos(v); } +template inline T csc_impl(const T v, real_type_tag) { return T(1) / std::sin(v); } +template inline T r2d_impl(const T v, real_type_tag) { return (v * T(numeric::constant::_180_pi)); } +template inline T d2r_impl(const T v, real_type_tag) { return (v * T(numeric::constant::pi_180)); } +template inline T d2g_impl(const T v, real_type_tag) { return (v * T(10.0/9.0)); } +template inline T g2d_impl(const T v, real_type_tag) { return (v * T(9.0/10.0)); } +template inline T notl_impl(const T v, real_type_tag) { return (std::not_equal_to()(T(0),v) ? T(0) : T(1)); } +template inline T frac_impl(const T v, real_type_tag) { return (v - static_cast(v)); } +template inline T trunc_impl(const T v, real_type_tag) { return T(static_cast(v)); } + +template inline T const_pi_impl(real_type_tag) { return T(numeric::constant::pi); } +template inline T const_e_impl(real_type_tag) { return T(numeric::constant::e); } +template inline T const_qnan_impl(real_type_tag) { return std::numeric_limits::quiet_NaN(); } + +template inline T abs_impl(const T v, int_type_tag) { return ((v >= T(0)) ? v : -v); } +template inline T exp_impl(const T v, int_type_tag) { return std::exp (v); } +template inline T log_impl(const T v, int_type_tag) { return std::log (v); } +template inline T log10_impl(const T v, int_type_tag) { return std::log10(v); } +template inline T log2_impl(const T v, int_type_tag) { return std::log(v)/T(numeric::constant::log2); } +template inline T neg_impl(const T v, int_type_tag) { return -v; } +template inline T pos_impl(const T v, int_type_tag) { return +v; } +template inline T ceil_impl(const T v, int_type_tag) { return v; } +template inline T floor_impl(const T v, int_type_tag) { return v; } +template inline T round_impl(const T v, int_type_tag) { return v; } +template inline T notl_impl(const T v, int_type_tag) { return !v; } +template inline T sqrt_impl(const T v, int_type_tag) { return std::sqrt (v); } +template inline T frac_impl(const T , int_type_tag) { return T(0); } +template inline T trunc_impl(const T v, int_type_tag) { return v; } +template inline T acos_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } +template inline T acosh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } +template inline T asin_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } +template inline T asinh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } +template inline T atan_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } +template inline T atanh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } +template inline T cos_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } +template inline T cosh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } +template inline T sin_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } +template inline T sinh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } +template inline T tan_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } +template inline T tanh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } +template inline T cot_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } +template inline T sec_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } +template inline T csc_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + +template +inline bool is_integer_impl(const T& v, real_type_tag) +{ +return std::equal_to()(T(0),std::fmod(v,T(1))); +} + +template +inline bool is_integer_impl(const T&, int_type_tag) +{ +return true; +} +} + +template +struct numeric_info { enum { length = 0, size = 32, bound_length = 0, min_exp = 0, max_exp = 0 }; }; + +template <> struct numeric_info { enum { length = 10, size = 16, bound_length = 9 }; }; +template <> struct numeric_info { enum { min_exp = -38, max_exp = +38 }; }; +template <> struct numeric_info { enum { min_exp = -308, max_exp = +308 }; }; +template <> struct numeric_info { enum { min_exp = -308, max_exp = +308 }; }; + +template +inline int to_int32(const T v) +{ +const typename details::number_type::type num_type; +return to_int32_impl(v, num_type); +} + +template +inline _int64_t to_int64(const T v) +{ +const typename details::number_type::type num_type; +return to_int64_impl(v, num_type); +} + +template +inline bool is_nan(const T v) +{ +const typename details::number_type::type num_type; +return is_nan_impl(v, num_type); +} + +template +inline T min(const T v0, const T v1) +{ +const typename details::number_type::type num_type; +return min_impl(v0, v1, num_type); +} + +template +inline T max(const T v0, const T v1) +{ +const typename details::number_type::type num_type; +return max_impl(v0, v1, num_type); +} + +template +inline T equal(const T v0, const T v1) +{ +const typename details::number_type::type num_type; +return equal_impl(v0, v1, num_type); +} + +template +inline T nequal(const T v0, const T v1) +{ +const typename details::number_type::type num_type; +return nequal_impl(v0, v1, num_type); +} + +template +inline T modulus(const T v0, const T v1) +{ +const typename details::number_type::type num_type; +return modulus_impl(v0, v1, num_type); +} + +template +inline T pow(const T v0, const T v1) +{ +const typename details::number_type::type num_type; +return pow_impl(v0, v1, num_type); +} + +template +inline T logn(const T v0, const T v1) +{ +const typename details::number_type::type num_type; +return logn_impl(v0, v1, num_type); +} + +template +inline T root(const T v0, const T v1) +{ +const typename details::number_type::type num_type; +return root_impl(v0, v1, num_type); +} + +template +inline T roundn(const T v0, const T v1) +{ +const typename details::number_type::type num_type; +return roundn_impl(v0, v1, num_type); +} + +template +inline T hypot(const T v0, const T v1) +{ +const typename details::number_type::type num_type; +return hypot_impl(v0, v1, num_type); +} + +template +inline T atan2(const T v0, const T v1) +{ +const typename details::number_type::type num_type; +return atan2_impl(v0, v1, num_type); +} + +template +inline T shr(const T v0, const T v1) +{ +const typename details::number_type::type num_type; +return shr_impl(v0, v1, num_type); +} + +template +inline T shl(const T v0, const T v1) +{ +const typename details::number_type::type num_type; +return shl_impl(v0, v1, num_type); +} + +template +inline T and_opr(const T v0, const T v1) +{ +const typename details::number_type::type num_type; +return and_impl(v0, v1, num_type); +} + +template +inline T nand_opr(const T v0, const T v1) +{ +const typename details::number_type::type num_type; +return nand_impl(v0, v1, num_type); +} + +template +inline T or_opr(const T v0, const T v1) +{ +const typename details::number_type::type num_type; +return or_impl(v0, v1, num_type); +} + +template +inline T nor_opr(const T v0, const T v1) +{ +const typename details::number_type::type num_type; +return nor_impl(v0, v1, num_type); +} + +template +inline T xor_opr(const T v0, const T v1) +{ +const typename details::number_type::type num_type; +return xor_impl(v0, v1, num_type); +} + +template +inline T xnor_opr(const T v0, const T v1) +{ +const typename details::number_type::type num_type; +return xnor_impl(v0, v1, num_type); +} + +template +inline bool is_integer(const T v) +{ +const typename details::number_type::type num_type; +return is_integer_impl(v, num_type); +} + +template +struct fast_exp +{ +static inline T result(T v) +{ +unsigned int k = N; +T l = T(1); + +while (k) +{ +if (1 == (k % 2)) +{ +l *= v; +--k; +} + +v *= v; +k /= 2; +} + +return l; +} +}; + +template struct fast_exp { static inline T result(const T v) { T v_5 = fast_exp::result(v); return v_5 * v_5; } }; +template struct fast_exp { static inline T result(const T v) { return fast_exp::result(v) * v; } }; +template struct fast_exp { static inline T result(const T v) { T v_4 = fast_exp::result(v); return v_4 * v_4; } }; +template struct fast_exp { static inline T result(const T v) { return fast_exp::result(v) * v; } }; +template struct fast_exp { static inline T result(const T v) { T v_3 = fast_exp::result(v); return v_3 * v_3; } }; +template struct fast_exp { static inline T result(const T v) { return fast_exp::result(v) * v; } }; +template struct fast_exp { static inline T result(const T v) { T v_2 = v * v; return v_2 * v_2; } }; +template struct fast_exp { static inline T result(const T v) { return v * v * v; } }; +template struct fast_exp { static inline T result(const T v) { return v * v; } }; +template struct fast_exp { static inline T result(const T v) { return v; } }; +template struct fast_exp { static inline T result(const T ) { return T(1); } }; + +#define exprtk_define_unary_function(FunctionName) \ + template \ + inline T FunctionName (const T v) \ + { \ + const typename details::number_type::type num_type; \ + return FunctionName##_impl(v,num_type); \ + } \ + +exprtk_define_unary_function(abs ) +exprtk_define_unary_function(acos ) +exprtk_define_unary_function(acosh) +exprtk_define_unary_function(asin ) +exprtk_define_unary_function(asinh) +exprtk_define_unary_function(atan ) +exprtk_define_unary_function(atanh) +exprtk_define_unary_function(ceil ) +exprtk_define_unary_function(cos ) +exprtk_define_unary_function(cosh ) +exprtk_define_unary_function(exp ) +exprtk_define_unary_function(expm1) +exprtk_define_unary_function(floor) +exprtk_define_unary_function(log ) +exprtk_define_unary_function(log10) +exprtk_define_unary_function(log2 ) +exprtk_define_unary_function(log1p) +exprtk_define_unary_function(neg ) +exprtk_define_unary_function(pos ) +exprtk_define_unary_function(round) +exprtk_define_unary_function(sin ) +exprtk_define_unary_function(sinc ) +exprtk_define_unary_function(sinh ) +exprtk_define_unary_function(sqrt ) +exprtk_define_unary_function(tan ) +exprtk_define_unary_function(tanh ) +exprtk_define_unary_function(cot ) +exprtk_define_unary_function(sec ) +exprtk_define_unary_function(csc ) +exprtk_define_unary_function(r2d ) +exprtk_define_unary_function(d2r ) +exprtk_define_unary_function(d2g ) +exprtk_define_unary_function(g2d ) +exprtk_define_unary_function(notl ) +exprtk_define_unary_function(sgn ) +exprtk_define_unary_function(erf ) +exprtk_define_unary_function(erfc ) +exprtk_define_unary_function(ncdf ) +exprtk_define_unary_function(frac ) +exprtk_define_unary_function(trunc) +#undef exprtk_define_unary_function +} + +template +inline T compute_pow10(T d, const int exponent) +{ +static const double fract10[] = +{ +0.0, +1.0E+001, 1.0E+002, 1.0E+003, 1.0E+004, 1.0E+005, 1.0E+006, 1.0E+007, 1.0E+008, 1.0E+009, 1.0E+010, +1.0E+011, 1.0E+012, 1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016, 1.0E+017, 1.0E+018, 1.0E+019, 1.0E+020, +1.0E+021, 1.0E+022, 1.0E+023, 1.0E+024, 1.0E+025, 1.0E+026, 1.0E+027, 1.0E+028, 1.0E+029, 1.0E+030, +1.0E+031, 1.0E+032, 1.0E+033, 1.0E+034, 1.0E+035, 1.0E+036, 1.0E+037, 1.0E+038, 1.0E+039, 1.0E+040, +1.0E+041, 1.0E+042, 1.0E+043, 1.0E+044, 1.0E+045, 1.0E+046, 1.0E+047, 1.0E+048, 1.0E+049, 1.0E+050, +1.0E+051, 1.0E+052, 1.0E+053, 1.0E+054, 1.0E+055, 1.0E+056, 1.0E+057, 1.0E+058, 1.0E+059, 1.0E+060, +1.0E+061, 1.0E+062, 1.0E+063, 1.0E+064, 1.0E+065, 1.0E+066, 1.0E+067, 1.0E+068, 1.0E+069, 1.0E+070, +1.0E+071, 1.0E+072, 1.0E+073, 1.0E+074, 1.0E+075, 1.0E+076, 1.0E+077, 1.0E+078, 1.0E+079, 1.0E+080, +1.0E+081, 1.0E+082, 1.0E+083, 1.0E+084, 1.0E+085, 1.0E+086, 1.0E+087, 1.0E+088, 1.0E+089, 1.0E+090, +1.0E+091, 1.0E+092, 1.0E+093, 1.0E+094, 1.0E+095, 1.0E+096, 1.0E+097, 1.0E+098, 1.0E+099, 1.0E+100, +1.0E+101, 1.0E+102, 1.0E+103, 1.0E+104, 1.0E+105, 1.0E+106, 1.0E+107, 1.0E+108, 1.0E+109, 1.0E+110, +1.0E+111, 1.0E+112, 1.0E+113, 1.0E+114, 1.0E+115, 1.0E+116, 1.0E+117, 1.0E+118, 1.0E+119, 1.0E+120, +1.0E+121, 1.0E+122, 1.0E+123, 1.0E+124, 1.0E+125, 1.0E+126, 1.0E+127, 1.0E+128, 1.0E+129, 1.0E+130, +1.0E+131, 1.0E+132, 1.0E+133, 1.0E+134, 1.0E+135, 1.0E+136, 1.0E+137, 1.0E+138, 1.0E+139, 1.0E+140, +1.0E+141, 1.0E+142, 1.0E+143, 1.0E+144, 1.0E+145, 1.0E+146, 1.0E+147, 1.0E+148, 1.0E+149, 1.0E+150, +1.0E+151, 1.0E+152, 1.0E+153, 1.0E+154, 1.0E+155, 1.0E+156, 1.0E+157, 1.0E+158, 1.0E+159, 1.0E+160, +1.0E+161, 1.0E+162, 1.0E+163, 1.0E+164, 1.0E+165, 1.0E+166, 1.0E+167, 1.0E+168, 1.0E+169, 1.0E+170, +1.0E+171, 1.0E+172, 1.0E+173, 1.0E+174, 1.0E+175, 1.0E+176, 1.0E+177, 1.0E+178, 1.0E+179, 1.0E+180, +1.0E+181, 1.0E+182, 1.0E+183, 1.0E+184, 1.0E+185, 1.0E+186, 1.0E+187, 1.0E+188, 1.0E+189, 1.0E+190, +1.0E+191, 1.0E+192, 1.0E+193, 1.0E+194, 1.0E+195, 1.0E+196, 1.0E+197, 1.0E+198, 1.0E+199, 1.0E+200, +1.0E+201, 1.0E+202, 1.0E+203, 1.0E+204, 1.0E+205, 1.0E+206, 1.0E+207, 1.0E+208, 1.0E+209, 1.0E+210, +1.0E+211, 1.0E+212, 1.0E+213, 1.0E+214, 1.0E+215, 1.0E+216, 1.0E+217, 1.0E+218, 1.0E+219, 1.0E+220, +1.0E+221, 1.0E+222, 1.0E+223, 1.0E+224, 1.0E+225, 1.0E+226, 1.0E+227, 1.0E+228, 1.0E+229, 1.0E+230, +1.0E+231, 1.0E+232, 1.0E+233, 1.0E+234, 1.0E+235, 1.0E+236, 1.0E+237, 1.0E+238, 1.0E+239, 1.0E+240, +1.0E+241, 1.0E+242, 1.0E+243, 1.0E+244, 1.0E+245, 1.0E+246, 1.0E+247, 1.0E+248, 1.0E+249, 1.0E+250, +1.0E+251, 1.0E+252, 1.0E+253, 1.0E+254, 1.0E+255, 1.0E+256, 1.0E+257, 1.0E+258, 1.0E+259, 1.0E+260, +1.0E+261, 1.0E+262, 1.0E+263, 1.0E+264, 1.0E+265, 1.0E+266, 1.0E+267, 1.0E+268, 1.0E+269, 1.0E+270, +1.0E+271, 1.0E+272, 1.0E+273, 1.0E+274, 1.0E+275, 1.0E+276, 1.0E+277, 1.0E+278, 1.0E+279, 1.0E+280, +1.0E+281, 1.0E+282, 1.0E+283, 1.0E+284, 1.0E+285, 1.0E+286, 1.0E+287, 1.0E+288, 1.0E+289, 1.0E+290, +1.0E+291, 1.0E+292, 1.0E+293, 1.0E+294, 1.0E+295, 1.0E+296, 1.0E+297, 1.0E+298, 1.0E+299, 1.0E+300, +1.0E+301, 1.0E+302, 1.0E+303, 1.0E+304, 1.0E+305, 1.0E+306, 1.0E+307, 1.0E+308 +}; + +static const int fract10_size = static_cast(sizeof(fract10) / sizeof(double)); + +const int e = std::abs(exponent); + +if (exponent >= std::numeric_limits::min_exponent10) +{ +if (e < fract10_size) +{ +if (exponent > 0) +return T(d * fract10[e]); +else +return T(d / fract10[e]); +} +else +return T(d * std::pow(10.0, 10.0 * exponent)); +} +else +{ +d /= T(fract10[ -std::numeric_limits::min_exponent10]); +return T(d / fract10[-exponent + std::numeric_limits::min_exponent10]); +} +} + +template +inline bool string_to_type_converter_impl_ref(Iterator& itr, const Iterator end, T& result) +{ +if (itr == end) +return false; + +const bool negative = ('-' == (*itr)); + +if (negative || ('+' == (*itr))) +{ +if (end == ++itr) +return false; +} + +static const uchar_t zero = static_cast('0'); + +while ((end != itr) && (zero == (*itr))) ++itr; + +bool return_result = true; +unsigned int digit = 0; +const std::size_t length = static_cast(std::distance(itr,end)); + +if (length <= 4) +{ +exprtk_disable_fallthrough_begin +switch (length) +{ +#ifdef exprtk_use_lut + +#define exprtk_process_digit \ + if ((digit = details::digit_table[(int)*itr++]) < 10) \ + result = result * 10 + (digit); \ + else \ + { \ + return_result = false; \ + break; \ + } \ + +#else + +#define exprtk_process_digit \ + if ((digit = (*itr++ - zero)) < 10) \ + result = result * T(10) + digit; \ + else \ + { \ + return_result = false; \ + break; \ + } \ + +#endif + +case 4 : exprtk_process_digit +case 3 : exprtk_process_digit +case 2 : exprtk_process_digit +case 1 : if ((digit = (*itr - zero))>= 10) +{ +digit = 0; +return_result = false; +} + +#undef exprtk_process_digit +} +exprtk_disable_fallthrough_end +} +else +return_result = false; + +if (length && return_result) +{ +result = result * 10 + static_cast(digit); +++itr; +} + +result = negative ? -result : result; +return return_result; +} + +template +static inline bool parse_nan(Iterator& itr, const Iterator end, T& t) +{ +typedef typename std::iterator_traits::value_type type; + +static const std::size_t nan_length = 3; + +if (std::distance(itr,end) != static_cast(nan_length)) +return false; + +if (static_cast('n') == (*itr)) +{ +if ( +(static_cast('a') != *(itr + 1)) || +(static_cast('n') != *(itr + 2)) +) +{ +return false; +} +} +else if ( +(static_cast('A') != *(itr + 1)) || +(static_cast('N') != *(itr + 2)) +) +{ +return false; +} + +t = std::numeric_limits::quiet_NaN(); + +return true; +} + +template +static inline bool parse_inf(Iterator& itr, const Iterator end, T& t, const bool negative) +{ +static const char_t inf_uc[] = "INFINITY"; +static const char_t inf_lc[] = "infinity"; +static const std::size_t inf_length = 8; + +const std::size_t length = static_cast(std::distance(itr,end)); + +if ((3 != length) && (inf_length != length)) +return false; + +char_cptr inf_itr = ('i' == (*itr)) ? inf_lc : inf_uc; + +while (end != itr) +{ +if (*inf_itr == static_cast(*itr)) +{ +++itr; +++inf_itr; +continue; +} +else +return false; +} + +if (negative) +t = -std::numeric_limits::infinity(); +else +t = std::numeric_limits::infinity(); + +return true; +} + +template +inline bool valid_exponent(const int exponent, numeric::details::real_type_tag) +{ +using namespace details::numeric; +return (numeric_info::min_exp <= exponent) && (exponent <= numeric_info::max_exp); +} + +template +inline bool string_to_real(Iterator& itr_external, const Iterator end, T& t, numeric::details::real_type_tag) +{ +if (end == itr_external) return false; + +Iterator itr = itr_external; + +T d = T(0); + +const bool negative = ('-' == (*itr)); + +if (negative || '+' == (*itr)) +{ +if (end == ++itr) +return false; +} + +bool instate = false; + +static const char_t zero = static_cast('0'); + +#define parse_digit_1(d) \ + if ((digit = (*itr - zero)) < 10) \ + { d = d * T(10) + digit; } \ + else \ + { break; } \ + if (end == ++itr) break; \ + +#define parse_digit_2(d) \ + if ((digit = (*itr - zero)) < 10) \ + { d = d * T(10) + digit; } \ + else \ + { break; } \ + ++itr; \ + +if ('.' != (*itr)) +{ +const Iterator curr = itr; + +while ((end != itr) && (zero == (*itr))) ++itr; + +while (end != itr) +{ +unsigned int digit; +parse_digit_1(d) +parse_digit_1(d) +parse_digit_2(d) +} + +if (curr != itr) instate = true; +} + +int exponent = 0; + +if (end != itr) +{ +if ('.' == (*itr)) +{ +const Iterator curr = ++itr; +T tmp_d = T(0); + +while (end != itr) +{ +unsigned int digit; +parse_digit_1(tmp_d) +parse_digit_1(tmp_d) +parse_digit_2(tmp_d) +} + +if (curr != itr) +{ +instate = true; + +const int frac_exponent = static_cast(-std::distance(curr, itr)); + +if (!valid_exponent(frac_exponent, numeric::details::real_type_tag())) +return false; + +d += compute_pow10(tmp_d, frac_exponent); +} + +#undef parse_digit_1 +#undef parse_digit_2 +} + +if (end != itr) +{ +typename std::iterator_traits::value_type c = (*itr); + +if (('e' == c) || ('E' == c)) +{ +int exp = 0; + +if (!details::string_to_type_converter_impl_ref(++itr, end, exp)) +{ +if (end == itr) +return false; +else +c = (*itr); +} + +exponent += exp; +} + +if (end != itr) +{ +if (('f' == c) || ('F' == c) || ('l' == c) || ('L' == c)) +++itr; +else if ('#' == c) +{ +if (end == ++itr) +return false; +else if (('I' <= (*itr)) && ((*itr) <= 'n')) +{ +if (('i' == (*itr)) || ('I' == (*itr))) +{ +return parse_inf(itr, end, t, negative); +} +else if (('n' == (*itr)) || ('N' == (*itr))) +{ +return parse_nan(itr, end, t); +} +else +return false; +} +else +return false; +} +else if (('I' <= (*itr)) && ((*itr) <= 'n')) +{ +if (('i' == (*itr)) || ('I' == (*itr))) +{ +return parse_inf(itr, end, t, negative); +} +else if (('n' == (*itr)) || ('N' == (*itr))) +{ +return parse_nan(itr, end, t); +} +else +return false; +} +else +return false; +} +} +} + +if ((end != itr) || (!instate)) +return false; +else if (!valid_exponent(exponent, numeric::details::real_type_tag())) +return false; +else if (exponent) +d = compute_pow10(d,exponent); + +t = static_cast((negative) ? -d : d); +return true; +} + +template +inline bool string_to_real(const std::string& s, T& t) +{ +const typename numeric::details::number_type::type num_type; + +char_cptr begin = s.data(); +char_cptr end = s.data() + s.size(); + +return string_to_real(begin, end, t, num_type); +} + +template +struct functor_t +{ +/* + Note: The following definitions for Type, may require tweaking + based on the compiler and target architecture. The benchmark + should provide enough information to make the right choice. + */ +//typedef T Type; +//typedef const T Type; +typedef const T& Type; +typedef T& RefType; +typedef T (*qfunc_t)(Type t0, Type t1, Type t2, Type t3); +typedef T (*tfunc_t)(Type t0, Type t1, Type t2); +typedef T (*bfunc_t)(Type t0, Type t1); +typedef T (*ufunc_t)(Type t0); +}; + +} // namespace details + +struct loop_runtime_check +{ +enum loop_types +{ +e_invalid = 0, +e_for_loop = 1, +e_while_loop = 2, +e_repeat_until_loop = 4, +e_all_loops = 7 +}; + +enum violation_type +{ +e_unknown = 0, +e_iteration_count = 1, +e_timeout = 2 +}; + +loop_types loop_set; + +loop_runtime_check() +: loop_set(e_invalid) +, max_loop_iterations(0) +{} + +details::_uint64_t max_loop_iterations; + +struct violation_context +{ +loop_types loop; +violation_type violation; +details::_uint64_t iteration_count; +}; + +virtual bool check() +{ +return true; +} + +virtual void handle_runtime_violation(const violation_context&) +{ +throw std::runtime_error("ExprTk Loop run-time violation."); +} + +virtual ~loop_runtime_check() {} +}; + +typedef loop_runtime_check* loop_runtime_check_ptr; + +namespace lexer +{ +struct token +{ +enum token_type +{ +e_none = 0, e_error = 1, e_err_symbol = 2, +e_err_number = 3, e_err_string = 4, e_err_sfunc = 5, +e_eof = 6, e_number = 7, e_symbol = 8, +e_string = 9, e_assign = 10, e_addass = 11, +e_subass = 12, e_mulass = 13, e_divass = 14, +e_modass = 15, e_shr = 16, e_shl = 17, +e_lte = 18, e_ne = 19, e_gte = 20, +e_swap = 21, e_lt = '<', e_gt = '>', +e_eq = '=', e_rbracket = ')', e_lbracket = '(', +e_rsqrbracket = ']', e_lsqrbracket = '[', e_rcrlbracket = '}', +e_lcrlbracket = '{', e_comma = ',', e_add = '+', +e_sub = '-', e_div = '/', e_mul = '*', +e_mod = '%', e_pow = '^', e_colon = ':', +e_ternary = '?' +}; + +token() +: type(e_none) +, value("") +, position(std::numeric_limits::max()) +{} + +void clear() +{ +type = e_none; +value = ""; +position = std::numeric_limits::max(); +} + +template +inline token& set_operator(const token_type tt, +const Iterator begin, const Iterator end, +const Iterator base_begin = Iterator(0)) +{ +type = tt; +value.assign(begin,end); +if (base_begin) +position = static_cast(std::distance(base_begin,begin)); +return (*this); +} + +template +inline token& set_symbol(const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0)) +{ +type = e_symbol; +value.assign(begin,end); +if (base_begin) +position = static_cast(std::distance(base_begin,begin)); +return (*this); +} + +template +inline token& set_numeric(const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0)) +{ +type = e_number; +value.assign(begin,end); +if (base_begin) +position = static_cast(std::distance(base_begin,begin)); +return (*this); +} + +template +inline token& set_string(const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0)) +{ +type = e_string; +value.assign(begin,end); +if (base_begin) +position = static_cast(std::distance(base_begin,begin)); +return (*this); +} + +inline token& set_string(const std::string& s, const std::size_t p) +{ +type = e_string; +value = s; +position = p; +return (*this); +} + +template +inline token& set_error(const token_type et, +const Iterator begin, const Iterator end, +const Iterator base_begin = Iterator(0)) +{ +if ( +(e_error == et) || +(e_err_symbol == et) || +(e_err_number == et) || +(e_err_string == et) || +(e_err_sfunc == et) +) +{ +type = et; +} +else +type = e_error; + +value.assign(begin,end); + +if (base_begin) +position = static_cast(std::distance(base_begin,begin)); + +return (*this); +} + +static inline std::string to_str(token_type t) +{ +switch (t) +{ +case e_none : return "NONE"; +case e_error : return "ERROR"; +case e_err_symbol : return "ERROR_SYMBOL"; +case e_err_number : return "ERROR_NUMBER"; +case e_err_string : return "ERROR_STRING"; +case e_eof : return "EOF"; +case e_number : return "NUMBER"; +case e_symbol : return "SYMBOL"; +case e_string : return "STRING"; +case e_assign : return ":="; +case e_addass : return "+="; +case e_subass : return "-="; +case e_mulass : return "*="; +case e_divass : return "/="; +case e_modass : return "%="; +case e_shr : return ">>"; +case e_shl : return "<<"; +case e_lte : return "<="; +case e_ne : return "!="; +case e_gte : return ">="; +case e_lt : return "<"; +case e_gt : return ">"; +case e_eq : return "="; +case e_rbracket : return ")"; +case e_lbracket : return "("; +case e_rsqrbracket : return "]"; +case e_lsqrbracket : return "["; +case e_rcrlbracket : return "}"; +case e_lcrlbracket : return "{"; +case e_comma : return ","; +case e_add : return "+"; +case e_sub : return "-"; +case e_div : return "/"; +case e_mul : return "*"; +case e_mod : return "%"; +case e_pow : return "^"; +case e_colon : return ":"; +case e_ternary : return "?"; +case e_swap : return "<=>"; +default : return "UNKNOWN"; +} +} + +inline bool is_error() const +{ +return ( +(e_error == type) || +(e_err_symbol == type) || +(e_err_number == type) || +(e_err_string == type) || +(e_err_sfunc == type) +); +} + +token_type type; +std::string value; +std::size_t position; +}; + +class generator +{ +public: + +typedef token token_t; +typedef std::vector token_list_t; +typedef token_list_t::iterator token_list_itr_t; +typedef details::char_t char_t; + +generator() +: base_itr_(0) +, s_itr_ (0) +, s_end_ (0) +{ +clear(); +} + +inline void clear() +{ +base_itr_ = 0; +s_itr_ = 0; +s_end_ = 0; +token_list_.clear(); +token_itr_ = token_list_.end(); +store_token_itr_ = token_list_.end(); +} + +inline bool process(const std::string& str) +{ +base_itr_ = str.data(); +s_itr_ = str.data(); +s_end_ = str.data() + str.size(); + +eof_token_.set_operator(token_t::e_eof,s_end_,s_end_,base_itr_); +token_list_.clear(); + +while (!is_end(s_itr_)) +{ +scan_token(); + +if (!token_list_.empty() && token_list_.back().is_error()) +return false; +} + +return true; +} + +inline bool empty() const +{ +return token_list_.empty(); +} + +inline std::size_t size() const +{ +return token_list_.size(); +} + +inline void begin() +{ +token_itr_ = token_list_.begin(); +store_token_itr_ = token_list_.begin(); +} + +inline void store() +{ +store_token_itr_ = token_itr_; +} + +inline void restore() +{ +token_itr_ = store_token_itr_; +} + +inline token_t& next_token() +{ +if (token_list_.end() != token_itr_) +{ +return *token_itr_++; +} +else +return eof_token_; +} + +inline token_t& peek_next_token() +{ +if (token_list_.end() != token_itr_) +{ +return *token_itr_; +} +else +return eof_token_; +} + +inline token_t& operator[](const std::size_t& index) +{ +if (index < token_list_.size()) +return token_list_[index]; +else +return eof_token_; +} + +inline token_t operator[](const std::size_t& index) const +{ +if (index < token_list_.size()) +return token_list_[index]; +else +return eof_token_; +} + +inline bool finished() const +{ +return (token_list_.end() == token_itr_); +} + +inline void insert_front(token_t::token_type tk_type) +{ +if ( +!token_list_.empty() && +(token_list_.end() != token_itr_) +) +{ +token_t t = *token_itr_; + +t.type = tk_type; +token_itr_ = token_list_.insert(token_itr_,t); +} +} + +inline std::string substr(const std::size_t& begin, const std::size_t& end) const +{ +const details::char_cptr begin_itr = ((base_itr_ + begin) < s_end_) ? (base_itr_ + begin) : s_end_; +const details::char_cptr end_itr = ((base_itr_ + end ) < s_end_) ? (base_itr_ + end ) : s_end_; + +return std::string(begin_itr,end_itr); +} + +inline std::string remaining() const +{ +if (finished()) +return ""; +else if (token_list_.begin() != token_itr_) +return std::string(base_itr_ + (token_itr_ - 1)->position, s_end_); +else +return std::string(base_itr_ + token_itr_->position, s_end_); +} + +private: + +inline bool is_end(details::char_cptr itr) const +{ +return (s_end_ == itr); +} + +#ifndef exprtk_disable_comments +inline bool is_comment_start(details::char_cptr itr) const +{ +const char_t c0 = *(itr + 0); +const char_t c1 = *(itr + 1); + +if ('#' == c0) +return true; +else if (!is_end(itr + 1)) +{ +if (('/' == c0) && ('/' == c1)) return true; +if (('/' == c0) && ('*' == c1)) return true; +} +return false; +} +#else +inline bool is_comment_start(details::char_cptr) const +{ +return false; +} +#endif + +inline void skip_whitespace() +{ +while (!is_end(s_itr_) && details::is_whitespace(*s_itr_)) +{ +++s_itr_; +} +} + +inline void skip_comments() +{ +#ifndef exprtk_disable_comments +// The following comment styles are supported: +// 1. // .... \n +// 2. # .... \n +// 3. /* .... */ +struct test +{ +static inline bool comment_start(const char_t c0, const char_t c1, int& mode, int& incr) +{ +mode = 0; +if ('#' == c0) { mode = 1; incr = 1; } +else if ('/' == c0) +{ +if ('/' == c1) { mode = 1; incr = 2; } +else if ('*' == c1) { mode = 2; incr = 2; } +} +return (0 != mode); +} + +static inline bool comment_end(const char_t c0, const char_t c1, int& mode) +{ +if ( +((1 == mode) && ('\n' == c0)) || +((2 == mode) && ( '*' == c0) && ('/' == c1)) +) +{ +mode = 0; +return true; +} +else +return false; +} +}; + +int mode = 0; +int increment = 0; + +if (is_end(s_itr_)) +return; +else if (!test::comment_start(*s_itr_, *(s_itr_ + 1), mode, increment)) +return; + +details::char_cptr cmt_start = s_itr_; + +s_itr_ += increment; + +while (!is_end(s_itr_)) +{ +if ((1 == mode) && test::comment_end(*s_itr_, 0, mode)) +{ +++s_itr_; +return; +} + +if ((2 == mode)) +{ +if (!is_end((s_itr_ + 1)) && test::comment_end(*s_itr_, *(s_itr_ + 1), mode)) +{ +s_itr_ += 2; +return; +} +} + +++s_itr_; +} + +if (2 == mode) +{ +token_t t; +t.set_error(token::e_error, cmt_start, cmt_start + mode, base_itr_); +token_list_.push_back(t); +} +#endif +} + +inline void scan_token() +{ +if (details::is_whitespace(*s_itr_)) +{ +skip_whitespace(); +return; +} +else if (is_comment_start(s_itr_)) +{ +skip_comments(); +return; +} +else if (details::is_operator_char(*s_itr_)) +{ +scan_operator(); +return; +} +else if (details::is_letter(*s_itr_)) +{ +scan_symbol(); +return; +} +else if (details::is_digit((*s_itr_)) || ('.' == (*s_itr_))) +{ +scan_number(); +return; +} +else if ('$' == (*s_itr_)) +{ +scan_special_function(); +return; +} +#ifndef exprtk_disable_string_capabilities +else if ('\'' == (*s_itr_)) +{ +scan_string(); +return; +} +#endif +else if ('~' == (*s_itr_)) +{ +token_t t; +t.set_symbol(s_itr_, s_itr_ + 1, base_itr_); +token_list_.push_back(t); +++s_itr_; +return; +} +else +{ +token_t t; +t.set_error(token::e_error, s_itr_, s_itr_ + 2, base_itr_); +token_list_.push_back(t); +++s_itr_; +} +} + +inline void scan_operator() +{ +token_t t; + +const char_t c0 = s_itr_[0]; + +if (!is_end(s_itr_ + 1)) +{ +const char_t c1 = s_itr_[1]; + +if (!is_end(s_itr_ + 2)) +{ +const char_t c2 = s_itr_[2]; + +if ((c0 == '<') && (c1 == '=') && (c2 == '>')) +{ +t.set_operator(token_t::e_swap, s_itr_, s_itr_ + 3, base_itr_); +token_list_.push_back(t); +s_itr_ += 3; +return; +} +} + +token_t::token_type ttype = token_t::e_none; + +if ((c0 == '<') && (c1 == '=')) ttype = token_t::e_lte; +else if ((c0 == '>') && (c1 == '=')) ttype = token_t::e_gte; +else if ((c0 == '<') && (c1 == '>')) ttype = token_t::e_ne; +else if ((c0 == '!') && (c1 == '=')) ttype = token_t::e_ne; +else if ((c0 == '=') && (c1 == '=')) ttype = token_t::e_eq; +else if ((c0 == ':') && (c1 == '=')) ttype = token_t::e_assign; +else if ((c0 == '<') && (c1 == '<')) ttype = token_t::e_shl; +else if ((c0 == '>') && (c1 == '>')) ttype = token_t::e_shr; +else if ((c0 == '+') && (c1 == '=')) ttype = token_t::e_addass; +else if ((c0 == '-') && (c1 == '=')) ttype = token_t::e_subass; +else if ((c0 == '*') && (c1 == '=')) ttype = token_t::e_mulass; +else if ((c0 == '/') && (c1 == '=')) ttype = token_t::e_divass; +else if ((c0 == '%') && (c1 == '=')) ttype = token_t::e_modass; + +if (token_t::e_none != ttype) +{ +t.set_operator(ttype, s_itr_, s_itr_ + 2, base_itr_); +token_list_.push_back(t); +s_itr_ += 2; +return; +} +} + +if ('<' == c0) +t.set_operator(token_t::e_lt , s_itr_, s_itr_ + 1, base_itr_); +else if ('>' == c0) +t.set_operator(token_t::e_gt , s_itr_, s_itr_ + 1, base_itr_); +else if (';' == c0) +t.set_operator(token_t::e_eof, s_itr_, s_itr_ + 1, base_itr_); +else if ('&' == c0) +t.set_symbol(s_itr_, s_itr_ + 1, base_itr_); +else if ('|' == c0) +t.set_symbol(s_itr_, s_itr_ + 1, base_itr_); +else +t.set_operator(token_t::token_type(c0), s_itr_, s_itr_ + 1, base_itr_); + +token_list_.push_back(t); +++s_itr_; +} + +inline void scan_symbol() +{ +details::char_cptr initial_itr = s_itr_; + +while (!is_end(s_itr_)) +{ +if (!details::is_letter_or_digit(*s_itr_) && ('_' != (*s_itr_))) +{ +if ('.' != (*s_itr_)) +break; +/* + Permit symbols that contain a 'dot' + Allowed : abc.xyz, a123.xyz, abc.123, abc_.xyz a123_.xyz abc._123 + Disallowed: .abc, abc., abc., abc. + */ +if ( +(s_itr_ != initial_itr) && +!is_end(s_itr_ + 1) && +!details::is_letter_or_digit(*(s_itr_ + 1)) && +('_' != (*(s_itr_ + 1))) +) +break; +} + +++s_itr_; +} + +token_t t; +t.set_symbol(initial_itr,s_itr_,base_itr_); +token_list_.push_back(t); +} + +inline void scan_number() +{ +/* + Attempt to match a valid numeric value in one of the following formats: + (01) 123456 + (02) 123456. + (03) 123.456 + (04) 123.456e3 + (05) 123.456E3 + (06) 123.456e+3 + (07) 123.456E+3 + (08) 123.456e-3 + (09) 123.456E-3 + (00) .1234 + (11) .1234e3 + (12) .1234E+3 + (13) .1234e+3 + (14) .1234E-3 + (15) .1234e-3 + */ + +details::char_cptr initial_itr = s_itr_; +bool dot_found = false; +bool e_found = false; +bool post_e_sign_found = false; +bool post_e_digit_found = false; +token_t t; + +while (!is_end(s_itr_)) +{ +if ('.' == (*s_itr_)) +{ +if (dot_found) +{ +t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); +token_list_.push_back(t); + +return; +} + +dot_found = true; +++s_itr_; + +continue; +} +else if ('e' == std::tolower(*s_itr_)) +{ +const char_t& c = *(s_itr_ + 1); + +if (is_end(s_itr_ + 1)) +{ +t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); +token_list_.push_back(t); + +return; +} +else if ( +('+' != c) && +('-' != c) && +!details::is_digit(c) +) +{ +t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); +token_list_.push_back(t); + +return; +} + +e_found = true; +++s_itr_; + +continue; +} +else if (e_found && details::is_sign(*s_itr_) && !post_e_digit_found) +{ +if (post_e_sign_found) +{ +t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); +token_list_.push_back(t); + +return; +} + +post_e_sign_found = true; +++s_itr_; + +continue; +} +else if (e_found && details::is_digit(*s_itr_)) +{ +post_e_digit_found = true; +++s_itr_; + +continue; +} +else if (('.' != (*s_itr_)) && !details::is_digit(*s_itr_)) +break; +else +++s_itr_; +} + +t.set_numeric(initial_itr, s_itr_, base_itr_); +token_list_.push_back(t); + +return; +} + +inline void scan_special_function() +{ +details::char_cptr initial_itr = s_itr_; +token_t t; + +// $fdd(x,x,x) = at least 11 chars +if (std::distance(s_itr_,s_end_) < 11) +{ +t.set_error( +token::e_err_sfunc, +initial_itr, std::min(initial_itr + 11, s_end_), +base_itr_); +token_list_.push_back(t); + +return; +} + +if ( +!(('$' == *s_itr_) && +(details::imatch ('f',*(s_itr_ + 1))) && +(details::is_digit(*(s_itr_ + 2))) && +(details::is_digit(*(s_itr_ + 3)))) +) +{ +t.set_error( +token::e_err_sfunc, +initial_itr, std::min(initial_itr + 4, s_end_), +base_itr_); +token_list_.push_back(t); + +return; +} + +s_itr_ += 4; // $fdd = 4chars + +t.set_symbol(initial_itr, s_itr_, base_itr_); +token_list_.push_back(t); + +return; +} + +#ifndef exprtk_disable_string_capabilities +inline void scan_string() +{ +details::char_cptr initial_itr = s_itr_ + 1; +token_t t; + +if (std::distance(s_itr_,s_end_) < 2) +{ +t.set_error(token::e_err_string, s_itr_, s_end_, base_itr_); +token_list_.push_back(t); + +return; +} + +++s_itr_; + +bool escaped_found = false; +bool escaped = false; + +while (!is_end(s_itr_)) +{ +if (!details::is_valid_string_char(*s_itr_)) +{ +t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_); +token_list_.push_back(t); + +return; +} +else if (!escaped && ('\\' == *s_itr_)) +{ +escaped_found = true; +escaped = true; +++s_itr_; + +continue; +} +else if (!escaped) +{ +if ('\'' == *s_itr_) +break; +} +else if (escaped) +{ +if ( +!is_end(s_itr_) && ('0' == *(s_itr_)) && +((s_itr_ + 4) <= s_end_) +) +{ +const bool x_seperator = ('X' == std::toupper(*(s_itr_ + 1))); + +const bool both_digits = details::is_hex_digit(*(s_itr_ + 2)) && +details::is_hex_digit(*(s_itr_ + 3)) ; + +if (!(x_seperator && both_digits)) +{ +t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_); +token_list_.push_back(t); + +return; +} +else +s_itr_ += 3; +} + +escaped = false; +} + +++s_itr_; +} + +if (is_end(s_itr_)) +{ +t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_); +token_list_.push_back(t); + +return; +} + +if (!escaped_found) +t.set_string(initial_itr, s_itr_, base_itr_); +else +{ +std::string parsed_string(initial_itr,s_itr_); + +if (!details::cleanup_escapes(parsed_string)) +{ +t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_); +token_list_.push_back(t); + +return; +} + +t.set_string( +parsed_string, +static_cast(std::distance(base_itr_,initial_itr))); +} + +token_list_.push_back(t); +++s_itr_; + +return; +} +#endif + +private: + +token_list_t token_list_; +token_list_itr_t token_itr_; +token_list_itr_t store_token_itr_; +token_t eof_token_; +details::char_cptr base_itr_; +details::char_cptr s_itr_; +details::char_cptr s_end_; + +friend class token_scanner; +friend class token_modifier; +friend class token_inserter; +friend class token_joiner; +}; // class generator + +class helper_interface +{ +public: + +virtual void init() { } +virtual void reset() { } +virtual bool result() { return true; } +virtual std::size_t process(generator&) { return 0; } +virtual ~helper_interface() { } +}; + +class token_scanner : public helper_interface +{ +public: + +virtual ~token_scanner() {} + +explicit token_scanner(const std::size_t& stride) +: stride_(stride) +{ +if (stride > 4) +{ +throw std::invalid_argument("token_scanner() - Invalid stride value"); +} +} + +inline std::size_t process(generator& g) exprtk_override +{ +if (g.token_list_.size() >= stride_) +{ +for (std::size_t i = 0; i < (g.token_list_.size() - stride_ + 1); ++i) +{ +token t; + +switch (stride_) +{ +case 1 : +{ +const token& t0 = g.token_list_[i]; + +if (!operator()(t0)) +{ +return i; +} +} +break; + +case 2 : +{ +const token& t0 = g.token_list_[i ]; +const token& t1 = g.token_list_[i + 1]; + +if (!operator()(t0, t1)) +{ +return i; +} +} +break; + +case 3 : +{ +const token& t0 = g.token_list_[i ]; +const token& t1 = g.token_list_[i + 1]; +const token& t2 = g.token_list_[i + 2]; + +if (!operator()(t0, t1, t2)) +{ +return i; +} +} +break; + +case 4 : +{ +const token& t0 = g.token_list_[i ]; +const token& t1 = g.token_list_[i + 1]; +const token& t2 = g.token_list_[i + 2]; +const token& t3 = g.token_list_[i + 3]; + +if (!operator()(t0, t1, t2, t3)) +{ +return i; +} +} +break; +} +} +} + +return (g.token_list_.size() - stride_ + 1); +} + +virtual bool operator() (const token&) +{ +return false; +} + +virtual bool operator() (const token&, const token&) +{ +return false; +} + +virtual bool operator() (const token&, const token&, const token&) +{ +return false; +} + +virtual bool operator() (const token&, const token&, const token&, const token&) +{ +return false; +} + +private: + +const std::size_t stride_; +}; // class token_scanner + +class token_modifier : public helper_interface +{ +public: + +inline std::size_t process(generator& g) exprtk_override +{ +std::size_t changes = 0; + +for (std::size_t i = 0; i < g.token_list_.size(); ++i) +{ +if (modify(g.token_list_[i])) changes++; +} + +return changes; +} + +virtual bool modify(token& t) = 0; +}; + +class token_inserter : public helper_interface +{ +public: + +explicit token_inserter(const std::size_t& stride) +: stride_(stride) +{ +if (stride > 5) +{ +throw std::invalid_argument("token_inserter() - Invalid stride value"); +} +} + +inline std::size_t process(generator& g) exprtk_override +{ +if (g.token_list_.empty()) +return 0; +else if (g.token_list_.size() < stride_) +return 0; + +std::size_t changes = 0; + +typedef std::pair insert_t; +std::vector insert_list; +insert_list.reserve(10000); + +for (std::size_t i = 0; i < (g.token_list_.size() - stride_ + 1); ++i) +{ +int insert_index = -1; +token t; + +switch (stride_) +{ +case 1 : insert_index = insert(g.token_list_[i],t); +break; + +case 2 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], t); +break; + +case 3 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], g.token_list_[i + 2], t); +break; + +case 4 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], g.token_list_[i + 2], g.token_list_[i + 3], t); +break; + +case 5 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], g.token_list_[i + 2], g.token_list_[i + 3], g.token_list_[i + 4], t); +break; +} + +if ((insert_index >= 0) && (insert_index <= (static_cast(stride_) + 1))) +{ +insert_list.push_back(insert_t(i, t)); +changes++; +} +} + +if (!insert_list.empty()) +{ +generator::token_list_t token_list; + +std::size_t insert_index = 0; + +for (std::size_t i = 0; i < g.token_list_.size(); ++i) +{ +token_list.push_back(g.token_list_[i]); + +if ( +(insert_index < insert_list.size()) && +(insert_list[insert_index].first == i) +) +{ +token_list.push_back(insert_list[insert_index].second); +insert_index++; +} +} + +std::swap(g.token_list_,token_list); +} + +return changes; +} + +#define token_inserter_empty_body \ + { \ + return -1; \ + } \ + +inline virtual int insert(const token&, token&) +token_inserter_empty_body + +inline virtual int insert(const token&, const token&, token&) +token_inserter_empty_body + +inline virtual int insert(const token&, const token&, const token&, token&) +token_inserter_empty_body + +inline virtual int insert(const token&, const token&, const token&, const token&, token&) +token_inserter_empty_body + +inline virtual int insert(const token&, const token&, const token&, const token&, const token&, token&) +token_inserter_empty_body + +#undef token_inserter_empty_body + +private: + +const std::size_t stride_; +}; + +class token_joiner : public helper_interface +{ +public: + +explicit token_joiner(const std::size_t& stride) +: stride_(stride) +{} + +inline std::size_t process(generator& g) exprtk_override +{ +if (g.token_list_.empty()) +return 0; + +switch (stride_) +{ +case 2 : return process_stride_2(g); +case 3 : return process_stride_3(g); +default : return 0; +} +} + +virtual bool join(const token&, const token&, token&) { return false; } +virtual bool join(const token&, const token&, const token&, token&) { return false; } + +private: + +inline std::size_t process_stride_2(generator& g) +{ +if (g.token_list_.size() < 2) +return 0; + +std::size_t changes = 0; + +generator::token_list_t token_list; +token_list.reserve(10000); + +for (int i = 0; i < static_cast(g.token_list_.size() - 1); ++i) +{ +token t; + +for ( ; ; ) +{ +if (!join(g[i], g[i + 1], t)) +{ +token_list.push_back(g[i]); +break; +} + +token_list.push_back(t); + +++changes; + +i+=2; + +if (static_cast(i) >= (g.token_list_.size() - 1)) +break; +} +} + +token_list.push_back(g.token_list_.back()); + +assert(token_list.size() <= g.token_list_.size()); + +std::swap(token_list, g.token_list_); + +return changes; +} + +inline std::size_t process_stride_3(generator& g) +{ +if (g.token_list_.size() < 3) +return 0; + +std::size_t changes = 0; + +generator::token_list_t token_list; +token_list.reserve(10000); + +for (int i = 0; i < static_cast(g.token_list_.size() - 2); ++i) +{ +token t; + +for ( ; ; ) +{ +if (!join(g[i], g[i + 1], g[i + 2], t)) +{ +token_list.push_back(g[i]); +break; +} + +token_list.push_back(t); + +++changes; + +i+=3; + +if (static_cast(i) >= (g.token_list_.size() - 2)) +break; +} +} + +token_list.push_back(*(g.token_list_.begin() + g.token_list_.size() - 2)); +token_list.push_back(*(g.token_list_.begin() + g.token_list_.size() - 1)); + +assert(token_list.size() <= g.token_list_.size()); + +std::swap(token_list, g.token_list_); + +return changes; +} + +const std::size_t stride_; +}; + +namespace helper +{ + +inline void dump(const lexer::generator& generator) +{ +for (std::size_t i = 0; i < generator.size(); ++i) +{ +const lexer::token& t = generator[i]; +printf("Token[%02d] @ %03d %6s --> '%s'\n", +static_cast(i), +static_cast(t.position), +t.to_str(t.type).c_str(), +t.value.c_str()); +} +} + +class commutative_inserter : public lexer::token_inserter +{ +public: + +using lexer::token_inserter::insert; + +commutative_inserter() +: lexer::token_inserter(2) +{} + +inline void ignore_symbol(const std::string& symbol) +{ +ignore_set_.insert(symbol); +} + +inline int insert(const lexer::token& t0, const lexer::token& t1, lexer::token& new_token) exprtk_override +{ +bool match = false; +new_token.type = lexer::token::e_mul; +new_token.value = "*"; +new_token.position = t1.position; + +if (t0.type == lexer::token::e_symbol) +{ +if (ignore_set_.end() != ignore_set_.find(t0.value)) +{ +return -1; +} +else if (!t0.value.empty() && ('$' == t0.value[0])) +{ +return -1; +} +} + +if (t1.type == lexer::token::e_symbol) +{ +if (ignore_set_.end() != ignore_set_.find(t1.value)) +{ +return -1; +} +} +if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_symbol )) match = true; +else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lbracket )) match = true; +else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lcrlbracket)) match = true; +else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lsqrbracket)) match = true; +else if ((t0.type == lexer::token::e_symbol ) && (t1.type == lexer::token::e_number )) match = true; +else if ((t0.type == lexer::token::e_rbracket ) && (t1.type == lexer::token::e_number )) match = true; +else if ((t0.type == lexer::token::e_rcrlbracket) && (t1.type == lexer::token::e_number )) match = true; +else if ((t0.type == lexer::token::e_rsqrbracket) && (t1.type == lexer::token::e_number )) match = true; +else if ((t0.type == lexer::token::e_rbracket ) && (t1.type == lexer::token::e_symbol )) match = true; +else if ((t0.type == lexer::token::e_rcrlbracket) && (t1.type == lexer::token::e_symbol )) match = true; +else if ((t0.type == lexer::token::e_rsqrbracket) && (t1.type == lexer::token::e_symbol )) match = true; +else if ((t0.type == lexer::token::e_symbol ) && (t1.type == lexer::token::e_symbol )) match = true; + +return (match) ? 1 : -1; +} + +private: + +std::set ignore_set_; +}; + +class operator_joiner : public token_joiner +{ +public: + +explicit operator_joiner(const std::size_t& stride) +: token_joiner(stride) +{} + +inline bool join(const lexer::token& t0, const lexer::token& t1, lexer::token& t) exprtk_override +{ +// ': =' --> ':=' +if ((t0.type == lexer::token::e_colon) && (t1.type == lexer::token::e_eq)) +{ +t.type = lexer::token::e_assign; +t.value = ":="; +t.position = t0.position; + +return true; +} +// '+ =' --> '+=' +else if ((t0.type == lexer::token::e_add) && (t1.type == lexer::token::e_eq)) +{ +t.type = lexer::token::e_addass; +t.value = "+="; +t.position = t0.position; + +return true; +} +// '- =' --> '-=' +else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_eq)) +{ +t.type = lexer::token::e_subass; +t.value = "-="; +t.position = t0.position; + +return true; +} +// '* =' --> '*=' +else if ((t0.type == lexer::token::e_mul) && (t1.type == lexer::token::e_eq)) +{ +t.type = lexer::token::e_mulass; +t.value = "*="; +t.position = t0.position; + +return true; +} +// '/ =' --> '/=' +else if ((t0.type == lexer::token::e_div) && (t1.type == lexer::token::e_eq)) +{ +t.type = lexer::token::e_divass; +t.value = "/="; +t.position = t0.position; + +return true; +} +// '% =' --> '%=' +else if ((t0.type == lexer::token::e_mod) && (t1.type == lexer::token::e_eq)) +{ +t.type = lexer::token::e_modass; +t.value = "%="; +t.position = t0.position; + +return true; +} +// '> =' --> '>=' +else if ((t0.type == lexer::token::e_gt) && (t1.type == lexer::token::e_eq)) +{ +t.type = lexer::token::e_gte; +t.value = ">="; +t.position = t0.position; + +return true; +} +// '< =' --> '<=' +else if ((t0.type == lexer::token::e_lt) && (t1.type == lexer::token::e_eq)) +{ +t.type = lexer::token::e_lte; +t.value = "<="; +t.position = t0.position; + +return true; +} +// '= =' --> '==' +else if ((t0.type == lexer::token::e_eq) && (t1.type == lexer::token::e_eq)) +{ +t.type = lexer::token::e_eq; +t.value = "=="; +t.position = t0.position; + +return true; +} +// '! =' --> '!=' +else if ((static_cast(t0.type) == '!') && (t1.type == lexer::token::e_eq)) +{ +t.type = lexer::token::e_ne; +t.value = "!="; +t.position = t0.position; + +return true; +} +// '< >' --> '<>' +else if ((t0.type == lexer::token::e_lt) && (t1.type == lexer::token::e_gt)) +{ +t.type = lexer::token::e_ne; +t.value = "<>"; +t.position = t0.position; + +return true; +} +// '<= >' --> '<=>' +else if ((t0.type == lexer::token::e_lte) && (t1.type == lexer::token::e_gt)) +{ +t.type = lexer::token::e_swap; +t.value = "<=>"; +t.position = t0.position; + +return true; +} +// '+ -' --> '-' +else if ((t0.type == lexer::token::e_add) && (t1.type == lexer::token::e_sub)) +{ +t.type = lexer::token::e_sub; +t.value = "-"; +t.position = t0.position; + +return true; +} +// '- +' --> '-' +else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_add)) +{ +t.type = lexer::token::e_sub; +t.value = "-"; +t.position = t0.position; + +return true; +} +// '- -' --> '+' +else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_sub)) +{ +/* + Note: May need to reconsider this when wanting to implement + pre/postfix decrement operator + */ +t.type = lexer::token::e_add; +t.value = "+"; +t.position = t0.position; + +return true; +} +else +return false; +} + +inline bool join(const lexer::token& t0, +const lexer::token& t1, +const lexer::token& t2, +lexer::token& t) exprtk_override +{ +// '[ * ]' --> '[*]' +if ( +(t0.type == lexer::token::e_lsqrbracket) && +(t1.type == lexer::token::e_mul ) && +(t2.type == lexer::token::e_rsqrbracket) +) +{ +t.type = lexer::token::e_symbol; +t.value = "[*]"; +t.position = t0.position; + +return true; +} +else +return false; +} +}; + +class bracket_checker : public lexer::token_scanner +{ +public: + +using lexer::token_scanner::operator(); + +bracket_checker() +: token_scanner(1) +, state_(true) +{} + +bool result() +{ +if (!stack_.empty()) +{ +lexer::token t; +t.value = stack_.top().first; +t.position = stack_.top().second; +error_token_ = t; +state_ = false; + +return false; +} +else +return state_; +} + +lexer::token error_token() +{ +return error_token_; +} + +void reset() +{ +// Why? because msvc doesn't support swap properly. +stack_ = std::stack >(); +state_ = true; +error_token_.clear(); +} + +bool operator() (const lexer::token& t) +{ +if ( +!t.value.empty() && +(lexer::token::e_string != t.type) && +(lexer::token::e_symbol != t.type) && +exprtk::details::is_bracket(t.value[0]) +) +{ +details::char_t c = t.value[0]; + +if (t.type == lexer::token::e_lbracket ) stack_.push(std::make_pair(')',t.position)); +else if (t.type == lexer::token::e_lcrlbracket) stack_.push(std::make_pair('}',t.position)); +else if (t.type == lexer::token::e_lsqrbracket) stack_.push(std::make_pair(']',t.position)); +else if (exprtk::details::is_right_bracket(c)) +{ +if (stack_.empty()) +{ +state_ = false; +error_token_ = t; + +return false; +} +else if (c != stack_.top().first) +{ +state_ = false; +error_token_ = t; + +return false; +} +else +stack_.pop(); +} +} + +return true; +} + +private: + +bool state_; +std::stack > stack_; +lexer::token error_token_; +}; + +template +class numeric_checker exprtk_final : public lexer::token_scanner +{ +public: + +using lexer::token_scanner::operator(); + +numeric_checker() +: token_scanner (1) +, current_index_(0) +{} + +bool result() +{ +return error_list_.empty(); +} + +void reset() +{ +error_list_.clear(); +current_index_ = 0; +} + +bool operator() (const lexer::token& t) +{ +if (token::e_number == t.type) +{ +T v; + +if (!exprtk::details::string_to_real(t.value,v)) +{ +error_list_.push_back(current_index_); +} +} + +++current_index_; + +return true; +} + +std::size_t error_count() const +{ +return error_list_.size(); +} + +std::size_t error_index(const std::size_t& i) +{ +if (i < error_list_.size()) +return error_list_[i]; +else +return std::numeric_limits::max(); +} + +void clear_errors() +{ +error_list_.clear(); +} + +private: + +std::size_t current_index_; +std::vector error_list_; +}; + +class symbol_replacer : public lexer::token_modifier +{ +private: + +typedef std::map,details::ilesscompare> replace_map_t; + +public: + +bool remove(const std::string& target_symbol) +{ +const replace_map_t::iterator itr = replace_map_.find(target_symbol); + +if (replace_map_.end() == itr) +return false; + +replace_map_.erase(itr); + +return true; +} + +bool add_replace(const std::string& target_symbol, +const std::string& replace_symbol, +const lexer::token::token_type token_type = lexer::token::e_symbol) +{ +const replace_map_t::iterator itr = replace_map_.find(target_symbol); + +if (replace_map_.end() != itr) +{ +return false; +} + +replace_map_[target_symbol] = std::make_pair(replace_symbol,token_type); + +return true; +} + +void clear() +{ +replace_map_.clear(); +} + +private: + +bool modify(lexer::token& t) +{ +if (lexer::token::e_symbol == t.type) +{ +if (replace_map_.empty()) +return false; + +const replace_map_t::iterator itr = replace_map_.find(t.value); + +if (replace_map_.end() != itr) +{ +t.value = itr->second.first; +t.type = itr->second.second; + +return true; +} +} + +return false; +} + +replace_map_t replace_map_; +}; + +class sequence_validator exprtk_final : public lexer::token_scanner +{ +private: + +typedef std::pair token_pair_t; +typedef std::set set_t; + +public: + +using lexer::token_scanner::operator(); + +sequence_validator() +: lexer::token_scanner(2) +{ +add_invalid(lexer::token::e_number, lexer::token::e_number); +add_invalid(lexer::token::e_string, lexer::token::e_string); +add_invalid(lexer::token::e_number, lexer::token::e_string); +add_invalid(lexer::token::e_string, lexer::token::e_number); + +add_invalid_set1(lexer::token::e_assign ); +add_invalid_set1(lexer::token::e_shr ); +add_invalid_set1(lexer::token::e_shl ); +add_invalid_set1(lexer::token::e_lte ); +add_invalid_set1(lexer::token::e_ne ); +add_invalid_set1(lexer::token::e_gte ); +add_invalid_set1(lexer::token::e_lt ); +add_invalid_set1(lexer::token::e_gt ); +add_invalid_set1(lexer::token::e_eq ); +add_invalid_set1(lexer::token::e_comma ); +add_invalid_set1(lexer::token::e_add ); +add_invalid_set1(lexer::token::e_sub ); +add_invalid_set1(lexer::token::e_div ); +add_invalid_set1(lexer::token::e_mul ); +add_invalid_set1(lexer::token::e_mod ); +add_invalid_set1(lexer::token::e_pow ); +add_invalid_set1(lexer::token::e_colon ); +add_invalid_set1(lexer::token::e_ternary); +} + +bool result() +{ +return error_list_.empty(); +} + +bool operator() (const lexer::token& t0, const lexer::token& t1) +{ +const set_t::value_type p = std::make_pair(t0.type,t1.type); + +if (invalid_bracket_check(t0.type,t1.type)) +{ +error_list_.push_back(std::make_pair(t0,t1)); +} +else if (invalid_comb_.find(p) != invalid_comb_.end()) +{ +error_list_.push_back(std::make_pair(t0,t1)); +} + +return true; +} + +std::size_t error_count() const +{ +return error_list_.size(); +} + +std::pair error(const std::size_t index) +{ +if (index < error_list_.size()) +{ +return error_list_[index]; +} +else +{ +static const lexer::token error_token; +return std::make_pair(error_token,error_token); +} +} + +void clear_errors() +{ +error_list_.clear(); +} + +private: + +void add_invalid(const lexer::token::token_type base, const lexer::token::token_type t) +{ +invalid_comb_.insert(std::make_pair(base,t)); +} + +void add_invalid_set1(const lexer::token::token_type t) +{ +add_invalid(t, lexer::token::e_assign); +add_invalid(t, lexer::token::e_shr ); +add_invalid(t, lexer::token::e_shl ); +add_invalid(t, lexer::token::e_lte ); +add_invalid(t, lexer::token::e_ne ); +add_invalid(t, lexer::token::e_gte ); +add_invalid(t, lexer::token::e_lt ); +add_invalid(t, lexer::token::e_gt ); +add_invalid(t, lexer::token::e_eq ); +add_invalid(t, lexer::token::e_comma ); +add_invalid(t, lexer::token::e_div ); +add_invalid(t, lexer::token::e_mul ); +add_invalid(t, lexer::token::e_mod ); +add_invalid(t, lexer::token::e_pow ); +add_invalid(t, lexer::token::e_colon ); +} + +bool invalid_bracket_check(const lexer::token::token_type base, const lexer::token::token_type t) +{ +if (details::is_right_bracket(static_cast(base))) +{ +switch (t) +{ +case lexer::token::e_assign : return (']' != base); +case lexer::token::e_string : return (')' != base); +default : return false; +} +} +else if (details::is_left_bracket(static_cast(base))) +{ +if (details::is_right_bracket(static_cast(t))) +return false; +else if (details::is_left_bracket(static_cast(t))) +return false; +else +{ +switch (t) +{ +case lexer::token::e_number : return false; +case lexer::token::e_symbol : return false; +case lexer::token::e_string : return false; +case lexer::token::e_add : return false; +case lexer::token::e_sub : return false; +case lexer::token::e_colon : return false; +case lexer::token::e_ternary : return false; +default : return true ; +} +} +} +else if (details::is_right_bracket(static_cast(t))) +{ +switch (base) +{ +case lexer::token::e_number : return false; +case lexer::token::e_symbol : return false; +case lexer::token::e_string : return false; +case lexer::token::e_eof : return false; +case lexer::token::e_colon : return false; +case lexer::token::e_ternary : return false; +default : return true ; +} +} +else if (details::is_left_bracket(static_cast(t))) +{ +switch (base) +{ +case lexer::token::e_rbracket : return true; +case lexer::token::e_rsqrbracket : return true; +case lexer::token::e_rcrlbracket : return true; +default : return false; +} +} + +return false; +} + +set_t invalid_comb_; +std::vector > error_list_; +}; + +class sequence_validator_3tokens exprtk_final : public lexer::token_scanner +{ +private: + +typedef lexer::token::token_type token_t; +typedef std::pair > token_triplet_t; +typedef std::set set_t; + +public: + +using lexer::token_scanner::operator(); + +sequence_validator_3tokens() +: lexer::token_scanner(3) +{ +add_invalid(lexer::token::e_number , lexer::token::e_number , lexer::token::e_number); +add_invalid(lexer::token::e_string , lexer::token::e_string , lexer::token::e_string); +add_invalid(lexer::token::e_comma , lexer::token::e_comma , lexer::token::e_comma ); + +add_invalid(lexer::token::e_add , lexer::token::e_add , lexer::token::e_add ); +add_invalid(lexer::token::e_sub , lexer::token::e_sub , lexer::token::e_sub ); +add_invalid(lexer::token::e_div , lexer::token::e_div , lexer::token::e_div ); +add_invalid(lexer::token::e_mul , lexer::token::e_mul , lexer::token::e_mul ); +add_invalid(lexer::token::e_mod , lexer::token::e_mod , lexer::token::e_mod ); +add_invalid(lexer::token::e_pow , lexer::token::e_pow , lexer::token::e_pow ); + +add_invalid(lexer::token::e_add , lexer::token::e_sub , lexer::token::e_add ); +add_invalid(lexer::token::e_sub , lexer::token::e_add , lexer::token::e_sub ); +add_invalid(lexer::token::e_div , lexer::token::e_mul , lexer::token::e_div ); +add_invalid(lexer::token::e_mul , lexer::token::e_div , lexer::token::e_mul ); +add_invalid(lexer::token::e_mod , lexer::token::e_pow , lexer::token::e_mod ); +add_invalid(lexer::token::e_pow , lexer::token::e_mod , lexer::token::e_pow ); +} + +bool result() +{ +return error_list_.empty(); +} + +bool operator() (const lexer::token& t0, const lexer::token& t1, const lexer::token& t2) +{ +const set_t::value_type p = std::make_pair(t0.type,std::make_pair(t1.type,t2.type)); + +if (invalid_comb_.find(p) != invalid_comb_.end()) +{ +error_list_.push_back(std::make_pair(t0,t1)); +} + +return true; +} + +std::size_t error_count() const +{ +return error_list_.size(); +} + +std::pair error(const std::size_t index) +{ +if (index < error_list_.size()) +{ +return error_list_[index]; +} +else +{ +static const lexer::token error_token; +return std::make_pair(error_token,error_token); +} +} + +void clear_errors() +{ +error_list_.clear(); +} + +private: + +void add_invalid(const token_t t0, const token_t t1, const token_t t2) +{ +invalid_comb_.insert(std::make_pair(t0,std::make_pair(t1,t2))); +} + +set_t invalid_comb_; +std::vector > error_list_; +}; + +struct helper_assembly +{ +inline bool register_scanner(lexer::token_scanner* scanner) +{ +if (token_scanner_list.end() != std::find(token_scanner_list.begin(), +token_scanner_list.end (), +scanner)) +{ +return false; +} + +token_scanner_list.push_back(scanner); + +return true; +} + +inline bool register_modifier(lexer::token_modifier* modifier) +{ +if (token_modifier_list.end() != std::find(token_modifier_list.begin(), +token_modifier_list.end (), +modifier)) +{ +return false; +} + +token_modifier_list.push_back(modifier); + +return true; +} + +inline bool register_joiner(lexer::token_joiner* joiner) +{ +if (token_joiner_list.end() != std::find(token_joiner_list.begin(), +token_joiner_list.end (), +joiner)) +{ +return false; +} + +token_joiner_list.push_back(joiner); + +return true; +} + +inline bool register_inserter(lexer::token_inserter* inserter) +{ +if (token_inserter_list.end() != std::find(token_inserter_list.begin(), +token_inserter_list.end (), +inserter)) +{ +return false; +} + +token_inserter_list.push_back(inserter); + +return true; +} + +inline bool run_modifiers(lexer::generator& g) +{ +error_token_modifier = reinterpret_cast(0); + +for (std::size_t i = 0; i < token_modifier_list.size(); ++i) +{ +lexer::token_modifier& modifier = (*token_modifier_list[i]); + +modifier.reset(); +modifier.process(g); + +if (!modifier.result()) +{ +error_token_modifier = token_modifier_list[i]; + +return false; +} +} + +return true; +} + +inline bool run_joiners(lexer::generator& g) +{ +error_token_joiner = reinterpret_cast(0); + +for (std::size_t i = 0; i < token_joiner_list.size(); ++i) +{ +lexer::token_joiner& joiner = (*token_joiner_list[i]); + +joiner.reset(); +joiner.process(g); + +if (!joiner.result()) +{ +error_token_joiner = token_joiner_list[i]; + +return false; +} +} + +return true; +} + +inline bool run_inserters(lexer::generator& g) +{ +error_token_inserter = reinterpret_cast(0); + +for (std::size_t i = 0; i < token_inserter_list.size(); ++i) +{ +lexer::token_inserter& inserter = (*token_inserter_list[i]); + +inserter.reset(); +inserter.process(g); + +if (!inserter.result()) +{ +error_token_inserter = token_inserter_list[i]; + +return false; +} +} + +return true; +} + +inline bool run_scanners(lexer::generator& g) +{ +error_token_scanner = reinterpret_cast(0); + +for (std::size_t i = 0; i < token_scanner_list.size(); ++i) +{ +lexer::token_scanner& scanner = (*token_scanner_list[i]); + +scanner.reset(); +scanner.process(g); + +if (!scanner.result()) +{ +error_token_scanner = token_scanner_list[i]; + +return false; +} +} + +return true; +} + +std::vector token_scanner_list; +std::vector token_modifier_list; +std::vector token_joiner_list; +std::vector token_inserter_list; + +lexer::token_scanner* error_token_scanner; +lexer::token_modifier* error_token_modifier; +lexer::token_joiner* error_token_joiner; +lexer::token_inserter* error_token_inserter; +}; +} + +class parser_helper +{ +public: + +typedef token token_t; +typedef generator generator_t; + +inline bool init(const std::string& str) +{ +if (!lexer_.process(str)) +{ +return false; +} + +lexer_.begin(); + +next_token(); + +return true; +} + +inline generator_t& lexer() +{ +return lexer_; +} + +inline const generator_t& lexer() const +{ +return lexer_; +} + +inline void store_token() +{ +lexer_.store(); +store_current_token_ = current_token_; +} + +inline void restore_token() +{ +lexer_.restore(); +current_token_ = store_current_token_; +} + +inline void next_token() +{ +current_token_ = lexer_.next_token(); +} + +inline const token_t& current_token() const +{ +return current_token_; +} + +enum token_advance_mode +{ +e_hold = 0, +e_advance = 1 +}; + +inline void advance_token(const token_advance_mode mode) +{ +if (e_advance == mode) +{ +next_token(); +} +} + +inline bool token_is(const token_t::token_type& ttype, const token_advance_mode mode = e_advance) +{ +if (current_token().type != ttype) +{ +return false; +} + +advance_token(mode); + +return true; +} + +inline bool token_is(const token_t::token_type& ttype, +const std::string& value, +const token_advance_mode mode = e_advance) +{ +if ( +(current_token().type != ttype) || +!exprtk::details::imatch(value,current_token().value) +) +{ +return false; +} + +advance_token(mode); + +return true; +} + +inline bool peek_token_is(const token_t::token_type& ttype) +{ +return (lexer_.peek_next_token().type == ttype); +} + +inline bool peek_token_is(const std::string& s) +{ +return (exprtk::details::imatch(lexer_.peek_next_token().value,s)); +} + +private: + +generator_t lexer_; +token_t current_token_; +token_t store_current_token_; +}; +} + +template +class vector_view +{ +public: + +typedef T* data_ptr_t; + +vector_view(data_ptr_t data, const std::size_t& size) +: size_(size) +, data_(data) +, data_ref_(0) +{} + +vector_view(const vector_view& vv) +: size_(vv.size_) +, data_(vv.data_) +, data_ref_(0) +{} + +inline void rebase(data_ptr_t data) +{ +data_ = data; + +if (!data_ref_.empty()) +{ +for (std::size_t i = 0; i < data_ref_.size(); ++i) +{ +(*data_ref_[i]) = data; +} +} +} + +inline data_ptr_t data() const +{ +return data_; +} + +inline std::size_t size() const +{ +return size_; +} + +inline const T& operator[](const std::size_t index) const +{ +return data_[index]; +} + +inline T& operator[](const std::size_t index) +{ +return data_[index]; +} + +void set_ref(data_ptr_t* data_ref) +{ +data_ref_.push_back(data_ref); +} + +private: + +const std::size_t size_; +data_ptr_t data_; +std::vector data_ref_; +}; + +template +inline vector_view make_vector_view(T* data, +const std::size_t size, const std::size_t offset = 0) +{ +return vector_view(data + offset, size); +} + +template +inline vector_view make_vector_view(std::vector& v, +const std::size_t size, const std::size_t offset = 0) +{ +return vector_view(v.data() + offset, size); +} + +template class results_context; + +template +struct type_store +{ +enum store_type +{ +e_unknown, +e_scalar , +e_vector , +e_string +}; + +type_store() +: data(0) +, size(0) +, type(e_unknown) +{} + +union +{ +void* data; +T* vec_data; +}; + +std::size_t size; +store_type type; + +class parameter_list +{ +public: + +explicit parameter_list(std::vector& pl) +: parameter_list_(pl) +{} + +inline bool empty() const +{ +return parameter_list_.empty(); +} + +inline std::size_t size() const +{ +return parameter_list_.size(); +} + +inline type_store& operator[](const std::size_t& index) +{ +return parameter_list_[index]; +} + +inline const type_store& operator[](const std::size_t& index) const +{ +return parameter_list_[index]; +} + +inline type_store& front() +{ +return parameter_list_[0]; +} + +inline const type_store& front() const +{ +return parameter_list_[0]; +} + +inline type_store& back() +{ +return parameter_list_.back(); +} + +inline const type_store& back() const +{ +return parameter_list_.back(); +} + +private: + +std::vector& parameter_list_; + +friend class results_context; +}; + +template +struct type_view +{ +typedef type_store type_store_t; +typedef ViewType value_t; + +explicit type_view(type_store_t& ts) +: ts_(ts) +, data_(reinterpret_cast(ts_.data)) +{} + +explicit type_view(const type_store_t& ts) +: ts_(const_cast(ts)) +, data_(reinterpret_cast(ts_.data)) +{} + +inline std::size_t size() const +{ +return ts_.size; +} + +inline value_t& operator[](const std::size_t& i) +{ +return data_[i]; +} + +inline const value_t& operator[](const std::size_t& i) const +{ +return data_[i]; +} + +inline const value_t* begin() const { return data_; } +inline value_t* begin() { return data_; } + +inline const value_t* end() const +{ +return static_cast(data_ + ts_.size); +} + +inline value_t* end() +{ +return static_cast(data_ + ts_.size); +} + +type_store_t& ts_; +value_t* data_; +}; + +typedef type_view vector_view; +typedef type_view string_view; + +struct scalar_view +{ +typedef type_store type_store_t; +typedef T value_t; + +explicit scalar_view(type_store_t& ts) +: v_(*reinterpret_cast(ts.data)) +{} + +explicit scalar_view(const type_store_t& ts) +: v_(*reinterpret_cast(const_cast(ts).data)) +{} + +inline value_t& operator() () +{ +return v_; +} + +inline const value_t& operator() () const +{ +return v_; +} + +template +inline bool to_int(IntType& i) const +{ +if (!exprtk::details::numeric::is_integer(v_)) +return false; + +i = static_cast(v_); + +return true; +} + +template +inline bool to_uint(UIntType& u) const +{ +if (v_ < T(0)) +return false; +else if (!exprtk::details::numeric::is_integer(v_)) +return false; + +u = static_cast(v_); + +return true; +} + +T& v_; +}; +}; + +template +inline std::string to_str(const StringView& view) +{ +return std::string(view.begin(),view.size()); +} + +#ifndef exprtk_disable_return_statement +namespace details +{ +template class return_node; +template class return_envelope_node; +} +#endif + +template +class results_context +{ +public: + +typedef type_store type_store_t; + +results_context() +: results_available_(false) +{} + +inline std::size_t count() const +{ +if (results_available_) +return parameter_list_.size(); +else +return 0; +} + +inline type_store_t& operator[](const std::size_t& index) +{ +return parameter_list_[index]; +} + +inline const type_store_t& operator[](const std::size_t& index) const +{ +return parameter_list_[index]; +} + +private: + +inline void clear() +{ +results_available_ = false; +} + +typedef std::vector ts_list_t; +typedef typename type_store_t::parameter_list parameter_list_t; + +inline void assign(const parameter_list_t& pl) +{ +parameter_list_ = pl.parameter_list_; +results_available_ = true; +} + +bool results_available_; +ts_list_t parameter_list_; + +#ifndef exprtk_disable_return_statement +friend class details::return_node; +friend class details::return_envelope_node; +#endif +}; + +namespace details +{ +enum operator_type +{ +e_default , e_null , e_add , e_sub , +e_mul , e_div , e_mod , e_pow , +e_atan2 , e_min , e_max , e_avg , +e_sum , e_prod , e_lt , e_lte , +e_eq , e_equal , e_ne , e_nequal , +e_gte , e_gt , e_and , e_nand , +e_or , e_nor , e_xor , e_xnor , +e_mand , e_mor , e_scand , e_scor , +e_shr , e_shl , e_abs , e_acos , +e_acosh , e_asin , e_asinh , e_atan , +e_atanh , e_ceil , e_cos , e_cosh , +e_exp , e_expm1 , e_floor , e_log , +e_log10 , e_log2 , e_log1p , e_logn , +e_neg , e_pos , e_round , e_roundn , +e_root , e_sqrt , e_sin , e_sinc , +e_sinh , e_sec , e_csc , e_tan , +e_tanh , e_cot , e_clamp , e_iclamp , +e_inrange , e_sgn , e_r2d , e_d2r , +e_d2g , e_g2d , e_hypot , e_notl , +e_erf , e_erfc , e_ncdf , e_frac , +e_trunc , e_assign , e_addass , e_subass , +e_mulass , e_divass , e_modass , e_in , +e_like , e_ilike , e_multi , e_smulti , +e_swap , + +// Do not add new functions/operators after this point. +e_sf00 = 1000, e_sf01 = 1001, e_sf02 = 1002, e_sf03 = 1003, +e_sf04 = 1004, e_sf05 = 1005, e_sf06 = 1006, e_sf07 = 1007, +e_sf08 = 1008, e_sf09 = 1009, e_sf10 = 1010, e_sf11 = 1011, +e_sf12 = 1012, e_sf13 = 1013, e_sf14 = 1014, e_sf15 = 1015, +e_sf16 = 1016, e_sf17 = 1017, e_sf18 = 1018, e_sf19 = 1019, +e_sf20 = 1020, e_sf21 = 1021, e_sf22 = 1022, e_sf23 = 1023, +e_sf24 = 1024, e_sf25 = 1025, e_sf26 = 1026, e_sf27 = 1027, +e_sf28 = 1028, e_sf29 = 1029, e_sf30 = 1030, e_sf31 = 1031, +e_sf32 = 1032, e_sf33 = 1033, e_sf34 = 1034, e_sf35 = 1035, +e_sf36 = 1036, e_sf37 = 1037, e_sf38 = 1038, e_sf39 = 1039, +e_sf40 = 1040, e_sf41 = 1041, e_sf42 = 1042, e_sf43 = 1043, +e_sf44 = 1044, e_sf45 = 1045, e_sf46 = 1046, e_sf47 = 1047, +e_sf48 = 1048, e_sf49 = 1049, e_sf50 = 1050, e_sf51 = 1051, +e_sf52 = 1052, e_sf53 = 1053, e_sf54 = 1054, e_sf55 = 1055, +e_sf56 = 1056, e_sf57 = 1057, e_sf58 = 1058, e_sf59 = 1059, +e_sf60 = 1060, e_sf61 = 1061, e_sf62 = 1062, e_sf63 = 1063, +e_sf64 = 1064, e_sf65 = 1065, e_sf66 = 1066, e_sf67 = 1067, +e_sf68 = 1068, e_sf69 = 1069, e_sf70 = 1070, e_sf71 = 1071, +e_sf72 = 1072, e_sf73 = 1073, e_sf74 = 1074, e_sf75 = 1075, +e_sf76 = 1076, e_sf77 = 1077, e_sf78 = 1078, e_sf79 = 1079, +e_sf80 = 1080, e_sf81 = 1081, e_sf82 = 1082, e_sf83 = 1083, +e_sf84 = 1084, e_sf85 = 1085, e_sf86 = 1086, e_sf87 = 1087, +e_sf88 = 1088, e_sf89 = 1089, e_sf90 = 1090, e_sf91 = 1091, +e_sf92 = 1092, e_sf93 = 1093, e_sf94 = 1094, e_sf95 = 1095, +e_sf96 = 1096, e_sf97 = 1097, e_sf98 = 1098, e_sf99 = 1099, +e_sffinal = 1100, +e_sf4ext00 = 2000, e_sf4ext01 = 2001, e_sf4ext02 = 2002, e_sf4ext03 = 2003, +e_sf4ext04 = 2004, e_sf4ext05 = 2005, e_sf4ext06 = 2006, e_sf4ext07 = 2007, +e_sf4ext08 = 2008, e_sf4ext09 = 2009, e_sf4ext10 = 2010, e_sf4ext11 = 2011, +e_sf4ext12 = 2012, e_sf4ext13 = 2013, e_sf4ext14 = 2014, e_sf4ext15 = 2015, +e_sf4ext16 = 2016, e_sf4ext17 = 2017, e_sf4ext18 = 2018, e_sf4ext19 = 2019, +e_sf4ext20 = 2020, e_sf4ext21 = 2021, e_sf4ext22 = 2022, e_sf4ext23 = 2023, +e_sf4ext24 = 2024, e_sf4ext25 = 2025, e_sf4ext26 = 2026, e_sf4ext27 = 2027, +e_sf4ext28 = 2028, e_sf4ext29 = 2029, e_sf4ext30 = 2030, e_sf4ext31 = 2031, +e_sf4ext32 = 2032, e_sf4ext33 = 2033, e_sf4ext34 = 2034, e_sf4ext35 = 2035, +e_sf4ext36 = 2036, e_sf4ext37 = 2037, e_sf4ext38 = 2038, e_sf4ext39 = 2039, +e_sf4ext40 = 2040, e_sf4ext41 = 2041, e_sf4ext42 = 2042, e_sf4ext43 = 2043, +e_sf4ext44 = 2044, e_sf4ext45 = 2045, e_sf4ext46 = 2046, e_sf4ext47 = 2047, +e_sf4ext48 = 2048, e_sf4ext49 = 2049, e_sf4ext50 = 2050, e_sf4ext51 = 2051, +e_sf4ext52 = 2052, e_sf4ext53 = 2053, e_sf4ext54 = 2054, e_sf4ext55 = 2055, +e_sf4ext56 = 2056, e_sf4ext57 = 2057, e_sf4ext58 = 2058, e_sf4ext59 = 2059, +e_sf4ext60 = 2060, e_sf4ext61 = 2061 +}; + +inline std::string to_str(const operator_type opr) +{ +switch (opr) +{ +case e_add : return "+" ; +case e_sub : return "-" ; +case e_mul : return "*" ; +case e_div : return "/" ; +case e_mod : return "%" ; +case e_pow : return "^" ; +case e_assign : return ":=" ; +case e_addass : return "+=" ; +case e_subass : return "-=" ; +case e_mulass : return "*=" ; +case e_divass : return "/=" ; +case e_modass : return "%=" ; +case e_lt : return "<" ; +case e_lte : return "<=" ; +case e_eq : return "==" ; +case e_equal : return "=" ; +case e_ne : return "!=" ; +case e_nequal : return "<>" ; +case e_gte : return ">=" ; +case e_gt : return ">" ; +case e_and : return "and" ; +case e_or : return "or" ; +case e_xor : return "xor" ; +case e_nand : return "nand"; +case e_nor : return "nor" ; +case e_xnor : return "xnor"; +default : return "N/A" ; +} +} + +struct base_operation_t +{ +base_operation_t(const operator_type t, const unsigned int& np) +: type(t) +, num_params(np) +{} + +operator_type type; +unsigned int num_params; +}; + +namespace loop_unroll +{ +#ifndef exprtk_disable_superscalar_unroll +const unsigned int global_loop_batch_size = 16; +#else +const unsigned int global_loop_batch_size = 4; +#endif + +struct details +{ +explicit details(const std::size_t& vsize, +const unsigned int loop_batch_size = global_loop_batch_size) +: batch_size(loop_batch_size ) +, remainder (vsize % batch_size) +, upper_bound(static_cast(vsize - (remainder ? loop_batch_size : 0))) +{} + +unsigned int batch_size; +int remainder; +int upper_bound; +}; +} + +#ifdef exprtk_enable_debugging +inline void dump_ptr(const std::string& s, const void* ptr, const std::size_t size = 0) +{ +if (size) +exprtk_debug(("%s - addr: %p size: %d\n", +s.c_str(), +ptr, +static_cast(size))); +else +exprtk_debug(("%s - addr: %p\n",s.c_str(),ptr)); +} +#else +inline void dump_ptr(const std::string&, const void*) {} +inline void dump_ptr(const std::string&, const void*, const std::size_t) {} +#endif + +template +class vec_data_store +{ +public: + +typedef vec_data_store type; +typedef T* data_t; + +private: + +struct control_block +{ +control_block() +: ref_count(1) +, size (0) +, data (0) +, destruct (true) +{} + +explicit control_block(const std::size_t& dsize) +: ref_count(1 ) +, size (dsize) +, data (0 ) +, destruct (true ) +{ create_data(); } + +control_block(const std::size_t& dsize, data_t dptr, bool dstrct = false) +: ref_count(1 ) +, size (dsize ) +, data (dptr ) +, destruct (dstrct) +{} + +~control_block() +{ +if (data && destruct && (0 == ref_count)) +{ +dump_ptr("~vec_data_store::control_block() data",data); +delete[] data; +data = reinterpret_cast(0); +} +} + +static inline control_block* create(const std::size_t& dsize, data_t data_ptr = data_t(0), bool dstrct = false) +{ +if (dsize) +{ +if (0 == data_ptr) +return (new control_block(dsize)); +else +return (new control_block(dsize, data_ptr, dstrct)); +} +else +return (new control_block); +} + +static inline void destroy(control_block*& cntrl_blck) +{ +if (cntrl_blck) +{ +if ( +(0 != cntrl_blck->ref_count) && +(0 == --cntrl_blck->ref_count) +) +{ +delete cntrl_blck; +} + +cntrl_blck = 0; +} +} + +std::size_t ref_count; +std::size_t size; +data_t data; +bool destruct; + +private: + +control_block(const control_block&) exprtk_delete; +control_block& operator=(const control_block&) exprtk_delete; + +inline void create_data() +{ +destruct = true; +data = new T[size]; +std::fill_n(data, size, T(0)); +dump_ptr("control_block::create_data() - data", data, size); +} +}; + +public: + +vec_data_store() +: control_block_(control_block::create(0)) +{} + +explicit vec_data_store(const std::size_t& size) +: control_block_(control_block::create(size,reinterpret_cast(0),true)) +{} + +vec_data_store(const std::size_t& size, data_t data, bool dstrct = false) +: control_block_(control_block::create(size, data, dstrct)) +{} + +vec_data_store(const type& vds) +{ +control_block_ = vds.control_block_; +control_block_->ref_count++; +} + +~vec_data_store() +{ +control_block::destroy(control_block_); +} + +type& operator=(const type& vds) +{ +if (this != &vds) +{ +std::size_t final_size = min_size(control_block_, vds.control_block_); + +vds.control_block_->size = final_size; +control_block_->size = final_size; + +if (control_block_->destruct || (0 == control_block_->data)) +{ +control_block::destroy(control_block_); + +control_block_ = vds.control_block_; +control_block_->ref_count++; +} +} + +return (*this); +} + +inline data_t data() +{ +return control_block_->data; +} + +inline data_t data() const +{ +return control_block_->data; +} + +inline std::size_t size() const +{ +return control_block_->size; +} + +inline data_t& ref() +{ +return control_block_->data; +} + +inline void dump() const +{ +#ifdef exprtk_enable_debugging +exprtk_debug(("size: %d\taddress:%p\tdestruct:%c\n", +size(), +data(), +(control_block_->destruct ? 'T' : 'F'))); + +for (std::size_t i = 0; i < size(); ++i) +{ +if (5 == i) +exprtk_debug(("\n")); + +exprtk_debug(("%15.10f ",data()[i])); +} +exprtk_debug(("\n")); +#endif +} + +static inline void match_sizes(type& vds0, type& vds1) +{ +const std::size_t size = min_size(vds0.control_block_,vds1.control_block_); +vds0.control_block_->size = size; +vds1.control_block_->size = size; +} + +private: + +static inline std::size_t min_size(const control_block* cb0, const control_block* cb1) +{ +const std::size_t size0 = cb0->size; +const std::size_t size1 = cb1->size; + +if (size0 && size1) +return std::min(size0,size1); +else +return (size0) ? size0 : size1; +} + +control_block* control_block_; +}; + +namespace numeric +{ +namespace details +{ +template +inline T process_impl(const operator_type operation, const T arg) +{ +switch (operation) +{ +case e_abs : return numeric::abs (arg); +case e_acos : return numeric::acos (arg); +case e_acosh : return numeric::acosh(arg); +case e_asin : return numeric::asin (arg); +case e_asinh : return numeric::asinh(arg); +case e_atan : return numeric::atan (arg); +case e_atanh : return numeric::atanh(arg); +case e_ceil : return numeric::ceil (arg); +case e_cos : return numeric::cos (arg); +case e_cosh : return numeric::cosh (arg); +case e_exp : return numeric::exp (arg); +case e_expm1 : return numeric::expm1(arg); +case e_floor : return numeric::floor(arg); +case e_log : return numeric::log (arg); +case e_log10 : return numeric::log10(arg); +case e_log2 : return numeric::log2 (arg); +case e_log1p : return numeric::log1p(arg); +case e_neg : return numeric::neg (arg); +case e_pos : return numeric::pos (arg); +case e_round : return numeric::round(arg); +case e_sin : return numeric::sin (arg); +case e_sinc : return numeric::sinc (arg); +case e_sinh : return numeric::sinh (arg); +case e_sqrt : return numeric::sqrt (arg); +case e_tan : return numeric::tan (arg); +case e_tanh : return numeric::tanh (arg); +case e_cot : return numeric::cot (arg); +case e_sec : return numeric::sec (arg); +case e_csc : return numeric::csc (arg); +case e_r2d : return numeric::r2d (arg); +case e_d2r : return numeric::d2r (arg); +case e_d2g : return numeric::d2g (arg); +case e_g2d : return numeric::g2d (arg); +case e_notl : return numeric::notl (arg); +case e_sgn : return numeric::sgn (arg); +case e_erf : return numeric::erf (arg); +case e_erfc : return numeric::erfc (arg); +case e_ncdf : return numeric::ncdf (arg); +case e_frac : return numeric::frac (arg); +case e_trunc : return numeric::trunc(arg); + +default : exprtk_debug(("numeric::details::process_impl - Invalid unary operation.\n")); +return std::numeric_limits::quiet_NaN(); +} +} + +template +inline T process_impl(const operator_type operation, const T arg0, const T arg1) +{ +switch (operation) +{ +case e_add : return (arg0 + arg1); +case e_sub : return (arg0 - arg1); +case e_mul : return (arg0 * arg1); +case e_div : return (arg0 / arg1); +case e_mod : return modulus(arg0,arg1); +case e_pow : return pow(arg0,arg1); +case e_atan2 : return atan2(arg0,arg1); +case e_min : return std::min(arg0,arg1); +case e_max : return std::max(arg0,arg1); +case e_logn : return logn(arg0,arg1); +case e_lt : return (arg0 < arg1) ? T(1) : T(0); +case e_lte : return (arg0 <= arg1) ? T(1) : T(0); +case e_eq : return std::equal_to()(arg0,arg1) ? T(1) : T(0); +case e_ne : return std::not_equal_to()(arg0,arg1) ? T(1) : T(0); +case e_gte : return (arg0 >= arg1) ? T(1) : T(0); +case e_gt : return (arg0 > arg1) ? T(1) : T(0); +case e_and : return and_opr (arg0,arg1); +case e_nand : return nand_opr(arg0,arg1); +case e_or : return or_opr (arg0,arg1); +case e_nor : return nor_opr (arg0,arg1); +case e_xor : return xor_opr (arg0,arg1); +case e_xnor : return xnor_opr(arg0,arg1); +case e_root : return root (arg0,arg1); +case e_roundn : return roundn (arg0,arg1); +case e_equal : return equal (arg0,arg1); +case e_nequal : return nequal (arg0,arg1); +case e_hypot : return hypot (arg0,arg1); +case e_shr : return shr (arg0,arg1); +case e_shl : return shl (arg0,arg1); + +default : exprtk_debug(("numeric::details::process_impl - Invalid binary operation.\n")); +return std::numeric_limits::quiet_NaN(); +} +} + +template +inline T process_impl(const operator_type operation, const T arg0, const T arg1, int_type_tag) +{ +switch (operation) +{ +case e_add : return (arg0 + arg1); +case e_sub : return (arg0 - arg1); +case e_mul : return (arg0 * arg1); +case e_div : return (arg0 / arg1); +case e_mod : return arg0 % arg1; +case e_pow : return pow(arg0,arg1); +case e_min : return std::min(arg0,arg1); +case e_max : return std::max(arg0,arg1); +case e_logn : return logn(arg0,arg1); +case e_lt : return (arg0 < arg1) ? T(1) : T(0); +case e_lte : return (arg0 <= arg1) ? T(1) : T(0); +case e_eq : return (arg0 == arg1) ? T(1) : T(0); +case e_ne : return (arg0 != arg1) ? T(1) : T(0); +case e_gte : return (arg0 >= arg1) ? T(1) : T(0); +case e_gt : return (arg0 > arg1) ? T(1) : T(0); +case e_and : return ((arg0 != T(0)) && (arg1 != T(0))) ? T(1) : T(0); +case e_nand : return ((arg0 != T(0)) && (arg1 != T(0))) ? T(0) : T(1); +case e_or : return ((arg0 != T(0)) || (arg1 != T(0))) ? T(1) : T(0); +case e_nor : return ((arg0 != T(0)) || (arg1 != T(0))) ? T(0) : T(1); +case e_xor : return arg0 ^ arg1; +case e_xnor : return !(arg0 ^ arg1); +case e_root : return root(arg0,arg1); +case e_equal : return arg0 == arg1; +case e_nequal : return arg0 != arg1; +case e_hypot : return hypot(arg0,arg1); +case e_shr : return arg0 >> arg1; +case e_shl : return arg0 << arg1; + +default : exprtk_debug(("numeric::details::process_impl - Invalid binary operation.\n")); +return std::numeric_limits::quiet_NaN(); +} +} +} + +template +inline T process(const operator_type operation, const T arg) +{ +return exprtk::details::numeric::details::process_impl(operation,arg); +} + +template +inline T process(const operator_type operation, const T arg0, const T arg1) +{ +return exprtk::details::numeric::details::process_impl(operation, arg0, arg1); +} +} + +template +struct node_collector_interface +{ +typedef Node* node_ptr_t; +typedef Node** node_pp_t; +typedef std::vector noderef_list_t; + +virtual ~node_collector_interface() {} + +virtual void collect_nodes(noderef_list_t&) {} +}; + +template +struct node_depth_base; + +template +class expression_node : public node_collector_interface >, +public node_depth_base > +{ +public: + +enum node_type +{ +e_none , e_null , e_constant , e_unary , +e_binary , e_binary_ext , e_trinary , e_quaternary , +e_vararg , e_conditional , e_while , e_repeat , +e_for , e_switch , e_mswitch , e_return , +e_retenv , e_variable , e_stringvar , e_stringconst , +e_stringvarrng , e_cstringvarrng , e_strgenrange , e_strconcat , +e_stringvarsize , e_strswap , e_stringsize , e_stringvararg , +e_function , e_vafunction , e_genfunction , e_strfunction , +e_strcondition , e_strccondition , e_add , e_sub , +e_mul , e_div , e_mod , e_pow , +e_lt , e_lte , e_gt , e_gte , +e_eq , e_ne , e_and , e_nand , +e_or , e_nor , e_xor , e_xnor , +e_in , e_like , e_ilike , e_inranges , +e_ipow , e_ipowinv , e_abs , e_acos , +e_acosh , e_asin , e_asinh , e_atan , +e_atanh , e_ceil , e_cos , e_cosh , +e_exp , e_expm1 , e_floor , e_log , +e_log10 , e_log2 , e_log1p , e_neg , +e_pos , e_round , e_sin , e_sinc , +e_sinh , e_sqrt , e_tan , e_tanh , +e_cot , e_sec , e_csc , e_r2d , +e_d2r , e_d2g , e_g2d , e_notl , +e_sgn , e_erf , e_erfc , e_ncdf , +e_frac , e_trunc , e_uvouv , e_vov , +e_cov , e_voc , e_vob , e_bov , +e_cob , e_boc , e_vovov , e_vovoc , +e_vocov , e_covov , e_covoc , e_vovovov , +e_vovovoc , e_vovocov , e_vocovov , e_covovov , +e_covocov , e_vocovoc , e_covovoc , e_vococov , +e_sf3ext , e_sf4ext , e_nulleq , e_strass , +e_vector , e_vecelem , e_rbvecelem , e_rbveccelem , +e_vecdefass , e_vecvalass , e_vecvecass , e_vecopvalass , +e_vecopvecass , e_vecfunc , e_vecvecswap , e_vecvecineq , +e_vecvalineq , e_valvecineq , e_vecvecarith , e_vecvalarith , +e_valvecarith , e_vecunaryop , e_vecondition , e_break , +e_continue , e_swap +}; + +typedef T value_type; +typedef expression_node* expression_ptr; +typedef node_collector_interface > nci_t; +typedef typename nci_t::noderef_list_t noderef_list_t; +typedef node_depth_base > ndb_t; + +virtual ~expression_node() {} + +inline virtual T value() const +{ +return std::numeric_limits::quiet_NaN(); +} + +inline virtual expression_node* branch(const std::size_t& index = 0) const +{ +return reinterpret_cast(index * 0); +} + +inline virtual node_type type() const +{ +return e_none; +} +}; // class expression_node + +template +inline bool is_generally_string_node(const expression_node* node); + +inline bool is_true(const double v) +{ +return std::not_equal_to()(0.0,v); +} + +inline bool is_true(const long double v) +{ +return std::not_equal_to()(0.0L,v); +} + +inline bool is_true(const float v) +{ +return std::not_equal_to()(0.0f,v); +} + +template +inline bool is_true(const expression_node* node) +{ +return std::not_equal_to()(T(0),node->value()); +} + +template +inline bool is_true(const std::pair*,bool>& node) +{ +return std::not_equal_to()(T(0),node.first->value()); +} + +template +inline bool is_false(const expression_node* node) +{ +return std::equal_to()(T(0),node->value()); +} + +template +inline bool is_false(const std::pair*,bool>& node) +{ +return std::equal_to()(T(0),node.first->value()); +} + +template +inline bool is_unary_node(const expression_node* node) +{ +return node && (details::expression_node::e_unary == node->type()); +} + +template +inline bool is_neg_unary_node(const expression_node* node) +{ +return node && (details::expression_node::e_neg == node->type()); +} + +template +inline bool is_binary_node(const expression_node* node) +{ +return node && (details::expression_node::e_binary == node->type()); +} + +template +inline bool is_variable_node(const expression_node* node) +{ +return node && (details::expression_node::e_variable == node->type()); +} + +template +inline bool is_ivariable_node(const expression_node* node) +{ +return node && +( +details::expression_node::e_variable == node->type() || +details::expression_node::e_vecelem == node->type() || +details::expression_node::e_rbvecelem == node->type() || +details::expression_node::e_rbveccelem == node->type() +); +} + +template +inline bool is_vector_elem_node(const expression_node* node) +{ +return node && (details::expression_node::e_vecelem == node->type()); +} + +template +inline bool is_rebasevector_elem_node(const expression_node* node) +{ +return node && (details::expression_node::e_rbvecelem == node->type()); +} + +template +inline bool is_rebasevector_celem_node(const expression_node* node) +{ +return node && (details::expression_node::e_rbveccelem == node->type()); +} + +template +inline bool is_vector_node(const expression_node* node) +{ +return node && (details::expression_node::e_vector == node->type()); +} + +template +inline bool is_ivector_node(const expression_node* node) +{ +if (node) +{ +switch (node->type()) +{ +case details::expression_node::e_vector : +case details::expression_node::e_vecvalass : +case details::expression_node::e_vecvecass : +case details::expression_node::e_vecopvalass : +case details::expression_node::e_vecopvecass : +case details::expression_node::e_vecvecswap : +case details::expression_node::e_vecvecarith : +case details::expression_node::e_vecvalarith : +case details::expression_node::e_valvecarith : +case details::expression_node::e_vecunaryop : +case details::expression_node::e_vecondition : return true; +default : return false; +} +} +else +return false; +} + +template +inline bool is_constant_node(const expression_node* node) +{ +return node && +( +details::expression_node::e_constant == node->type() || +details::expression_node::e_stringconst == node->type() +); +} + +template +inline bool is_null_node(const expression_node* node) +{ +return node && (details::expression_node::e_null == node->type()); +} + +template +inline bool is_break_node(const expression_node* node) +{ +return node && (details::expression_node::e_break == node->type()); +} + +template +inline bool is_continue_node(const expression_node* node) +{ +return node && (details::expression_node::e_continue == node->type()); +} + +template +inline bool is_swap_node(const expression_node* node) +{ +return node && (details::expression_node::e_swap == node->type()); +} + +template +inline bool is_function(const expression_node* node) +{ +return node && (details::expression_node::e_function == node->type()); +} + +template +inline bool is_return_node(const expression_node* node) +{ +return node && (details::expression_node::e_return == node->type()); +} + +template class unary_node; + +template +inline bool is_negate_node(const expression_node* node) +{ +if (node && is_unary_node(node)) +{ +return (details::e_neg == static_cast*>(node)->operation()); +} +else +return false; +} + +template +inline bool branch_deletable(expression_node* node) +{ +return (0 != node) && +!is_variable_node(node) && +!is_string_node (node) ; +} + +template +inline bool all_nodes_valid(expression_node* (&b)[N]) +{ +for (std::size_t i = 0; i < N; ++i) +{ +if (0 == b[i]) return false; +} + +return true; +} + +template class Sequence> +inline bool all_nodes_valid(const Sequence*,Allocator>& b) +{ +for (std::size_t i = 0; i < b.size(); ++i) +{ +if (0 == b[i]) return false; +} + +return true; +} + +template +inline bool all_nodes_variables(expression_node* (&b)[N]) +{ +for (std::size_t i = 0; i < N; ++i) +{ +if (0 == b[i]) +return false; +else if (!is_variable_node(b[i])) +return false; +} + +return true; +} + +template class Sequence> +inline bool all_nodes_variables(Sequence*,Allocator>& b) +{ +for (std::size_t i = 0; i < b.size(); ++i) +{ +if (0 == b[i]) +return false; +else if (!is_variable_node(b[i])) +return false; +} + +return true; +} + +template +class node_collection_destructor +{ +public: + +typedef node_collector_interface nci_t; + +typedef typename nci_t::node_ptr_t node_ptr_t; +typedef typename nci_t::node_pp_t node_pp_t; +typedef typename nci_t::noderef_list_t noderef_list_t; + +static void delete_nodes(node_ptr_t& root) +{ +std::vector node_delete_list; +node_delete_list.reserve(1000); + +collect_nodes(root, node_delete_list); + +for (std::size_t i = 0; i < node_delete_list.size(); ++i) +{ +node_ptr_t& node = *node_delete_list[i]; +exprtk_debug(("ncd::delete_nodes() - deleting: %p\n", static_cast(node))); +delete node; +node = reinterpret_cast(0); +} +} + +private: + +static void collect_nodes(node_ptr_t& root, noderef_list_t& node_delete_list) +{ +std::deque node_list; +node_list.push_back(root); +node_delete_list.push_back(&root); + +noderef_list_t child_node_delete_list; +child_node_delete_list.reserve(1000); + +while (!node_list.empty()) +{ +node_list.front()->collect_nodes(child_node_delete_list); + +if (!child_node_delete_list.empty()) +{ +for (std::size_t i = 0; i < child_node_delete_list.size(); ++i) +{ +node_pp_t& node = child_node_delete_list[i]; + +if (0 == (*node)) +{ +exprtk_debug(("ncd::collect_nodes() - null node encountered.\n")); +} + +node_list.push_back(*node); +} + +node_delete_list.insert( +node_delete_list.end(), +child_node_delete_list.begin(), child_node_delete_list.end()); + +child_node_delete_list.clear(); +} + +node_list.pop_front(); +} + +std::reverse(node_delete_list.begin(), node_delete_list.end()); +} +}; + +template +inline void free_all_nodes(NodeAllocator& node_allocator, expression_node* (&b)[N]) +{ +for (std::size_t i = 0; i < N; ++i) +{ +free_node(node_allocator,b[i]); +} +} + +template class Sequence> +inline void free_all_nodes(NodeAllocator& node_allocator, Sequence*,Allocator>& b) +{ +for (std::size_t i = 0; i < b.size(); ++i) +{ +free_node(node_allocator,b[i]); +} + +b.clear(); +} + +template +inline void free_node(NodeAllocator&, expression_node*& node) +{ +if ((0 == node) || is_variable_node(node) || is_string_node(node)) +{ +return; +} + +node_collection_destructor > +::delete_nodes(node); +} + +template +inline void destroy_node(expression_node*& node) +{ +if (0 != node) +{ +node_collection_destructor > +::delete_nodes(node); +} +} + +template +struct node_depth_base +{ +typedef Node* node_ptr_t; +typedef std::pair nb_pair_t; + +node_depth_base() +: depth_set(false) +, depth(0) +{} + +virtual ~node_depth_base() {} + +virtual std::size_t node_depth() const { return 1; } + +std::size_t compute_node_depth(const Node* const& node) const +{ +if (!depth_set) +{ +depth = 1 + (node ? node->node_depth() : 0); +depth_set = true; +} + +return depth; +} + +std::size_t compute_node_depth(const nb_pair_t& branch) const +{ +if (!depth_set) +{ +depth = 1 + (branch.first ? branch.first->node_depth() : 0); +depth_set = true; +} + +return depth; +} + +template +std::size_t compute_node_depth(const nb_pair_t (&branch)[N]) const +{ +if (!depth_set) +{ +depth = 0; +for (std::size_t i = 0; i < N; ++i) +{ +if (branch[i].first) +{ +depth = std::max(depth,branch[i].first->node_depth()); +} +} +depth += 1; +depth_set = true; +} + +return depth; +} + +template +std::size_t compute_node_depth(const BranchType& n0, const BranchType& n1) const +{ +if (!depth_set) +{ +depth = 1 + std::max(compute_node_depth(n0), compute_node_depth(n1)); +depth_set = true; +} + +return depth; +} + +template +std::size_t compute_node_depth(const BranchType& n0, const BranchType& n1, +const BranchType& n2) const +{ +if (!depth_set) +{ +depth = 1 + std::max( +std::max(compute_node_depth(n0), compute_node_depth(n1)), +compute_node_depth(n2)); +depth_set = true; +} + +return depth; +} + +template +std::size_t compute_node_depth(const BranchType& n0, const BranchType& n1, +const BranchType& n2, const BranchType& n3) const +{ +if (!depth_set) +{ +depth = 1 + std::max( +std::max(compute_node_depth(n0), compute_node_depth(n1)), +std::max(compute_node_depth(n2), compute_node_depth(n3))); +depth_set = true; +} + +return depth; +} + +template class Sequence> +std::size_t compute_node_depth(const Sequence& branch_list) const +{ +if (!depth_set) +{ +for (std::size_t i = 0; i < branch_list.size(); ++i) +{ +if (branch_list[i]) +{ +depth = std::max(depth, compute_node_depth(branch_list[i])); +} +} +depth_set = true; +} + +return depth; +} + +template class Sequence> +std::size_t compute_node_depth(const Sequence& branch_list) const +{ +if (!depth_set) +{ +for (std::size_t i = 0; i < branch_list.size(); ++i) +{ +if (branch_list[i].first) +{ +depth = std::max(depth, compute_node_depth(branch_list[i].first)); +} +} +depth_set = true; +} + +return depth; +} + +mutable bool depth_set; +mutable std::size_t depth; + +template +void collect(node_ptr_t const& node, +const bool deletable, +NodeSequence& delete_node_list) const +{ +if ((0 != node) && deletable) +{ +delete_node_list.push_back(const_cast(&node)); +} +} + +template +void collect(const nb_pair_t& branch, +NodeSequence& delete_node_list) const +{ +collect(branch.first, branch.second, delete_node_list); +} + +template +void collect(Node*& node, +NodeSequence& delete_node_list) const +{ +collect(node, branch_deletable(node), delete_node_list); +} + +template +void collect(const nb_pair_t(&branch)[N], +NodeSequence& delete_node_list) const +{ +for (std::size_t i = 0; i < N; ++i) +{ +collect(branch[i].first, branch[i].second, delete_node_list); +} +} + +template class Sequence, +typename NodeSequence> +void collect(const Sequence& branch, +NodeSequence& delete_node_list) const +{ +for (std::size_t i = 0; i < branch.size(); ++i) +{ +collect(branch[i].first, branch[i].second, delete_node_list); +} +} + +template class Sequence, +typename NodeSequence> +void collect(const Sequence& branch_list, +NodeSequence& delete_node_list) const +{ +for (std::size_t i = 0; i < branch_list.size(); ++i) +{ +collect(branch_list[i], branch_deletable(branch_list[i]), delete_node_list); +} +} + +template class Sequence, +typename NodeSequence> +void collect(const Sequence& branch_list, +const Sequence& branch_deletable_list, +NodeSequence& delete_node_list) const +{ +for (std::size_t i = 0; i < branch_list.size(); ++i) +{ +collect(branch_list[i], branch_deletable_list[i], delete_node_list); +} +} +}; + +template +class vector_holder +{ +private: + +typedef Type value_type; +typedef value_type* value_ptr; +typedef const value_ptr const_value_ptr; + +class vector_holder_base +{ +public: + +virtual ~vector_holder_base() {} + +inline value_ptr operator[](const std::size_t& index) const +{ +return value_at(index); +} + +inline std::size_t size() const +{ +return vector_size(); +} + +inline value_ptr data() const +{ +return value_at(0); +} + +virtual inline bool rebaseable() const +{ +return false; +} + +virtual void set_ref(value_ptr*) {} + +protected: + +virtual value_ptr value_at(const std::size_t&) const = 0; +virtual std::size_t vector_size() const = 0; +}; + +class array_vector_impl : public vector_holder_base +{ +public: + +array_vector_impl(const Type* vec, const std::size_t& vec_size) +: vec_(vec) +, size_(vec_size) +{} + +protected: + +value_ptr value_at(const std::size_t& index) const +{ +if (index < size_) +return const_cast(vec_ + index); +else +return const_value_ptr(0); +} + +std::size_t vector_size() const +{ +return size_; +} + +private: + +array_vector_impl(const array_vector_impl&) exprtk_delete; +array_vector_impl& operator=(const array_vector_impl&) exprtk_delete; + +const Type* vec_; +const std::size_t size_; +}; + +template class Sequence> +class sequence_vector_impl : public vector_holder_base +{ +public: + +typedef Sequence sequence_t; + +sequence_vector_impl(sequence_t& seq) +: sequence_(seq) +{} + +protected: + +value_ptr value_at(const std::size_t& index) const +{ +return (index < sequence_.size()) ? (&sequence_[index]) : const_value_ptr(0); +} + +std::size_t vector_size() const +{ +return sequence_.size(); +} + +private: + +sequence_vector_impl(const sequence_vector_impl&) exprtk_delete; +sequence_vector_impl& operator=(const sequence_vector_impl&) exprtk_delete; + +sequence_t& sequence_; +}; + +class vector_view_impl : public vector_holder_base +{ +public: + +typedef exprtk::vector_view vector_view_t; + +vector_view_impl(vector_view_t& vec_view) +: vec_view_(vec_view) +{} + +void set_ref(value_ptr* ref) +{ +vec_view_.set_ref(ref); +} + +virtual inline bool rebaseable() const +{ +return true; +} + +protected: + +value_ptr value_at(const std::size_t& index) const +{ +return (index < vec_view_.size()) ? (&vec_view_[index]) : const_value_ptr(0); +} + +std::size_t vector_size() const +{ +return vec_view_.size(); +} + +private: + +vector_view_impl(const vector_view_impl&) exprtk_delete; +vector_view_impl& operator=(const vector_view_impl&) exprtk_delete; + +vector_view_t& vec_view_; +}; + +public: + +typedef typename details::vec_data_store vds_t; + +vector_holder(Type* vec, const std::size_t& vec_size) +: vector_holder_base_(new(buffer)array_vector_impl(vec,vec_size)) +{} + +explicit vector_holder(const vds_t& vds) +: vector_holder_base_(new(buffer)array_vector_impl(vds.data(),vds.size())) +{} + +template +explicit vector_holder(std::vector& vec) +: vector_holder_base_(new(buffer)sequence_vector_impl(vec)) +{} + +explicit vector_holder(exprtk::vector_view& vec) +: vector_holder_base_(new(buffer)vector_view_impl(vec)) +{} + +inline value_ptr operator[](const std::size_t& index) const +{ +return (*vector_holder_base_)[index]; +} + +inline std::size_t size() const +{ +return vector_holder_base_->size(); +} + +inline value_ptr data() const +{ +return vector_holder_base_->data(); +} + +void set_ref(value_ptr* ref) +{ +vector_holder_base_->set_ref(ref); +} + +bool rebaseable() const +{ +return vector_holder_base_->rebaseable(); +} + +private: + +mutable vector_holder_base* vector_holder_base_; +uchar_t buffer[64]; +}; + +template +class null_node exprtk_final : public expression_node +{ +public: + +inline T value() const exprtk_override +{ +return std::numeric_limits::quiet_NaN(); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_null; +} +}; + +template +inline void construct_branch_pair(std::pair*,bool> (&branch)[N], +expression_node* b, +const std::size_t& index) +{ +if (b && (index < N)) +{ +branch[index] = std::make_pair(b,branch_deletable(b)); +} +} + +template +inline void construct_branch_pair(std::pair*,bool>& branch, expression_node* b) +{ +if (b) +{ +branch = std::make_pair(b,branch_deletable(b)); +} +} + +template +inline void init_branches(std::pair*,bool> (&branch)[N], +expression_node* b0, +expression_node* b1 = reinterpret_cast*>(0), +expression_node* b2 = reinterpret_cast*>(0), +expression_node* b3 = reinterpret_cast*>(0), +expression_node* b4 = reinterpret_cast*>(0), +expression_node* b5 = reinterpret_cast*>(0), +expression_node* b6 = reinterpret_cast*>(0), +expression_node* b7 = reinterpret_cast*>(0), +expression_node* b8 = reinterpret_cast*>(0), +expression_node* b9 = reinterpret_cast*>(0)) +{ +construct_branch_pair(branch, b0, 0); +construct_branch_pair(branch, b1, 1); +construct_branch_pair(branch, b2, 2); +construct_branch_pair(branch, b3, 3); +construct_branch_pair(branch, b4, 4); +construct_branch_pair(branch, b5, 5); +construct_branch_pair(branch, b6, 6); +construct_branch_pair(branch, b7, 7); +construct_branch_pair(branch, b8, 8); +construct_branch_pair(branch, b9, 9); +} + +template +class null_eq_node exprtk_final : public expression_node +{ +public: + +typedef expression_node* expression_ptr; +typedef std::pair branch_t; + +explicit null_eq_node(expression_ptr branch, const bool equality = true) +: equality_(equality) +{ +construct_branch_pair(branch_, branch); +} + +inline T value() const exprtk_override +{ +assert(branch_.first); + +const T v = branch_.first->value(); +const bool result = details::numeric::is_nan(v); + +if (result) +return equality_ ? T(1) : T(0); +else +return equality_ ? T(0) : T(1); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_nulleq; +} + +inline expression_node* branch(const std::size_t&) const exprtk_override +{ +return branch_.first; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::collect(branch_, node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::compute_node_depth(branch_); +} + +private: + +bool equality_; +branch_t branch_; +}; + +template +class literal_node exprtk_final : public expression_node +{ +public: + +explicit literal_node(const T& v) +: value_(v) +{} + +inline T value() const exprtk_override +{ +return value_; +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_constant; +} + +inline expression_node* branch(const std::size_t&) const exprtk_override +{ +return reinterpret_cast*>(0); +} + +private: + +literal_node(const literal_node&) exprtk_delete; +literal_node& operator=(const literal_node&) exprtk_delete; + +const T value_; +}; + +template +struct range_pack; + +template +struct range_data_type; + +template +class range_interface +{ +public: + +typedef range_pack range_t; + +virtual ~range_interface() {} + +virtual range_t& range_ref() = 0; + +virtual const range_t& range_ref() const = 0; +}; + +#ifndef exprtk_disable_string_capabilities +template +class string_base_node +{ +public: + +typedef range_data_type range_data_type_t; + +virtual ~string_base_node() {} + +virtual std::string str () const = 0; + +virtual char_cptr base() const = 0; + +virtual std::size_t size() const = 0; +}; + +template +class string_literal_node exprtk_final +: public expression_node , +public string_base_node, +public range_interface +{ +public: + +typedef range_pack range_t; + +explicit string_literal_node(const std::string& v) +: value_(v) +{ +rp_.n0_c = std::make_pair(true,0); +rp_.n1_c = std::make_pair(true,v.size() - 1); +rp_.cache.first = rp_.n0_c.second; +rp_.cache.second = rp_.n1_c.second; +} + +inline T value() const exprtk_override +{ +return std::numeric_limits::quiet_NaN(); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_stringconst; +} + +inline expression_node* branch(const std::size_t&) const exprtk_override +{ +return reinterpret_cast*>(0); +} + +std::string str() const exprtk_override +{ +return value_; +} + +char_cptr base() const exprtk_override +{ +return value_.data(); +} + +std::size_t size() const exprtk_override +{ +return value_.size(); +} + +range_t& range_ref() exprtk_override +{ +return rp_; +} + +const range_t& range_ref() const exprtk_override +{ +return rp_; +} + +private: + +string_literal_node(const string_literal_node&) exprtk_delete; +string_literal_node& operator=(const string_literal_node&) exprtk_delete; + +const std::string value_; +range_t rp_; +}; +#endif + +template +class unary_node : public expression_node +{ +public: + +typedef expression_node* expression_ptr; +typedef std::pair branch_t; + +unary_node(const operator_type& opr, expression_ptr branch) +: operation_(opr) +{ +construct_branch_pair(branch_,branch); +} + +inline T value() const exprtk_override +{ +assert(branch_.first); +const T arg = branch_.first->value(); +return numeric::process(operation_,arg); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_unary; +} + +inline operator_type operation() +{ +return operation_; +} + +inline expression_node* branch(const std::size_t&) const exprtk_override +{ +return branch_.first; +} + +inline void release() +{ +branch_.second = false; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::collect(branch_, node_delete_list); +} + +std::size_t node_depth() const exprtk_final +{ +return expression_node::ndb_t::compute_node_depth(branch_); +} + +private: + +operator_type operation_; +branch_t branch_; +}; + +template +class binary_node : public expression_node +{ +public: + +typedef expression_node* expression_ptr; +typedef std::pair branch_t; + +binary_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1) +: operation_(opr) +{ +init_branches<2>(branch_, branch0, branch1); +} + +inline T value() const exprtk_override +{ +assert(branch_[0].first); +assert(branch_[1].first); + +const T arg0 = branch_[0].first->value(); +const T arg1 = branch_[1].first->value(); + +return numeric::process(operation_, arg0, arg1); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_binary; +} + +inline operator_type operation() +{ +return operation_; +} + +inline expression_node* branch(const std::size_t& index = 0) const exprtk_override +{ +if (0 == index) +return branch_[0].first; +else if (1 == index) +return branch_[1].first; +else +return reinterpret_cast(0); +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::template collect(branch_, node_delete_list); +} + +std::size_t node_depth() const exprtk_final +{ +return expression_node::ndb_t::template compute_node_depth<2>(branch_); +} + +private: + +operator_type operation_; +branch_t branch_[2]; +}; + +template +class binary_ext_node exprtk_final : public expression_node +{ +public: + +typedef expression_node* expression_ptr; +typedef std::pair branch_t; + +binary_ext_node(expression_ptr branch0, expression_ptr branch1) +{ +init_branches<2>(branch_, branch0, branch1); +} + +inline T value() const exprtk_override +{ +assert(branch_[0].first); +assert(branch_[1].first); + +const T arg0 = branch_[0].first->value(); +const T arg1 = branch_[1].first->value(); + +return Operation::process(arg0,arg1); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_binary_ext; +} + +inline operator_type operation() +{ +return Operation::operation(); +} + +inline expression_node* branch(const std::size_t& index = 0) const exprtk_override +{ +if (0 == index) +return branch_[0].first; +else if (1 == index) +return branch_[1].first; +else +return reinterpret_cast(0); +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::template collect(branch_, node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::template compute_node_depth<2>(branch_); +} + +protected: + +branch_t branch_[2]; +}; + +template +class trinary_node : public expression_node +{ +public: + +typedef expression_node* expression_ptr; +typedef std::pair branch_t; + +trinary_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1, +expression_ptr branch2) +: operation_(opr) +{ +init_branches<3>(branch_, branch0, branch1, branch2); +} + +inline T value() const exprtk_override +{ +assert(branch_[0].first); +assert(branch_[1].first); +assert(branch_[2].first); + +const T arg0 = branch_[0].first->value(); +const T arg1 = branch_[1].first->value(); +const T arg2 = branch_[2].first->value(); + +switch (operation_) +{ +case e_inrange : return (arg1 < arg0) ? T(0) : ((arg1 > arg2) ? T(0) : T(1)); + +case e_clamp : return (arg1 < arg0) ? arg0 : (arg1 > arg2 ? arg2 : arg1); + +case e_iclamp : if ((arg1 <= arg0) || (arg1 >= arg2)) +return arg1; +else +return ((T(2) * arg1 <= (arg2 + arg0)) ? arg0 : arg2); + +default : exprtk_debug(("trinary_node::value() - Error: Invalid operation\n")); +return std::numeric_limits::quiet_NaN(); +} +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_trinary; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::template collect(branch_, node_delete_list); +} + +std::size_t node_depth() const exprtk_override exprtk_final +{ +return expression_node::ndb_t::template compute_node_depth<3>(branch_); +} + +protected: + +operator_type operation_; +branch_t branch_[3]; +}; + +template +class quaternary_node : public expression_node +{ +public: + +typedef expression_node* expression_ptr; +typedef std::pair branch_t; + +quaternary_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1, +expression_ptr branch2, +expression_ptr branch3) +: operation_(opr) +{ +init_branches<4>(branch_, branch0, branch1, branch2, branch3); +} + +inline T value() const exprtk_override +{ +return std::numeric_limits::quiet_NaN(); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_quaternary; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::template collect(branch_, node_delete_list); +} + +std::size_t node_depth() const exprtk_override exprtk_final +{ +return expression_node::ndb_t::template compute_node_depth<4>(branch_); +} + +protected: + +operator_type operation_; +branch_t branch_[4]; +}; + +template +class conditional_node exprtk_final : public expression_node +{ +public: + +typedef expression_node* expression_ptr; +typedef std::pair branch_t; + +conditional_node(expression_ptr condition, +expression_ptr consequent, +expression_ptr alternative) +{ +construct_branch_pair(condition_ , condition ); +construct_branch_pair(consequent_ , consequent ); +construct_branch_pair(alternative_, alternative); +} + +inline T value() const exprtk_override +{ +assert(condition_ .first); +assert(consequent_ .first); +assert(alternative_.first); + +if (is_true(condition_)) +return consequent_.first->value(); +else +return alternative_.first->value(); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_conditional; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::collect(condition_ , node_delete_list); +expression_node::ndb_t::collect(consequent_ , node_delete_list); +expression_node::ndb_t::collect(alternative_ , node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::compute_node_depth +(condition_, consequent_, alternative_); +} + +private: + +branch_t condition_; +branch_t consequent_; +branch_t alternative_; +}; + +template +class cons_conditional_node exprtk_final : public expression_node +{ +public: + +// Consequent only conditional statement node +typedef expression_node* expression_ptr; +typedef std::pair branch_t; + +cons_conditional_node(expression_ptr condition, +expression_ptr consequent) +{ +construct_branch_pair(condition_ , condition ); +construct_branch_pair(consequent_, consequent); +} + +inline T value() const exprtk_override +{ +assert(condition_ .first); +assert(consequent_.first); + +if (is_true(condition_)) +return consequent_.first->value(); +else +return std::numeric_limits::quiet_NaN(); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_conditional; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::collect(condition_ , node_delete_list); +expression_node::ndb_t::collect(consequent_ , node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t:: +compute_node_depth(condition_, consequent_); +} + +private: + +branch_t condition_; +branch_t consequent_; +}; + +#ifndef exprtk_disable_break_continue +template +class break_exception +{ +public: + +explicit break_exception(const T& v) +: value(v) +{} + +T value; +}; + +class continue_exception {}; + +template +class break_node exprtk_final : public expression_node +{ +public: + +typedef expression_node* expression_ptr; +typedef std::pair branch_t; + +break_node(expression_ptr ret = expression_ptr(0)) +{ +construct_branch_pair(return_, ret); +} + +inline T value() const exprtk_override +{ +const T result = return_.first ? +return_.first->value() : +std::numeric_limits::quiet_NaN(); + +throw break_exception(result); + +#ifndef _MSC_VER +return std::numeric_limits::quiet_NaN(); +#endif +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_break; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::collect(return_, node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::compute_node_depth(return_); +} + +private: + +branch_t return_; +}; + +template +class continue_node exprtk_final : public expression_node +{ +public: + +inline T value() const exprtk_override +{ +throw continue_exception(); +#ifndef _MSC_VER +return std::numeric_limits::quiet_NaN(); +#endif +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_break; +} +}; +#endif + +struct loop_runtime_checker +{ +loop_runtime_checker(loop_runtime_check_ptr loop_runtime_check, +loop_runtime_check::loop_types lp_typ = loop_runtime_check::e_invalid) +: iteration_count_(0) +, loop_runtime_check_(loop_runtime_check) +, max_loop_iterations_(loop_runtime_check_->max_loop_iterations) +, loop_type_(lp_typ) +{ +assert(loop_runtime_check_); +} + +inline void reset(const _uint64_t initial_value = 0) const +{ +iteration_count_ = initial_value; +} + +inline bool check() const +{ +if ( +(0 == loop_runtime_check_) || +((++iteration_count_ <= max_loop_iterations_) && loop_runtime_check_->check()) +) +{ +return true; +} + +loop_runtime_check::violation_context ctxt; +ctxt.loop = loop_type_; +ctxt.violation = loop_runtime_check::e_iteration_count; + +loop_runtime_check_->handle_runtime_violation(ctxt); + +return false; +} + +mutable _uint64_t iteration_count_; +mutable loop_runtime_check_ptr loop_runtime_check_; +const details::_uint64_t& max_loop_iterations_; +loop_runtime_check::loop_types loop_type_; +}; + +template +class while_loop_node : public expression_node +{ +public: + +typedef expression_node* expression_ptr; +typedef std::pair branch_t; + +while_loop_node(expression_ptr condition, +expression_ptr loop_body) +{ +construct_branch_pair(condition_, condition); +construct_branch_pair(loop_body_, loop_body); +} + +inline T value() const exprtk_override +{ +assert(condition_.first); +assert(loop_body_.first); + +T result = T(0); + +while (is_true(condition_)) +{ +result = loop_body_.first->value(); +} + +return result; +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_while; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::collect(condition_ , node_delete_list); +expression_node::ndb_t::collect(loop_body_ , node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::compute_node_depth(condition_, loop_body_); +} + +protected: + +branch_t condition_; +branch_t loop_body_; +}; + +template +class while_loop_rtc_node exprtk_final +: public while_loop_node +, public loop_runtime_checker +{ +public: + +typedef while_loop_node parent_t; +typedef expression_node* expression_ptr; + +while_loop_rtc_node(expression_ptr condition, +expression_ptr loop_body, +loop_runtime_check_ptr loop_rt_chk) +: parent_t(condition, loop_body) +, loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_while_loop) +{} + +inline T value() const exprtk_override +{ +assert(parent_t::condition_.first); +assert(parent_t::loop_body_.first); + +T result = T(0); + +loop_runtime_checker::reset(); + +while (is_true(parent_t::condition_) && loop_runtime_checker::check()) +{ +result = parent_t::loop_body_.first->value(); +} + +return result; +} +}; + +template +class repeat_until_loop_node : public expression_node +{ +public: + +typedef expression_node* expression_ptr; +typedef std::pair branch_t; + +repeat_until_loop_node(expression_ptr condition, +expression_ptr loop_body) +{ +construct_branch_pair(condition_, condition); +construct_branch_pair(loop_body_, loop_body); +} + +inline T value() const exprtk_override +{ +assert(condition_.first); +assert(loop_body_.first); + +T result = T(0); + +do +{ +result = loop_body_.first->value(); +} +while (is_false(condition_.first)); + +return result; +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_repeat; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::collect(condition_ , node_delete_list); +expression_node::ndb_t::collect(loop_body_ , node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::compute_node_depth(condition_, loop_body_); +} + +protected: + +branch_t condition_; +branch_t loop_body_; +}; + +template +class repeat_until_loop_rtc_node exprtk_final +: public repeat_until_loop_node +, public loop_runtime_checker +{ +public: + +typedef repeat_until_loop_node parent_t; +typedef expression_node* expression_ptr; + +repeat_until_loop_rtc_node(expression_ptr condition, +expression_ptr loop_body, +loop_runtime_check_ptr loop_rt_chk) +: parent_t(condition, loop_body) +, loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_repeat_until_loop) +{} + +inline T value() const exprtk_override +{ +assert(parent_t::condition_.first); +assert(parent_t::loop_body_.first); + +T result = T(0); + +loop_runtime_checker::reset(1); + +do +{ +result = parent_t::loop_body_.first->value(); +} +while (is_false(parent_t::condition_.first) && loop_runtime_checker::check()); + +return result; +} +}; + +template +class for_loop_node : public expression_node +{ +public: + +typedef expression_node* expression_ptr; +typedef std::pair branch_t; + +for_loop_node(expression_ptr initialiser, +expression_ptr condition, +expression_ptr incrementor, +expression_ptr loop_body) +{ +construct_branch_pair(initialiser_, initialiser); +construct_branch_pair(condition_ , condition ); +construct_branch_pair(incrementor_, incrementor); +construct_branch_pair(loop_body_ , loop_body ); +} + +inline T value() const exprtk_override +{ +assert(condition_.first); +assert(loop_body_.first); + +T result = T(0); + +if (initialiser_.first) +initialiser_.first->value(); + +if (incrementor_.first) +{ +while (is_true(condition_)) +{ +result = loop_body_.first->value(); +incrementor_.first->value(); +} +} +else +{ +while (is_true(condition_)) +{ +result = loop_body_.first->value(); +} +} + +return result; +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_for; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::collect(initialiser_ , node_delete_list); +expression_node::ndb_t::collect(condition_ , node_delete_list); +expression_node::ndb_t::collect(incrementor_ , node_delete_list); +expression_node::ndb_t::collect(loop_body_ , node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::compute_node_depth +(initialiser_, condition_, incrementor_, loop_body_); +} + +protected: + +branch_t initialiser_; +branch_t condition_ ; +branch_t incrementor_; +branch_t loop_body_ ; +}; + +template +class for_loop_rtc_node exprtk_final +: public for_loop_node +, public loop_runtime_checker +{ +public: + +typedef for_loop_node parent_t; +typedef expression_node* expression_ptr; + +for_loop_rtc_node(expression_ptr initialiser, +expression_ptr condition, +expression_ptr incrementor, +expression_ptr loop_body, +loop_runtime_check_ptr loop_rt_chk) +: parent_t(initialiser, condition, incrementor, loop_body) +, loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_for_loop) +{} + +inline T value() const exprtk_override +{ +assert(parent_t::condition_.first); +assert(parent_t::loop_body_.first); + +T result = T(0); + +loop_runtime_checker::reset(); + +if (parent_t::initialiser_.first) +parent_t::initialiser_.first->value(); + +if (parent_t::incrementor_.first) +{ +while (is_true(parent_t::condition_) && loop_runtime_checker::check()) +{ +result = parent_t::loop_body_.first->value(); +parent_t::incrementor_.first->value(); +} +} +else +{ +while (is_true(parent_t::condition_) && loop_runtime_checker::check()) +{ +result = parent_t::loop_body_.first->value(); +} +} + +return result; +} +}; + +#ifndef exprtk_disable_break_continue +template +class while_loop_bc_node : public while_loop_node +{ +public: + +typedef while_loop_node parent_t; +typedef expression_node* expression_ptr; + +while_loop_bc_node(expression_ptr condition, +expression_ptr loop_body) +: parent_t(condition, loop_body) +{} + +inline T value() const exprtk_override +{ +assert(parent_t::condition_.first); +assert(parent_t::loop_body_.first); + +T result = T(0); + +while (is_true(parent_t::condition_)) +{ +try +{ +result = parent_t::loop_body_.first->value(); +} +catch(const break_exception& e) +{ +return e.value; +} +catch(const continue_exception&) +{} +} + +return result; +} +}; + +template +class while_loop_bc_rtc_node exprtk_final +: public while_loop_bc_node +, public loop_runtime_checker +{ +public: + +typedef while_loop_bc_node parent_t; +typedef expression_node* expression_ptr; + +while_loop_bc_rtc_node(expression_ptr condition, +expression_ptr loop_body, +loop_runtime_check_ptr loop_rt_chk) +: parent_t(condition, loop_body) +, loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_while_loop) +{} + +inline T value() const exprtk_override +{ +assert(parent_t::condition_.first); +assert(parent_t::loop_body_.first); + +T result = T(0); + +loop_runtime_checker::reset(); + +while (is_true(parent_t::condition_) && loop_runtime_checker::check()) +{ +try +{ +result = parent_t::loop_body_.first->value(); +} +catch(const break_exception& e) +{ +return e.value; +} +catch(const continue_exception&) +{} +} + +return result; +} +}; + +template +class repeat_until_loop_bc_node : public repeat_until_loop_node +{ +public: + +typedef repeat_until_loop_node parent_t; +typedef expression_node* expression_ptr; + +repeat_until_loop_bc_node(expression_ptr condition, +expression_ptr loop_body) +: parent_t(condition, loop_body) +{} + +inline T value() const exprtk_override +{ +assert(parent_t::condition_.first); +assert(parent_t::loop_body_.first); + +T result = T(0); + +do +{ +try +{ +result = parent_t::loop_body_.first->value(); +} +catch(const break_exception& e) +{ +return e.value; +} +catch(const continue_exception&) +{} +} +while (is_false(parent_t::condition_.first)); + +return result; +} +}; + +template +class repeat_until_loop_bc_rtc_node exprtk_final +: public repeat_until_loop_bc_node, +public loop_runtime_checker +{ +public: + +typedef repeat_until_loop_bc_node parent_t; +typedef expression_node* expression_ptr; + +repeat_until_loop_bc_rtc_node(expression_ptr condition, +expression_ptr loop_body, +loop_runtime_check_ptr loop_rt_chk) +: parent_t(condition, loop_body) +, loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_repeat_until_loop) +{} + +inline T value() const exprtk_override +{ +assert(parent_t::condition_.first); +assert(parent_t::loop_body_.first); + +T result = T(0); + +loop_runtime_checker::reset(); + +do +{ +try +{ +result = parent_t::loop_body_.first->value(); +} +catch(const break_exception& e) +{ +return e.value; +} +catch(const continue_exception&) +{} +} +while (is_false(parent_t::condition_.first) && loop_runtime_checker::check()); + +return result; +} +}; + +template +class for_loop_bc_node : public for_loop_node +{ +public: + +typedef for_loop_node parent_t; +typedef expression_node* expression_ptr; + +for_loop_bc_node(expression_ptr initialiser, +expression_ptr condition, +expression_ptr incrementor, +expression_ptr loop_body) +: parent_t(initialiser, condition, incrementor, loop_body) +{} + +inline T value() const exprtk_override +{ +assert(parent_t::condition_.first); +assert(parent_t::loop_body_.first); + +T result = T(0); + +if (parent_t::initialiser_.first) +parent_t::initialiser_.first->value(); + +if (parent_t::incrementor_.first) +{ +while (is_true(parent_t::condition_)) +{ +try +{ +result = parent_t::loop_body_.first->value(); +} +catch(const break_exception& e) +{ +return e.value; +} +catch(const continue_exception&) +{} + +parent_t::incrementor_.first->value(); +} +} +else +{ +while (is_true(parent_t::condition_)) +{ +try +{ +result = parent_t::loop_body_.first->value(); +} +catch(const break_exception& e) +{ +return e.value; +} +catch(const continue_exception&) +{} +} +} + +return result; +} +}; + +template +class for_loop_bc_rtc_node exprtk_final +: public for_loop_bc_node +, public loop_runtime_checker +{ +public: + +typedef for_loop_bc_node parent_t; +typedef expression_node* expression_ptr; + +for_loop_bc_rtc_node(expression_ptr initialiser, +expression_ptr condition, +expression_ptr incrementor, +expression_ptr loop_body, +loop_runtime_check_ptr loop_rt_chk) +: parent_t(initialiser, condition, incrementor, loop_body) +, loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_for_loop) +{} + +inline T value() const exprtk_override +{ +assert(parent_t::condition_.first); +assert(parent_t::loop_body_.first); + +T result = T(0); + +loop_runtime_checker::reset(); + +if (parent_t::initialiser_.first) +parent_t::initialiser_.first->value(); + +if (parent_t::incrementor_.first) +{ +while (is_true(parent_t::condition_) && loop_runtime_checker::check()) +{ +try +{ +result = parent_t::loop_body_.first->value(); +} +catch(const break_exception& e) +{ +return e.value; +} +catch(const continue_exception&) +{} + +parent_t::incrementor_.first->value(); +} +} +else +{ +while (is_true(parent_t::condition_) && loop_runtime_checker::check()) +{ +try +{ +result = parent_t::loop_body_.first->value(); +} +catch(const break_exception& e) +{ +return e.value; +} +catch(const continue_exception&) +{} +} +} + +return result; +} +}; +#endif + +template +class switch_node : public expression_node +{ +public: + +typedef expression_node* expression_ptr; +typedef std::pair branch_t; + +template class Sequence> +explicit switch_node(const Sequence& arg_list) +{ +if (1 != (arg_list.size() & 1)) +return; + +arg_list_.resize(arg_list.size()); + +for (std::size_t i = 0; i < arg_list.size(); ++i) +{ +if (arg_list[i]) +{ +construct_branch_pair(arg_list_[i], arg_list[i]); +} +else +{ +arg_list_.clear(); +return; +} +} +} + +inline T value() const exprtk_override +{ +if (!arg_list_.empty()) +{ +const std::size_t upper_bound = (arg_list_.size() - 1); + +for (std::size_t i = 0; i < upper_bound; i += 2) +{ +expression_ptr condition = arg_list_[i ].first; +expression_ptr consequent = arg_list_[i + 1].first; + +if (is_true(condition)) +{ +return consequent->value(); +} +} + +return arg_list_[upper_bound].first->value(); +} +else +return std::numeric_limits::quiet_NaN(); +} + +inline typename expression_node::node_type type() const exprtk_override exprtk_final +{ +return expression_node::e_switch; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::collect(arg_list_, node_delete_list); +} + +std::size_t node_depth() const exprtk_override exprtk_final +{ +return expression_node::ndb_t::compute_node_depth(arg_list_); +} + +protected: + +std::vector arg_list_; +}; + +template +class switch_n_node exprtk_final : public switch_node +{ +public: + +typedef expression_node* expression_ptr; + +template class Sequence> +explicit switch_n_node(const Sequence& arg_list) +: switch_node(arg_list) +{} + +inline T value() const exprtk_override +{ +return Switch_N::process(switch_node::arg_list_); +} +}; + +template +class multi_switch_node exprtk_final : public expression_node +{ +public: + +typedef expression_node* expression_ptr; +typedef std::pair branch_t; + +template class Sequence> +explicit multi_switch_node(const Sequence& arg_list) +{ +if (0 != (arg_list.size() & 1)) +return; + +arg_list_.resize(arg_list.size()); + +for (std::size_t i = 0; i < arg_list.size(); ++i) +{ +if (arg_list[i]) +{ +construct_branch_pair(arg_list_[i], arg_list[i]); +} +else +{ +arg_list_.clear(); +return; +} +} +} + +inline T value() const exprtk_override +{ +T result = T(0); + +if (arg_list_.empty()) +{ +return std::numeric_limits::quiet_NaN(); +} + +const std::size_t upper_bound = (arg_list_.size() - 1); + +for (std::size_t i = 0; i < upper_bound; i += 2) +{ +expression_ptr condition = arg_list_[i ].first; +expression_ptr consequent = arg_list_[i + 1].first; + +if (is_true(condition)) +{ +result = consequent->value(); +} +} + +return result; +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_mswitch; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::collect(arg_list_, node_delete_list); +} + +std::size_t node_depth() const exprtk_override exprtk_final +{ +return expression_node::ndb_t::compute_node_depth(arg_list_); +} + +private: + +std::vector arg_list_; +}; + +template +class ivariable +{ +public: + +virtual ~ivariable() {} + +virtual T& ref() = 0; +virtual const T& ref() const = 0; +}; + +template +class variable_node exprtk_final +: public expression_node, +public ivariable +{ +public: + +static T null_value; + +explicit variable_node() +: value_(&null_value) +{} + +explicit variable_node(T& v) +: value_(&v) +{} + +inline bool operator <(const variable_node& v) const +{ +return this < (&v); +} + +inline T value() const exprtk_override +{ +return (*value_); +} + +inline T& ref() exprtk_override +{ +return (*value_); +} + +inline const T& ref() const exprtk_override +{ +return (*value_); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_variable; +} + +private: + +T* value_; +}; + +template +T variable_node::null_value = T(std::numeric_limits::quiet_NaN()); + +template +struct range_pack +{ +typedef expression_node* expression_node_ptr; +typedef std::pair cached_range_t; + +range_pack() +: n0_e (std::make_pair(false,expression_node_ptr(0))) +, n1_e (std::make_pair(false,expression_node_ptr(0))) +, n0_c (std::make_pair(false,0)) +, n1_c (std::make_pair(false,0)) +, cache(std::make_pair(0,0)) +{} + +void clear() +{ +n0_e = std::make_pair(false,expression_node_ptr(0)); +n1_e = std::make_pair(false,expression_node_ptr(0)); +n0_c = std::make_pair(false,0); +n1_c = std::make_pair(false,0); +cache = std::make_pair(0,0); +} + +void free() +{ +if (n0_e.first && n0_e.second) +{ +n0_e.first = false; + +if ( +!is_variable_node(n0_e.second) && +!is_string_node (n0_e.second) +) +{ +destroy_node(n0_e.second); +} +} + +if (n1_e.first && n1_e.second) +{ +n1_e.first = false; + +if ( +!is_variable_node(n1_e.second) && +!is_string_node (n1_e.second) +) +{ +destroy_node(n1_e.second); +} +} +} + +bool const_range() const +{ +return ( n0_c.first && n1_c.first) && +(!n0_e.first && !n1_e.first); +} + +bool var_range() const +{ +return ( n0_e.first && n1_e.first) && +(!n0_c.first && !n1_c.first); +} + +bool operator() (std::size_t& r0, std::size_t& r1, +const std::size_t& size = std::numeric_limits::max()) const +{ +if (n0_c.first) +r0 = n0_c.second; +else if (n0_e.first) +{ +r0 = static_cast(details::numeric::to_int64(n0_e.second->value())); +} +else +return false; + +if (n1_c.first) +r1 = n1_c.second; +else if (n1_e.first) +{ +r1 = static_cast(details::numeric::to_int64(n1_e.second->value())); +} +else +return false; + +if ( +(std::numeric_limits::max() != size) && +(std::numeric_limits::max() == r1 ) +) +{ +r1 = size - 1; +} + +cache.first = r0; +cache.second = r1; + +#ifndef exprtk_enable_range_runtime_checks +return (r0 <= r1); +#else +return range_runtime_check(r0, r1, size); +#endif +} + +inline std::size_t const_size() const +{ +return (n1_c.second - n0_c.second + 1); +} + +inline std::size_t cache_size() const +{ +return (cache.second - cache.first + 1); +} + +std::pair n0_e; +std::pair n1_e; +std::pair n0_c; +std::pair n1_c; +mutable cached_range_t cache; + +#ifdef exprtk_enable_range_runtime_checks +bool range_runtime_check(const std::size_t r0, +const std::size_t r1, +const std::size_t size) const +{ +if (r0 >= size) +{ +throw std::runtime_error("range error: (r0 < 0) || (r0 >= size)"); +return false; +} + +if (r1 >= size) +{ +throw std::runtime_error("range error: (r1 < 0) || (r1 >= size)"); +return false; +} + +return (r0 <= r1); +} +#endif +}; + +template +class string_base_node; + +template +struct range_data_type +{ +typedef range_pack range_t; +typedef string_base_node* strbase_ptr_t; + +range_data_type() +: range(0) +, data (0) +, size (0) +, type_size(0) +, str_node (0) +{} + +range_t* range; +void* data; +std::size_t size; +std::size_t type_size; +strbase_ptr_t str_node; +}; + +template class vector_node; + +template +class vector_interface +{ +public: + +typedef vector_node* vector_node_ptr; +typedef vec_data_store vds_t; + +virtual ~vector_interface() {} + +virtual std::size_t size () const = 0; + +virtual vector_node_ptr vec() const = 0; + +virtual vector_node_ptr vec() = 0; + +virtual vds_t& vds () = 0; + +virtual const vds_t& vds () const = 0; + +virtual bool side_effect () const { return false; } +}; + +template +class vector_node exprtk_final +: public expression_node +, public vector_interface +{ +public: + +typedef expression_node* expression_ptr; +typedef vector_holder vector_holder_t; +typedef vector_node* vector_node_ptr; +typedef vec_data_store vds_t; + +explicit vector_node(vector_holder_t* vh) +: vector_holder_(vh) +, vds_((*vector_holder_).size(),(*vector_holder_)[0]) +{ +vector_holder_->set_ref(&vds_.ref()); +} + +vector_node(const vds_t& vds, vector_holder_t* vh) +: vector_holder_(vh) +, vds_(vds) +{} + +inline T value() const exprtk_override +{ +return vds().data()[0]; +} + +vector_node_ptr vec() const exprtk_override +{ +return const_cast(this); +} + +vector_node_ptr vec() exprtk_override +{ +return this; +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_vector; +} + +std::size_t size() const exprtk_override +{ +return vds().size(); +} + +vds_t& vds() exprtk_override +{ +return vds_; +} + +const vds_t& vds() const exprtk_override +{ +return vds_; +} + +inline vector_holder_t& vec_holder() +{ +return (*vector_holder_); +} + +private: + +vector_holder_t* vector_holder_; +vds_t vds_; +}; + +template +class vector_elem_node exprtk_final +: public expression_node, +public ivariable +{ +public: + +typedef expression_node* expression_ptr; +typedef vector_holder vector_holder_t; +typedef vector_holder_t* vector_holder_ptr; +typedef std::pair branch_t; + +vector_elem_node(expression_ptr index, vector_holder_ptr vec_holder) +: vec_holder_(vec_holder) +, vector_base_((*vec_holder)[0]) +{ +construct_branch_pair(index_, index); +} + +inline T value() const exprtk_override +{ +return *(vector_base_ + static_cast(details::numeric::to_int64(index_.first->value()))); +} + +inline T& ref() exprtk_override +{ +return *(vector_base_ + static_cast(details::numeric::to_int64(index_.first->value()))); +} + +inline const T& ref() const exprtk_override +{ +return *(vector_base_ + static_cast(details::numeric::to_int64(index_.first->value()))); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_vecelem; +} + +inline vector_holder_t& vec_holder() +{ +return (*vec_holder_); +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::collect(index_, node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::compute_node_depth(index_); +} + +private: + +vector_holder_ptr vec_holder_; +T* vector_base_; +branch_t index_; +}; + +template +class rebasevector_elem_node exprtk_final +: public expression_node, +public ivariable +{ +public: + +typedef expression_node* expression_ptr; +typedef vector_holder vector_holder_t; +typedef vector_holder_t* vector_holder_ptr; +typedef vec_data_store vds_t; +typedef std::pair branch_t; + +rebasevector_elem_node(expression_ptr index, vector_holder_ptr vec_holder) +: vector_holder_(vec_holder) +, vds_((*vector_holder_).size(),(*vector_holder_)[0]) +{ +vector_holder_->set_ref(&vds_.ref()); +construct_branch_pair(index_, index); +} + +inline T value() const exprtk_override +{ +return *(vds_.data() + static_cast(details::numeric::to_int64(index_.first->value()))); +} + +inline T& ref() exprtk_override +{ +return *(vds_.data() + static_cast(details::numeric::to_int64(index_.first->value()))); +} + +inline const T& ref() const exprtk_override +{ +return *(vds_.data() + static_cast(details::numeric::to_int64(index_.first->value()))); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_rbvecelem; +} + +inline vector_holder_t& vec_holder() +{ +return (*vector_holder_); +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::template collect(index_, node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::compute_node_depth(index_); +} + +private: + +vector_holder_ptr vector_holder_; +vds_t vds_; +branch_t index_; +}; + +template +class rebasevector_celem_node exprtk_final +: public expression_node, +public ivariable +{ +public: + +typedef expression_node* expression_ptr; +typedef vector_holder vector_holder_t; +typedef vector_holder_t* vector_holder_ptr; +typedef vec_data_store vds_t; + +rebasevector_celem_node(const std::size_t index, vector_holder_ptr vec_holder) +: index_(index) +, vector_holder_(vec_holder) +, vds_((*vector_holder_).size(),(*vector_holder_)[0]) +{ +vector_holder_->set_ref(&vds_.ref()); +} + +inline T value() const exprtk_override +{ +return *(vds_.data() + index_); +} + +inline T& ref() exprtk_override +{ +return *(vds_.data() + index_); +} + +inline const T& ref() const exprtk_override +{ +return *(vds_.data() + index_); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_rbveccelem; +} + +inline vector_holder_t& vec_holder() +{ +return (*vector_holder_); +} + +private: + +const std::size_t index_; +vector_holder_ptr vector_holder_; +vds_t vds_; +}; + +template +class vector_assignment_node exprtk_final : public expression_node +{ +public: + +typedef expression_node* expression_ptr; + +vector_assignment_node(T* vector_base, +const std::size_t& size, +const std::vector& initialiser_list, +const bool single_value_initialse) +: vector_base_(vector_base) +, initialiser_list_(initialiser_list) +, size_(size) +, single_value_initialse_(single_value_initialse) +{} + +inline T value() const exprtk_override +{ +if (single_value_initialse_) +{ +for (std::size_t i = 0; i < size_; ++i) +{ +*(vector_base_ + i) = initialiser_list_[0]->value(); +} +} +else +{ +const std::size_t initialiser_list_size = initialiser_list_.size(); + +for (std::size_t i = 0; i < initialiser_list_size; ++i) +{ +*(vector_base_ + i) = initialiser_list_[i]->value(); +} + +if (initialiser_list_size < size_) +{ +for (std::size_t i = initialiser_list_size; i < size_; ++i) +{ +*(vector_base_ + i) = T(0); +} +} +} + +return *(vector_base_); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_vecdefass; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::collect(initialiser_list_, node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::compute_node_depth(initialiser_list_); +} + +private: + +vector_assignment_node(const vector_assignment_node&) exprtk_delete; +vector_assignment_node& operator=(const vector_assignment_node&) exprtk_delete; + +mutable T* vector_base_; +std::vector initialiser_list_; +const std::size_t size_; +const bool single_value_initialse_; +}; + +template +class swap_node exprtk_final : public expression_node +{ +public: + +typedef expression_node* expression_ptr; +typedef variable_node* variable_node_ptr; + +swap_node(variable_node_ptr var0, variable_node_ptr var1) +: var0_(var0) +, var1_(var1) +{} + +inline T value() const exprtk_override +{ +std::swap(var0_->ref(),var1_->ref()); +return var1_->ref(); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_swap; +} + +private: + +variable_node_ptr var0_; +variable_node_ptr var1_; +}; + +template +class swap_generic_node exprtk_final : public binary_node +{ +public: + +typedef expression_node* expression_ptr; +typedef ivariable* ivariable_ptr; + +swap_generic_node(expression_ptr var0, expression_ptr var1) +: binary_node(details::e_swap, var0, var1) +, var0_(dynamic_cast(var0)) +, var1_(dynamic_cast(var1)) +{} + +inline T value() const exprtk_override +{ +std::swap(var0_->ref(),var1_->ref()); +return var1_->ref(); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_swap; +} + +private: + +ivariable_ptr var0_; +ivariable_ptr var1_; +}; + +template +class swap_vecvec_node exprtk_final +: public binary_node +, public vector_interface +{ +public: + +typedef expression_node* expression_ptr; +typedef vector_node * vector_node_ptr; +typedef vec_data_store vds_t; + +using binary_node::branch; + +swap_vecvec_node(expression_ptr branch0, +expression_ptr branch1) +: binary_node(details::e_swap, branch0, branch1) +, vec0_node_ptr_(0) +, vec1_node_ptr_(0) +, vec_size_ (0) +, initialised_ (false) +{ +if (is_ivector_node(branch(0))) +{ +vector_interface* vi = reinterpret_cast*>(0); + +if (0 != (vi = dynamic_cast*>(branch(0)))) +{ +vec0_node_ptr_ = vi->vec(); +vds() = vi->vds(); +} +} + +if (is_ivector_node(branch(1))) +{ +vector_interface* vi = reinterpret_cast*>(0); + +if (0 != (vi = dynamic_cast*>(branch(1)))) +{ +vec1_node_ptr_ = vi->vec(); +} +} + +if (vec0_node_ptr_ && vec1_node_ptr_) +{ +vec_size_ = std::min(vec0_node_ptr_->vds().size(), +vec1_node_ptr_->vds().size()); + +initialised_ = true; +} + +assert(initialised_); +} + +inline T value() const exprtk_override +{ +if (initialised_) +{ +assert(branch(0)); +assert(branch(1)); + +binary_node::branch(0)->value(); +binary_node::branch(1)->value(); + +T* vec0 = vec0_node_ptr_->vds().data(); +T* vec1 = vec1_node_ptr_->vds().data(); + +for (std::size_t i = 0; i < vec_size_; ++i) +{ +std::swap(vec0[i],vec1[i]); +} + +return vec1_node_ptr_->value(); +} +else +return std::numeric_limits::quiet_NaN(); +} + +vector_node_ptr vec() const exprtk_override +{ +return vec0_node_ptr_; +} + +vector_node_ptr vec() exprtk_override +{ +return vec0_node_ptr_; +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_vecvecswap; +} + +std::size_t size() const exprtk_override +{ +return vec_size_; +} + +vds_t& vds() exprtk_override +{ +return vds_; +} + +const vds_t& vds() const exprtk_override +{ +return vds_; +} + +private: + +vector_node* vec0_node_ptr_; +vector_node* vec1_node_ptr_; +std::size_t vec_size_; +bool initialised_; +vds_t vds_; +}; + +#ifndef exprtk_disable_string_capabilities +template +class stringvar_node exprtk_final +: public expression_node , +public string_base_node, +public range_interface +{ +public: + +typedef typename range_interface::range_t range_t; + +static std::string null_value; + +explicit stringvar_node() +: value_(&null_value) +{} + +explicit stringvar_node(std::string& v) +: value_(&v) +{ +rp_.n0_c = std::make_pair(true,0); +rp_.n1_c = std::make_pair(true,v.size() - 1); +rp_.cache.first = rp_.n0_c.second; +rp_.cache.second = rp_.n1_c.second; +} + +inline bool operator <(const stringvar_node& v) const +{ +return this < (&v); +} + +inline T value() const exprtk_override +{ +rp_.n1_c.second = (*value_).size() - 1; +rp_.cache.second = rp_.n1_c.second; + +return std::numeric_limits::quiet_NaN(); +} + +std::string str() const exprtk_override +{ +return ref(); +} + +char_cptr base() const exprtk_override +{ +return &(*value_)[0]; +} + +std::size_t size() const exprtk_override +{ +return ref().size(); +} + +std::string& ref() +{ +return (*value_); +} + +const std::string& ref() const +{ +return (*value_); +} + +range_t& range_ref() exprtk_override +{ +return rp_; +} + +const range_t& range_ref() const exprtk_override +{ +return rp_; +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_stringvar; +} + +void rebase(std::string& s) +{ +value_ = &s; +rp_.n0_c = std::make_pair(true,0); +rp_.n1_c = std::make_pair(true,value_->size() - 1); +rp_.cache.first = rp_.n0_c.second; +rp_.cache.second = rp_.n1_c.second; +} + +private: + +std::string* value_; +mutable range_t rp_; +}; + +template +std::string stringvar_node::null_value = std::string(""); + +template +class string_range_node exprtk_final +: public expression_node , +public string_base_node, +public range_interface +{ +public: + +typedef typename range_interface::range_t range_t; + +static std::string null_value; + +explicit string_range_node(std::string& v, const range_t& rp) +: value_(&v) +, rp_(rp) +{} + +virtual ~string_range_node() +{ +rp_.free(); +} + +inline bool operator <(const string_range_node& v) const +{ +return this < (&v); +} + +inline T value() const exprtk_override +{ +return std::numeric_limits::quiet_NaN(); +} + +inline std::string str() const exprtk_override +{ +return (*value_); +} + +char_cptr base() const exprtk_override +{ +return &(*value_)[0]; +} + +std::size_t size() const exprtk_override +{ +return ref().size(); +} + +inline range_t range() const +{ +return rp_; +} + +inline virtual std::string& ref() +{ +return (*value_); +} + +inline virtual const std::string& ref() const +{ +return (*value_); +} + +inline range_t& range_ref() exprtk_override +{ +return rp_; +} + +inline const range_t& range_ref() const exprtk_override +{ +return rp_; +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_stringvarrng; +} + +private: + +std::string* value_; +range_t rp_; +}; + +template +std::string string_range_node::null_value = std::string(""); + +template +class const_string_range_node exprtk_final +: public expression_node , +public string_base_node, +public range_interface +{ +public: + +typedef typename range_interface::range_t range_t; + +explicit const_string_range_node(const std::string& v, const range_t& rp) +: value_(v) +, rp_(rp) +{} + +~const_string_range_node() +{ +rp_.free(); +} + +inline T value() const exprtk_override +{ +return std::numeric_limits::quiet_NaN(); +} + +std::string str() const exprtk_override +{ +return value_; +} + +char_cptr base() const exprtk_override +{ +return value_.data(); +} + +std::size_t size() const exprtk_override +{ +return value_.size(); +} + +range_t range() const +{ +return rp_; +} + +range_t& range_ref() exprtk_override +{ +return rp_; +} + +const range_t& range_ref() const exprtk_override +{ +return rp_; +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_cstringvarrng; +} + +private: + +const_string_range_node(const const_string_range_node&) exprtk_delete; +const_string_range_node& operator=(const const_string_range_node&) exprtk_delete; + +const std::string value_; +range_t rp_; +}; + +template +class generic_string_range_node exprtk_final +: public expression_node , +public string_base_node, +public range_interface +{ +public: + +typedef expression_node * expression_ptr; +typedef stringvar_node * strvar_node_ptr; +typedef string_base_node* str_base_ptr; +typedef typename range_interface::range_t range_t; +typedef range_t* range_ptr; +typedef range_interface irange_t; +typedef irange_t* irange_ptr; +typedef std::pair branch_t; + +generic_string_range_node(expression_ptr str_branch, const range_t& brange) +: initialised_(false) +, str_base_ptr_ (0) +, str_range_ptr_(0) +, base_range_(brange) +{ +range_.n0_c = std::make_pair(true,0); +range_.n1_c = std::make_pair(true,0); +range_.cache.first = range_.n0_c.second; +range_.cache.second = range_.n1_c.second; + +construct_branch_pair(branch_, str_branch); + +if (is_generally_string_node(branch_.first)) +{ +str_base_ptr_ = dynamic_cast(branch_.first); + +if (0 == str_base_ptr_) +return; + +str_range_ptr_ = dynamic_cast(branch_.first); + +if (0 == str_range_ptr_) +return; +} + +initialised_ = (str_base_ptr_ && str_range_ptr_); + +assert(initialised_); +} + +~generic_string_range_node() +{ +base_range_.free(); +} + +inline T value() const exprtk_override +{ +if (initialised_) +{ +assert(branch_.first); + +branch_.first->value(); + +std::size_t str_r0 = 0; +std::size_t str_r1 = 0; + +std::size_t r0 = 0; +std::size_t r1 = 0; + +const range_t& range = str_range_ptr_->range_ref(); + +const std::size_t base_str_size = str_base_ptr_->size(); + +if ( +range (str_r0, str_r1, base_str_size) && +base_range_( r0, r1, base_str_size - str_r0) +) +{ +const std::size_t size = (r1 - r0) + 1; + +range_.n1_c.second = size - 1; +range_.cache.second = range_.n1_c.second; + +value_.assign(str_base_ptr_->base() + str_r0 + r0, size); +} +} + +return std::numeric_limits::quiet_NaN(); +} + +std::string str() const exprtk_override +{ +return value_; +} + +char_cptr base() const exprtk_override +{ +return &value_[0]; +} + +std::size_t size() const exprtk_override +{ +return value_.size(); +} + +range_t& range_ref() exprtk_override +{ +return range_; +} + +const range_t& range_ref() const exprtk_override +{ +return range_; +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_strgenrange; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::collect(branch_, node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::compute_node_depth(branch_); +} + +private: + +bool initialised_; +branch_t branch_; +str_base_ptr str_base_ptr_; +irange_ptr str_range_ptr_; +mutable range_t base_range_; +mutable range_t range_; +mutable std::string value_; +}; + +template +class string_concat_node exprtk_final +: public binary_node , +public string_base_node, +public range_interface +{ +public: + +typedef typename range_interface::range_t range_t; +typedef range_interface irange_t; +typedef irange_t* irange_ptr; +typedef range_t* range_ptr; +typedef expression_node * expression_ptr; +typedef string_base_node* str_base_ptr; + +using binary_node::branch; + +string_concat_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1) +: binary_node(opr, branch0, branch1) +, initialised_(false) +, str0_base_ptr_ (0) +, str1_base_ptr_ (0) +, str0_range_ptr_(0) +, str1_range_ptr_(0) +{ +range_.n0_c = std::make_pair(true,0); +range_.n1_c = std::make_pair(true,0); + +range_.cache.first = range_.n0_c.second; +range_.cache.second = range_.n1_c.second; + +if (is_generally_string_node(branch(0))) +{ +str0_base_ptr_ = dynamic_cast(branch(0)); + +if (0 == str0_base_ptr_) +return; + +str0_range_ptr_ = dynamic_cast(branch(0)); + +if (0 == str0_range_ptr_) +return; +} + +if (is_generally_string_node(branch(1))) +{ +str1_base_ptr_ = dynamic_cast(branch(1)); + +if (0 == str1_base_ptr_) +return; + +str1_range_ptr_ = dynamic_cast(branch(1)); + +if (0 == str1_range_ptr_) +return; +} + +initialised_ = str0_base_ptr_ && +str1_base_ptr_ && +str0_range_ptr_ && +str1_range_ptr_ ; + +assert(initialised_); +} + +inline T value() const exprtk_override +{ +if (initialised_) +{ +assert(branch(0)); +assert(branch(1)); + +branch(0)->value(); +branch(1)->value(); + +std::size_t str0_r0 = 0; +std::size_t str0_r1 = 0; + +std::size_t str1_r0 = 0; +std::size_t str1_r1 = 0; + +const range_t& range0 = str0_range_ptr_->range_ref(); +const range_t& range1 = str1_range_ptr_->range_ref(); + +if ( +range0(str0_r0, str0_r1, str0_base_ptr_->size()) && +range1(str1_r0, str1_r1, str1_base_ptr_->size()) +) +{ +const std::size_t size0 = (str0_r1 - str0_r0) + 1; +const std::size_t size1 = (str1_r1 - str1_r0) + 1; + +value_.assign(str0_base_ptr_->base() + str0_r0, size0); +value_.append(str1_base_ptr_->base() + str1_r0, size1); + +range_.n1_c.second = value_.size() - 1; +range_.cache.second = range_.n1_c.second; +} +} + +return std::numeric_limits::quiet_NaN(); +} + +std::string str() const exprtk_override +{ +return value_; +} + +char_cptr base() const exprtk_override +{ +return &value_[0]; +} + +std::size_t size() const exprtk_override +{ +return value_.size(); +} + +range_t& range_ref() exprtk_override +{ +return range_; +} + +const range_t& range_ref() const exprtk_override +{ +return range_; +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_strconcat; +} + +private: + +bool initialised_; +str_base_ptr str0_base_ptr_; +str_base_ptr str1_base_ptr_; +irange_ptr str0_range_ptr_; +irange_ptr str1_range_ptr_; +mutable range_t range_; +mutable std::string value_; +}; + +template +class swap_string_node exprtk_final +: public binary_node , +public string_base_node, +public range_interface +{ +public: + +typedef typename range_interface::range_t range_t; +typedef range_t* range_ptr; +typedef range_interface irange_t; +typedef irange_t* irange_ptr; +typedef expression_node * expression_ptr; +typedef stringvar_node * strvar_node_ptr; +typedef string_base_node* str_base_ptr; + +using binary_node::branch; + +swap_string_node(expression_ptr branch0, expression_ptr branch1) +: binary_node(details::e_swap, branch0, branch1), +initialised_(false), +str0_node_ptr_(0), +str1_node_ptr_(0) +{ +if (is_string_node(branch(0))) +{ +str0_node_ptr_ = static_cast(branch(0)); +} + +if (is_string_node(branch(1))) +{ +str1_node_ptr_ = static_cast(branch(1)); +} + +initialised_ = (str0_node_ptr_ && str1_node_ptr_); + +assert(initialised_); +} + +inline T value() const exprtk_override +{ +if (initialised_) +{ +assert(branch(0)); +assert(branch(1)); + +branch(0)->value(); +branch(1)->value(); + +std::swap(str0_node_ptr_->ref(), str1_node_ptr_->ref()); +} + +return std::numeric_limits::quiet_NaN(); +} + +std::string str() const exprtk_override +{ +return str0_node_ptr_->str(); +} + +char_cptr base() const exprtk_override +{ +return str0_node_ptr_->base(); +} + +std::size_t size() const exprtk_override +{ +return str0_node_ptr_->size(); +} + +range_t& range_ref() exprtk_override +{ +return str0_node_ptr_->range_ref(); +} + +const range_t& range_ref() const exprtk_override +{ +return str0_node_ptr_->range_ref(); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_strswap; +} + +private: + +bool initialised_; +strvar_node_ptr str0_node_ptr_; +strvar_node_ptr str1_node_ptr_; +}; + +template +class swap_genstrings_node exprtk_final : public binary_node +{ +public: + +typedef typename range_interface::range_t range_t; +typedef range_t* range_ptr; +typedef range_interface irange_t; +typedef irange_t* irange_ptr; +typedef expression_node * expression_ptr; +typedef string_base_node* str_base_ptr; + +using binary_node::branch; + +swap_genstrings_node(expression_ptr branch0, +expression_ptr branch1) +: binary_node(details::e_default, branch0, branch1) +, str0_base_ptr_ (0) +, str1_base_ptr_ (0) +, str0_range_ptr_(0) +, str1_range_ptr_(0) +, initialised_(false) +{ +if (is_generally_string_node(branch(0))) +{ +str0_base_ptr_ = dynamic_cast(branch(0)); + +if (0 == str0_base_ptr_) +return; + +irange_ptr range = dynamic_cast(branch(0)); + +if (0 == range) +return; + +str0_range_ptr_ = &(range->range_ref()); +} + +if (is_generally_string_node(branch(1))) +{ +str1_base_ptr_ = dynamic_cast(branch(1)); + +if (0 == str1_base_ptr_) +return; + +irange_ptr range = dynamic_cast(branch(1)); + +if (0 == range) +return; + +str1_range_ptr_ = &(range->range_ref()); +} + +initialised_ = str0_base_ptr_ && +str1_base_ptr_ && +str0_range_ptr_ && +str1_range_ptr_ ; + +assert(initialised_); +} + +inline T value() const exprtk_override +{ +if (initialised_) +{ +assert(branch(0)); +assert(branch(1)); + +branch(0)->value(); +branch(1)->value(); + +std::size_t str0_r0 = 0; +std::size_t str0_r1 = 0; + +std::size_t str1_r0 = 0; +std::size_t str1_r1 = 0; + +const range_t& range0 = (*str0_range_ptr_); +const range_t& range1 = (*str1_range_ptr_); + +if ( +range0(str0_r0, str0_r1, str0_base_ptr_->size()) && +range1(str1_r0, str1_r1, str1_base_ptr_->size()) +) +{ +const std::size_t size0 = range0.cache_size(); +const std::size_t size1 = range1.cache_size(); +const std::size_t max_size = std::min(size0,size1); + +char_ptr s0 = const_cast(str0_base_ptr_->base() + str0_r0); +char_ptr s1 = const_cast(str1_base_ptr_->base() + str1_r0); + +loop_unroll::details lud(max_size); +char_cptr upper_bound = s0 + lud.upper_bound; + +while (s0 < upper_bound) +{ +#define exprtk_loop(N) \ + std::swap(s0[N], s1[N]); \ + +exprtk_loop( 0) exprtk_loop( 1) +exprtk_loop( 2) exprtk_loop( 3) +#ifndef exprtk_disable_superscalar_unroll +exprtk_loop( 4) exprtk_loop( 5) +exprtk_loop( 6) exprtk_loop( 7) +exprtk_loop( 8) exprtk_loop( 9) +exprtk_loop(10) exprtk_loop(11) +exprtk_loop(12) exprtk_loop(13) +exprtk_loop(14) exprtk_loop(15) +#endif + +s0 += lud.batch_size; +s1 += lud.batch_size; +} + +int i = 0; + +exprtk_disable_fallthrough_begin +switch (lud.remainder) +{ +#define case_stmt(N) \ + case N : { std::swap(s0[i], s1[i]); ++i; } \ + +#ifndef exprtk_disable_superscalar_unroll +case_stmt(15) case_stmt(14) +case_stmt(13) case_stmt(12) +case_stmt(11) case_stmt(10) +case_stmt( 9) case_stmt( 8) +case_stmt( 7) case_stmt( 6) +case_stmt( 5) case_stmt( 4) +#endif +case_stmt( 3) case_stmt( 2) +case_stmt( 1) +} +exprtk_disable_fallthrough_end + +#undef exprtk_loop +#undef case_stmt +} +} + +return std::numeric_limits::quiet_NaN(); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_strswap; +} + +private: + +swap_genstrings_node(const swap_genstrings_node&) exprtk_delete; +swap_genstrings_node& operator=(const swap_genstrings_node&) exprtk_delete; + +str_base_ptr str0_base_ptr_; +str_base_ptr str1_base_ptr_; +range_ptr str0_range_ptr_; +range_ptr str1_range_ptr_; +bool initialised_; +}; + +template +class stringvar_size_node exprtk_final : public expression_node +{ +public: + +static std::string null_value; + +explicit stringvar_size_node() +: value_(&null_value) +{} + +explicit stringvar_size_node(std::string& v) +: value_(&v) +{} + +inline T value() const exprtk_override +{ +return T((*value_).size()); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_stringvarsize; +} + +private: + +std::string* value_; +}; + +template +std::string stringvar_size_node::null_value = std::string(""); + +template +class string_size_node exprtk_final : public expression_node +{ +public: + +typedef expression_node * expression_ptr; +typedef string_base_node* str_base_ptr; +typedef std::pair branch_t; + +explicit string_size_node(expression_ptr branch) +: str_base_ptr_(0) +{ +construct_branch_pair(branch_, branch); + +if (is_generally_string_node(branch_.first)) +{ +str_base_ptr_ = dynamic_cast(branch_.first); + +if (0 == str_base_ptr_) +return; +} +} + +inline T value() const exprtk_override +{ +T result = std::numeric_limits::quiet_NaN(); + +if (str_base_ptr_) +{ +branch_.first->value(); +result = T(str_base_ptr_->size()); +} + +return result; +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_stringsize; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::collect(branch_, node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::compute_node_depth(branch_); +} + +private: + +branch_t branch_; +str_base_ptr str_base_ptr_; +}; + +struct asn_assignment +{ +static inline void execute(std::string& s, char_cptr data, const std::size_t size) +{ s.assign(data,size); } +}; + +struct asn_addassignment +{ +static inline void execute(std::string& s, char_cptr data, const std::size_t size) +{ s.append(data,size); } +}; + +template +class assignment_string_node exprtk_final +: public binary_node , +public string_base_node, +public range_interface +{ +public: + +typedef typename range_interface::range_t range_t; +typedef range_t* range_ptr; +typedef range_interface irange_t; +typedef irange_t* irange_ptr; +typedef expression_node * expression_ptr; +typedef stringvar_node * strvar_node_ptr; +typedef string_base_node* str_base_ptr; + +using binary_node::branch; + +assignment_string_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1) +: binary_node(opr, branch0, branch1) +, initialised_(false) +, str0_base_ptr_ (0) +, str1_base_ptr_ (0) +, str0_node_ptr_ (0) +, str1_range_ptr_(0) +{ +if (is_string_node(branch(0))) +{ +str0_node_ptr_ = static_cast(branch(0)); +str0_base_ptr_ = dynamic_cast(branch(0)); +} + +if (is_generally_string_node(branch(1))) +{ +str1_base_ptr_ = dynamic_cast(branch(1)); + +if (0 == str1_base_ptr_) +return; + +irange_ptr range = dynamic_cast(branch(1)); + +if (0 == range) +return; + +str1_range_ptr_ = &(range->range_ref()); +} + +initialised_ = str0_base_ptr_ && +str1_base_ptr_ && +str0_node_ptr_ && +str1_range_ptr_ ; + +assert(initialised_); +} + +inline T value() const exprtk_override +{ +if (initialised_) +{ +assert(branch(0)); +assert(branch(1)); + +branch(1)->value(); + +std::size_t r0 = 0; +std::size_t r1 = 0; + +const range_t& range = (*str1_range_ptr_); + +if (range(r0, r1, str1_base_ptr_->size())) +{ +AssignmentProcess::execute(str0_node_ptr_->ref(), +str1_base_ptr_->base() + r0, +(r1 - r0) + 1); + +branch(0)->value(); +} +} + +return std::numeric_limits::quiet_NaN(); +} + +std::string str() const exprtk_override +{ +return str0_node_ptr_->str(); +} + +char_cptr base() const exprtk_override +{ +return str0_node_ptr_->base(); +} + +std::size_t size() const exprtk_override +{ +return str0_node_ptr_->size(); +} + +range_t& range_ref() exprtk_override +{ +return str0_node_ptr_->range_ref(); +} + +const range_t& range_ref() const exprtk_override +{ +return str0_node_ptr_->range_ref(); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_strass; +} + +private: + +bool initialised_; +str_base_ptr str0_base_ptr_; +str_base_ptr str1_base_ptr_; +strvar_node_ptr str0_node_ptr_; +range_ptr str1_range_ptr_; +}; + +template +class assignment_string_range_node exprtk_final +: public binary_node , +public string_base_node, +public range_interface +{ +public: + +typedef typename range_interface::range_t range_t; +typedef range_t* range_ptr; +typedef range_interface irange_t; +typedef irange_t* irange_ptr; +typedef expression_node * expression_ptr; +typedef stringvar_node * strvar_node_ptr; +typedef string_range_node* str_rng_node_ptr; +typedef string_base_node * str_base_ptr; + +using binary_node::branch; + +assignment_string_range_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1) +: binary_node(opr, branch0, branch1) +, initialised_(false) +, str0_base_ptr_ (0) +, str1_base_ptr_ (0) +, str0_rng_node_ptr_(0) +, str0_range_ptr_ (0) +, str1_range_ptr_ (0) +{ +if (is_string_range_node(branch(0))) +{ +str0_rng_node_ptr_ = static_cast(branch(0)); +str0_base_ptr_ = dynamic_cast(branch(0)); +irange_ptr range = dynamic_cast(branch(0)); + +if (0 == range) +return; + +str0_range_ptr_ = &(range->range_ref()); +} + +if (is_generally_string_node(branch(1))) +{ +str1_base_ptr_ = dynamic_cast(branch(1)); + +if (0 == str1_base_ptr_) +return; + +irange_ptr range = dynamic_cast(branch(1)); + +if (0 == range) +return; + +str1_range_ptr_ = &(range->range_ref()); +} + +initialised_ = str0_base_ptr_ && +str1_base_ptr_ && +str0_rng_node_ptr_ && +str0_range_ptr_ && +str1_range_ptr_ ; + +assert(initialised_); +} + +inline T value() const exprtk_override +{ +if (initialised_) +{ +assert(branch(0)); +assert(branch(1)); + +branch(0)->value(); +branch(1)->value(); + +std::size_t s0_r0 = 0; +std::size_t s0_r1 = 0; + +std::size_t s1_r0 = 0; +std::size_t s1_r1 = 0; + +const range_t& range0 = (*str0_range_ptr_); +const range_t& range1 = (*str1_range_ptr_); + +if ( +range0(s0_r0, s0_r1, str0_base_ptr_->size()) && +range1(s1_r0, s1_r1, str1_base_ptr_->size()) +) +{ +const std::size_t size = std::min((s0_r1 - s0_r0), (s1_r1 - s1_r0)) + 1; + +std::copy(str1_base_ptr_->base() + s1_r0, +str1_base_ptr_->base() + s1_r0 + size, +const_cast(base() + s0_r0)); +} +} + +return std::numeric_limits::quiet_NaN(); +} + +std::string str() const exprtk_override +{ +return str0_base_ptr_->str(); +} + +char_cptr base() const exprtk_override +{ +return str0_base_ptr_->base(); +} + +std::size_t size() const exprtk_override +{ +return str0_base_ptr_->size(); +} + +range_t& range_ref() exprtk_override +{ +return str0_rng_node_ptr_->range_ref(); +} + +const range_t& range_ref() const exprtk_override +{ +return str0_rng_node_ptr_->range_ref(); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_strass; +} + +private: + +bool initialised_; +str_base_ptr str0_base_ptr_; +str_base_ptr str1_base_ptr_; +str_rng_node_ptr str0_rng_node_ptr_; +range_ptr str0_range_ptr_; +range_ptr str1_range_ptr_; +}; + +template +class conditional_string_node exprtk_final +: public trinary_node , +public string_base_node, +public range_interface +{ +public: + +typedef typename range_interface::range_t range_t; +typedef range_t* range_ptr; +typedef range_interface irange_t; +typedef irange_t* irange_ptr; +typedef expression_node * expression_ptr; +typedef string_base_node* str_base_ptr; + +conditional_string_node(expression_ptr condition, +expression_ptr consequent, +expression_ptr alternative) +: trinary_node(details::e_default, consequent, alternative, condition) +, initialised_(false) +, str0_base_ptr_ (0) +, str1_base_ptr_ (0) +, str0_range_ptr_(0) +, str1_range_ptr_(0) +, condition_ (condition ) +, consequent_ (consequent ) +, alternative_(alternative) +{ +range_.n0_c = std::make_pair(true,0); +range_.n1_c = std::make_pair(true,0); + +range_.cache.first = range_.n0_c.second; +range_.cache.second = range_.n1_c.second; + +if (is_generally_string_node(trinary_node::branch_[0].first)) +{ +str0_base_ptr_ = dynamic_cast(trinary_node::branch_[0].first); + +if (0 == str0_base_ptr_) +return; + +str0_range_ptr_ = dynamic_cast(trinary_node::branch_[0].first); + +if (0 == str0_range_ptr_) +return; +} + +if (is_generally_string_node(trinary_node::branch_[1].first)) +{ +str1_base_ptr_ = dynamic_cast(trinary_node::branch_[1].first); + +if (0 == str1_base_ptr_) +return; + +str1_range_ptr_ = dynamic_cast(trinary_node::branch_[1].first); + +if (0 == str1_range_ptr_) +return; +} + +initialised_ = str0_base_ptr_ && +str1_base_ptr_ && +str0_range_ptr_ && +str1_range_ptr_ ; + +assert(initialised_); +} + +inline T value() const exprtk_override +{ +if (initialised_) +{ +assert(condition_ ); +assert(consequent_ ); +assert(alternative_); + +std::size_t r0 = 0; +std::size_t r1 = 0; + +if (is_true(condition_)) +{ +consequent_->value(); + +const range_t& range = str0_range_ptr_->range_ref(); + +if (range(r0, r1, str0_base_ptr_->size())) +{ +const std::size_t size = (r1 - r0) + 1; + +value_.assign(str0_base_ptr_->base() + r0, size); + +range_.n1_c.second = value_.size() - 1; +range_.cache.second = range_.n1_c.second; + +return T(1); +} +} +else +{ +alternative_->value(); + +const range_t& range = str1_range_ptr_->range_ref(); + +if (range(r0, r1, str1_base_ptr_->size())) +{ +const std::size_t size = (r1 - r0) + 1; + +value_.assign(str1_base_ptr_->base() + r0, size); + +range_.n1_c.second = value_.size() - 1; +range_.cache.second = range_.n1_c.second; + +return T(0); +} +} +} + +return std::numeric_limits::quiet_NaN(); +} + +std::string str() const exprtk_override +{ +return value_; +} + +char_cptr base() const exprtk_override +{ +return &value_[0]; +} + +std::size_t size() const exprtk_override +{ +return value_.size(); +} + +range_t& range_ref() exprtk_override +{ +return range_; +} + +const range_t& range_ref() const exprtk_override +{ +return range_; +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_strcondition; +} + +private: + +bool initialised_; +str_base_ptr str0_base_ptr_; +str_base_ptr str1_base_ptr_; +irange_ptr str0_range_ptr_; +irange_ptr str1_range_ptr_; +mutable range_t range_; +mutable std::string value_; + +expression_ptr condition_; +expression_ptr consequent_; +expression_ptr alternative_; +}; + +template +class cons_conditional_str_node exprtk_final +: public binary_node , +public string_base_node, +public range_interface +{ +public: + +typedef typename range_interface::range_t range_t; +typedef range_t* range_ptr; +typedef range_interface irange_t; +typedef irange_t* irange_ptr; +typedef expression_node * expression_ptr; +typedef string_base_node* str_base_ptr; + +using binary_node::branch; + +cons_conditional_str_node(expression_ptr condition, +expression_ptr consequent) +: binary_node(details::e_default, consequent, condition) +, initialised_(false) +, str0_base_ptr_ (0) +, str0_range_ptr_(0) +, condition_ (condition ) +, consequent_(consequent) +{ +range_.n0_c = std::make_pair(true,0); +range_.n1_c = std::make_pair(true,0); + +range_.cache.first = range_.n0_c.second; +range_.cache.second = range_.n1_c.second; + +if (is_generally_string_node(branch(0))) +{ +str0_base_ptr_ = dynamic_cast(branch(0)); + +if (0 == str0_base_ptr_) +return; + +str0_range_ptr_ = dynamic_cast(branch(0)); + +if (0 == str0_range_ptr_) +return; +} + +initialised_ = str0_base_ptr_ && str0_range_ptr_ ; + +assert(initialised_); +} + +inline T value() const exprtk_override +{ +if (initialised_) +{ +assert(condition_ ); +assert(consequent_); + +if (is_true(condition_)) +{ +consequent_->value(); + +const range_t& range = str0_range_ptr_->range_ref(); + +std::size_t r0 = 0; +std::size_t r1 = 0; + +if (range(r0, r1, str0_base_ptr_->size())) +{ +const std::size_t size = (r1 - r0) + 1; + +value_.assign(str0_base_ptr_->base() + r0, size); + +range_.n1_c.second = value_.size() - 1; +range_.cache.second = range_.n1_c.second; + +return T(1); +} +} +} + +return std::numeric_limits::quiet_NaN(); +} + +std::string str() const +{ +return value_; +} + +char_cptr base() const +{ +return &value_[0]; +} + +std::size_t size() const +{ +return value_.size(); +} + +range_t& range_ref() +{ +return range_; +} + +const range_t& range_ref() const +{ +return range_; +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_strccondition; +} + +private: + +bool initialised_; +str_base_ptr str0_base_ptr_; +irange_ptr str0_range_ptr_; +mutable range_t range_; +mutable std::string value_; + +expression_ptr condition_; +expression_ptr consequent_; +}; + +template +class str_vararg_node exprtk_final +: public expression_node , +public string_base_node, +public range_interface +{ +public: + +typedef typename range_interface::range_t range_t; +typedef range_t* range_ptr; +typedef range_interface irange_t; +typedef irange_t* irange_ptr; +typedef expression_node * expression_ptr; +typedef string_base_node* str_base_ptr; +typedef std::pair branch_t; + +template class Sequence> +explicit str_vararg_node(const Sequence& arg_list) +: initialised_(false) +, str_base_ptr_ (0) +, str_range_ptr_(0) +{ +construct_branch_pair(final_node_, const_cast(arg_list.back())); + +if (0 == final_node_.first) +return; +else if (!is_generally_string_node(final_node_.first)) +return; + +str_base_ptr_ = dynamic_cast(final_node_.first); + +if (0 == str_base_ptr_) +return; + +str_range_ptr_ = dynamic_cast(final_node_.first); + +if (0 == str_range_ptr_) +return; + +initialised_ = str_base_ptr_ && str_range_ptr_; + +if (arg_list.size() > 1) +{ +const std::size_t arg_list_size = arg_list.size() - 1; + +arg_list_.resize(arg_list_size); + +for (std::size_t i = 0; i < arg_list_size; ++i) +{ +if (arg_list[i]) +{ +construct_branch_pair(arg_list_[i], arg_list[i]); +} +else +{ +arg_list_.clear(); +return; +} +} +} +} + +inline T value() const exprtk_override +{ +if (!arg_list_.empty()) +{ +VarArgFunction::process(arg_list_); +} + +final_node_.first->value(); + +return std::numeric_limits::quiet_NaN(); +} + +std::string str() const exprtk_override +{ +return str_base_ptr_->str(); +} + +char_cptr base() const exprtk_override +{ +return str_base_ptr_->base(); +} + +std::size_t size() const exprtk_override +{ +return str_base_ptr_->size(); +} + +range_t& range_ref() exprtk_override +{ +return str_range_ptr_->range_ref(); +} + +const range_t& range_ref() const exprtk_override +{ +return str_range_ptr_->range_ref(); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_stringvararg; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::collect(final_node_ , node_delete_list); +expression_node::ndb_t::collect(arg_list_ , node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return std::max( +expression_node::ndb_t::compute_node_depth(final_node_), +expression_node::ndb_t::compute_node_depth(arg_list_ )); +} + +private: + +bool initialised_; +branch_t final_node_; +str_base_ptr str_base_ptr_; +irange_ptr str_range_ptr_; +std::vector arg_list_; +}; +#endif + +template +inline T axn(const T a, const T x) +{ +// a*x^n +return a * exprtk::details::numeric::fast_exp::result(x); +} + +template +inline T axnb(const T a, const T x, const T b) +{ +// a*x^n+b +return a * exprtk::details::numeric::fast_exp::result(x) + b; +} + +template +struct sf_base +{ +typedef typename details::functor_t::Type Type; +typedef typename details::functor_t functor_t; +typedef typename functor_t::qfunc_t quaternary_functor_t; +typedef typename functor_t::tfunc_t trinary_functor_t; +typedef typename functor_t::bfunc_t binary_functor_t; +typedef typename functor_t::ufunc_t unary_functor_t; +}; + +#define define_sfop3(NN, OP0, OP1) \ + template \ + struct sf##NN##_op : public sf_base \ + { \ + typedef typename sf_base::Type const Type; \ + static inline T process(Type x, Type y, Type z) \ + { \ + return (OP0); \ + } \ + static inline std::string id() \ + { \ + return (OP1); \ + } \ + }; \ + +define_sfop3(00,(x + y) / z ,"(t+t)/t") +define_sfop3(01,(x + y) * z ,"(t+t)*t") +define_sfop3(02,(x + y) - z ,"(t+t)-t") +define_sfop3(03,(x + y) + z ,"(t+t)+t") +define_sfop3(04,(x - y) + z ,"(t-t)+t") +define_sfop3(05,(x - y) / z ,"(t-t)/t") +define_sfop3(06,(x - y) * z ,"(t-t)*t") +define_sfop3(07,(x * y) + z ,"(t*t)+t") +define_sfop3(08,(x * y) - z ,"(t*t)-t") +define_sfop3(09,(x * y) / z ,"(t*t)/t") +define_sfop3(10,(x * y) * z ,"(t*t)*t") +define_sfop3(11,(x / y) + z ,"(t/t)+t") +define_sfop3(12,(x / y) - z ,"(t/t)-t") +define_sfop3(13,(x / y) / z ,"(t/t)/t") +define_sfop3(14,(x / y) * z ,"(t/t)*t") +define_sfop3(15,x / (y + z) ,"t/(t+t)") +define_sfop3(16,x / (y - z) ,"t/(t-t)") +define_sfop3(17,x / (y * z) ,"t/(t*t)") +define_sfop3(18,x / (y / z) ,"t/(t/t)") +define_sfop3(19,x * (y + z) ,"t*(t+t)") +define_sfop3(20,x * (y - z) ,"t*(t-t)") +define_sfop3(21,x * (y * z) ,"t*(t*t)") +define_sfop3(22,x * (y / z) ,"t*(t/t)") +define_sfop3(23,x - (y + z) ,"t-(t+t)") +define_sfop3(24,x - (y - z) ,"t-(t-t)") +define_sfop3(25,x - (y / z) ,"t-(t/t)") +define_sfop3(26,x - (y * z) ,"t-(t*t)") +define_sfop3(27,x + (y * z) ,"t+(t*t)") +define_sfop3(28,x + (y / z) ,"t+(t/t)") +define_sfop3(29,x + (y + z) ,"t+(t+t)") +define_sfop3(30,x + (y - z) ,"t+(t-t)") +define_sfop3(31,(axnb(x,y,z))," ") +define_sfop3(32,(axnb(x,y,z))," ") +define_sfop3(33,(axnb(x,y,z))," ") +define_sfop3(34,(axnb(x,y,z))," ") +define_sfop3(35,(axnb(x,y,z))," ") +define_sfop3(36,(axnb(x,y,z))," ") +define_sfop3(37,(axnb(x,y,z))," ") +define_sfop3(38,(axnb(x,y,z))," ") +define_sfop3(39,x * numeric::log(y) + z,"") +define_sfop3(40,x * numeric::log(y) - z,"") +define_sfop3(41,x * numeric::log10(y) + z,"") +define_sfop3(42,x * numeric::log10(y) - z,"") +define_sfop3(43,x * numeric::sin(y) + z ,"") +define_sfop3(44,x * numeric::sin(y) - z ,"") +define_sfop3(45,x * numeric::cos(y) + z ,"") +define_sfop3(46,x * numeric::cos(y) - z ,"") +define_sfop3(47,details::is_true(x) ? y : z,"") + +#define define_sfop4(NN, OP0, OP1) \ + template \ + struct sf##NN##_op : public sf_base \ + { \ + typedef typename sf_base::Type const Type; \ + static inline T process(Type x, Type y, Type z, Type w) \ + { \ + return (OP0); \ + } \ + static inline std::string id() \ + { \ + return (OP1); \ + } \ + }; \ + +define_sfop4(48,(x + ((y + z) / w)),"t+((t+t)/t)") +define_sfop4(49,(x + ((y + z) * w)),"t+((t+t)*t)") +define_sfop4(50,(x + ((y - z) / w)),"t+((t-t)/t)") +define_sfop4(51,(x + ((y - z) * w)),"t+((t-t)*t)") +define_sfop4(52,(x + ((y * z) / w)),"t+((t*t)/t)") +define_sfop4(53,(x + ((y * z) * w)),"t+((t*t)*t)") +define_sfop4(54,(x + ((y / z) + w)),"t+((t/t)+t)") +define_sfop4(55,(x + ((y / z) / w)),"t+((t/t)/t)") +define_sfop4(56,(x + ((y / z) * w)),"t+((t/t)*t)") +define_sfop4(57,(x - ((y + z) / w)),"t-((t+t)/t)") +define_sfop4(58,(x - ((y + z) * w)),"t-((t+t)*t)") +define_sfop4(59,(x - ((y - z) / w)),"t-((t-t)/t)") +define_sfop4(60,(x - ((y - z) * w)),"t-((t-t)*t)") +define_sfop4(61,(x - ((y * z) / w)),"t-((t*t)/t)") +define_sfop4(62,(x - ((y * z) * w)),"t-((t*t)*t)") +define_sfop4(63,(x - ((y / z) / w)),"t-((t/t)/t)") +define_sfop4(64,(x - ((y / z) * w)),"t-((t/t)*t)") +define_sfop4(65,(((x + y) * z) - w),"((t+t)*t)-t") +define_sfop4(66,(((x - y) * z) - w),"((t-t)*t)-t") +define_sfop4(67,(((x * y) * z) - w),"((t*t)*t)-t") +define_sfop4(68,(((x / y) * z) - w),"((t/t)*t)-t") +define_sfop4(69,(((x + y) / z) - w),"((t+t)/t)-t") +define_sfop4(70,(((x - y) / z) - w),"((t-t)/t)-t") +define_sfop4(71,(((x * y) / z) - w),"((t*t)/t)-t") +define_sfop4(72,(((x / y) / z) - w),"((t/t)/t)-t") +define_sfop4(73,((x * y) + (z * w)),"(t*t)+(t*t)") +define_sfop4(74,((x * y) - (z * w)),"(t*t)-(t*t)") +define_sfop4(75,((x * y) + (z / w)),"(t*t)+(t/t)") +define_sfop4(76,((x * y) - (z / w)),"(t*t)-(t/t)") +define_sfop4(77,((x / y) + (z / w)),"(t/t)+(t/t)") +define_sfop4(78,((x / y) - (z / w)),"(t/t)-(t/t)") +define_sfop4(79,((x / y) - (z * w)),"(t/t)-(t*t)") +define_sfop4(80,(x / (y + (z * w))),"t/(t+(t*t))") +define_sfop4(81,(x / (y - (z * w))),"t/(t-(t*t))") +define_sfop4(82,(x * (y + (z * w))),"t*(t+(t*t))") +define_sfop4(83,(x * (y - (z * w))),"t*(t-(t*t))") + +define_sfop4(84,(axn(x,y) + axn(z,w)),"") +define_sfop4(85,(axn(x,y) + axn(z,w)),"") +define_sfop4(86,(axn(x,y) + axn(z,w)),"") +define_sfop4(87,(axn(x,y) + axn(z,w)),"") +define_sfop4(88,(axn(x,y) + axn(z,w)),"") +define_sfop4(89,(axn(x,y) + axn(z,w)),"") +define_sfop4(90,(axn(x,y) + axn(z,w)),"") +define_sfop4(91,(axn(x,y) + axn(z,w)),"") +define_sfop4(92,((details::is_true(x) && details::is_true(y)) ? z : w),"") +define_sfop4(93,((details::is_true(x) || details::is_true(y)) ? z : w),"") +define_sfop4(94,((x < y) ? z : w),"") +define_sfop4(95,((x <= y) ? z : w),"") +define_sfop4(96,((x > y) ? z : w),"") +define_sfop4(97,((x >= y) ? z : w),"") +define_sfop4(98,(details::is_true(numeric::equal(x,y)) ? z : w),"") +define_sfop4(99,(x * numeric::sin(y) + z * numeric::cos(w)),"") + +define_sfop4(ext00,((x + y) - (z * w)),"(t+t)-(t*t)") +define_sfop4(ext01,((x + y) - (z / w)),"(t+t)-(t/t)") +define_sfop4(ext02,((x + y) + (z * w)),"(t+t)+(t*t)") +define_sfop4(ext03,((x + y) + (z / w)),"(t+t)+(t/t)") +define_sfop4(ext04,((x - y) + (z * w)),"(t-t)+(t*t)") +define_sfop4(ext05,((x - y) + (z / w)),"(t-t)+(t/t)") +define_sfop4(ext06,((x - y) - (z * w)),"(t-t)-(t*t)") +define_sfop4(ext07,((x - y) - (z / w)),"(t-t)-(t/t)") +define_sfop4(ext08,((x + y) - (z - w)),"(t+t)-(t-t)") +define_sfop4(ext09,((x + y) + (z - w)),"(t+t)+(t-t)") +define_sfop4(ext10,((x + y) + (z + w)),"(t+t)+(t+t)") +define_sfop4(ext11,((x + y) * (z - w)),"(t+t)*(t-t)") +define_sfop4(ext12,((x + y) / (z - w)),"(t+t)/(t-t)") +define_sfop4(ext13,((x - y) - (z + w)),"(t-t)-(t+t)") +define_sfop4(ext14,((x - y) + (z + w)),"(t-t)+(t+t)") +define_sfop4(ext15,((x - y) * (z + w)),"(t-t)*(t+t)") +define_sfop4(ext16,((x - y) / (z + w)),"(t-t)/(t+t)") +define_sfop4(ext17,((x * y) - (z + w)),"(t*t)-(t+t)") +define_sfop4(ext18,((x / y) - (z + w)),"(t/t)-(t+t)") +define_sfop4(ext19,((x * y) + (z + w)),"(t*t)+(t+t)") +define_sfop4(ext20,((x / y) + (z + w)),"(t/t)+(t+t)") +define_sfop4(ext21,((x * y) + (z - w)),"(t*t)+(t-t)") +define_sfop4(ext22,((x / y) + (z - w)),"(t/t)+(t-t)") +define_sfop4(ext23,((x * y) - (z - w)),"(t*t)-(t-t)") +define_sfop4(ext24,((x / y) - (z - w)),"(t/t)-(t-t)") +define_sfop4(ext25,((x + y) * (z * w)),"(t+t)*(t*t)") +define_sfop4(ext26,((x + y) * (z / w)),"(t+t)*(t/t)") +define_sfop4(ext27,((x + y) / (z * w)),"(t+t)/(t*t)") +define_sfop4(ext28,((x + y) / (z / w)),"(t+t)/(t/t)") +define_sfop4(ext29,((x - y) / (z * w)),"(t-t)/(t*t)") +define_sfop4(ext30,((x - y) / (z / w)),"(t-t)/(t/t)") +define_sfop4(ext31,((x - y) * (z * w)),"(t-t)*(t*t)") +define_sfop4(ext32,((x - y) * (z / w)),"(t-t)*(t/t)") +define_sfop4(ext33,((x * y) * (z + w)),"(t*t)*(t+t)") +define_sfop4(ext34,((x / y) * (z + w)),"(t/t)*(t+t)") +define_sfop4(ext35,((x * y) / (z + w)),"(t*t)/(t+t)") +define_sfop4(ext36,((x / y) / (z + w)),"(t/t)/(t+t)") +define_sfop4(ext37,((x * y) / (z - w)),"(t*t)/(t-t)") +define_sfop4(ext38,((x / y) / (z - w)),"(t/t)/(t-t)") +define_sfop4(ext39,((x * y) * (z - w)),"(t*t)*(t-t)") +define_sfop4(ext40,((x * y) / (z * w)),"(t*t)/(t*t)") +define_sfop4(ext41,((x / y) * (z / w)),"(t/t)*(t/t)") +define_sfop4(ext42,((x / y) * (z - w)),"(t/t)*(t-t)") +define_sfop4(ext43,((x * y) * (z * w)),"(t*t)*(t*t)") +define_sfop4(ext44,(x + (y * (z / w))),"t+(t*(t/t))") +define_sfop4(ext45,(x - (y * (z / w))),"t-(t*(t/t))") +define_sfop4(ext46,(x + (y / (z * w))),"t+(t/(t*t))") +define_sfop4(ext47,(x - (y / (z * w))),"t-(t/(t*t))") +define_sfop4(ext48,(((x - y) - z) * w),"((t-t)-t)*t") +define_sfop4(ext49,(((x - y) - z) / w),"((t-t)-t)/t") +define_sfop4(ext50,(((x - y) + z) * w),"((t-t)+t)*t") +define_sfop4(ext51,(((x - y) + z) / w),"((t-t)+t)/t") +define_sfop4(ext52,((x + (y - z)) * w),"(t+(t-t))*t") +define_sfop4(ext53,((x + (y - z)) / w),"(t+(t-t))/t") +define_sfop4(ext54,((x + y) / (z + w)),"(t+t)/(t+t)") +define_sfop4(ext55,((x - y) / (z - w)),"(t-t)/(t-t)") +define_sfop4(ext56,((x + y) * (z + w)),"(t+t)*(t+t)") +define_sfop4(ext57,((x - y) * (z - w)),"(t-t)*(t-t)") +define_sfop4(ext58,((x - y) + (z - w)),"(t-t)+(t-t)") +define_sfop4(ext59,((x - y) - (z - w)),"(t-t)-(t-t)") +define_sfop4(ext60,((x / y) + (z * w)),"(t/t)+(t*t)") +define_sfop4(ext61,(((x * y) * z) / w),"((t*t)*t)/t") + +#undef define_sfop3 +#undef define_sfop4 + +template +class sf3_node exprtk_final : public trinary_node +{ +public: + +typedef expression_node* expression_ptr; + +sf3_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1, +expression_ptr branch2) +: trinary_node(opr, branch0, branch1, branch2) +{} + +inline T value() const exprtk_override +{ +assert(trinary_node::branch_[0].first); +assert(trinary_node::branch_[1].first); +assert(trinary_node::branch_[2].first); + +const T x = trinary_node::branch_[0].first->value(); +const T y = trinary_node::branch_[1].first->value(); +const T z = trinary_node::branch_[2].first->value(); + +return SpecialFunction::process(x, y, z); +} +}; + +template +class sf4_node exprtk_final : public quaternary_node +{ +public: + +typedef expression_node* expression_ptr; + +sf4_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1, +expression_ptr branch2, +expression_ptr branch3) +: quaternary_node(opr, branch0, branch1, branch2, branch3) +{} + +inline T value() const exprtk_override +{ +assert(quaternary_node::branch_[0].first); +assert(quaternary_node::branch_[1].first); +assert(quaternary_node::branch_[2].first); +assert(quaternary_node::branch_[3].first); + +const T x = quaternary_node::branch_[0].first->value(); +const T y = quaternary_node::branch_[1].first->value(); +const T z = quaternary_node::branch_[2].first->value(); +const T w = quaternary_node::branch_[3].first->value(); + +return SpecialFunction::process(x, y, z, w); +} +}; + +template +class sf3_var_node exprtk_final : public expression_node +{ +public: + +typedef expression_node* expression_ptr; + +sf3_var_node(const T& v0, const T& v1, const T& v2) +: v0_(v0) +, v1_(v1) +, v2_(v2) +{} + +inline T value() const exprtk_override +{ +return SpecialFunction::process(v0_, v1_, v2_); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_trinary; +} + +private: + +sf3_var_node(const sf3_var_node&) exprtk_delete; +sf3_var_node& operator=(const sf3_var_node&) exprtk_delete; + +const T& v0_; +const T& v1_; +const T& v2_; +}; + +template +class sf4_var_node exprtk_final : public expression_node +{ +public: + +typedef expression_node* expression_ptr; + +sf4_var_node(const T& v0, const T& v1, const T& v2, const T& v3) +: v0_(v0) +, v1_(v1) +, v2_(v2) +, v3_(v3) +{} + +inline T value() const exprtk_override +{ +return SpecialFunction::process(v0_, v1_, v2_, v3_); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_trinary; +} + +private: + +sf4_var_node(const sf4_var_node&) exprtk_delete; +sf4_var_node& operator=(const sf4_var_node&) exprtk_delete; + +const T& v0_; +const T& v1_; +const T& v2_; +const T& v3_; +}; + +template +class vararg_node exprtk_final : public expression_node +{ +public: + +typedef expression_node* expression_ptr; +typedef std::pair branch_t; + +template class Sequence> +explicit vararg_node(const Sequence& arg_list) +{ +arg_list_.resize(arg_list.size()); + +for (std::size_t i = 0; i < arg_list.size(); ++i) +{ +if (arg_list[i]) +{ +construct_branch_pair(arg_list_[i],arg_list[i]); +} +else +{ +arg_list_.clear(); +return; +} +} +} + +inline T value() const exprtk_override +{ +return VarArgFunction::process(arg_list_); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_vararg; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::collect(arg_list_, node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::compute_node_depth(arg_list_); +} + +private: + +std::vector arg_list_; +}; + +template +class vararg_varnode exprtk_final : public expression_node +{ +public: + +typedef expression_node* expression_ptr; + +template class Sequence> +explicit vararg_varnode(const Sequence& arg_list) +{ +arg_list_.resize(arg_list.size()); + +for (std::size_t i = 0; i < arg_list.size(); ++i) +{ +if (arg_list[i] && is_variable_node(arg_list[i])) +{ +variable_node* var_node_ptr = static_cast*>(arg_list[i]); +arg_list_[i] = (&var_node_ptr->ref()); +} +else +{ +arg_list_.clear(); +return; +} +} +} + +inline T value() const exprtk_override +{ +if (!arg_list_.empty()) +return VarArgFunction::process(arg_list_); +else +return std::numeric_limits::quiet_NaN(); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_vararg; +} + +private: + +std::vector arg_list_; +}; + +template +class vectorize_node exprtk_final : public expression_node +{ +public: + +typedef expression_node* expression_ptr; +typedef std::pair branch_t; + +explicit vectorize_node(const expression_ptr v) +: ivec_ptr_(0) +{ +construct_branch_pair(v_, v); + +if (is_ivector_node(v_.first)) +{ +ivec_ptr_ = dynamic_cast*>(v_.first); +} +else +ivec_ptr_ = 0; +} + +inline T value() const exprtk_override +{ +if (ivec_ptr_) +{ +assert(v_.first); + +v_.first->value(); + +return VecFunction::process(ivec_ptr_); +} +else +return std::numeric_limits::quiet_NaN(); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_vecfunc; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::collect(v_, node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::compute_node_depth(v_); +} + +private: + +vector_interface* ivec_ptr_; +branch_t v_; +}; + +template +class assignment_node exprtk_final : public binary_node +{ +public: + +typedef expression_node* expression_ptr; +using binary_node::branch; + +assignment_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1) +: binary_node(opr, branch0, branch1) +, var_node_ptr_(0) +{ +if (is_variable_node(branch(0))) +{ +var_node_ptr_ = static_cast*>(branch(0)); +} +} + +inline T value() const exprtk_override +{ +if (var_node_ptr_) +{ +assert(branch(1)); + +T& result = var_node_ptr_->ref(); +result = branch(1)->value(); + +return result; +} +else +return std::numeric_limits::quiet_NaN(); +} + +private: + +variable_node* var_node_ptr_; +}; + +template +class assignment_vec_elem_node exprtk_final : public binary_node +{ +public: + +typedef expression_node* expression_ptr; +using binary_node::branch; + +assignment_vec_elem_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1) +: binary_node(opr, branch0, branch1) +, vec_node_ptr_(0) +{ +if (is_vector_elem_node(branch(0))) +{ +vec_node_ptr_ = static_cast*>(branch(0)); +} +} + +inline T value() const exprtk_override +{ +if (vec_node_ptr_) +{ +assert(branch(1)); + +T& result = vec_node_ptr_->ref(); +result = branch(1)->value(); + +return result; +} +else +return std::numeric_limits::quiet_NaN(); +} + +private: + +vector_elem_node* vec_node_ptr_; +}; + +template +class assignment_rebasevec_elem_node exprtk_final : public binary_node +{ +public: + +typedef expression_node* expression_ptr; +using expression_node::branch; + +assignment_rebasevec_elem_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1) +: binary_node(opr, branch0, branch1) +, rbvec_node_ptr_(0) +{ +if (is_rebasevector_elem_node(branch(0))) +{ +rbvec_node_ptr_ = static_cast*>(branch(0)); +} +} + +inline T value() const exprtk_override +{ +if (rbvec_node_ptr_) +{ +assert(branch(1)); + +T& result = rbvec_node_ptr_->ref(); + +result = branch(1)->value(); + +return result; +} +else +return std::numeric_limits::quiet_NaN(); +} + +private: + +rebasevector_elem_node* rbvec_node_ptr_; +}; + +template +class assignment_rebasevec_celem_node exprtk_final : public binary_node +{ +public: + +typedef expression_node* expression_ptr; +using binary_node::branch; + +assignment_rebasevec_celem_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1) +: binary_node(opr, branch0, branch1) +, rbvec_node_ptr_(0) +{ +if (is_rebasevector_celem_node(branch(0))) +{ +rbvec_node_ptr_ = static_cast*>(branch(0)); +} +} + +inline T value() const exprtk_override +{ +if (rbvec_node_ptr_) +{ +assert(branch(1)); + +T& result = rbvec_node_ptr_->ref(); +result = branch(1)->value(); + +return result; +} +else +return std::numeric_limits::quiet_NaN(); +} + +private: + +rebasevector_celem_node* rbvec_node_ptr_; +}; + +template +class assignment_vec_node exprtk_final +: public binary_node +, public vector_interface +{ +public: + +typedef expression_node* expression_ptr; +typedef vector_node* vector_node_ptr; +typedef vec_data_store vds_t; + +using binary_node::branch; + +assignment_vec_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1) +: binary_node(opr, branch0, branch1) +, vec_node_ptr_(0) +{ +if (is_vector_node(branch(0))) +{ +vec_node_ptr_ = static_cast*>(branch(0)); +vds() = vec_node_ptr_->vds(); +} +} + +inline T value() const exprtk_override +{ +if (vec_node_ptr_) +{ +assert(branch(1)); + +const T v = branch(1)->value(); + +T* vec = vds().data(); + +loop_unroll::details lud(size()); +const T* upper_bound = vec + lud.upper_bound; + +while (vec < upper_bound) +{ +#define exprtk_loop(N) \ + vec[N] = v; \ + +exprtk_loop( 0) exprtk_loop( 1) +exprtk_loop( 2) exprtk_loop( 3) +#ifndef exprtk_disable_superscalar_unroll +exprtk_loop( 4) exprtk_loop( 5) +exprtk_loop( 6) exprtk_loop( 7) +exprtk_loop( 8) exprtk_loop( 9) +exprtk_loop(10) exprtk_loop(11) +exprtk_loop(12) exprtk_loop(13) +exprtk_loop(14) exprtk_loop(15) +#endif + +vec += lud.batch_size; +} + +exprtk_disable_fallthrough_begin +switch (lud.remainder) +{ +#define case_stmt(N) \ + case N : *vec++ = v; \ + +#ifndef exprtk_disable_superscalar_unroll +case_stmt(15) case_stmt(14) +case_stmt(13) case_stmt(12) +case_stmt(11) case_stmt(10) +case_stmt( 9) case_stmt( 8) +case_stmt( 7) case_stmt( 6) +case_stmt( 5) case_stmt( 4) +#endif +case_stmt( 3) case_stmt( 2) +case_stmt( 1) +} +exprtk_disable_fallthrough_end + +#undef exprtk_loop +#undef case_stmt + +return vec_node_ptr_->value(); +} +else +return std::numeric_limits::quiet_NaN(); +} + +vector_node_ptr vec() const exprtk_override +{ +return vec_node_ptr_; +} + +vector_node_ptr vec() exprtk_override +{ +return vec_node_ptr_; +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_vecvalass; +} + +std::size_t size() const exprtk_override +{ +return vds().size(); +} + +vds_t& vds() exprtk_override +{ +return vds_; +} + +const vds_t& vds() const exprtk_override +{ +return vds_; +} + +private: + +vector_node* vec_node_ptr_; +vds_t vds_; +}; + +template +class assignment_vecvec_node exprtk_final +: public binary_node +, public vector_interface +{ +public: + +typedef expression_node* expression_ptr; +typedef vector_node* vector_node_ptr; +typedef vec_data_store vds_t; + +using binary_node::branch; + +assignment_vecvec_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1) +: binary_node(opr, branch0, branch1) +, vec0_node_ptr_(0) +, vec1_node_ptr_(0) +, initialised_(false) +, src_is_ivec_(false) +{ +if (is_vector_node(branch(0))) +{ +vec0_node_ptr_ = static_cast*>(branch(0)); +vds() = vec0_node_ptr_->vds(); +} + +if (is_vector_node(branch(1))) +{ +vec1_node_ptr_ = static_cast*>(branch(1)); +vds_t::match_sizes(vds(),vec1_node_ptr_->vds()); +} +else if (is_ivector_node(branch(1))) +{ +vector_interface* vi = reinterpret_cast*>(0); + +if (0 != (vi = dynamic_cast*>(branch(1)))) +{ +vec1_node_ptr_ = vi->vec(); + +if (!vi->side_effect()) +{ +vi->vds() = vds(); +src_is_ivec_ = true; +} +else +vds_t::match_sizes(vds(),vi->vds()); +} +} + +initialised_ = (vec0_node_ptr_ && vec1_node_ptr_); + +assert(initialised_); +} + +inline T value() const exprtk_override +{ +if (initialised_) +{ +assert(branch(1)); + +branch(1)->value(); + +if (src_is_ivec_) +return vec0_node_ptr_->value(); + +T* vec0 = vec0_node_ptr_->vds().data(); +T* vec1 = vec1_node_ptr_->vds().data(); + +loop_unroll::details lud(size()); +const T* upper_bound = vec0 + lud.upper_bound; + +while (vec0 < upper_bound) +{ +#define exprtk_loop(N) \ + vec0[N] = vec1[N]; \ + +exprtk_loop( 0) exprtk_loop( 1) +exprtk_loop( 2) exprtk_loop( 3) +#ifndef exprtk_disable_superscalar_unroll +exprtk_loop( 4) exprtk_loop( 5) +exprtk_loop( 6) exprtk_loop( 7) +exprtk_loop( 8) exprtk_loop( 9) +exprtk_loop(10) exprtk_loop(11) +exprtk_loop(12) exprtk_loop(13) +exprtk_loop(14) exprtk_loop(15) +#endif + +vec0 += lud.batch_size; +vec1 += lud.batch_size; +} + +exprtk_disable_fallthrough_begin +switch (lud.remainder) +{ +#define case_stmt(N) \ + case N : *vec0++ = *vec1++; \ + +#ifndef exprtk_disable_superscalar_unroll +case_stmt(15) case_stmt(14) +case_stmt(13) case_stmt(12) +case_stmt(11) case_stmt(10) +case_stmt( 9) case_stmt( 8) +case_stmt( 7) case_stmt( 6) +case_stmt( 5) case_stmt( 4) +#endif +case_stmt( 3) case_stmt( 2) +case_stmt( 1) +} +exprtk_disable_fallthrough_end + +#undef exprtk_loop +#undef case_stmt + +return vec0_node_ptr_->value(); +} +else +return std::numeric_limits::quiet_NaN(); +} + +vector_node_ptr vec() exprtk_override +{ +return vec0_node_ptr_; +} + +vector_node_ptr vec() const exprtk_override +{ +return vec0_node_ptr_; +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_vecvecass; +} + +std::size_t size() const exprtk_override +{ +return vds().size(); +} + +vds_t& vds() exprtk_override +{ +return vds_; +} + +const vds_t& vds() const exprtk_override +{ +return vds_; +} + +private: + +vector_node* vec0_node_ptr_; +vector_node* vec1_node_ptr_; +bool initialised_; +bool src_is_ivec_; +vds_t vds_; +}; + +template +class assignment_op_node exprtk_final : public binary_node +{ +public: + +typedef expression_node* expression_ptr; +using binary_node::branch; + +assignment_op_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1) +: binary_node(opr, branch0, branch1) +, var_node_ptr_(0) +{ +if (is_variable_node(branch(0))) +{ +var_node_ptr_ = static_cast*>(branch(0)); +} +} + +inline T value() const exprtk_override +{ +if (var_node_ptr_) +{ +assert(branch(1)); + +T& v = var_node_ptr_->ref(); +v = Operation::process(v,branch(1)->value()); + +return v; +} +else +return std::numeric_limits::quiet_NaN(); +} + +private: + +variable_node* var_node_ptr_; +}; + +template +class assignment_vec_elem_op_node exprtk_final : public binary_node +{ +public: + +typedef expression_node* expression_ptr; +using binary_node::branch; + +assignment_vec_elem_op_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1) +: binary_node(opr, branch0, branch1) +, vec_node_ptr_(0) +{ +if (is_vector_elem_node(branch(0))) +{ +vec_node_ptr_ = static_cast*>(branch(0)); +} +} + +inline T value() const exprtk_override +{ +if (vec_node_ptr_) +{ +assert(branch(1)); + +T& v = vec_node_ptr_->ref(); +v = Operation::process(v,branch(1)->value()); + +return v; +} +else +return std::numeric_limits::quiet_NaN(); +} + +private: + +vector_elem_node* vec_node_ptr_; +}; + +template +class assignment_rebasevec_elem_op_node exprtk_final : public binary_node +{ +public: + +typedef expression_node* expression_ptr; +using binary_node::branch; + +assignment_rebasevec_elem_op_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1) +: binary_node(opr, branch0, branch1) +, rbvec_node_ptr_(0) +{ +if (is_rebasevector_elem_node(branch(0))) +{ +rbvec_node_ptr_ = static_cast*>(branch(0)); +} +} + +inline T value() const exprtk_override +{ +if (rbvec_node_ptr_) +{ +assert(branch(1)); + +T& v = rbvec_node_ptr_->ref(); +v = Operation::process(v,branch(1)->value()); + +return v; +} +else +return std::numeric_limits::quiet_NaN(); +} + +private: + +rebasevector_elem_node* rbvec_node_ptr_; +}; + +template +class assignment_rebasevec_celem_op_node exprtk_final : public binary_node +{ +public: + +typedef expression_node* expression_ptr; +using binary_node::branch; + +assignment_rebasevec_celem_op_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1) +: binary_node(opr, branch0, branch1) +, rbvec_node_ptr_(0) +{ +if (is_rebasevector_celem_node(branch(0))) +{ +rbvec_node_ptr_ = static_cast*>(branch(0)); +} +} + +inline T value() const exprtk_override +{ +if (rbvec_node_ptr_) +{ +assert(branch(1)); + +T& v = rbvec_node_ptr_->ref(); +v = Operation::process(v,branch(1)->value()); + +return v; +} +else +return std::numeric_limits::quiet_NaN(); +} + +private: + +rebasevector_celem_node* rbvec_node_ptr_; +}; + +template +class assignment_vec_op_node exprtk_final +: public binary_node +, public vector_interface +{ +public: + +typedef expression_node* expression_ptr; +typedef vector_node* vector_node_ptr; +typedef vec_data_store vds_t; + +using binary_node::branch; + +assignment_vec_op_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1) +: binary_node(opr, branch0, branch1) +, vec_node_ptr_(0) +{ +if (is_vector_node(branch(0))) +{ +vec_node_ptr_ = static_cast*>(branch(0)); +vds() = vec_node_ptr_->vds(); +} +} + +inline T value() const exprtk_override +{ +if (vec_node_ptr_) +{ +assert(branch(1)); + +const T v = branch(1)->value(); + +T* vec = vds().data(); + +loop_unroll::details lud(size()); +const T* upper_bound = vec + lud.upper_bound; + +while (vec < upper_bound) +{ +#define exprtk_loop(N) \ + Operation::assign(vec[N],v); \ + +exprtk_loop( 0) exprtk_loop( 1) +exprtk_loop( 2) exprtk_loop( 3) +#ifndef exprtk_disable_superscalar_unroll +exprtk_loop( 4) exprtk_loop( 5) +exprtk_loop( 6) exprtk_loop( 7) +exprtk_loop( 8) exprtk_loop( 9) +exprtk_loop(10) exprtk_loop(11) +exprtk_loop(12) exprtk_loop(13) +exprtk_loop(14) exprtk_loop(15) +#endif + +vec += lud.batch_size; +} + +exprtk_disable_fallthrough_begin +switch (lud.remainder) +{ +#define case_stmt(N) \ + case N : Operation::assign(*vec++,v); \ + +#ifndef exprtk_disable_superscalar_unroll +case_stmt(15) case_stmt(14) +case_stmt(13) case_stmt(12) +case_stmt(11) case_stmt(10) +case_stmt( 9) case_stmt( 8) +case_stmt( 7) case_stmt( 6) +case_stmt( 5) case_stmt( 4) +#endif +case_stmt( 3) case_stmt( 2) +case_stmt( 1) +} +exprtk_disable_fallthrough_end + +#undef exprtk_loop +#undef case_stmt + +return vec_node_ptr_->value(); +} +else +return std::numeric_limits::quiet_NaN(); +} + +vector_node_ptr vec() const exprtk_override +{ +return vec_node_ptr_; +} + +vector_node_ptr vec() exprtk_override +{ +return vec_node_ptr_; +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_vecopvalass; +} + +std::size_t size() const exprtk_override +{ +return vds().size(); +} + +vds_t& vds() exprtk_override +{ +return vds_; +} + +const vds_t& vds() const exprtk_override +{ +return vds_; +} + +bool side_effect() const exprtk_override +{ +return true; +} + +private: + +vector_node* vec_node_ptr_; +vds_t vds_; +}; + +template +class assignment_vecvec_op_node exprtk_final +: public binary_node +, public vector_interface +{ +public: + +typedef expression_node* expression_ptr; +typedef vector_node* vector_node_ptr; +typedef vec_data_store vds_t; + +using binary_node::branch; + +assignment_vecvec_op_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1) +: binary_node(opr, branch0, branch1) +, vec0_node_ptr_(0) +, vec1_node_ptr_(0) +, initialised_(false) +{ +if (is_vector_node(branch(0))) +{ +vec0_node_ptr_ = static_cast*>(branch(0)); +vds() = vec0_node_ptr_->vds(); +} + +if (is_vector_node(branch(1))) +{ +vec1_node_ptr_ = static_cast*>(branch(1)); +vec1_node_ptr_->vds() = vds(); +} +else if (is_ivector_node(branch(1))) +{ +vector_interface* vi = reinterpret_cast*>(0); + +if (0 != (vi = dynamic_cast*>(branch(1)))) +{ +vec1_node_ptr_ = vi->vec(); +vec1_node_ptr_->vds() = vds(); +} +else +vds_t::match_sizes(vds(),vec1_node_ptr_->vds()); +} + +initialised_ = (vec0_node_ptr_ && vec1_node_ptr_); + +assert(initialised_); +} + +inline T value() const exprtk_override +{ +if (initialised_) +{ +assert(branch(0)); +assert(branch(1)); + +branch(0)->value(); +branch(1)->value(); + +T* vec0 = vec0_node_ptr_->vds().data(); +const T* vec1 = vec1_node_ptr_->vds().data(); + +loop_unroll::details lud(size()); +const T* upper_bound = vec0 + lud.upper_bound; + +while (vec0 < upper_bound) +{ +#define exprtk_loop(N) \ + vec0[N] = Operation::process(vec0[N], vec1[N]); \ + +exprtk_loop( 0) exprtk_loop( 1) +exprtk_loop( 2) exprtk_loop( 3) +#ifndef exprtk_disable_superscalar_unroll +exprtk_loop( 4) exprtk_loop( 5) +exprtk_loop( 6) exprtk_loop( 7) +exprtk_loop( 8) exprtk_loop( 9) +exprtk_loop(10) exprtk_loop(11) +exprtk_loop(12) exprtk_loop(13) +exprtk_loop(14) exprtk_loop(15) +#endif + +vec0 += lud.batch_size; +vec1 += lud.batch_size; +} + +int i = 0; + +exprtk_disable_fallthrough_begin +switch (lud.remainder) +{ +#define case_stmt(N) \ + case N : { vec0[i] = Operation::process(vec0[i], vec1[i]); ++i; } \ + +#ifndef exprtk_disable_superscalar_unroll +case_stmt(15) case_stmt(14) +case_stmt(13) case_stmt(12) +case_stmt(11) case_stmt(10) +case_stmt( 9) case_stmt( 8) +case_stmt( 7) case_stmt( 6) +case_stmt( 5) case_stmt( 4) +#endif +case_stmt( 3) case_stmt( 2) +case_stmt( 1) +} +exprtk_disable_fallthrough_end + +#undef exprtk_loop +#undef case_stmt + +return vec0_node_ptr_->value(); +} +else +return std::numeric_limits::quiet_NaN(); +} + +vector_node_ptr vec() const exprtk_override +{ +return vec0_node_ptr_; +} + +vector_node_ptr vec() exprtk_override +{ +return vec0_node_ptr_; +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_vecopvecass; +} + +std::size_t size() const exprtk_override +{ +return vds().size(); +} + +vds_t& vds() exprtk_override +{ +return vds_; +} + +const vds_t& vds() const exprtk_override +{ +return vds_; +} + +bool side_effect() const exprtk_override +{ +return true; +} + +private: + +vector_node* vec0_node_ptr_; +vector_node* vec1_node_ptr_; +bool initialised_; +vds_t vds_; +}; + +template +class vec_binop_vecvec_node exprtk_final +: public binary_node +, public vector_interface +{ +public: + +typedef expression_node* expression_ptr; +typedef vector_node* vector_node_ptr; +typedef vector_holder* vector_holder_ptr; +typedef vec_data_store vds_t; + +using binary_node::branch; + +vec_binop_vecvec_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1) +: binary_node(opr, branch0, branch1) +, vec0_node_ptr_(0) +, vec1_node_ptr_(0) +, temp_ (0) +, temp_vec_node_(0) +, initialised_(false) +{ +bool v0_is_ivec = false; +bool v1_is_ivec = false; + +if (is_vector_node(branch(0))) +{ +vec0_node_ptr_ = static_cast(branch(0)); +} +else if (is_ivector_node(branch(0))) +{ +vector_interface* vi = reinterpret_cast*>(0); + +if (0 != (vi = dynamic_cast*>(branch(0)))) +{ +vec0_node_ptr_ = vi->vec(); +v0_is_ivec = true; +} +} + +if (is_vector_node(branch(1))) +{ +vec1_node_ptr_ = static_cast(branch(1)); +} +else if (is_ivector_node(branch(1))) +{ +vector_interface* vi = reinterpret_cast*>(0); + +if (0 != (vi = dynamic_cast*>(branch(1)))) +{ +vec1_node_ptr_ = vi->vec(); +v1_is_ivec = true; +} +} + +if (vec0_node_ptr_ && vec1_node_ptr_) +{ +vector_holder& vec0 = vec0_node_ptr_->vec_holder(); +vector_holder& vec1 = vec1_node_ptr_->vec_holder(); + +if (v0_is_ivec && (vec0.size() <= vec1.size())) +vds_ = vds_t(vec0_node_ptr_->vds()); +else if (v1_is_ivec && (vec1.size() <= vec0.size())) +vds_ = vds_t(vec1_node_ptr_->vds()); +else +vds_ = vds_t(std::min(vec0.size(),vec1.size())); + +temp_ = new vector_holder(vds().data(),vds().size()); +temp_vec_node_ = new vector_node (vds(),temp_); + +initialised_ = true; +} + +assert(initialised_); +} + +~vec_binop_vecvec_node() +{ +delete temp_; +delete temp_vec_node_; +} + +inline T value() const exprtk_override +{ +if (initialised_) +{ +assert(branch(0)); +assert(branch(1)); + +branch(0)->value(); +branch(1)->value(); + +const T* vec0 = vec0_node_ptr_->vds().data(); +const T* vec1 = vec1_node_ptr_->vds().data(); +T* vec2 = vds().data(); + +loop_unroll::details lud(size()); +const T* upper_bound = vec2 + lud.upper_bound; + +while (vec2 < upper_bound) +{ +#define exprtk_loop(N) \ + vec2[N] = Operation::process(vec0[N], vec1[N]); \ + +exprtk_loop( 0) exprtk_loop( 1) +exprtk_loop( 2) exprtk_loop( 3) +#ifndef exprtk_disable_superscalar_unroll +exprtk_loop( 4) exprtk_loop( 5) +exprtk_loop( 6) exprtk_loop( 7) +exprtk_loop( 8) exprtk_loop( 9) +exprtk_loop(10) exprtk_loop(11) +exprtk_loop(12) exprtk_loop(13) +exprtk_loop(14) exprtk_loop(15) +#endif + +vec0 += lud.batch_size; +vec1 += lud.batch_size; +vec2 += lud.batch_size; +} + +int i = 0; + +exprtk_disable_fallthrough_begin +switch (lud.remainder) +{ +#define case_stmt(N) \ + case N : { vec2[i] = Operation::process(vec0[i], vec1[i]); ++i; } \ + +#ifndef exprtk_disable_superscalar_unroll +case_stmt(15) case_stmt(14) +case_stmt(13) case_stmt(12) +case_stmt(11) case_stmt(10) +case_stmt( 9) case_stmt( 8) +case_stmt( 7) case_stmt( 6) +case_stmt( 5) case_stmt( 4) +#endif +case_stmt( 3) case_stmt( 2) +case_stmt( 1) +} +exprtk_disable_fallthrough_end + +#undef exprtk_loop +#undef case_stmt + +return (vds().data())[0]; +} +else +return std::numeric_limits::quiet_NaN(); +} + +vector_node_ptr vec() const exprtk_override +{ +return temp_vec_node_; +} + +vector_node_ptr vec() exprtk_override +{ +return temp_vec_node_; +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_vecvecarith; +} + +std::size_t size() const exprtk_override +{ +return vds_.size(); +} + +vds_t& vds() exprtk_override +{ +return vds_; +} + +const vds_t& vds() const exprtk_override +{ +return vds_; +} + +private: + +vector_node_ptr vec0_node_ptr_; +vector_node_ptr vec1_node_ptr_; +vector_holder_ptr temp_; +vector_node_ptr temp_vec_node_; +bool initialised_; +vds_t vds_; +}; + +template +class vec_binop_vecval_node exprtk_final +: public binary_node +, public vector_interface +{ +public: + +typedef expression_node* expression_ptr; +typedef vector_node* vector_node_ptr; +typedef vector_holder* vector_holder_ptr; +typedef vec_data_store vds_t; + +using binary_node::branch; + +vec_binop_vecval_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1) +: binary_node(opr, branch0, branch1) +, vec0_node_ptr_(0) +, temp_ (0) +, temp_vec_node_(0) +{ +bool v0_is_ivec = false; + +if (is_vector_node(branch(0))) +{ +vec0_node_ptr_ = static_cast(branch(0)); +} +else if (is_ivector_node(branch(0))) +{ +vector_interface* vi = reinterpret_cast*>(0); + +if (0 != (vi = dynamic_cast*>(branch(0)))) +{ +vec0_node_ptr_ = vi->vec(); +v0_is_ivec = true; +} +} + +if (vec0_node_ptr_) +{ +if (v0_is_ivec) +vds() = vec0_node_ptr_->vds(); +else +vds() = vds_t(vec0_node_ptr_->size()); + +temp_ = new vector_holder(vds()); +temp_vec_node_ = new vector_node (vds(),temp_); +} +} + +~vec_binop_vecval_node() +{ +delete temp_; +delete temp_vec_node_; +} + +inline T value() const exprtk_override +{ +if (vec0_node_ptr_) +{ +assert(branch(0)); +assert(branch(1)); + +branch(0)->value(); +const T v = branch(1)->value(); + +const T* vec0 = vec0_node_ptr_->vds().data(); +T* vec1 = vds().data(); + +loop_unroll::details lud(size()); +const T* upper_bound = vec0 + lud.upper_bound; + +while (vec0 < upper_bound) +{ +#define exprtk_loop(N) \ + vec1[N] = Operation::process(vec0[N], v); \ + +exprtk_loop( 0) exprtk_loop( 1) +exprtk_loop( 2) exprtk_loop( 3) +#ifndef exprtk_disable_superscalar_unroll +exprtk_loop( 4) exprtk_loop( 5) +exprtk_loop( 6) exprtk_loop( 7) +exprtk_loop( 8) exprtk_loop( 9) +exprtk_loop(10) exprtk_loop(11) +exprtk_loop(12) exprtk_loop(13) +exprtk_loop(14) exprtk_loop(15) +#endif + +vec0 += lud.batch_size; +vec1 += lud.batch_size; +} + +int i = 0; + +exprtk_disable_fallthrough_begin +switch (lud.remainder) +{ +#define case_stmt(N) \ + case N : { vec1[i] = Operation::process(vec0[i], v); ++i; } \ + +#ifndef exprtk_disable_superscalar_unroll +case_stmt(15) case_stmt(14) +case_stmt(13) case_stmt(12) +case_stmt(11) case_stmt(10) +case_stmt( 9) case_stmt( 8) +case_stmt( 7) case_stmt( 6) +case_stmt( 5) case_stmt( 4) +#endif +case_stmt( 3) case_stmt( 2) +case_stmt( 1) +} +exprtk_disable_fallthrough_end + +#undef exprtk_loop +#undef case_stmt + +return (vds().data())[0]; +} +else +return std::numeric_limits::quiet_NaN(); +} + +vector_node_ptr vec() const exprtk_override +{ +return temp_vec_node_; +} + +vector_node_ptr vec() exprtk_override +{ +return temp_vec_node_; +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_vecvalarith; +} + +std::size_t size() const exprtk_override +{ +return vds().size(); +} + +vds_t& vds() exprtk_override +{ +return vds_; +} + +const vds_t& vds() const exprtk_override +{ +return vds_; +} + +private: + +vector_node_ptr vec0_node_ptr_; +vector_holder_ptr temp_; +vector_node_ptr temp_vec_node_; +vds_t vds_; +}; + +template +class vec_binop_valvec_node exprtk_final +: public binary_node +, public vector_interface +{ +public: + +typedef expression_node* expression_ptr; +typedef vector_node* vector_node_ptr; +typedef vector_holder* vector_holder_ptr; +typedef vec_data_store vds_t; + +using binary_node::branch; + +vec_binop_valvec_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1) +: binary_node(opr, branch0, branch1) +, vec1_node_ptr_(0) +, temp_ (0) +, temp_vec_node_(0) +{ +bool v1_is_ivec = false; + +if (is_vector_node(branch(1))) +{ +vec1_node_ptr_ = static_cast(branch(1)); +} +else if (is_ivector_node(branch(1))) +{ +vector_interface* vi = reinterpret_cast*>(0); + +if (0 != (vi = dynamic_cast*>(branch(1)))) +{ +vec1_node_ptr_ = vi->vec(); +v1_is_ivec = true; +} +} + +if (vec1_node_ptr_) +{ +if (v1_is_ivec) +vds() = vec1_node_ptr_->vds(); +else +vds() = vds_t(vec1_node_ptr_->size()); + +temp_ = new vector_holder(vds()); +temp_vec_node_ = new vector_node (vds(),temp_); +} +} + +~vec_binop_valvec_node() +{ +delete temp_; +delete temp_vec_node_; +} + +inline T value() const exprtk_override +{ +if (vec1_node_ptr_) +{ +assert(branch(0)); +assert(branch(1)); + +const T v = branch(0)->value(); +branch(1)->value(); + +T* vec0 = vds().data(); +const T* vec1 = vec1_node_ptr_->vds().data(); + +loop_unroll::details lud(size()); +const T* upper_bound = vec0 + lud.upper_bound; + +while (vec0 < upper_bound) +{ +#define exprtk_loop(N) \ + vec0[N] = Operation::process(v, vec1[N]); \ + +exprtk_loop( 0) exprtk_loop( 1) +exprtk_loop( 2) exprtk_loop( 3) +#ifndef exprtk_disable_superscalar_unroll +exprtk_loop( 4) exprtk_loop( 5) +exprtk_loop( 6) exprtk_loop( 7) +exprtk_loop( 8) exprtk_loop( 9) +exprtk_loop(10) exprtk_loop(11) +exprtk_loop(12) exprtk_loop(13) +exprtk_loop(14) exprtk_loop(15) +#endif + +vec0 += lud.batch_size; +vec1 += lud.batch_size; +} + +int i = 0; + +exprtk_disable_fallthrough_begin +switch (lud.remainder) +{ +#define case_stmt(N) \ + case N : { vec0[i] = Operation::process(v, vec1[i]); ++i; } \ + +#ifndef exprtk_disable_superscalar_unroll +case_stmt(15) case_stmt(14) +case_stmt(13) case_stmt(12) +case_stmt(11) case_stmt(10) +case_stmt( 9) case_stmt( 8) +case_stmt( 7) case_stmt( 6) +case_stmt( 5) case_stmt( 4) +#endif +case_stmt( 3) case_stmt( 2) +case_stmt( 1) +} +exprtk_disable_fallthrough_end + +#undef exprtk_loop +#undef case_stmt + +return (vds().data())[0]; +} +else +return std::numeric_limits::quiet_NaN(); +} + +vector_node_ptr vec() const exprtk_override +{ +return temp_vec_node_; +} + +vector_node_ptr vec() exprtk_override +{ +return temp_vec_node_; +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_vecvalarith; +} + +std::size_t size() const exprtk_override +{ +return vds().size(); +} + +vds_t& vds() exprtk_override +{ +return vds_; +} + +const vds_t& vds() const exprtk_override +{ +return vds_; +} + +private: + +vector_node_ptr vec1_node_ptr_; +vector_holder_ptr temp_; +vector_node_ptr temp_vec_node_; +vds_t vds_; +}; + +template +class unary_vector_node exprtk_final +: public unary_node +, public vector_interface +{ +public: + +typedef expression_node* expression_ptr; +typedef vector_node* vector_node_ptr; +typedef vector_holder* vector_holder_ptr; +typedef vec_data_store vds_t; + +using expression_node::branch; + +unary_vector_node(const operator_type& opr, expression_ptr branch0) +: unary_node(opr, branch0) +, vec0_node_ptr_(0) +, temp_ (0) +, temp_vec_node_(0) +{ +bool vec0_is_ivec = false; + +if (is_vector_node(branch())) +{ +vec0_node_ptr_ = static_cast(branch()); +} +else if (is_ivector_node(branch())) +{ +vector_interface* vi = reinterpret_cast*>(0); + +if (0 != (vi = dynamic_cast*>(branch()))) +{ +vec0_node_ptr_ = vi->vec(); +vec0_is_ivec = true; +} +} + +if (vec0_node_ptr_) +{ +if (vec0_is_ivec) +vds_ = vec0_node_ptr_->vds(); +else +vds_ = vds_t(vec0_node_ptr_->size()); + +temp_ = new vector_holder(vds()); +temp_vec_node_ = new vector_node (vds(),temp_); +} +} + +~unary_vector_node() +{ +delete temp_; +delete temp_vec_node_; +} + +inline T value() const exprtk_override +{ +assert(branch()); + +branch()->value(); + +if (vec0_node_ptr_) +{ +const T* vec0 = vec0_node_ptr_->vds().data(); +T* vec1 = vds().data(); + +loop_unroll::details lud(size()); +const T* upper_bound = vec0 + lud.upper_bound; + +while (vec0 < upper_bound) +{ +#define exprtk_loop(N) \ + vec1[N] = Operation::process(vec0[N]); \ + +exprtk_loop( 0) exprtk_loop( 1) +exprtk_loop( 2) exprtk_loop( 3) +#ifndef exprtk_disable_superscalar_unroll +exprtk_loop( 4) exprtk_loop( 5) +exprtk_loop( 6) exprtk_loop( 7) +exprtk_loop( 8) exprtk_loop( 9) +exprtk_loop(10) exprtk_loop(11) +exprtk_loop(12) exprtk_loop(13) +exprtk_loop(14) exprtk_loop(15) +#endif + +vec0 += lud.batch_size; +vec1 += lud.batch_size; +} + +int i = 0; + +exprtk_disable_fallthrough_begin +switch (lud.remainder) +{ +#define case_stmt(N) \ + case N : { vec1[i] = Operation::process(vec0[i]); ++i; } \ + +#ifndef exprtk_disable_superscalar_unroll +case_stmt(15) case_stmt(14) +case_stmt(13) case_stmt(12) +case_stmt(11) case_stmt(10) +case_stmt( 9) case_stmt( 8) +case_stmt( 7) case_stmt( 6) +case_stmt( 5) case_stmt( 4) +#endif +case_stmt( 3) case_stmt( 2) +case_stmt( 1) +} +exprtk_disable_fallthrough_end + +#undef exprtk_loop +#undef case_stmt + +return (vds().data())[0]; +} +else +return std::numeric_limits::quiet_NaN(); +} + +vector_node_ptr vec() const exprtk_override +{ +return temp_vec_node_; +} + +vector_node_ptr vec() exprtk_override +{ +return temp_vec_node_; +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_vecunaryop; +} + +std::size_t size() const exprtk_override +{ +return vds().size(); +} + +vds_t& vds() exprtk_override +{ +return vds_; +} + +const vds_t& vds() const exprtk_override +{ +return vds_; +} + +private: + +vector_node_ptr vec0_node_ptr_; +vector_holder_ptr temp_; +vector_node_ptr temp_vec_node_; +vds_t vds_; +}; + +template +class conditional_vector_node exprtk_final +: public expression_node +, public vector_interface +{ +public: + +typedef expression_node * expression_ptr; +typedef vector_interface* vec_interface_ptr; +typedef vector_node * vector_node_ptr; +typedef vector_holder * vector_holder_ptr; +typedef vec_data_store vds_t; +typedef std::pair branch_t; + +conditional_vector_node(expression_ptr condition, +expression_ptr consequent, +expression_ptr alternative) +: consequent_node_ptr_ (0) +, alternative_node_ptr_(0) +, temp_vec_node_ (0) +, temp_ (0) +, vec_size_ (0) +, initialised_ (false) +{ +construct_branch_pair(condition_ , condition ); +construct_branch_pair(consequent_ , consequent ); +construct_branch_pair(alternative_, alternative); + +if (details::is_ivector_node(consequent_.first)) +{ +vec_interface_ptr ivec_ptr = dynamic_cast(consequent_.first); + +if (0 != ivec_ptr) +{ +consequent_node_ptr_ = ivec_ptr->vec(); +} +} + +if (details::is_ivector_node(alternative_.first)) +{ +vec_interface_ptr ivec_ptr = dynamic_cast(alternative_.first); + +if (0 != ivec_ptr) +{ +alternative_node_ptr_ = ivec_ptr->vec(); +} +} + +if (consequent_node_ptr_ && alternative_node_ptr_) +{ +vec_size_ = std::min(consequent_node_ptr_ ->vds().size(), +alternative_node_ptr_->vds().size()); + +vds_ = vds_t(vec_size_); +temp_ = new vector_holder(vds_); +temp_vec_node_ = new vector_node (vds(),temp_); + +initialised_ = true; +} + +assert(initialised_ && (vec_size_ > 0)); +} + +~conditional_vector_node() +{ +delete temp_; +delete temp_vec_node_; +} + +inline T value() const exprtk_override +{ +if (initialised_) +{ +assert(condition_ .first); +assert(consequent_ .first); +assert(alternative_.first); + +T result = T(0); +T* source_vector = 0; +T* result_vector = vds().data(); + +if (is_true(condition_)) +{ +result = consequent_.first->value(); +source_vector = consequent_node_ptr_->vds().data(); +} +else +{ +result = alternative_.first->value(); +source_vector = alternative_node_ptr_->vds().data(); +} + +for (std::size_t i = 0; i < vec_size_; ++i) +{ +result_vector[i] = source_vector[i]; +} + +return result; +} + +return std::numeric_limits::quiet_NaN(); +} + +vector_node_ptr vec() const exprtk_override +{ +return temp_vec_node_; +} + +vector_node_ptr vec() exprtk_override +{ +return temp_vec_node_; +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_vecondition; +} + +std::size_t size() const exprtk_override +{ +return vec_size_; +} + +vds_t& vds() exprtk_override +{ +return vds_; +} + +const vds_t& vds() const exprtk_override +{ +return vds_; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::collect(condition_ , node_delete_list); +expression_node::ndb_t::collect(consequent_ , node_delete_list); +expression_node::ndb_t::collect(alternative_ , node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::compute_node_depth +(condition_, consequent_, alternative_); +} + +private: + +branch_t condition_; +branch_t consequent_; +branch_t alternative_; +vector_node_ptr consequent_node_ptr_; +vector_node_ptr alternative_node_ptr_; +vector_node_ptr temp_vec_node_; +vector_holder_ptr temp_; +vds_t vds_; +std::size_t vec_size_; +bool initialised_; +}; + +template +class scand_node exprtk_final : public binary_node +{ +public: + +typedef expression_node* expression_ptr; +using binary_node::branch; + +scand_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1) +: binary_node(opr, branch0, branch1) +{} + +inline T value() const exprtk_override +{ +assert(branch(0)); +assert(branch(1)); + +return ( +std::not_equal_to() +(T(0),branch(0)->value()) && +std::not_equal_to() +(T(0),branch(1)->value()) +) ? T(1) : T(0); +} +}; + +template +class scor_node exprtk_final : public binary_node +{ +public: + +typedef expression_node* expression_ptr; +using binary_node::branch; + +scor_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1) +: binary_node(opr, branch0, branch1) +{} + +inline T value() const exprtk_override +{ +assert(branch(0)); +assert(branch(1)); + +return ( +std::not_equal_to() +(T(0),branch(0)->value()) || +std::not_equal_to() +(T(0),branch(1)->value()) +) ? T(1) : T(0); +} +}; + +template +class function_N_node exprtk_final : public expression_node +{ +public: + +// Function of N paramters. +typedef expression_node* expression_ptr; +typedef std::pair branch_t; +typedef IFunction ifunction; + +explicit function_N_node(ifunction* func) +: function_((N == func->param_count) ? func : reinterpret_cast(0)) +, parameter_count_(func->param_count) +{} + +template +bool init_branches(expression_ptr (&b)[NumBranches]) +{ +// Needed for incompetent and broken msvc compiler versions +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif +if (N != NumBranches) +return false; +else +{ +for (std::size_t i = 0; i < NumBranches; ++i) +{ +if (b[i]) +branch_[i] = std::make_pair(b[i],branch_deletable(b[i])); +else +return false; +} +return true; +} +#ifdef _MSC_VER +#pragma warning(pop) +#endif +} + +inline bool operator <(const function_N_node& fn) const +{ +return this < (&fn); +} + +inline T value() const exprtk_override +{ +// Needed for incompetent and broken msvc compiler versions +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif +if ((0 == function_) || (0 == N)) +return std::numeric_limits::quiet_NaN(); +else +{ +T v[N]; +evaluate_branches::execute(v,branch_); +return invoke::execute(*function_,v); +} +#ifdef _MSC_VER +#pragma warning(pop) +#endif +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_function; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::template collect(branch_, node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::template compute_node_depth(branch_); +} + +template +struct evaluate_branches +{ +static inline void execute(T_ (&v)[BranchCount], const branch_t (&b)[BranchCount]) +{ +for (std::size_t i = 0; i < BranchCount; ++i) +{ +v[i] = b[i].first->value(); +} +} +}; + +template +struct evaluate_branches +{ +static inline void execute(T_ (&v)[5], const branch_t (&b)[5]) +{ +v[0] = b[0].first->value(); +v[1] = b[1].first->value(); +v[2] = b[2].first->value(); +v[3] = b[3].first->value(); +v[4] = b[4].first->value(); +} +}; + +template +struct evaluate_branches +{ +static inline void execute(T_ (&v)[4], const branch_t (&b)[4]) +{ +v[0] = b[0].first->value(); +v[1] = b[1].first->value(); +v[2] = b[2].first->value(); +v[3] = b[3].first->value(); +} +}; + +template +struct evaluate_branches +{ +static inline void execute(T_ (&v)[3], const branch_t (&b)[3]) +{ +v[0] = b[0].first->value(); +v[1] = b[1].first->value(); +v[2] = b[2].first->value(); +} +}; + +template +struct evaluate_branches +{ +static inline void execute(T_ (&v)[2], const branch_t (&b)[2]) +{ +v[0] = b[0].first->value(); +v[1] = b[1].first->value(); +} +}; + +template +struct evaluate_branches +{ +static inline void execute(T_ (&v)[1], const branch_t (&b)[1]) +{ +v[0] = b[0].first->value(); +} +}; + +template +struct invoke { static inline T execute(ifunction&, branch_t (&)[ParamCount]) { return std::numeric_limits::quiet_NaN(); } }; + +template +struct invoke +{ +static inline T_ execute(ifunction& f, T_ (&v)[20]) +{ return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14],v[15],v[16],v[17],v[18],v[19]); } +}; + +template +struct invoke +{ +static inline T_ execute(ifunction& f, T_ (&v)[19]) +{ return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14],v[15],v[16],v[17],v[18]); } +}; + +template +struct invoke +{ +static inline T_ execute(ifunction& f, T_ (&v)[18]) +{ return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15], v[16], v[17]); } +}; + +template +struct invoke +{ +static inline T_ execute(ifunction& f, T_ (&v)[17]) +{ return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15], v[16]); } +}; + +template +struct invoke +{ +static inline T_ execute(ifunction& f, T_ (&v)[16]) +{ return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15]); } +}; + +template +struct invoke +{ +static inline T_ execute(ifunction& f, T_ (&v)[15]) +{ return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14]); } +}; + +template +struct invoke +{ +static inline T_ execute(ifunction& f, T_ (&v)[14]) +{ return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13]); } +}; + +template +struct invoke +{ +static inline T_ execute(ifunction& f, T_ (&v)[13]) +{ return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12]); } +}; + +template +struct invoke +{ +static inline T_ execute(ifunction& f, T_ (&v)[12]) +{ return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11]); } +}; + +template +struct invoke +{ +static inline T_ execute(ifunction& f, T_ (&v)[11]) +{ return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10]); } +}; + +template +struct invoke +{ +static inline T_ execute(ifunction& f, T_ (&v)[10]) +{ return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9]); } +}; + +template +struct invoke +{ +static inline T_ execute(ifunction& f, T_ (&v)[9]) +{ return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8]); } +}; + +template +struct invoke +{ +static inline T_ execute(ifunction& f, T_ (&v)[8]) +{ return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); } +}; + +template +struct invoke +{ +static inline T_ execute(ifunction& f, T_ (&v)[7]) +{ return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6]); } +}; + +template +struct invoke +{ +static inline T_ execute(ifunction& f, T_ (&v)[6]) +{ return f(v[0], v[1], v[2], v[3], v[4], v[5]); } +}; + +template +struct invoke +{ +static inline T_ execute(ifunction& f, T_ (&v)[5]) +{ return f(v[0], v[1], v[2], v[3], v[4]); } +}; + +template +struct invoke +{ +static inline T_ execute(ifunction& f, T_ (&v)[4]) +{ return f(v[0], v[1], v[2], v[3]); } +}; + +template +struct invoke +{ +static inline T_ execute(ifunction& f, T_ (&v)[3]) +{ return f(v[0], v[1], v[2]); } +}; + +template +struct invoke +{ +static inline T_ execute(ifunction& f, T_ (&v)[2]) +{ return f(v[0], v[1]); } +}; + +template +struct invoke +{ +static inline T_ execute(ifunction& f, T_ (&v)[1]) +{ return f(v[0]); } +}; + +private: + +ifunction* function_; +std::size_t parameter_count_; +branch_t branch_[N]; +}; + +template +class function_N_node exprtk_final : public expression_node +{ +public: + +typedef expression_node* expression_ptr; +typedef IFunction ifunction; + +explicit function_N_node(ifunction* func) +: function_((0 == func->param_count) ? func : reinterpret_cast(0)) +{} + +inline bool operator <(const function_N_node& fn) const +{ +return this < (&fn); +} + +inline T value() const exprtk_override +{ +if (function_) +return (*function_)(); +else +return std::numeric_limits::quiet_NaN(); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_function; +} + +private: + +ifunction* function_; +}; + +template +class vararg_function_node exprtk_final : public expression_node +{ +public: + +typedef expression_node* expression_ptr; + +vararg_function_node(VarArgFunction* func, +const std::vector& arg_list) +: function_(func) +, arg_list_(arg_list) +{ +value_list_.resize(arg_list.size(),std::numeric_limits::quiet_NaN()); +} + +inline bool operator <(const vararg_function_node& fn) const +{ +return this < (&fn); +} + +inline T value() const exprtk_override +{ +if (function_) +{ +populate_value_list(); +return (*function_)(value_list_); +} +else +return std::numeric_limits::quiet_NaN(); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_vafunction; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +for (std::size_t i = 0; i < arg_list_.size(); ++i) +{ +if (arg_list_[i] && !details::is_variable_node(arg_list_[i])) +{ +node_delete_list.push_back(&arg_list_[i]); +} +} +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::compute_node_depth(arg_list_); +} + +private: + +inline void populate_value_list() const +{ +for (std::size_t i = 0; i < arg_list_.size(); ++i) +{ +value_list_[i] = arg_list_[i]->value(); +} +} + +VarArgFunction* function_; +std::vector arg_list_; +mutable std::vector value_list_; +}; + +template +class generic_function_node : public expression_node +{ +public: + +typedef type_store type_store_t; +typedef expression_node* expression_ptr; +typedef variable_node variable_node_t; +typedef vector_node vector_node_t; +typedef variable_node_t* variable_node_ptr_t; +typedef vector_node_t* vector_node_ptr_t; +typedef range_interface range_interface_t; +typedef range_data_type range_data_type_t; +typedef typename range_interface::range_t range_t; + +typedef std::pair branch_t; +typedef std::pair void_t; + +typedef std::vector tmp_vs_t; +typedef std::vector typestore_list_t; +typedef std::vector range_list_t; + +explicit generic_function_node(const std::vector& arg_list, +GenericFunction* func = reinterpret_cast(0)) +: function_(func) +, arg_list_(arg_list) +{} + +virtual ~generic_function_node() {} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::collect(branch_, node_delete_list); +} + +std::size_t node_depth() const exprtk_override exprtk_final +{ +return expression_node::ndb_t::compute_node_depth(branch_); +} + +virtual bool init_branches() +{ +expr_as_vec1_store_.resize(arg_list_.size(),T(0) ); +typestore_list_ .resize(arg_list_.size(),type_store_t() ); +range_list_ .resize(arg_list_.size(),range_data_type_t()); +branch_ .resize(arg_list_.size(),branch_t(reinterpret_cast(0),false)); + +for (std::size_t i = 0; i < arg_list_.size(); ++i) +{ +type_store_t& ts = typestore_list_[i]; + +if (0 == arg_list_[i]) +return false; +else if (is_ivector_node(arg_list_[i])) +{ +vector_interface* vi = reinterpret_cast*>(0); + +if (0 == (vi = dynamic_cast*>(arg_list_[i]))) +return false; + +ts.size = vi->size(); +ts.data = vi->vds().data(); +ts.type = type_store_t::e_vector; +vi->vec()->vec_holder().set_ref(&ts.vec_data); +} +#ifndef exprtk_disable_string_capabilities +else if (is_generally_string_node(arg_list_[i])) +{ +string_base_node* sbn = reinterpret_cast*>(0); + +if (0 == (sbn = dynamic_cast*>(arg_list_[i]))) +return false; + +ts.size = sbn->size(); +ts.data = reinterpret_cast(const_cast(sbn->base())); +ts.type = type_store_t::e_string; + +range_list_[i].data = ts.data; +range_list_[i].size = ts.size; +range_list_[i].type_size = sizeof(char); +range_list_[i].str_node = sbn; + +range_interface_t* ri = reinterpret_cast(0); + +if (0 == (ri = dynamic_cast(arg_list_[i]))) +return false; + +const range_t& rp = ri->range_ref(); + +if ( +rp.const_range() && +is_const_string_range_node(arg_list_[i]) +) +{ +ts.size = rp.const_size(); +ts.data = static_cast(ts.data) + rp.n0_c.second; +range_list_[i].range = reinterpret_cast(0); +} +else +range_list_[i].range = &(ri->range_ref()); +} +#endif +else if (is_variable_node(arg_list_[i])) +{ +variable_node_ptr_t var = variable_node_ptr_t(0); + +if (0 == (var = dynamic_cast(arg_list_[i]))) +return false; + +ts.size = 1; +ts.data = &var->ref(); +ts.type = type_store_t::e_scalar; +} +else +{ +ts.size = 1; +ts.data = reinterpret_cast(&expr_as_vec1_store_[i]); +ts.type = type_store_t::e_scalar; +} + +branch_[i] = std::make_pair(arg_list_[i],branch_deletable(arg_list_[i])); +} + +return true; +} + +inline bool operator <(const generic_function_node& fn) const +{ +return this < (&fn); +} + +inline T value() const exprtk_override +{ +if (function_) +{ +if (populate_value_list()) +{ +typedef typename GenericFunction::parameter_list_t parameter_list_t; + +return (*function_)(parameter_list_t(typestore_list_)); +} +} + +return std::numeric_limits::quiet_NaN(); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_genfunction; +} + +protected: + +inline virtual bool populate_value_list() const +{ +for (std::size_t i = 0; i < branch_.size(); ++i) +{ +expr_as_vec1_store_[i] = branch_[i].first->value(); +} + +for (std::size_t i = 0; i < branch_.size(); ++i) +{ +range_data_type_t& rdt = range_list_[i]; + +if (rdt.range) +{ +const range_t& rp = (*rdt.range); +std::size_t r0 = 0; +std::size_t r1 = 0; + +if (rp(r0, r1, rdt.size)) +{ +type_store_t& ts = typestore_list_[i]; + +ts.size = rp.cache_size(); +#ifndef exprtk_disable_string_capabilities +if (ts.type == type_store_t::e_string) +ts.data = const_cast(rdt.str_node->base()) + rp.cache.first; +else +#endif +ts.data = static_cast(rdt.data) + (rp.cache.first * rdt.type_size); +} +else +return false; +} +} + +return true; +} + +GenericFunction* function_; +mutable typestore_list_t typestore_list_; + +private: + +std::vector arg_list_; +std::vector branch_; +mutable tmp_vs_t expr_as_vec1_store_; +mutable range_list_t range_list_; +}; + +#ifndef exprtk_disable_string_capabilities +template +class string_function_node : public generic_function_node, +public string_base_node, +public range_interface +{ +public: + +typedef generic_function_node gen_function_t; +typedef typename range_interface::range_t range_t; + +string_function_node(StringFunction* func, +const std::vector& arg_list) +: gen_function_t(arg_list,func) +{ +range_.n0_c = std::make_pair(true,0); +range_.n1_c = std::make_pair(true,0); +range_.cache.first = range_.n0_c.second; +range_.cache.second = range_.n1_c.second; +} + +inline bool operator <(const string_function_node& fn) const +{ +return this < (&fn); +} + +inline T value() const exprtk_override +{ +if (gen_function_t::function_) +{ +if (gen_function_t::populate_value_list()) +{ +typedef typename StringFunction::parameter_list_t parameter_list_t; + +const T result = (*gen_function_t::function_) +( +ret_string_, +parameter_list_t(gen_function_t::typestore_list_) +); + +range_.n1_c.second = ret_string_.size() - 1; +range_.cache.second = range_.n1_c.second; + +return result; +} +} + +return std::numeric_limits::quiet_NaN(); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_strfunction; +} + +std::string str() const exprtk_override +{ +return ret_string_; +} + +char_cptr base() const exprtk_override +{ +return &ret_string_[0]; +} + +std::size_t size() const exprtk_override +{ +return ret_string_.size(); +} + +range_t& range_ref() exprtk_override +{ +return range_; +} + +const range_t& range_ref() const exprtk_override +{ +return range_; +} + +protected: + +mutable range_t range_; +mutable std::string ret_string_; +}; +#endif + +template +class multimode_genfunction_node : public generic_function_node +{ +public: + +typedef generic_function_node gen_function_t; +typedef typename gen_function_t::range_t range_t; + +multimode_genfunction_node(GenericFunction* func, +const std::size_t& param_seq_index, +const std::vector& arg_list) +: gen_function_t(arg_list,func) +, param_seq_index_(param_seq_index) +{} + +inline T value() const exprtk_override +{ +if (gen_function_t::function_) +{ +if (gen_function_t::populate_value_list()) +{ +typedef typename GenericFunction::parameter_list_t parameter_list_t; + +return (*gen_function_t::function_) +( +param_seq_index_, +parameter_list_t(gen_function_t::typestore_list_) +); +} +} + +return std::numeric_limits::quiet_NaN(); +} + +inline typename expression_node::node_type type() const exprtk_override exprtk_final +{ +return expression_node::e_genfunction; +} + +private: + +std::size_t param_seq_index_; +}; + +#ifndef exprtk_disable_string_capabilities +template +class multimode_strfunction_node exprtk_final : public string_function_node +{ +public: + +typedef string_function_node str_function_t; +typedef typename str_function_t::range_t range_t; + +multimode_strfunction_node(StringFunction* func, +const std::size_t& param_seq_index, +const std::vector& arg_list) +: str_function_t(func,arg_list) +, param_seq_index_(param_seq_index) +{} + +inline T value() const exprtk_override +{ +if (str_function_t::function_) +{ +if (str_function_t::populate_value_list()) +{ +typedef typename StringFunction::parameter_list_t parameter_list_t; + +const T result = (*str_function_t::function_) +( +param_seq_index_, +str_function_t::ret_string_, +parameter_list_t(str_function_t::typestore_list_) +); + +str_function_t::range_.n1_c.second = str_function_t::ret_string_.size() - 1; +str_function_t::range_.cache.second = str_function_t::range_.n1_c.second; + +return result; +} +} + +return std::numeric_limits::quiet_NaN(); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_strfunction; +} + +private: + +const std::size_t param_seq_index_; +}; +#endif + +class return_exception +{}; + +template +class null_igenfunc +{ +public: + +virtual ~null_igenfunc() {} + +typedef type_store generic_type; +typedef typename generic_type::parameter_list parameter_list_t; + +inline virtual T operator() (parameter_list_t) +{ +return std::numeric_limits::quiet_NaN(); +} +}; + +#ifndef exprtk_disable_return_statement +template +class return_node exprtk_final : public generic_function_node > +{ +public: + +typedef results_context results_context_t; +typedef null_igenfunc igeneric_function_t; +typedef igeneric_function_t* igeneric_function_ptr; +typedef generic_function_node gen_function_t; + +return_node(const std::vector& arg_list, +results_context_t& rc) +: gen_function_t (arg_list) +, results_context_(&rc) +{} + +inline T value() const exprtk_override +{ +if ( +(0 != results_context_) && +gen_function_t::populate_value_list() +) +{ +typedef typename type_store::parameter_list parameter_list_t; + +results_context_-> +assign(parameter_list_t(gen_function_t::typestore_list_)); + +throw return_exception(); +} + +return std::numeric_limits::quiet_NaN(); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_return; +} + +private: + +results_context_t* results_context_; +}; + +template +class return_envelope_node exprtk_final : public expression_node +{ +public: + +typedef expression_node* expression_ptr; +typedef results_context results_context_t; +typedef std::pair branch_t; + +return_envelope_node(expression_ptr body, results_context_t& rc) +: results_context_(&rc ) +, return_invoked_ (false) +{ +construct_branch_pair(body_, body); +} + +inline T value() const exprtk_override +{ +assert(body_.first); + +try +{ +return_invoked_ = false; +results_context_->clear(); + +return body_.first->value(); +} +catch(const return_exception&) +{ +return_invoked_ = true; +return std::numeric_limits::quiet_NaN(); +} +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_retenv; +} + +inline bool* retinvk_ptr() +{ +return &return_invoked_; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::collect(body_, node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::compute_node_depth(body_); +} + +private: + +results_context_t* results_context_; +mutable bool return_invoked_; +branch_t body_; +}; +#endif + +#define exprtk_define_unary_op(OpName) \ + template \ + struct OpName##_op \ + { \ + typedef typename functor_t::Type Type; \ + typedef typename expression_node::node_type node_t; \ + \ + static inline T process(Type v) \ + { \ + return numeric:: OpName (v); \ + } \ + \ + static inline node_t type() \ + { \ + return expression_node::e_##OpName; \ + } \ + \ + static inline details::operator_type operation() \ + { \ + return details::e_##OpName; \ + } \ + }; \ + +exprtk_define_unary_op(abs ) +exprtk_define_unary_op(acos ) +exprtk_define_unary_op(acosh) +exprtk_define_unary_op(asin ) +exprtk_define_unary_op(asinh) +exprtk_define_unary_op(atan ) +exprtk_define_unary_op(atanh) +exprtk_define_unary_op(ceil ) +exprtk_define_unary_op(cos ) +exprtk_define_unary_op(cosh ) +exprtk_define_unary_op(cot ) +exprtk_define_unary_op(csc ) +exprtk_define_unary_op(d2g ) +exprtk_define_unary_op(d2r ) +exprtk_define_unary_op(erf ) +exprtk_define_unary_op(erfc ) +exprtk_define_unary_op(exp ) +exprtk_define_unary_op(expm1) +exprtk_define_unary_op(floor) +exprtk_define_unary_op(frac ) +exprtk_define_unary_op(g2d ) +exprtk_define_unary_op(log ) +exprtk_define_unary_op(log10) +exprtk_define_unary_op(log2 ) +exprtk_define_unary_op(log1p) +exprtk_define_unary_op(ncdf ) +exprtk_define_unary_op(neg ) +exprtk_define_unary_op(notl ) +exprtk_define_unary_op(pos ) +exprtk_define_unary_op(r2d ) +exprtk_define_unary_op(round) +exprtk_define_unary_op(sec ) +exprtk_define_unary_op(sgn ) +exprtk_define_unary_op(sin ) +exprtk_define_unary_op(sinc ) +exprtk_define_unary_op(sinh ) +exprtk_define_unary_op(sqrt ) +exprtk_define_unary_op(tan ) +exprtk_define_unary_op(tanh ) +exprtk_define_unary_op(trunc) +#undef exprtk_define_unary_op + +template +struct opr_base +{ +typedef typename details::functor_t::Type Type; +typedef typename details::functor_t::RefType RefType; +typedef typename details::functor_t functor_t; +typedef typename functor_t::qfunc_t quaternary_functor_t; +typedef typename functor_t::tfunc_t trinary_functor_t; +typedef typename functor_t::bfunc_t binary_functor_t; +typedef typename functor_t::ufunc_t unary_functor_t; +}; + +template +struct add_op : public opr_base +{ +typedef typename opr_base::Type Type; +typedef typename opr_base::RefType RefType; + +static inline T process(Type t1, Type t2) { return t1 + t2; } +static inline T process(Type t1, Type t2, Type t3) { return t1 + t2 + t3; } +static inline void assign(RefType t1, Type t2) { t1 += t2; } +static inline typename expression_node::node_type type() { return expression_node::e_add; } +static inline details::operator_type operation() { return details::e_add; } +}; + +template +struct mul_op : public opr_base +{ +typedef typename opr_base::Type Type; +typedef typename opr_base::RefType RefType; + +static inline T process(Type t1, Type t2) { return t1 * t2; } +static inline T process(Type t1, Type t2, Type t3) { return t1 * t2 * t3; } +static inline void assign(RefType t1, Type t2) { t1 *= t2; } +static inline typename expression_node::node_type type() { return expression_node::e_mul; } +static inline details::operator_type operation() { return details::e_mul; } +}; + +template +struct sub_op : public opr_base +{ +typedef typename opr_base::Type Type; +typedef typename opr_base::RefType RefType; + +static inline T process(Type t1, Type t2) { return t1 - t2; } +static inline T process(Type t1, Type t2, Type t3) { return t1 - t2 - t3; } +static inline void assign(RefType t1, Type t2) { t1 -= t2; } +static inline typename expression_node::node_type type() { return expression_node::e_sub; } +static inline details::operator_type operation() { return details::e_sub; } +}; + +template +struct div_op : public opr_base +{ +typedef typename opr_base::Type Type; +typedef typename opr_base::RefType RefType; + +static inline T process(Type t1, Type t2) { return t1 / t2; } +static inline T process(Type t1, Type t2, Type t3) { return t1 / t2 / t3; } +static inline void assign(RefType t1, Type t2) { t1 /= t2; } +static inline typename expression_node::node_type type() { return expression_node::e_div; } +static inline details::operator_type operation() { return details::e_div; } +}; + +template +struct mod_op : public opr_base +{ +typedef typename opr_base::Type Type; +typedef typename opr_base::RefType RefType; + +static inline T process(Type t1, Type t2) { return numeric::modulus(t1,t2); } +static inline void assign(RefType t1, Type t2) { t1 = numeric::modulus(t1,t2); } +static inline typename expression_node::node_type type() { return expression_node::e_mod; } +static inline details::operator_type operation() { return details::e_mod; } +}; + +template +struct pow_op : public opr_base +{ +typedef typename opr_base::Type Type; +typedef typename opr_base::RefType RefType; + +static inline T process(Type t1, Type t2) { return numeric::pow(t1,t2); } +static inline void assign(RefType t1, Type t2) { t1 = numeric::pow(t1,t2); } +static inline typename expression_node::node_type type() { return expression_node::e_pow; } +static inline details::operator_type operation() { return details::e_pow; } +}; + +template +struct lt_op : public opr_base +{ +typedef typename opr_base::Type Type; + +static inline T process(Type t1, Type t2) { return ((t1 < t2) ? T(1) : T(0)); } +static inline T process(const std::string& t1, const std::string& t2) { return ((t1 < t2) ? T(1) : T(0)); } +static inline typename expression_node::node_type type() { return expression_node::e_lt; } +static inline details::operator_type operation() { return details::e_lt; } +}; + +template +struct lte_op : public opr_base +{ +typedef typename opr_base::Type Type; + +static inline T process(Type t1, Type t2) { return ((t1 <= t2) ? T(1) : T(0)); } +static inline T process(const std::string& t1, const std::string& t2) { return ((t1 <= t2) ? T(1) : T(0)); } +static inline typename expression_node::node_type type() { return expression_node::e_lte; } +static inline details::operator_type operation() { return details::e_lte; } +}; + +template +struct gt_op : public opr_base +{ +typedef typename opr_base::Type Type; + +static inline T process(Type t1, Type t2) { return ((t1 > t2) ? T(1) : T(0)); } +static inline T process(const std::string& t1, const std::string& t2) { return ((t1 > t2) ? T(1) : T(0)); } +static inline typename expression_node::node_type type() { return expression_node::e_gt; } +static inline details::operator_type operation() { return details::e_gt; } +}; + +template +struct gte_op : public opr_base +{ +typedef typename opr_base::Type Type; + +static inline T process(Type t1, Type t2) { return ((t1 >= t2) ? T(1) : T(0)); } +static inline T process(const std::string& t1, const std::string& t2) { return ((t1 >= t2) ? T(1) : T(0)); } +static inline typename expression_node::node_type type() { return expression_node::e_gte; } +static inline details::operator_type operation() { return details::e_gte; } +}; + +template +struct eq_op : public opr_base +{ +typedef typename opr_base::Type Type; +static inline T process(Type t1, Type t2) { return (std::equal_to()(t1,t2) ? T(1) : T(0)); } +static inline T process(const std::string& t1, const std::string& t2) { return ((t1 == t2) ? T(1) : T(0)); } +static inline typename expression_node::node_type type() { return expression_node::e_eq; } +static inline details::operator_type operation() { return details::e_eq; } +}; + +template +struct equal_op : public opr_base +{ +typedef typename opr_base::Type Type; + +static inline T process(Type t1, Type t2) { return numeric::equal(t1,t2); } +static inline T process(const std::string& t1, const std::string& t2) { return ((t1 == t2) ? T(1) : T(0)); } +static inline typename expression_node::node_type type() { return expression_node::e_eq; } +static inline details::operator_type operation() { return details::e_equal; } +}; + +template +struct ne_op : public opr_base +{ +typedef typename opr_base::Type Type; + +static inline T process(Type t1, Type t2) { return (std::not_equal_to()(t1,t2) ? T(1) : T(0)); } +static inline T process(const std::string& t1, const std::string& t2) { return ((t1 != t2) ? T(1) : T(0)); } +static inline typename expression_node::node_type type() { return expression_node::e_ne; } +static inline details::operator_type operation() { return details::e_ne; } +}; + +template +struct and_op : public opr_base +{ +typedef typename opr_base::Type Type; + +static inline T process(Type t1, Type t2) { return (details::is_true(t1) && details::is_true(t2)) ? T(1) : T(0); } +static inline typename expression_node::node_type type() { return expression_node::e_and; } +static inline details::operator_type operation() { return details::e_and; } +}; + +template +struct nand_op : public opr_base +{ +typedef typename opr_base::Type Type; + +static inline T process(Type t1, Type t2) { return (details::is_true(t1) && details::is_true(t2)) ? T(0) : T(1); } +static inline typename expression_node::node_type type() { return expression_node::e_nand; } +static inline details::operator_type operation() { return details::e_nand; } +}; + +template +struct or_op : public opr_base +{ +typedef typename opr_base::Type Type; + +static inline T process(Type t1, Type t2) { return (details::is_true(t1) || details::is_true(t2)) ? T(1) : T(0); } +static inline typename expression_node::node_type type() { return expression_node::e_or; } +static inline details::operator_type operation() { return details::e_or; } +}; + +template +struct nor_op : public opr_base +{ +typedef typename opr_base::Type Type; + +static inline T process(Type t1, Type t2) { return (details::is_true(t1) || details::is_true(t2)) ? T(0) : T(1); } +static inline typename expression_node::node_type type() { return expression_node::e_nor; } +static inline details::operator_type operation() { return details::e_nor; } +}; + +template +struct xor_op : public opr_base +{ +typedef typename opr_base::Type Type; + +static inline T process(Type t1, Type t2) { return numeric::xor_opr(t1,t2); } +static inline typename expression_node::node_type type() { return expression_node::e_nor; } +static inline details::operator_type operation() { return details::e_xor; } +}; + +template +struct xnor_op : public opr_base +{ +typedef typename opr_base::Type Type; + +static inline T process(Type t1, Type t2) { return numeric::xnor_opr(t1,t2); } +static inline typename expression_node::node_type type() { return expression_node::e_nor; } +static inline details::operator_type operation() { return details::e_xnor; } +}; + +template +struct in_op : public opr_base +{ +typedef typename opr_base::Type Type; + +static inline T process(const T&, const T&) { return std::numeric_limits::quiet_NaN(); } +static inline T process(const std::string& t1, const std::string& t2) { return ((std::string::npos != t2.find(t1)) ? T(1) : T(0)); } +static inline typename expression_node::node_type type() { return expression_node::e_in; } +static inline details::operator_type operation() { return details::e_in; } +}; + +template +struct like_op : public opr_base +{ +typedef typename opr_base::Type Type; + +static inline T process(const T&, const T&) { return std::numeric_limits::quiet_NaN(); } +static inline T process(const std::string& t1, const std::string& t2) { return (details::wc_match(t2,t1) ? T(1) : T(0)); } +static inline typename expression_node::node_type type() { return expression_node::e_like; } +static inline details::operator_type operation() { return details::e_like; } +}; + +template +struct ilike_op : public opr_base +{ +typedef typename opr_base::Type Type; + +static inline T process(const T&, const T&) { return std::numeric_limits::quiet_NaN(); } +static inline T process(const std::string& t1, const std::string& t2) { return (details::wc_imatch(t2,t1) ? T(1) : T(0)); } +static inline typename expression_node::node_type type() { return expression_node::e_ilike; } +static inline details::operator_type operation() { return details::e_ilike; } +}; + +template +struct inrange_op : public opr_base +{ +typedef typename opr_base::Type Type; + +static inline T process(const T& t0, const T& t1, const T& t2) { return ((t0 <= t1) && (t1 <= t2)) ? T(1) : T(0); } +static inline T process(const std::string& t0, const std::string& t1, const std::string& t2) +{ +return ((t0 <= t1) && (t1 <= t2)) ? T(1) : T(0); +} +static inline typename expression_node::node_type type() { return expression_node::e_inranges; } +static inline details::operator_type operation() { return details::e_inrange; } +}; + +template +inline T value(details::expression_node* n) +{ +return n->value(); +} + +template +inline T value(std::pair*,bool> n) +{ +return n.first->value(); +} + +template +inline T value(const T* t) +{ +return (*t); +} + +template +inline T value(const T& t) +{ +return t; +} + +template +struct vararg_add_op : public opr_base +{ +typedef typename opr_base::Type Type; + +template class Sequence> +static inline T process(const Sequence& arg_list) +{ +switch (arg_list.size()) +{ +case 0 : return T(0); +case 1 : return process_1(arg_list); +case 2 : return process_2(arg_list); +case 3 : return process_3(arg_list); +case 4 : return process_4(arg_list); +case 5 : return process_5(arg_list); +default : +{ +T result = T(0); + +for (std::size_t i = 0; i < arg_list.size(); ++i) +{ +result += value(arg_list[i]); +} + +return result; +} +} +} + +template +static inline T process_1(const Sequence& arg_list) +{ +return value(arg_list[0]); +} + +template +static inline T process_2(const Sequence& arg_list) +{ +return value(arg_list[0]) + value(arg_list[1]); +} + +template +static inline T process_3(const Sequence& arg_list) +{ +return value(arg_list[0]) + value(arg_list[1]) + +value(arg_list[2]) ; +} + +template +static inline T process_4(const Sequence& arg_list) +{ +return value(arg_list[0]) + value(arg_list[1]) + +value(arg_list[2]) + value(arg_list[3]) ; +} + +template +static inline T process_5(const Sequence& arg_list) +{ +return value(arg_list[0]) + value(arg_list[1]) + +value(arg_list[2]) + value(arg_list[3]) + +value(arg_list[4]) ; +} +}; + +template +struct vararg_mul_op : public opr_base +{ +typedef typename opr_base::Type Type; + +template class Sequence> +static inline T process(const Sequence& arg_list) +{ +switch (arg_list.size()) +{ +case 0 : return T(0); +case 1 : return process_1(arg_list); +case 2 : return process_2(arg_list); +case 3 : return process_3(arg_list); +case 4 : return process_4(arg_list); +case 5 : return process_5(arg_list); +default : +{ +T result = T(value(arg_list[0])); + +for (std::size_t i = 1; i < arg_list.size(); ++i) +{ +result *= value(arg_list[i]); +} + +return result; +} +} +} + +template +static inline T process_1(const Sequence& arg_list) +{ +return value(arg_list[0]); +} + +template +static inline T process_2(const Sequence& arg_list) +{ +return value(arg_list[0]) * value(arg_list[1]); +} + +template +static inline T process_3(const Sequence& arg_list) +{ +return value(arg_list[0]) * value(arg_list[1]) * +value(arg_list[2]) ; +} + +template +static inline T process_4(const Sequence& arg_list) +{ +return value(arg_list[0]) * value(arg_list[1]) * +value(arg_list[2]) * value(arg_list[3]) ; +} + +template +static inline T process_5(const Sequence& arg_list) +{ +return value(arg_list[0]) * value(arg_list[1]) * +value(arg_list[2]) * value(arg_list[3]) * +value(arg_list[4]) ; +} +}; + +template +struct vararg_avg_op : public opr_base +{ +typedef typename opr_base::Type Type; + +template class Sequence> +static inline T process(const Sequence& arg_list) +{ +switch (arg_list.size()) +{ +case 0 : return T(0); +case 1 : return process_1(arg_list); +case 2 : return process_2(arg_list); +case 3 : return process_3(arg_list); +case 4 : return process_4(arg_list); +case 5 : return process_5(arg_list); +default : return vararg_add_op::process(arg_list) / T(arg_list.size()); +} +} + +template +static inline T process_1(const Sequence& arg_list) +{ +return value(arg_list[0]); +} + +template +static inline T process_2(const Sequence& arg_list) +{ +return (value(arg_list[0]) + value(arg_list[1])) / T(2); +} + +template +static inline T process_3(const Sequence& arg_list) +{ +return (value(arg_list[0]) + value(arg_list[1]) + value(arg_list[2])) / T(3); +} + +template +static inline T process_4(const Sequence& arg_list) +{ +return (value(arg_list[0]) + value(arg_list[1]) + +value(arg_list[2]) + value(arg_list[3])) / T(4); +} + +template +static inline T process_5(const Sequence& arg_list) +{ +return (value(arg_list[0]) + value(arg_list[1]) + +value(arg_list[2]) + value(arg_list[3]) + +value(arg_list[4])) / T(5); +} +}; + +template +struct vararg_min_op : public opr_base +{ +typedef typename opr_base::Type Type; + +template class Sequence> +static inline T process(const Sequence& arg_list) +{ +switch (arg_list.size()) +{ +case 0 : return T(0); +case 1 : return process_1(arg_list); +case 2 : return process_2(arg_list); +case 3 : return process_3(arg_list); +case 4 : return process_4(arg_list); +case 5 : return process_5(arg_list); +default : +{ +T result = T(value(arg_list[0])); + +for (std::size_t i = 1; i < arg_list.size(); ++i) +{ +const T v = value(arg_list[i]); + +if (v < result) +result = v; +} + +return result; +} +} +} + +template +static inline T process_1(const Sequence& arg_list) +{ +return value(arg_list[0]); +} + +template +static inline T process_2(const Sequence& arg_list) +{ +return std::min(value(arg_list[0]),value(arg_list[1])); +} + +template +static inline T process_3(const Sequence& arg_list) +{ +return std::min(std::min(value(arg_list[0]),value(arg_list[1])),value(arg_list[2])); +} + +template +static inline T process_4(const Sequence& arg_list) +{ +return std::min( +std::min(value(arg_list[0]), value(arg_list[1])), +std::min(value(arg_list[2]), value(arg_list[3]))); +} + +template +static inline T process_5(const Sequence& arg_list) +{ +return std::min( +std::min(std::min(value(arg_list[0]), value(arg_list[1])), +std::min(value(arg_list[2]), value(arg_list[3]))), +value(arg_list[4])); +} +}; + +template +struct vararg_max_op : public opr_base +{ +typedef typename opr_base::Type Type; + +template class Sequence> +static inline T process(const Sequence& arg_list) +{ +switch (arg_list.size()) +{ +case 0 : return T(0); +case 1 : return process_1(arg_list); +case 2 : return process_2(arg_list); +case 3 : return process_3(arg_list); +case 4 : return process_4(arg_list); +case 5 : return process_5(arg_list); +default : +{ +T result = T(value(arg_list[0])); + +for (std::size_t i = 1; i < arg_list.size(); ++i) +{ +const T v = value(arg_list[i]); + +if (v > result) +result = v; +} + +return result; +} +} +} + +template +static inline T process_1(const Sequence& arg_list) +{ +return value(arg_list[0]); +} + +template +static inline T process_2(const Sequence& arg_list) +{ +return std::max(value(arg_list[0]),value(arg_list[1])); +} + +template +static inline T process_3(const Sequence& arg_list) +{ +return std::max(std::max(value(arg_list[0]),value(arg_list[1])),value(arg_list[2])); +} + +template +static inline T process_4(const Sequence& arg_list) +{ +return std::max( +std::max(value(arg_list[0]), value(arg_list[1])), +std::max(value(arg_list[2]), value(arg_list[3]))); +} + +template +static inline T process_5(const Sequence& arg_list) +{ +return std::max( +std::max(std::max(value(arg_list[0]), value(arg_list[1])), +std::max(value(arg_list[2]), value(arg_list[3]))), +value(arg_list[4])); +} +}; + +template +struct vararg_mand_op : public opr_base +{ +typedef typename opr_base::Type Type; + +template class Sequence> +static inline T process(const Sequence& arg_list) +{ +switch (arg_list.size()) +{ +case 1 : return process_1(arg_list); +case 2 : return process_2(arg_list); +case 3 : return process_3(arg_list); +case 4 : return process_4(arg_list); +case 5 : return process_5(arg_list); +default : +{ +for (std::size_t i = 0; i < arg_list.size(); ++i) +{ +if (std::equal_to()(T(0), value(arg_list[i]))) +return T(0); +} + +return T(1); +} +} +} + +template +static inline T process_1(const Sequence& arg_list) +{ +return std::not_equal_to() +(T(0), value(arg_list[0])) ? T(1) : T(0); +} + +template +static inline T process_2(const Sequence& arg_list) +{ +return ( +std::not_equal_to()(T(0), value(arg_list[0])) && +std::not_equal_to()(T(0), value(arg_list[1])) +) ? T(1) : T(0); +} + +template +static inline T process_3(const Sequence& arg_list) +{ +return ( +std::not_equal_to()(T(0), value(arg_list[0])) && +std::not_equal_to()(T(0), value(arg_list[1])) && +std::not_equal_to()(T(0), value(arg_list[2])) +) ? T(1) : T(0); +} + +template +static inline T process_4(const Sequence& arg_list) +{ +return ( +std::not_equal_to()(T(0), value(arg_list[0])) && +std::not_equal_to()(T(0), value(arg_list[1])) && +std::not_equal_to()(T(0), value(arg_list[2])) && +std::not_equal_to()(T(0), value(arg_list[3])) +) ? T(1) : T(0); +} + +template +static inline T process_5(const Sequence& arg_list) +{ +return ( +std::not_equal_to()(T(0), value(arg_list[0])) && +std::not_equal_to()(T(0), value(arg_list[1])) && +std::not_equal_to()(T(0), value(arg_list[2])) && +std::not_equal_to()(T(0), value(arg_list[3])) && +std::not_equal_to()(T(0), value(arg_list[4])) +) ? T(1) : T(0); +} +}; + +template +struct vararg_mor_op : public opr_base +{ +typedef typename opr_base::Type Type; + +template class Sequence> +static inline T process(const Sequence& arg_list) +{ +switch (arg_list.size()) +{ +case 1 : return process_1(arg_list); +case 2 : return process_2(arg_list); +case 3 : return process_3(arg_list); +case 4 : return process_4(arg_list); +case 5 : return process_5(arg_list); +default : +{ +for (std::size_t i = 0; i < arg_list.size(); ++i) +{ +if (std::not_equal_to()(T(0), value(arg_list[i]))) +return T(1); +} + +return T(0); +} +} +} + +template +static inline T process_1(const Sequence& arg_list) +{ +return std::not_equal_to() +(T(0), value(arg_list[0])) ? T(1) : T(0); +} + +template +static inline T process_2(const Sequence& arg_list) +{ +return ( +std::not_equal_to()(T(0), value(arg_list[0])) || +std::not_equal_to()(T(0), value(arg_list[1])) +) ? T(1) : T(0); +} + +template +static inline T process_3(const Sequence& arg_list) +{ +return ( +std::not_equal_to()(T(0), value(arg_list[0])) || +std::not_equal_to()(T(0), value(arg_list[1])) || +std::not_equal_to()(T(0), value(arg_list[2])) +) ? T(1) : T(0); +} + +template +static inline T process_4(const Sequence& arg_list) +{ +return ( +std::not_equal_to()(T(0), value(arg_list[0])) || +std::not_equal_to()(T(0), value(arg_list[1])) || +std::not_equal_to()(T(0), value(arg_list[2])) || +std::not_equal_to()(T(0), value(arg_list[3])) +) ? T(1) : T(0); +} + +template +static inline T process_5(const Sequence& arg_list) +{ +return ( +std::not_equal_to()(T(0), value(arg_list[0])) || +std::not_equal_to()(T(0), value(arg_list[1])) || +std::not_equal_to()(T(0), value(arg_list[2])) || +std::not_equal_to()(T(0), value(arg_list[3])) || +std::not_equal_to()(T(0), value(arg_list[4])) +) ? T(1) : T(0); +} +}; + +template +struct vararg_multi_op : public opr_base +{ +typedef typename opr_base::Type Type; + +template class Sequence> +static inline T process(const Sequence& arg_list) +{ +switch (arg_list.size()) +{ +case 0 : return std::numeric_limits::quiet_NaN(); +case 1 : return process_1(arg_list); +case 2 : return process_2(arg_list); +case 3 : return process_3(arg_list); +case 4 : return process_4(arg_list); +case 5 : return process_5(arg_list); +case 6 : return process_6(arg_list); +case 7 : return process_7(arg_list); +case 8 : return process_8(arg_list); +default : +{ +for (std::size_t i = 0; i < (arg_list.size() - 1); ++i) +{ +value(arg_list[i]); +} + +return value(arg_list.back()); +} +} +} + +template +static inline T process_1(const Sequence& arg_list) +{ +return value(arg_list[0]); +} + +template +static inline T process_2(const Sequence& arg_list) +{ +value(arg_list[0]); +return value(arg_list[1]); +} + +template +static inline T process_3(const Sequence& arg_list) +{ +value(arg_list[0]); +value(arg_list[1]); +return value(arg_list[2]); +} + +template +static inline T process_4(const Sequence& arg_list) +{ +value(arg_list[0]); +value(arg_list[1]); +value(arg_list[2]); +return value(arg_list[3]); +} + +template +static inline T process_5(const Sequence& arg_list) +{ +value(arg_list[0]); +value(arg_list[1]); +value(arg_list[2]); +value(arg_list[3]); +return value(arg_list[4]); +} + +template +static inline T process_6(const Sequence& arg_list) +{ +value(arg_list[0]); +value(arg_list[1]); +value(arg_list[2]); +value(arg_list[3]); +value(arg_list[4]); +return value(arg_list[5]); +} + +template +static inline T process_7(const Sequence& arg_list) +{ +value(arg_list[0]); +value(arg_list[1]); +value(arg_list[2]); +value(arg_list[3]); +value(arg_list[4]); +value(arg_list[5]); +return value(arg_list[6]); +} + +template +static inline T process_8(const Sequence& arg_list) +{ +value(arg_list[0]); +value(arg_list[1]); +value(arg_list[2]); +value(arg_list[3]); +value(arg_list[4]); +value(arg_list[5]); +value(arg_list[6]); +return value(arg_list[7]); +} +}; + +template +struct vec_add_op +{ +typedef vector_interface* ivector_ptr; + +static inline T process(const ivector_ptr v) +{ +const T* vec = v->vec()->vds().data(); +const std::size_t vec_size = v->vec()->vds().size(); + +loop_unroll::details lud(vec_size); + +if (vec_size <= static_cast(lud.batch_size)) +{ +T result = T(0); +int i = 0; + +exprtk_disable_fallthrough_begin +switch (vec_size) +{ +#define case_stmt(N) \ + case N : result += vec[i++]; \ + +#ifndef exprtk_disable_superscalar_unroll +case_stmt(16) case_stmt(15) +case_stmt(14) case_stmt(13) +case_stmt(12) case_stmt(11) +case_stmt(10) case_stmt( 9) +case_stmt( 8) case_stmt( 7) +case_stmt( 6) case_stmt( 5) +#endif +case_stmt( 4) case_stmt( 3) +case_stmt( 2) case_stmt( 1) +} +exprtk_disable_fallthrough_end + +#undef case_stmt + +return result; +} + +T r[] = { +T(0), T(0), T(0), T(0), T(0), T(0), T(0), T(0), +T(0), T(0), T(0), T(0), T(0), T(0), T(0), T(0) +}; + +const T* upper_bound = vec + lud.upper_bound; + +while (vec < upper_bound) +{ +#define exprtk_loop(N) \ + r[N] += vec[N]; \ + +exprtk_loop( 0) exprtk_loop( 1) +exprtk_loop( 2) exprtk_loop( 3) +#ifndef exprtk_disable_superscalar_unroll +exprtk_loop( 4) exprtk_loop( 5) +exprtk_loop( 6) exprtk_loop( 7) +exprtk_loop( 8) exprtk_loop( 9) +exprtk_loop(10) exprtk_loop(11) +exprtk_loop(12) exprtk_loop(13) +exprtk_loop(14) exprtk_loop(15) +#endif + +vec += lud.batch_size; +} + +int i = 0; + +exprtk_disable_fallthrough_begin +switch (lud.remainder) +{ +#define case_stmt(N) \ + case N : r[0] += vec[i++]; \ + +#ifndef exprtk_disable_superscalar_unroll +case_stmt(15) case_stmt(14) +case_stmt(13) case_stmt(12) +case_stmt(11) case_stmt(10) +case_stmt( 9) case_stmt( 8) +case_stmt( 7) case_stmt( 6) +case_stmt( 5) case_stmt( 4) +#endif +case_stmt( 3) case_stmt( 2) +case_stmt( 1) +} +exprtk_disable_fallthrough_end + +#undef exprtk_loop +#undef case_stmt + +return (r[ 0] + r[ 1] + r[ 2] + r[ 3]) +#ifndef exprtk_disable_superscalar_unroll ++ (r[ 4] + r[ 5] + r[ 6] + r[ 7]) ++ (r[ 8] + r[ 9] + r[10] + r[11]) ++ (r[12] + r[13] + r[14] + r[15]) +#endif +; +} +}; + +template +struct vec_mul_op +{ +typedef vector_interface* ivector_ptr; + +static inline T process(const ivector_ptr v) +{ +const T* vec = v->vec()->vds().data(); +const std::size_t vec_size = v->vec()->vds().size(); + +loop_unroll::details lud(vec_size); + +if (vec_size <= static_cast(lud.batch_size)) +{ +T result = T(1); +int i = 0; + +exprtk_disable_fallthrough_begin +switch (vec_size) +{ +#define case_stmt(N) \ + case N : result *= vec[i++]; \ + +#ifndef exprtk_disable_superscalar_unroll +case_stmt(16) case_stmt(15) +case_stmt(14) case_stmt(13) +case_stmt(12) case_stmt(11) +case_stmt(10) case_stmt( 9) +case_stmt( 8) case_stmt( 7) +case_stmt( 6) case_stmt( 5) +#endif +case_stmt( 4) case_stmt( 3) +case_stmt( 2) case_stmt( 1) +} +exprtk_disable_fallthrough_end + +#undef case_stmt + +return result; +} + +T r[] = { +T(1), T(1), T(1), T(1), T(1), T(1), T(1), T(1), +T(1), T(1), T(1), T(1), T(1), T(1), T(1), T(1) +}; + +const T* upper_bound = vec + lud.upper_bound; + +while (vec < upper_bound) +{ +#define exprtk_loop(N) \ + r[N] *= vec[N]; \ + +exprtk_loop( 0) exprtk_loop( 1) +exprtk_loop( 2) exprtk_loop( 3) +#ifndef exprtk_disable_superscalar_unroll +exprtk_loop( 4) exprtk_loop( 5) +exprtk_loop( 6) exprtk_loop( 7) +exprtk_loop( 8) exprtk_loop( 9) +exprtk_loop(10) exprtk_loop(11) +exprtk_loop(12) exprtk_loop(13) +exprtk_loop(14) exprtk_loop(15) +#endif + +vec += lud.batch_size; +} + +int i = 0; + +exprtk_disable_fallthrough_begin +switch (lud.remainder) +{ +#define case_stmt(N) \ + case N : r[0] *= vec[i++]; \ + +#ifndef exprtk_disable_superscalar_unroll +case_stmt(15) case_stmt(14) +case_stmt(13) case_stmt(12) +case_stmt(11) case_stmt(10) +case_stmt( 9) case_stmt( 8) +case_stmt( 7) case_stmt( 6) +case_stmt( 5) case_stmt( 4) +#endif +case_stmt( 3) case_stmt( 2) +case_stmt( 1) +} +exprtk_disable_fallthrough_end + +#undef exprtk_loop +#undef case_stmt + +return (r[ 0] * r[ 1] * r[ 2] * r[ 3]) +#ifndef exprtk_disable_superscalar_unroll ++ (r[ 4] * r[ 5] * r[ 6] * r[ 7]) ++ (r[ 8] * r[ 9] * r[10] * r[11]) ++ (r[12] * r[13] * r[14] * r[15]) +#endif +; +} +}; + +template +struct vec_avg_op +{ +typedef vector_interface* ivector_ptr; + +static inline T process(const ivector_ptr v) +{ +const T vec_size = T(v->vec()->vds().size()); +return vec_add_op::process(v) / vec_size; +} +}; + +template +struct vec_min_op +{ +typedef vector_interface* ivector_ptr; + +static inline T process(const ivector_ptr v) +{ +const T* vec = v->vec()->vds().data(); +const std::size_t vec_size = v->vec()->vds().size(); + +T result = vec[0]; + +for (std::size_t i = 1; i < vec_size; ++i) +{ +const T v_i = vec[i]; + +if (v_i < result) +result = v_i; +} + +return result; +} +}; + +template +struct vec_max_op +{ +typedef vector_interface* ivector_ptr; + +static inline T process(const ivector_ptr v) +{ +const T* vec = v->vec()->vds().data(); +const std::size_t vec_size = v->vec()->vds().size(); + +T result = vec[0]; + +for (std::size_t i = 1; i < vec_size; ++i) +{ +const T v_i = vec[i]; + +if (v_i > result) +result = v_i; +} + +return result; +} +}; + +template +class vov_base_node : public expression_node +{ +public: + +virtual ~vov_base_node() {} + +inline virtual operator_type operation() const +{ +return details::e_default; +} + +virtual const T& v0() const = 0; + +virtual const T& v1() const = 0; +}; + +template +class cov_base_node : public expression_node +{ +public: + +virtual ~cov_base_node() {} + +inline virtual operator_type operation() const +{ +return details::e_default; +} + +virtual const T c() const = 0; + +virtual const T& v() const = 0; +}; + +template +class voc_base_node : public expression_node +{ +public: + +virtual ~voc_base_node() {} + +inline virtual operator_type operation() const +{ +return details::e_default; +} + +virtual const T c() const = 0; + +virtual const T& v() const = 0; +}; + +template +class vob_base_node : public expression_node +{ +public: + +virtual ~vob_base_node() {} + +virtual const T& v() const = 0; +}; + +template +class bov_base_node : public expression_node +{ +public: + +virtual ~bov_base_node() {} + +virtual const T& v() const = 0; +}; + +template +class cob_base_node : public expression_node +{ +public: + +virtual ~cob_base_node() {} + +inline virtual operator_type operation() const +{ +return details::e_default; +} + +virtual const T c() const = 0; + +virtual void set_c(const T) = 0; + +virtual expression_node* move_branch(const std::size_t& index) = 0; +}; + +template +class boc_base_node : public expression_node +{ +public: + +virtual ~boc_base_node() {} + +inline virtual operator_type operation() const +{ +return details::e_default; +} + +virtual const T c() const = 0; + +virtual void set_c(const T) = 0; + +virtual expression_node* move_branch(const std::size_t& index) = 0; +}; + +template +class uv_base_node : public expression_node +{ +public: + +virtual ~uv_base_node() {} + +inline virtual operator_type operation() const +{ +return details::e_default; +} + +virtual const T& v() const = 0; +}; + +template +class sos_base_node : public expression_node +{ +public: + +virtual ~sos_base_node() {} + +inline virtual operator_type operation() const +{ +return details::e_default; +} +}; + +template +class sosos_base_node : public expression_node +{ +public: + +virtual ~sosos_base_node() {} + +inline virtual operator_type operation() const +{ +return details::e_default; +} +}; + +template +class T0oT1oT2_base_node : public expression_node +{ +public: + +virtual ~T0oT1oT2_base_node() {} + +virtual std::string type_id() const = 0; +}; + +template +class T0oT1oT2oT3_base_node : public expression_node +{ +public: + +virtual ~T0oT1oT2oT3_base_node() {} + +virtual std::string type_id() const = 0; +}; + +template +class unary_variable_node exprtk_final : public uv_base_node +{ +public: + +typedef expression_node* expression_ptr; +typedef Operation operation_t; + +explicit unary_variable_node(const T& var) +: v_(var) +{} + +inline T value() const exprtk_override +{ +return Operation::process(v_); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return Operation::type(); +} + +inline operator_type operation() const exprtk_override +{ +return Operation::operation(); +} + +inline const T& v() const exprtk_override +{ +return v_; +} + +private: + +unary_variable_node(const unary_variable_node&) exprtk_delete; +unary_variable_node& operator=(const unary_variable_node&) exprtk_delete; + +const T& v_; +}; + +template +class uvouv_node exprtk_final : public expression_node +{ +public: + +// UOpr1(v0) Op UOpr2(v1) +typedef typename details::functor_t functor_t; +typedef typename functor_t::bfunc_t bfunc_t; +typedef typename functor_t::ufunc_t ufunc_t; +typedef expression_node* expression_ptr; + +explicit uvouv_node(const T& var0,const T& var1, +ufunc_t uf0, ufunc_t uf1, bfunc_t bf) +: v0_(var0) +, v1_(var1) +, u0_(uf0 ) +, u1_(uf1 ) +, f_ (bf ) +{} + +inline T value() const exprtk_override +{ +return f_(u0_(v0_),u1_(v1_)); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_uvouv; +} + +inline const T& v0() +{ +return v0_; +} + +inline const T& v1() +{ +return v1_; +} + +inline ufunc_t u0() +{ +return u0_; +} + +inline ufunc_t u1() +{ +return u1_; +} + +inline ufunc_t f() +{ +return f_; +} + +private: + +uvouv_node(const uvouv_node&) exprtk_delete; +uvouv_node& operator=(const uvouv_node&) exprtk_delete; + +const T& v0_; +const T& v1_; +const ufunc_t u0_; +const ufunc_t u1_; +const bfunc_t f_; +}; + +template +class unary_branch_node exprtk_final : public expression_node +{ +public: + +typedef Operation operation_t; +typedef expression_node* expression_ptr; +typedef std::pair branch_t; + +explicit unary_branch_node(expression_ptr branch) +{ +construct_branch_pair(branch_, branch); +} + +inline T value() const exprtk_override +{ +return Operation::process(branch_.first->value()); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return Operation::type(); +} + +inline operator_type operation() +{ +return Operation::operation(); +} + +inline expression_node* branch(const std::size_t&) const exprtk_override +{ +return branch_.first; +} + +inline void release() +{ +branch_.second = false; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::collect(branch_, node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::compute_node_depth(branch_); +} + +private: + +unary_branch_node(const unary_branch_node&) exprtk_delete; +unary_branch_node& operator=(const unary_branch_node&) exprtk_delete; + +branch_t branch_; +}; + +template struct is_const { enum {result = 0}; }; +template struct is_const { enum {result = 1}; }; +template struct is_const_ref { enum {result = 0}; }; +template struct is_const_ref { enum {result = 1}; }; +template struct is_ref { enum {result = 0}; }; +template struct is_ref { enum {result = 1}; }; +template struct is_ref { enum {result = 0}; }; + +template +struct param_to_str { static std::string result() { static const std::string r("v"); return r; } }; + +template <> +struct param_to_str<0> { static std::string result() { static const std::string r("c"); return r; } }; + +#define exprtk_crtype(Type) \ + param_to_str::result>::result() \ + +template +struct T0oT1oT2process +{ +typedef typename details::functor_t functor_t; +typedef typename functor_t::bfunc_t bfunc_t; + +struct mode0 +{ +static inline T process(const T& t0, const T& t1, const T& t2, const bfunc_t bf0, const bfunc_t bf1) +{ +// (T0 o0 T1) o1 T2 +return bf1(bf0(t0,t1),t2); +} + +template +static inline std::string id() +{ +static const std::string result = "(" + exprtk_crtype(T0) + "o" + +exprtk_crtype(T1) + ")o(" + +exprtk_crtype(T2) + ")" ; +return result; +} +}; + +struct mode1 +{ +static inline T process(const T& t0, const T& t1, const T& t2, const bfunc_t bf0, const bfunc_t bf1) +{ +// T0 o0 (T1 o1 T2) +return bf0(t0,bf1(t1,t2)); +} + +template +static inline std::string id() +{ +static const std::string result = "(" + exprtk_crtype(T0) + ")o(" + +exprtk_crtype(T1) + "o" + +exprtk_crtype(T2) + ")" ; +return result; +} +}; +}; + +template +struct T0oT1oT20T3process +{ +typedef typename details::functor_t functor_t; +typedef typename functor_t::bfunc_t bfunc_t; + +struct mode0 +{ +static inline T process(const T& t0, const T& t1, +const T& t2, const T& t3, +const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) +{ +// (T0 o0 T1) o1 (T2 o2 T3) +return bf1(bf0(t0,t1),bf2(t2,t3)); +} + +template +static inline std::string id() +{ +static const std::string result = "(" + exprtk_crtype(T0) + "o" + +exprtk_crtype(T1) + ")o" + +"(" + exprtk_crtype(T2) + "o" + +exprtk_crtype(T3) + ")" ; +return result; +} +}; + +struct mode1 +{ +static inline T process(const T& t0, const T& t1, +const T& t2, const T& t3, +const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) +{ +// (T0 o0 (T1 o1 (T2 o2 T3)) +return bf0(t0,bf1(t1,bf2(t2,t3))); +} +template +static inline std::string id() +{ +static const std::string result = "(" + exprtk_crtype(T0) + ")o((" + +exprtk_crtype(T1) + ")o(" + +exprtk_crtype(T2) + "o" + +exprtk_crtype(T3) + "))" ; +return result; +} +}; + +struct mode2 +{ +static inline T process(const T& t0, const T& t1, +const T& t2, const T& t3, +const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) +{ +// (T0 o0 ((T1 o1 T2) o2 T3) +return bf0(t0,bf2(bf1(t1,t2),t3)); +} + +template +static inline std::string id() +{ +static const std::string result = "(" + exprtk_crtype(T0) + ")o((" + +exprtk_crtype(T1) + "o" + +exprtk_crtype(T2) + ")o(" + +exprtk_crtype(T3) + "))" ; +return result; +} +}; + +struct mode3 +{ +static inline T process(const T& t0, const T& t1, +const T& t2, const T& t3, +const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) +{ +// (((T0 o0 T1) o1 T2) o2 T3) +return bf2(bf1(bf0(t0,t1),t2),t3); +} + +template +static inline std::string id() +{ +static const std::string result = "((" + exprtk_crtype(T0) + "o" + +exprtk_crtype(T1) + ")o(" + +exprtk_crtype(T2) + "))o(" + +exprtk_crtype(T3) + ")"; +return result; +} +}; + +struct mode4 +{ +static inline T process(const T& t0, const T& t1, +const T& t2, const T& t3, +const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) +{ +// ((T0 o0 (T1 o1 T2)) o2 T3 +return bf2(bf0(t0,bf1(t1,t2)),t3); +} + +template +static inline std::string id() +{ +static const std::string result = "((" + exprtk_crtype(T0) + ")o(" + +exprtk_crtype(T1) + "o" + +exprtk_crtype(T2) + "))o(" + +exprtk_crtype(T3) + ")" ; +return result; +} +}; +}; + +#undef exprtk_crtype + +template +struct nodetype_T0oT1 { static const typename expression_node::node_type result; }; +template +const typename expression_node::node_type nodetype_T0oT1::result = expression_node::e_none; + +#define synthesis_node_type_define(T0_, T1_, v_) \ + template \ + struct nodetype_T0oT1 { static const typename expression_node::node_type result; }; \ + template \ + const typename expression_node::node_type nodetype_T0oT1::result = expression_node:: v_; \ + +synthesis_node_type_define(const T0&, const T1&, e_vov) +synthesis_node_type_define(const T0&, const T1 , e_voc) +synthesis_node_type_define(const T0 , const T1&, e_cov) +synthesis_node_type_define( T0&, T1&, e_none) +synthesis_node_type_define(const T0 , const T1 , e_none) +synthesis_node_type_define( T0&, const T1 , e_none) +synthesis_node_type_define(const T0 , T1&, e_none) +synthesis_node_type_define(const T0&, T1&, e_none) +synthesis_node_type_define( T0&, const T1&, e_none) +#undef synthesis_node_type_define + +template +struct nodetype_T0oT1oT2 { static const typename expression_node::node_type result; }; +template +const typename expression_node::node_type nodetype_T0oT1oT2::result = expression_node::e_none; + +#define synthesis_node_type_define(T0_, T1_, T2_, v_) \ + template \ + struct nodetype_T0oT1oT2 { static const typename expression_node::node_type result; }; \ + template \ + const typename expression_node::node_type nodetype_T0oT1oT2::result = expression_node:: v_; \ + +synthesis_node_type_define(const T0&, const T1&, const T2&, e_vovov) +synthesis_node_type_define(const T0&, const T1&, const T2 , e_vovoc) +synthesis_node_type_define(const T0&, const T1 , const T2&, e_vocov) +synthesis_node_type_define(const T0 , const T1&, const T2&, e_covov) +synthesis_node_type_define(const T0 , const T1&, const T2 , e_covoc) +synthesis_node_type_define(const T0 , const T1 , const T2 , e_none ) +synthesis_node_type_define(const T0 , const T1 , const T2&, e_none ) +synthesis_node_type_define(const T0&, const T1 , const T2 , e_none ) +synthesis_node_type_define( T0&, T1&, T2&, e_none ) +#undef synthesis_node_type_define + +template +struct nodetype_T0oT1oT2oT3 { static const typename expression_node::node_type result; }; +template +const typename expression_node::node_type nodetype_T0oT1oT2oT3::result = expression_node::e_none; + +#define synthesis_node_type_define(T0_, T1_, T2_, T3_, v_) \ + template \ + struct nodetype_T0oT1oT2oT3 { static const typename expression_node::node_type result; }; \ + template \ + const typename expression_node::node_type nodetype_T0oT1oT2oT3::result = expression_node:: v_; \ + +synthesis_node_type_define(const T0&, const T1&, const T2&, const T3&, e_vovovov) +synthesis_node_type_define(const T0&, const T1&, const T2&, const T3 , e_vovovoc) +synthesis_node_type_define(const T0&, const T1&, const T2 , const T3&, e_vovocov) +synthesis_node_type_define(const T0&, const T1 , const T2&, const T3&, e_vocovov) +synthesis_node_type_define(const T0 , const T1&, const T2&, const T3&, e_covovov) +synthesis_node_type_define(const T0 , const T1&, const T2 , const T3&, e_covocov) +synthesis_node_type_define(const T0&, const T1 , const T2&, const T3 , e_vocovoc) +synthesis_node_type_define(const T0 , const T1&, const T2&, const T3 , e_covovoc) +synthesis_node_type_define(const T0&, const T1 , const T2 , const T3&, e_vococov) +synthesis_node_type_define(const T0 , const T1 , const T2 , const T3 , e_none ) +synthesis_node_type_define(const T0 , const T1 , const T2 , const T3&, e_none ) +synthesis_node_type_define(const T0 , const T1 , const T2&, const T3 , e_none ) +synthesis_node_type_define(const T0 , const T1&, const T2 , const T3 , e_none ) +synthesis_node_type_define(const T0&, const T1 , const T2 , const T3 , e_none ) +synthesis_node_type_define(const T0 , const T1 , const T2&, const T3&, e_none ) +synthesis_node_type_define(const T0&, const T1&, const T2 , const T3 , e_none ) +#undef synthesis_node_type_define + +template +class T0oT1 exprtk_final : public expression_node +{ +public: + +typedef typename details::functor_t functor_t; +typedef typename functor_t::bfunc_t bfunc_t; +typedef T value_type; +typedef T0oT1 node_type; + +T0oT1(T0 p0, T1 p1, const bfunc_t p2) +: t0_(p0) +, t1_(p1) +, f_ (p2) +{} + +inline typename expression_node::node_type type() const exprtk_override +{ +static const typename expression_node::node_type result = nodetype_T0oT1::result; +return result; +} + +inline operator_type operation() const exprtk_override +{ +return e_default; +} + +inline T value() const exprtk_override +{ +return f_(t0_,t1_); +} + +inline T0 t0() const +{ +return t0_; +} + +inline T1 t1() const +{ +return t1_; +} + +inline bfunc_t f() const +{ +return f_; +} + +template +static inline expression_node* allocate(Allocator& allocator, +T0 p0, T1 p1, +bfunc_t p2) +{ +return allocator +.template allocate_type +(p0, p1, p2); +} + +private: + +T0oT1(const T0oT1&) exprtk_delete; +T0oT1& operator=(const T0oT1&) { return (*this); } + +T0 t0_; +T1 t1_; +const bfunc_t f_; +}; + +template +class T0oT1oT2 exprtk_final : public T0oT1oT2_base_node +{ +public: + +typedef typename details::functor_t functor_t; +typedef typename functor_t::bfunc_t bfunc_t; +typedef T value_type; +typedef T0oT1oT2 node_type; +typedef ProcessMode process_mode_t; + +T0oT1oT2(T0 p0, T1 p1, T2 p2, const bfunc_t p3, const bfunc_t p4) +: t0_(p0) +, t1_(p1) +, t2_(p2) +, f0_(p3) +, f1_(p4) +{} + +inline typename expression_node::node_type type() const exprtk_override +{ +static const typename expression_node::node_type result = nodetype_T0oT1oT2::result; +return result; +} + +inline operator_type operation() +{ +return e_default; +} + +inline T value() const exprtk_override +{ +return ProcessMode::process(t0_, t1_, t2_, f0_, f1_); +} + +inline T0 t0() const +{ +return t0_; +} + +inline T1 t1() const +{ +return t1_; +} + +inline T2 t2() const +{ +return t2_; +} + +bfunc_t f0() const +{ +return f0_; +} + +bfunc_t f1() const +{ +return f1_; +} + +std::string type_id() const exprtk_override +{ +return id(); +} + +static inline std::string id() +{ +return process_mode_t::template id(); +} + +template +static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, bfunc_t p3, bfunc_t p4) +{ +return allocator +.template allocate_type +(p0, p1, p2, p3, p4); +} + +private: + +T0oT1oT2(const node_type&) exprtk_delete; +node_type& operator=(const node_type&) exprtk_delete; + +T0 t0_; +T1 t1_; +T2 t2_; +const bfunc_t f0_; +const bfunc_t f1_; +}; + +template +class T0oT1oT2oT3 exprtk_final : public T0oT1oT2oT3_base_node +{ +public: + +typedef typename details::functor_t functor_t; +typedef typename functor_t::bfunc_t bfunc_t; +typedef T value_type; +typedef T0_ T0; +typedef T1_ T1; +typedef T2_ T2; +typedef T3_ T3; +typedef T0oT1oT2oT3 node_type; +typedef ProcessMode process_mode_t; + +T0oT1oT2oT3(T0 p0, T1 p1, T2 p2, T3 p3, bfunc_t p4, bfunc_t p5, bfunc_t p6) +: t0_(p0) +, t1_(p1) +, t2_(p2) +, t3_(p3) +, f0_(p4) +, f1_(p5) +, f2_(p6) +{} + +inline T value() const exprtk_override +{ +return ProcessMode::process(t0_, t1_, t2_, t3_, f0_, f1_, f2_); +} + +inline T0 t0() const +{ +return t0_; +} + +inline T1 t1() const +{ +return t1_; +} + +inline T2 t2() const +{ +return t2_; +} + +inline T3 t3() const +{ +return t3_; +} + +inline bfunc_t f0() const +{ +return f0_; +} + +inline bfunc_t f1() const +{ +return f1_; +} + +inline bfunc_t f2() const +{ +return f2_; +} + +inline std::string type_id() const exprtk_override +{ +return id(); +} + +static inline std::string id() +{ +return process_mode_t::template id(); +} + +template +static inline expression_node* allocate(Allocator& allocator, +T0 p0, T1 p1, T2 p2, T3 p3, +bfunc_t p4, bfunc_t p5, bfunc_t p6) +{ +return allocator +.template allocate_type +(p0, p1, p2, p3, p4, p5, p6); +} + +private: + +T0oT1oT2oT3(const node_type&) exprtk_delete; +node_type& operator=(const node_type&) exprtk_delete; + +T0 t0_; +T1 t1_; +T2 t2_; +T3 t3_; +const bfunc_t f0_; +const bfunc_t f1_; +const bfunc_t f2_; +}; + +template +class T0oT1oT2_sf3 exprtk_final : public T0oT1oT2_base_node +{ +public: + +typedef typename details::functor_t functor_t; +typedef typename functor_t::tfunc_t tfunc_t; +typedef T value_type; +typedef T0oT1oT2_sf3 node_type; + +T0oT1oT2_sf3(T0 p0, T1 p1, T2 p2, const tfunc_t p3) +: t0_(p0) +, t1_(p1) +, t2_(p2) +, f_ (p3) +{} + +inline typename expression_node::node_type type() const exprtk_override +{ +static const typename expression_node::node_type result = nodetype_T0oT1oT2::result; +return result; +} + +inline operator_type operation() const exprtk_override +{ +return e_default; +} + +inline T value() const exprtk_override +{ +return f_(t0_, t1_, t2_); +} + +inline T0 t0() const +{ +return t0_; +} + +inline T1 t1() const +{ +return t1_; +} + +inline T2 t2() const +{ +return t2_; +} + +tfunc_t f() const +{ +return f_; +} + +std::string type_id() const +{ +return id(); +} + +static inline std::string id() +{ +return "sf3"; +} + +template +static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, tfunc_t p3) +{ +return allocator +.template allocate_type +(p0, p1, p2, p3); +} + +private: + +T0oT1oT2_sf3(const node_type&) exprtk_delete; +node_type& operator=(const node_type&) exprtk_delete; + +T0 t0_; +T1 t1_; +T2 t2_; +const tfunc_t f_; +}; + +template +class sf3ext_type_node : public T0oT1oT2_base_node +{ +public: + +virtual ~sf3ext_type_node() {} + +virtual T0 t0() const = 0; + +virtual T1 t1() const = 0; + +virtual T2 t2() const = 0; +}; + +template +class T0oT1oT2_sf3ext exprtk_final : public sf3ext_type_node +{ +public: + +typedef T value_type; +typedef T0oT1oT2_sf3ext node_type; + +T0oT1oT2_sf3ext(T0 p0, T1 p1, T2 p2) +: t0_(p0) +, t1_(p1) +, t2_(p2) +{} + +inline typename expression_node::node_type type() const exprtk_override +{ +static const typename expression_node::node_type result = nodetype_T0oT1oT2::result; +return result; +} + +inline operator_type operation() +{ +return e_default; +} + +inline T value() const exprtk_override +{ +return SF3Operation::process(t0_, t1_, t2_); +} + +T0 t0() const exprtk_override +{ +return t0_; +} + +T1 t1() const exprtk_override +{ +return t1_; +} + +T2 t2() const exprtk_override +{ +return t2_; +} + +std::string type_id() const exprtk_override +{ +return id(); +} + +static inline std::string id() +{ +return SF3Operation::id(); +} + +template +static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2) +{ +return allocator +.template allocate_type +(p0, p1, p2); +} + +private: + +T0oT1oT2_sf3ext(const node_type&) exprtk_delete; +node_type& operator=(const node_type&) exprtk_delete; + +T0 t0_; +T1 t1_; +T2 t2_; +}; + +template +inline bool is_sf3ext_node(const expression_node* n) +{ +switch (n->type()) +{ +case expression_node::e_vovov : return true; +case expression_node::e_vovoc : return true; +case expression_node::e_vocov : return true; +case expression_node::e_covov : return true; +case expression_node::e_covoc : return true; +default : return false; +} +} + +template +class T0oT1oT2oT3_sf4 exprtk_final : public T0oT1oT2_base_node +{ +public: + +typedef typename details::functor_t functor_t; +typedef typename functor_t::qfunc_t qfunc_t; +typedef T value_type; +typedef T0oT1oT2oT3_sf4 node_type; + +T0oT1oT2oT3_sf4(T0 p0, T1 p1, T2 p2, T3 p3, const qfunc_t p4) +: t0_(p0) +, t1_(p1) +, t2_(p2) +, t3_(p3) +, f_ (p4) +{} + +inline typename expression_node::node_type type() const exprtk_override +{ +static const typename expression_node::node_type result = nodetype_T0oT1oT2oT3::result; +return result; +} + +inline operator_type operation() const exprtk_override +{ +return e_default; +} + +inline T value() const exprtk_override +{ +return f_(t0_, t1_, t2_, t3_); +} + +inline T0 t0() const +{ +return t0_; +} + +inline T1 t1() const +{ +return t1_; +} + +inline T2 t2() const +{ +return t2_; +} + +inline T3 t3() const +{ +return t3_; +} + +qfunc_t f() const +{ +return f_; +} + +std::string type_id() const +{ +return id(); +} + +static inline std::string id() +{ +return "sf4"; +} + +template +static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, T3 p3, qfunc_t p4) +{ +return allocator +.template allocate_type +(p0, p1, p2, p3, p4); +} + +private: + +T0oT1oT2oT3_sf4(const node_type&) exprtk_delete; +node_type& operator=(const node_type&) exprtk_delete; + +T0 t0_; +T1 t1_; +T2 t2_; +T3 t3_; +const qfunc_t f_; +}; + +template +class T0oT1oT2oT3_sf4ext exprtk_final : public T0oT1oT2oT3_base_node +{ +public: + +typedef T value_type; +typedef T0oT1oT2oT3_sf4ext node_type; + +T0oT1oT2oT3_sf4ext(T0 p0, T1 p1, T2 p2, T3 p3) +: t0_(p0) +, t1_(p1) +, t2_(p2) +, t3_(p3) +{} + +inline typename expression_node::node_type type() const exprtk_override +{ +static const typename expression_node::node_type result = nodetype_T0oT1oT2oT3::result; +return result; +} + +inline T value() const exprtk_override +{ +return SF4Operation::process(t0_, t1_, t2_, t3_); +} + +inline T0 t0() const +{ +return t0_; +} + +inline T1 t1() const +{ +return t1_; +} + +inline T2 t2() const +{ +return t2_; +} + +inline T3 t3() const +{ +return t3_; +} + +std::string type_id() const exprtk_override +{ +return id(); +} + +static inline std::string id() +{ +return SF4Operation::id(); +} + +template +static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, T3 p3) +{ +return allocator +.template allocate_type +(p0, p1, p2, p3); +} + +private: + +T0oT1oT2oT3_sf4ext(const node_type&) exprtk_delete; +node_type& operator=(const node_type&) exprtk_delete; + +T0 t0_; +T1 t1_; +T2 t2_; +T3 t3_; +}; + +template +inline bool is_sf4ext_node(const expression_node* n) +{ +switch (n->type()) +{ +case expression_node::e_vovovov : return true; +case expression_node::e_vovovoc : return true; +case expression_node::e_vovocov : return true; +case expression_node::e_vocovov : return true; +case expression_node::e_covovov : return true; +case expression_node::e_covocov : return true; +case expression_node::e_vocovoc : return true; +case expression_node::e_covovoc : return true; +case expression_node::e_vococov : return true; +default : return false; +} +} + +template +struct T0oT1_define +{ +typedef details::T0oT1 type0; +}; + +template +struct T0oT1oT2_define +{ +typedef details::T0oT1oT2::mode0> type0; +typedef details::T0oT1oT2::mode1> type1; +typedef details::T0oT1oT2_sf3 sf3_type; +typedef details::sf3ext_type_node sf3_type_node; +}; + +template +struct T0oT1oT2oT3_define +{ +typedef details::T0oT1oT2oT3::mode0> type0; +typedef details::T0oT1oT2oT3::mode1> type1; +typedef details::T0oT1oT2oT3::mode2> type2; +typedef details::T0oT1oT2oT3::mode3> type3; +typedef details::T0oT1oT2oT3::mode4> type4; +typedef details::T0oT1oT2oT3_sf4 sf4_type; +}; + +template +class vov_node exprtk_final : public vov_base_node +{ +public: + +typedef expression_node* expression_ptr; +typedef Operation operation_t; + +// variable op variable node +explicit vov_node(const T& var0, const T& var1) +: v0_(var0) +, v1_(var1) +{} + +inline T value() const exprtk_override +{ +return Operation::process(v0_,v1_); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return Operation::type(); +} + +inline operator_type operation() const exprtk_override +{ +return Operation::operation(); +} + +inline const T& v0() const exprtk_override +{ +return v0_; +} + +inline const T& v1() const exprtk_override +{ +return v1_; +} + +protected: + +const T& v0_; +const T& v1_; + +private: + +vov_node(const vov_node&) exprtk_delete; +vov_node& operator=(const vov_node&) exprtk_delete; +}; + +template +class cov_node exprtk_final : public cov_base_node +{ +public: + +typedef expression_node* expression_ptr; +typedef Operation operation_t; + +// constant op variable node +explicit cov_node(const T& const_var, const T& var) +: c_(const_var) +, v_(var) +{} + +inline T value() const exprtk_override +{ +return Operation::process(c_,v_); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return Operation::type(); +} + +inline operator_type operation() const exprtk_override +{ +return Operation::operation(); +} + +inline const T c() const exprtk_override +{ +return c_; +} + +inline const T& v() const exprtk_override +{ +return v_; +} + +protected: + +const T c_; +const T& v_; + +private: + +cov_node(const cov_node&) exprtk_delete; +cov_node& operator=(const cov_node&) exprtk_delete; +}; + +template +class voc_node exprtk_final : public voc_base_node +{ +public: + +typedef expression_node* expression_ptr; +typedef Operation operation_t; + +// variable op constant node +explicit voc_node(const T& var, const T& const_var) +: v_(var) +, c_(const_var) +{} + +inline T value() const exprtk_override +{ +return Operation::process(v_,c_); +} + +inline operator_type operation() const exprtk_override +{ +return Operation::operation(); +} + +inline const T c() const exprtk_override +{ +return c_; +} + +inline const T& v() const exprtk_override +{ +return v_; +} + +protected: + +const T& v_; +const T c_; + +private: + +voc_node(const voc_node&) exprtk_delete; +voc_node& operator=(const voc_node&) exprtk_delete; +}; + +template +class vob_node exprtk_final : public vob_base_node +{ +public: + +typedef expression_node* expression_ptr; +typedef std::pair branch_t; +typedef Operation operation_t; + +// variable op constant node +explicit vob_node(const T& var, const expression_ptr branch) +: v_(var) +{ +construct_branch_pair(branch_, branch); +} + +inline T value() const exprtk_override +{ +assert(branch_.first); +return Operation::process(v_,branch_.first->value()); +} + +inline const T& v() const exprtk_override +{ +return v_; +} + +inline expression_node* branch(const std::size_t&) const exprtk_override +{ +return branch_.first; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::template collect(branch_, node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::compute_node_depth(branch_); +} + +private: + +vob_node(const vob_node&) exprtk_delete; +vob_node& operator=(const vob_node&) exprtk_delete; + +const T& v_; +branch_t branch_; +}; + +template +class bov_node exprtk_final : public bov_base_node +{ +public: + +typedef expression_node* expression_ptr; +typedef std::pair branch_t; +typedef Operation operation_t; + +// variable op constant node +explicit bov_node(const expression_ptr branch, const T& var) +: v_(var) +{ +construct_branch_pair(branch_, branch); +} + +inline T value() const exprtk_override +{ +assert(branch_.first); +return Operation::process(branch_.first->value(),v_); +} + +inline const T& v() const exprtk_override +{ +return v_; +} + +inline expression_node* branch(const std::size_t&) const exprtk_override +{ +return branch_.first; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::template collect(branch_, node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::compute_node_depth(branch_); +} + +private: + +bov_node(const bov_node&) exprtk_delete; +bov_node& operator=(const bov_node&) exprtk_delete; + +const T& v_; +branch_t branch_; +}; + +template +class cob_node exprtk_final : public cob_base_node +{ +public: + +typedef expression_node* expression_ptr; +typedef std::pair branch_t; +typedef Operation operation_t; + +// variable op constant node +explicit cob_node(const T const_var, const expression_ptr branch) +: c_(const_var) +{ +construct_branch_pair(branch_, branch); +} + +inline T value() const exprtk_override +{ +assert(branch_.first); +return Operation::process(c_,branch_.first->value()); +} + +inline operator_type operation() const exprtk_override +{ +return Operation::operation(); +} + +inline const T c() const exprtk_override +{ +return c_; +} + +inline void set_c(const T new_c) exprtk_override +{ +(*const_cast(&c_)) = new_c; +} + +inline expression_node* branch(const std::size_t&) const exprtk_override +{ +return branch_.first; +} + +inline expression_node* move_branch(const std::size_t&) exprtk_override +{ +branch_.second = false; +return branch_.first; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::template collect(branch_, node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::compute_node_depth(branch_); +} + +private: + +cob_node(const cob_node&) exprtk_delete; +cob_node& operator=(const cob_node&) exprtk_delete; + +const T c_; +branch_t branch_; +}; + +template +class boc_node exprtk_final : public boc_base_node +{ +public: + +typedef expression_node* expression_ptr; +typedef std::pair branch_t; +typedef Operation operation_t; + +// variable op constant node +explicit boc_node(const expression_ptr branch, const T const_var) +: c_(const_var) +{ +construct_branch_pair(branch_, branch); +} + +inline T value() const exprtk_override +{ +assert(branch_.first); +return Operation::process(branch_.first->value(),c_); +} + +inline operator_type operation() const exprtk_override +{ +return Operation::operation(); +} + +inline const T c() const exprtk_override +{ +return c_; +} + +inline void set_c(const T new_c) exprtk_override +{ +(*const_cast(&c_)) = new_c; +} + +inline expression_node* branch(const std::size_t&) const exprtk_override +{ +return branch_.first; +} + +inline expression_node* move_branch(const std::size_t&) exprtk_override +{ +branch_.second = false; +return branch_.first; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::template collect(branch_, node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::compute_node_depth(branch_); +} + +private: + +boc_node(const boc_node&) exprtk_delete; +boc_node& operator=(const boc_node&) exprtk_delete; + +const T c_; +branch_t branch_; +}; + +#ifndef exprtk_disable_string_capabilities +template +class sos_node exprtk_final : public sos_base_node +{ +public: + +typedef expression_node* expression_ptr; +typedef Operation operation_t; + +// string op string node +explicit sos_node(SType0 p0, SType1 p1) +: s0_(p0) +, s1_(p1) +{} + +inline T value() const exprtk_override +{ +return Operation::process(s0_,s1_); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return Operation::type(); +} + +inline operator_type operation() const exprtk_override +{ +return Operation::operation(); +} + +inline std::string& s0() +{ +return s0_; +} + +inline std::string& s1() +{ +return s1_; +} + +protected: + +SType0 s0_; +SType1 s1_; + +private: + +sos_node(const sos_node&) exprtk_delete; +sos_node& operator=(const sos_node&) exprtk_delete; +}; + +template +class str_xrox_node exprtk_final : public sos_base_node +{ +public: + +typedef expression_node* expression_ptr; +typedef Operation operation_t; +typedef str_xrox_node node_type; + +// string-range op string node +explicit str_xrox_node(SType0 p0, SType1 p1, RangePack rp0) +: s0_ (p0 ) +, s1_ (p1 ) +, rp0_(rp0) +{} + +~str_xrox_node() +{ +rp0_.free(); +} + +inline T value() const exprtk_override +{ +std::size_t r0 = 0; +std::size_t r1 = 0; + +if (rp0_(r0, r1, s0_.size())) +return Operation::process(s0_.substr(r0, (r1 - r0) + 1), s1_); +else +return T(0); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return Operation::type(); +} + +inline operator_type operation() const exprtk_override +{ +return Operation::operation(); +} + +inline std::string& s0() +{ +return s0_; +} + +inline std::string& s1() +{ +return s1_; +} + +protected: + +SType0 s0_; +SType1 s1_; +RangePack rp0_; + +private: + +str_xrox_node(const node_type&) exprtk_delete; +node_type& operator=(const node_type&) exprtk_delete; +}; + +template +class str_xoxr_node exprtk_final : public sos_base_node +{ +public: + +typedef expression_node* expression_ptr; +typedef Operation operation_t; +typedef str_xoxr_node node_type; + +// string op string range node +explicit str_xoxr_node(SType0 p0, SType1 p1, RangePack rp1) +: s0_ (p0 ) +, s1_ (p1 ) +, rp1_(rp1) +{} + +~str_xoxr_node() +{ +rp1_.free(); +} + +inline T value() const exprtk_override +{ +std::size_t r0 = 0; +std::size_t r1 = 0; + +if (rp1_(r0, r1, s1_.size())) +return Operation::process(s0_, s1_.substr(r0, (r1 - r0) + 1)); +else +return T(0); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return Operation::type(); +} + +inline operator_type operation() const exprtk_override +{ +return Operation::operation(); +} + +inline std::string& s0() +{ +return s0_; +} + +inline std::string& s1() +{ +return s1_; +} + +protected: + +SType0 s0_; +SType1 s1_; +RangePack rp1_; + +private: + +str_xoxr_node(const node_type&) exprtk_delete; +node_type& operator=(const node_type&) exprtk_delete; +}; + +template +class str_xroxr_node exprtk_final : public sos_base_node +{ +public: + +typedef expression_node* expression_ptr; +typedef Operation operation_t; +typedef str_xroxr_node node_type; + +// string-range op string-range node +explicit str_xroxr_node(SType0 p0, SType1 p1, RangePack rp0, RangePack rp1) +: s0_ (p0 ) +, s1_ (p1 ) +, rp0_(rp0) +, rp1_(rp1) +{} + +~str_xroxr_node() +{ +rp0_.free(); +rp1_.free(); +} + +inline T value() const exprtk_override +{ +std::size_t r0_0 = 0; +std::size_t r0_1 = 0; +std::size_t r1_0 = 0; +std::size_t r1_1 = 0; + +if ( +rp0_(r0_0, r1_0, s0_.size()) && +rp1_(r0_1, r1_1, s1_.size()) +) +{ +return Operation::process( +s0_.substr(r0_0, (r1_0 - r0_0) + 1), +s1_.substr(r0_1, (r1_1 - r0_1) + 1) +); +} +else +return T(0); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return Operation::type(); +} + +inline operator_type operation() const exprtk_override +{ +return Operation::operation(); +} + +inline std::string& s0() +{ +return s0_; +} + +inline std::string& s1() +{ +return s1_; +} + +protected: + +SType0 s0_; +SType1 s1_; +RangePack rp0_; +RangePack rp1_; + +private: + +str_xroxr_node(const node_type&) exprtk_delete; +node_type& operator=(const node_type&) exprtk_delete; +}; + +template +class str_sogens_node exprtk_final : public binary_node +{ +public: + +typedef expression_node * expression_ptr; +typedef string_base_node* str_base_ptr; +typedef range_pack range_t; +typedef range_t* range_ptr; +typedef range_interface irange_t; +typedef irange_t* irange_ptr; + +using binary_node::branch; + +str_sogens_node(const operator_type& opr, +expression_ptr branch0, +expression_ptr branch1) +: binary_node(opr, branch0, branch1) +, str0_base_ptr_ (0) +, str1_base_ptr_ (0) +, str0_range_ptr_(0) +, str1_range_ptr_(0) +{ +if (is_generally_string_node(branch(0))) +{ +str0_base_ptr_ = dynamic_cast(branch(0)); + +if (0 == str0_base_ptr_) +return; + +irange_ptr range = dynamic_cast(branch(0)); + +if (0 == range) +return; + +str0_range_ptr_ = &(range->range_ref()); +} + +if (is_generally_string_node(branch(1))) +{ +str1_base_ptr_ = dynamic_cast(branch(1)); + +if (0 == str1_base_ptr_) +return; + +irange_ptr range = dynamic_cast(branch(1)); + +if (0 == range) +return; + +str1_range_ptr_ = &(range->range_ref()); +} +} + +inline T value() const exprtk_override +{ +if ( +str0_base_ptr_ && +str1_base_ptr_ && +str0_range_ptr_ && +str1_range_ptr_ +) +{ +branch(0)->value(); +branch(1)->value(); + +std::size_t str0_r0 = 0; +std::size_t str0_r1 = 0; + +std::size_t str1_r0 = 0; +std::size_t str1_r1 = 0; + +const range_t& range0 = (*str0_range_ptr_); +const range_t& range1 = (*str1_range_ptr_); + +if ( +range0(str0_r0, str0_r1, str0_base_ptr_->size()) && +range1(str1_r0, str1_r1, str1_base_ptr_->size()) +) +{ +return Operation::process( +str0_base_ptr_->str().substr(str0_r0,(str0_r1 - str0_r0) + 1), +str1_base_ptr_->str().substr(str1_r0,(str1_r1 - str1_r0) + 1) +); +} +} + +return std::numeric_limits::quiet_NaN(); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return Operation::type(); +} + +private: + +str_sogens_node(const str_sogens_node&) exprtk_delete; +str_sogens_node& operator=(const str_sogens_node&) exprtk_delete; + +str_base_ptr str0_base_ptr_; +str_base_ptr str1_base_ptr_; +range_ptr str0_range_ptr_; +range_ptr str1_range_ptr_; +}; + +template +class sosos_node exprtk_final : public sosos_base_node +{ +public: + +typedef expression_node* expression_ptr; +typedef Operation operation_t; +typedef sosos_node node_type; + +// variable op variable node +explicit sosos_node(SType0 p0, SType1 p1, SType2 p2) +: s0_(p0) +, s1_(p1) +, s2_(p2) +{} + +inline T value() const exprtk_override +{ +return Operation::process(s0_, s1_, s2_); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return Operation::type(); +} + +inline operator_type operation() const exprtk_override +{ +return Operation::operation(); +} + +inline std::string& s0() +{ +return s0_; +} + +inline std::string& s1() +{ +return s1_; +} + +inline std::string& s2() +{ +return s2_; +} + +protected: + +SType0 s0_; +SType1 s1_; +SType2 s2_; + +private: + +sosos_node(const node_type&) exprtk_delete; +node_type& operator=(const node_type&) exprtk_delete; +}; +#endif + +template +class ipow_node exprtk_final: public expression_node +{ +public: + +typedef expression_node* expression_ptr; +typedef PowOp operation_t; + +explicit ipow_node(const T& v) +: v_(v) +{} + +inline T value() const exprtk_override +{ +return PowOp::result(v_); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_ipow; +} + +private: + +ipow_node(const ipow_node&) exprtk_delete; +ipow_node& operator=(const ipow_node&) exprtk_delete; + +const T& v_; +}; + +template +class bipow_node exprtk_final : public expression_node +{ +public: + +typedef expression_node* expression_ptr; +typedef std::pair branch_t; +typedef PowOp operation_t; + +explicit bipow_node(expression_ptr branch) +{ +construct_branch_pair(branch_, branch); +} + +inline T value() const exprtk_override +{ +assert(branch_.first); +return PowOp::result(branch_.first->value()); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_ipow; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::collect(branch_, node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::compute_node_depth(branch_); +} + +private: + +bipow_node(const bipow_node&) exprtk_delete; +bipow_node& operator=(const bipow_node&) exprtk_delete; + +branch_t branch_; +}; + +template +class ipowinv_node exprtk_final : public expression_node +{ +public: + +typedef expression_node* expression_ptr; +typedef PowOp operation_t; + +explicit ipowinv_node(const T& v) +: v_(v) +{} + +inline T value() const exprtk_override +{ +return (T(1) / PowOp::result(v_)); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_ipowinv; +} + +private: + +ipowinv_node(const ipowinv_node&) exprtk_delete; +ipowinv_node& operator=(const ipowinv_node&) exprtk_delete; + +const T& v_; +}; + +template +class bipowninv_node exprtk_final : public expression_node +{ +public: + +typedef expression_node* expression_ptr; +typedef std::pair branch_t; +typedef PowOp operation_t; + +explicit bipowninv_node(expression_ptr branch) +{ +construct_branch_pair(branch_, branch); +} + +inline T value() const exprtk_override +{ +assert(branch_.first); +return (T(1) / PowOp::result(branch_.first->value())); +} + +inline typename expression_node::node_type type() const exprtk_override +{ +return expression_node::e_ipowinv; +} + +void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override +{ +expression_node::ndb_t::template collect(branch_, node_delete_list); +} + +std::size_t node_depth() const exprtk_override +{ +return expression_node::ndb_t::compute_node_depth(branch_); +} + +private: + +bipowninv_node(const bipowninv_node&) exprtk_delete; +bipowninv_node& operator=(const bipowninv_node&) exprtk_delete; + +branch_t branch_; +}; + +template +inline bool is_vov_node(const expression_node* node) +{ +return (0 != dynamic_cast*>(node)); +} + +template +inline bool is_cov_node(const expression_node* node) +{ +return (0 != dynamic_cast*>(node)); +} + +template +inline bool is_voc_node(const expression_node* node) +{ +return (0 != dynamic_cast*>(node)); +} + +template +inline bool is_cob_node(const expression_node* node) +{ +return (0 != dynamic_cast*>(node)); +} + +template +inline bool is_boc_node(const expression_node* node) +{ +return (0 != dynamic_cast*>(node)); +} + +template +inline bool is_t0ot1ot2_node(const expression_node* node) +{ +return (0 != dynamic_cast*>(node)); +} + +template +inline bool is_t0ot1ot2ot3_node(const expression_node* node) +{ +return (0 != dynamic_cast*>(node)); +} + +template +inline bool is_uv_node(const expression_node* node) +{ +return (0 != dynamic_cast*>(node)); +} + +template +inline bool is_string_node(const expression_node* node) +{ +return node && (expression_node::e_stringvar == node->type()); +} + +template +inline bool is_string_range_node(const expression_node* node) +{ +return node && (expression_node::e_stringvarrng == node->type()); +} + +template +inline bool is_const_string_node(const expression_node* node) +{ +return node && (expression_node::e_stringconst == node->type()); +} + +template +inline bool is_const_string_range_node(const expression_node* node) +{ +return node && (expression_node::e_cstringvarrng == node->type()); +} + +template +inline bool is_string_assignment_node(const expression_node* node) +{ +return node && (expression_node::e_strass == node->type()); +} + +template +inline bool is_string_concat_node(const expression_node* node) +{ +return node && (expression_node::e_strconcat == node->type()); +} + +template +inline bool is_string_function_node(const expression_node* node) +{ +return node && (expression_node::e_strfunction == node->type()); +} + +template +inline bool is_string_condition_node(const expression_node* node) +{ +return node && (expression_node::e_strcondition == node->type()); +} + +template +inline bool is_string_ccondition_node(const expression_node* node) +{ +return node && (expression_node::e_strccondition == node->type()); +} + +template +inline bool is_string_vararg_node(const expression_node* node) +{ +return node && (expression_node::e_stringvararg == node->type()); +} + +template +inline bool is_genricstring_range_node(const expression_node* node) +{ +return node && (expression_node::e_strgenrange == node->type()); +} + +template +inline bool is_generally_string_node(const expression_node* node) +{ +if (node) +{ +switch (node->type()) +{ +case expression_node::e_stringvar : +case expression_node::e_stringconst : +case expression_node::e_stringvarrng : +case expression_node::e_cstringvarrng : +case expression_node::e_strgenrange : +case expression_node::e_strass : +case expression_node::e_strconcat : +case expression_node::e_strfunction : +case expression_node::e_strcondition : +case expression_node::e_strccondition : +case expression_node::e_stringvararg : return true; +default : return false; +} +} + +return false; +} + +class node_allocator +{ +public: + +template +inline expression_node* allocate(OpType& operation, ExprNode (&branch)[1]) +{ +expression_node* result = +allocate(operation, branch[0]); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate(OpType& operation, ExprNode (&branch)[2]) +{ +expression_node* result = +allocate(operation, branch[0], branch[1]); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate(OpType& operation, ExprNode (&branch)[3]) +{ +expression_node* result = +allocate(operation, branch[0], branch[1], branch[2]); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate(OpType& operation, ExprNode (&branch)[4]) +{ +expression_node* result = +allocate(operation, branch[0], branch[1], branch[2], branch[3]); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate(OpType& operation, ExprNode (&branch)[5]) +{ +expression_node* result = +allocate(operation, branch[0],branch[1], branch[2], branch[3], branch[4]); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate(OpType& operation, ExprNode (&branch)[6]) +{ +expression_node* result = +allocate(operation, branch[0], branch[1], branch[2], branch[3], branch[4], branch[5]); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate() const +{ +return (new node_type()); +} + +template class Sequence> +inline expression_node* allocate(const Sequence& seq) const +{ +expression_node* +result = (new node_type(seq)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate(T1& t1) const +{ +expression_node* +result = (new node_type(t1)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate_c(const T1& t1) const +{ +expression_node* +result = (new node_type(t1)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate(const T1& t1, const T2& t2) const +{ +expression_node* +result = (new node_type(t1, t2)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate_cr(const T1& t1, T2& t2) const +{ +expression_node* +result = (new node_type(t1, t2)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate_rc(T1& t1, const T2& t2) const +{ +expression_node* +result = (new node_type(t1, t2)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate_rr(T1& t1, T2& t2) const +{ +expression_node* +result = (new node_type(t1, t2)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate_tt(T1 t1, T2 t2) const +{ +expression_node* +result = (new node_type(t1, t2)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate_ttt(T1 t1, T2 t2, T3 t3) const +{ +expression_node* +result = (new node_type(t1, t2, t3)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate_tttt(T1 t1, T2 t2, T3 t3, T4 t4) const +{ +expression_node* +result = (new node_type(t1, t2, t3, t4)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate_rrr(T1& t1, T2& t2, T3& t3) const +{ +expression_node* +result = (new node_type(t1, t2, t3)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate_rrrr(T1& t1, T2& t2, T3& t3, T4& t4) const +{ +expression_node* +result = (new node_type(t1, t2, t3, t4)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate_rrrrr(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5) const +{ +expression_node* +result = (new node_type(t1, t2, t3, t4, t5)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate(const T1& t1, const T2& t2, +const T3& t3) const +{ +expression_node* +result = (new node_type(t1, t2, t3)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate(const T1& t1, const T2& t2, +const T3& t3, const T4& t4) const +{ +expression_node* +result = (new node_type(t1, t2, t3, t4)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate(const T1& t1, const T2& t2, +const T3& t3, const T4& t4, +const T5& t5) const +{ +expression_node* +result = (new node_type(t1, t2, t3, t4, t5)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate(const T1& t1, const T2& t2, +const T3& t3, const T4& t4, +const T5& t5, const T6& t6) const +{ +expression_node* +result = (new node_type(t1, t2, t3, t4, t5, t6)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate(const T1& t1, const T2& t2, +const T3& t3, const T4& t4, +const T5& t5, const T6& t6, +const T7& t7) const +{ +expression_node* +result = (new node_type(t1, t2, t3, t4, t5, t6, t7)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate(const T1& t1, const T2& t2, +const T3& t3, const T4& t4, +const T5& t5, const T6& t6, +const T7& t7, const T8& t8) const +{ +expression_node* +result = (new node_type(t1, t2, t3, t4, t5, t6, t7, t8)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate(const T1& t1, const T2& t2, +const T3& t3, const T4& t4, +const T5& t5, const T6& t6, +const T7& t7, const T8& t8, +const T9& t9) const +{ +expression_node* +result = (new node_type(t1, t2, t3, t4, t5, t6, t7, t8, t9)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate(const T1& t1, const T2& t2, +const T3& t3, const T4& t4, +const T5& t5, const T6& t6, +const T7& t7, const T8& t8, +const T9& t9, const T10& t10) const +{ +expression_node* +result = (new node_type(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate_type(T1 t1, T2 t2, T3 t3) const +{ +expression_node* +result = (new node_type(t1, t2, t3)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate_type(T1 t1, T2 t2, +T3 t3, T4 t4) const +{ +expression_node* +result = (new node_type(t1, t2, t3, t4)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate_type(T1 t1, T2 t2, +T3 t3, T4 t4, +T5 t5) const +{ +expression_node* +result = (new node_type(t1, t2, t3, t4, t5)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate_type(T1 t1, T2 t2, +T3 t3, T4 t4, +T5 t5, T6 t6) const +{ +expression_node* +result = (new node_type(t1, t2, t3, t4, t5, t6)); +result->node_depth(); +return result; +} + +template +inline expression_node* allocate_type(T1 t1, T2 t2, +T3 t3, T4 t4, +T5 t5, T6 t6, +T7 t7) const +{ +expression_node* +result = (new node_type(t1, t2, t3, t4, t5, t6, t7)); +result->node_depth(); +return result; +} + +template +void inline free(expression_node*& e) const +{ +exprtk_debug(("node_allocator::free() - deleting expression_node " +"type: %03d addr: %p\n", +static_cast(e->type()), +reinterpret_cast(e))); +delete e; +e = 0; +} +}; + +inline void load_operations_map(std::multimap& m) +{ +#define register_op(Symbol, Type, Args) \ + m.insert(std::make_pair(std::string(Symbol),details::base_operation_t(Type,Args))); \ + +register_op("abs" , e_abs , 1) +register_op("acos" , e_acos , 1) +register_op("acosh" , e_acosh , 1) +register_op("asin" , e_asin , 1) +register_op("asinh" , e_asinh , 1) +register_op("atan" , e_atan , 1) +register_op("atanh" , e_atanh , 1) +register_op("ceil" , e_ceil , 1) +register_op("cos" , e_cos , 1) +register_op("cosh" , e_cosh , 1) +register_op("exp" , e_exp , 1) +register_op("expm1" , e_expm1 , 1) +register_op("floor" , e_floor , 1) +register_op("log" , e_log , 1) +register_op("log10" , e_log10 , 1) +register_op("log2" , e_log2 , 1) +register_op("log1p" , e_log1p , 1) +register_op("round" , e_round , 1) +register_op("sin" , e_sin , 1) +register_op("sinc" , e_sinc , 1) +register_op("sinh" , e_sinh , 1) +register_op("sec" , e_sec , 1) +register_op("csc" , e_csc , 1) +register_op("sqrt" , e_sqrt , 1) +register_op("tan" , e_tan , 1) +register_op("tanh" , e_tanh , 1) +register_op("cot" , e_cot , 1) +register_op("rad2deg" , e_r2d , 1) +register_op("deg2rad" , e_d2r , 1) +register_op("deg2grad" , e_d2g , 1) +register_op("grad2deg" , e_g2d , 1) +register_op("sgn" , e_sgn , 1) +register_op("not" , e_notl , 1) +register_op("erf" , e_erf , 1) +register_op("erfc" , e_erfc , 1) +register_op("ncdf" , e_ncdf , 1) +register_op("frac" , e_frac , 1) +register_op("trunc" , e_trunc , 1) +register_op("atan2" , e_atan2 , 2) +register_op("mod" , e_mod , 2) +register_op("logn" , e_logn , 2) +register_op("pow" , e_pow , 2) +register_op("root" , e_root , 2) +register_op("roundn" , e_roundn , 2) +register_op("equal" , e_equal , 2) +register_op("not_equal" , e_nequal , 2) +register_op("hypot" , e_hypot , 2) +register_op("shr" , e_shr , 2) +register_op("shl" , e_shl , 2) +register_op("clamp" , e_clamp , 3) +register_op("iclamp" , e_iclamp , 3) +register_op("inrange" , e_inrange , 3) +#undef register_op +} + +} // namespace details + +class function_traits +{ +public: + +function_traits() +: allow_zero_parameters_(false) +, has_side_effects_(true) +, min_num_args_(0) +, max_num_args_(std::numeric_limits::max()) +{} + +inline bool& allow_zero_parameters() +{ +return allow_zero_parameters_; +} + +inline bool& has_side_effects() +{ +return has_side_effects_; +} + +std::size_t& min_num_args() +{ +return min_num_args_; +} + +std::size_t& max_num_args() +{ +return max_num_args_; +} + +private: + +bool allow_zero_parameters_; +bool has_side_effects_; +std::size_t min_num_args_; +std::size_t max_num_args_; +}; + +template +void enable_zero_parameters(FunctionType& func) +{ +func.allow_zero_parameters() = true; + +if (0 != func.min_num_args()) +{ +func.min_num_args() = 0; +} +} + +template +void disable_zero_parameters(FunctionType& func) +{ +func.allow_zero_parameters() = false; +} + +template +void enable_has_side_effects(FunctionType& func) +{ +func.has_side_effects() = true; +} + +template +void disable_has_side_effects(FunctionType& func) +{ +func.has_side_effects() = false; +} + +template +void set_min_num_args(FunctionType& func, const std::size_t& num_args) +{ +func.min_num_args() = num_args; + +if ((0 != func.min_num_args()) && func.allow_zero_parameters()) +func.allow_zero_parameters() = false; +} + +template +void set_max_num_args(FunctionType& func, const std::size_t& num_args) +{ +func.max_num_args() = num_args; +} + +template +class ifunction : public function_traits +{ +public: + +explicit ifunction(const std::size_t& pc) +: param_count(pc) +{} + +virtual ~ifunction() {} + +#define empty_method_body(N) \ + { \ + exprtk_debug(("ifunction::operator() - Operator(" #N ") has not been overridden\n")); \ + return std::numeric_limits::quiet_NaN(); \ + } \ + +inline virtual T operator() () +empty_method_body(0) + +inline virtual T operator() (const T&) +empty_method_body(1) + +inline virtual T operator() (const T&,const T&) +empty_method_body(2) + +inline virtual T operator() (const T&, const T&, const T&) +empty_method_body(3) + +inline virtual T operator() (const T&, const T&, const T&, const T&) +empty_method_body(4) + +inline virtual T operator() (const T&, const T&, const T&, const T&, const T&) +empty_method_body(5) + +inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&) +empty_method_body(6) + +inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&) +empty_method_body(7) + +inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) +empty_method_body(8) + +inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) +empty_method_body(9) + +inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) +empty_method_body(10) + +inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, +const T&) +empty_method_body(11) + +inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, +const T&, const T&) +empty_method_body(12) + +inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, +const T&, const T&, const T&) +empty_method_body(13) + +inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, +const T&, const T&, const T&, const T&) +empty_method_body(14) + +inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, +const T&, const T&, const T&, const T&, const T&) +empty_method_body(15) + +inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, +const T&, const T&, const T&, const T&, const T&, const T&) +empty_method_body(16) + +inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, +const T&, const T&, const T&, const T&, const T&, const T&, const T&) +empty_method_body(17) + +inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, +const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) +empty_method_body(18) + +inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, +const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) +empty_method_body(19) + +inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, +const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) +empty_method_body(20) + +#undef empty_method_body + +std::size_t param_count; +}; + +template +class ivararg_function : public function_traits +{ +public: + +virtual ~ivararg_function() {} + +inline virtual T operator() (const std::vector&) +{ +exprtk_debug(("ivararg_function::operator() - Operator has not been overridden\n")); +return std::numeric_limits::quiet_NaN(); +} +}; + +template +class igeneric_function : public function_traits +{ +public: + +enum return_type +{ +e_rtrn_scalar = 0, +e_rtrn_string = 1, +e_rtrn_overload = 2 +}; + +typedef T type; +typedef type_store generic_type; +typedef typename generic_type::parameter_list parameter_list_t; + +igeneric_function(const std::string& param_seq = "", const return_type rtr_type = e_rtrn_scalar) +: parameter_sequence(param_seq) +, rtrn_type(rtr_type) +{} + +virtual ~igeneric_function() {} + +#define igeneric_function_empty_body(N) \ + { \ + exprtk_debug(("igeneric_function::operator() - Operator(" #N ") has not been overridden\n")); \ + return std::numeric_limits::quiet_NaN(); \ + } \ + +// f(i_0,i_1,....,i_N) --> Scalar +inline virtual T operator() (parameter_list_t) +igeneric_function_empty_body(1) + +// f(i_0,i_1,....,i_N) --> String +inline virtual T operator() (std::string&, parameter_list_t) +igeneric_function_empty_body(2) + +// f(psi,i_0,i_1,....,i_N) --> Scalar +inline virtual T operator() (const std::size_t&, parameter_list_t) +igeneric_function_empty_body(3) + +// f(psi,i_0,i_1,....,i_N) --> String +inline virtual T operator() (const std::size_t&, std::string&, parameter_list_t) +igeneric_function_empty_body(4) + +std::string parameter_sequence; +return_type rtrn_type; +}; + +#ifndef exprtk_disable_string_capabilities +template +class stringvar_base +{ +public: + +typedef typename details::stringvar_node stringvar_node_t; + +stringvar_base(const std::string& name, stringvar_node_t* svn) +: name_(name) +, string_varnode_(svn) +{} + +bool valid() const +{ +return !name_.empty() && (0 != string_varnode_); +} + +std::string name() const +{ +assert(string_varnode_); +return name_; +} + +void rebase(std::string& s) +{ +assert(string_varnode_); +string_varnode_->rebase(s); +} + +private: + +std::string name_; +stringvar_node_t* string_varnode_; +}; +#endif + +template class parser; +template class expression_helper; + +template +class symbol_table +{ +public: + +enum symtab_mutability_type +{ +e_unknown = 0, +e_mutable = 1, +e_immutable = 2 +}; + +typedef T (*ff00_functor)(); +typedef T (*ff01_functor)(T); +typedef T (*ff02_functor)(T, T); +typedef T (*ff03_functor)(T, T, T); +typedef T (*ff04_functor)(T, T, T, T); +typedef T (*ff05_functor)(T, T, T, T, T); +typedef T (*ff06_functor)(T, T, T, T, T, T); +typedef T (*ff07_functor)(T, T, T, T, T, T, T); +typedef T (*ff08_functor)(T, T, T, T, T, T, T, T); +typedef T (*ff09_functor)(T, T, T, T, T, T, T, T, T); +typedef T (*ff10_functor)(T, T, T, T, T, T, T, T, T, T); +typedef T (*ff11_functor)(T, T, T, T, T, T, T, T, T, T, T); +typedef T (*ff12_functor)(T, T, T, T, T, T, T, T, T, T, T, T); +typedef T (*ff13_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T); +typedef T (*ff14_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T, T); +typedef T (*ff15_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T); + +protected: + +struct freefunc00 : public exprtk::ifunction +{ +using exprtk::ifunction::operator(); + +explicit freefunc00(ff00_functor ff) : exprtk::ifunction(0), f(ff) {} +inline T operator() () +{ return f(); } +ff00_functor f; +}; + +struct freefunc01 : public exprtk::ifunction +{ +using exprtk::ifunction::operator(); + +explicit freefunc01(ff01_functor ff) : exprtk::ifunction(1), f(ff) {} +inline T operator() (const T& v0) +{ return f(v0); } +ff01_functor f; +}; + +struct freefunc02 : public exprtk::ifunction +{ +using exprtk::ifunction::operator(); + +explicit freefunc02(ff02_functor ff) : exprtk::ifunction(2), f(ff) {} +inline T operator() (const T& v0, const T& v1) +{ return f(v0, v1); } +ff02_functor f; +}; + +struct freefunc03 : public exprtk::ifunction +{ +using exprtk::ifunction::operator(); + +explicit freefunc03(ff03_functor ff) : exprtk::ifunction(3), f(ff) {} +inline T operator() (const T& v0, const T& v1, const T& v2) +{ return f(v0, v1, v2); } +ff03_functor f; +}; + +struct freefunc04 : public exprtk::ifunction +{ +using exprtk::ifunction::operator(); + +explicit freefunc04(ff04_functor ff) : exprtk::ifunction(4), f(ff) {} +inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3) +{ return f(v0, v1, v2, v3); } +ff04_functor f; +}; + +struct freefunc05 : public exprtk::ifunction +{ +using exprtk::ifunction::operator(); + +explicit freefunc05(ff05_functor ff) : exprtk::ifunction(5), f(ff) {} +inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4) +{ return f(v0, v1, v2, v3, v4); } +ff05_functor f; +}; + +struct freefunc06 : public exprtk::ifunction +{ +using exprtk::ifunction::operator(); + +explicit freefunc06(ff06_functor ff) : exprtk::ifunction(6), f(ff) {} +inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) +{ return f(v0, v1, v2, v3, v4, v5); } +ff06_functor f; +}; + +struct freefunc07 : public exprtk::ifunction +{ +using exprtk::ifunction::operator(); + +explicit freefunc07(ff07_functor ff) : exprtk::ifunction(7), f(ff) {} +inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, +const T& v5, const T& v6) +{ return f(v0, v1, v2, v3, v4, v5, v6); } +ff07_functor f; +}; + +struct freefunc08 : public exprtk::ifunction +{ +using exprtk::ifunction::operator(); + +explicit freefunc08(ff08_functor ff) : exprtk::ifunction(8), f(ff) {} +inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, +const T& v5, const T& v6, const T& v7) +{ return f(v0, v1, v2, v3, v4, v5, v6, v7); } +ff08_functor f; +}; + +struct freefunc09 : public exprtk::ifunction +{ +using exprtk::ifunction::operator(); + +explicit freefunc09(ff09_functor ff) : exprtk::ifunction(9), f(ff) {} +inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, +const T& v5, const T& v6, const T& v7, const T& v8) +{ return f(v0, v1, v2, v3, v4, v5, v6, v7, v8); } +ff09_functor f; +}; + +struct freefunc10 : public exprtk::ifunction +{ +using exprtk::ifunction::operator(); + +explicit freefunc10(ff10_functor ff) : exprtk::ifunction(10), f(ff) {} +inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, +const T& v5, const T& v6, const T& v7, const T& v8, const T& v9) +{ return f(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); } +ff10_functor f; +}; + +struct freefunc11 : public exprtk::ifunction +{ +using exprtk::ifunction::operator(); + +explicit freefunc11(ff11_functor ff) : exprtk::ifunction(11), f(ff) {} +inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, +const T& v5, const T& v6, const T& v7, const T& v8, const T& v9, const T& v10) +{ return f(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10); } +ff11_functor f; +}; + +struct freefunc12 : public exprtk::ifunction +{ +using exprtk::ifunction::operator(); + +explicit freefunc12(ff12_functor ff) : exprtk::ifunction(12), f(ff) {} +inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, +const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, +const T& v10, const T& v11) +{ return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11); } +ff12_functor f; +}; + +struct freefunc13 : public exprtk::ifunction +{ +using exprtk::ifunction::operator(); + +explicit freefunc13(ff13_functor ff) : exprtk::ifunction(13), f(ff) {} +inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, +const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, +const T& v10, const T& v11, const T& v12) +{ return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12); } +ff13_functor f; +}; + +struct freefunc14 : public exprtk::ifunction +{ +using exprtk::ifunction::operator(); + +explicit freefunc14(ff14_functor ff) : exprtk::ifunction(14), f(ff) {} +inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, +const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, +const T& v10, const T& v11, const T& v12, const T& v13) +{ return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12, v13); } +ff14_functor f; +}; + +struct freefunc15 : public exprtk::ifunction +{ +using exprtk::ifunction::operator(); + +explicit freefunc15(ff15_functor ff) : exprtk::ifunction(15), f(ff) {} +inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, +const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, +const T& v10, const T& v11, const T& v12, const T& v13, const T& v14) +{ return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12, v13, v14); } +ff15_functor f; +}; + +template +struct type_store +{ +typedef details::expression_node* expression_ptr; +typedef typename details::variable_node variable_node_t; +typedef ifunction ifunction_t; +typedef ivararg_function ivararg_function_t; +typedef igeneric_function igeneric_function_t; +typedef details::vector_holder vector_t; +#ifndef exprtk_disable_string_capabilities +typedef typename details::stringvar_node stringvar_node_t; +#endif + +typedef Type type_t; +typedef type_t* type_ptr; +typedef std::pair type_pair_t; +typedef std::map type_map_t; +typedef typename type_map_t::iterator tm_itr_t; +typedef typename type_map_t::const_iterator tm_const_itr_t; + +enum { lut_size = 256 }; + +type_map_t map; +std::size_t size; + +type_store() +: size(0) +{} + +struct deleter +{ +#define exprtk_define_process(Type) \ + static inline void process(std::pair& n) \ + { \ + delete n.second; \ + } \ + +exprtk_define_process(variable_node_t ) +exprtk_define_process(vector_t ) +#ifndef exprtk_disable_string_capabilities +exprtk_define_process(stringvar_node_t) +#endif + +#undef exprtk_define_process + +template +static inline void process(std::pair&) +{} +}; + +inline bool symbol_exists(const std::string& symbol_name) const +{ +if (symbol_name.empty()) +return false; +else if (map.end() != map.find(symbol_name)) +return true; +else +return false; +} + +template +inline std::string entity_name(const PtrType& ptr) const +{ +if (map.empty()) +return std::string(); + +tm_const_itr_t itr = map.begin(); + +while (map.end() != itr) +{ +if (itr->second.second == ptr) +{ +return itr->first; +} +else +++itr; +} + +return std::string(); +} + +inline bool is_constant(const std::string& symbol_name) const +{ +if (symbol_name.empty()) +return false; +else +{ +const tm_const_itr_t itr = map.find(symbol_name); + +if (map.end() == itr) +return false; +else +return (*itr).second.first; +} +} + +template +inline bool add_impl(const std::string& symbol_name, RType t, const bool is_const) +{ +if (symbol_name.size() > 1) +{ +for (std::size_t i = 0; i < details::reserved_symbols_size; ++i) +{ +if (details::imatch(symbol_name, details::reserved_symbols[i])) +{ +return false; +} +} +} + +const tm_itr_t itr = map.find(symbol_name); + +if (map.end() == itr) +{ +map[symbol_name] = Tie::make(t,is_const); +++size; +} + +return true; +} + +struct tie_array +{ +static inline std::pair make(std::pair v, const bool is_const = false) +{ +return std::make_pair(is_const, new vector_t(v.first, v.second)); +} +}; + +struct tie_stdvec +{ +template +static inline std::pair make(std::vector& v, const bool is_const = false) +{ +return std::make_pair(is_const, new vector_t(v)); +} +}; + +struct tie_vecview +{ +static inline std::pair make(exprtk::vector_view& v, const bool is_const = false) +{ +return std::make_pair(is_const, new vector_t(v)); +} +}; + +struct tie_stddeq +{ +template +static inline std::pair make(std::deque& v, const bool is_const = false) +{ +return std::make_pair(is_const, new vector_t(v)); +} +}; + +template +inline bool add(const std::string& symbol_name, T (&v)[v_size], const bool is_const = false) +{ +return add_impl > +(symbol_name, std::make_pair(v,v_size), is_const); +} + +inline bool add(const std::string& symbol_name, T* v, const std::size_t v_size, const bool is_const = false) +{ +return add_impl > +(symbol_name, std::make_pair(v,v_size), is_const); +} + +template +inline bool add(const std::string& symbol_name, std::vector& v, const bool is_const = false) +{ +return add_impl&> +(symbol_name, v, is_const); +} + +inline bool add(const std::string& symbol_name, exprtk::vector_view& v, const bool is_const = false) +{ +return add_impl&> +(symbol_name, v, is_const); +} + +template +inline bool add(const std::string& symbol_name, std::deque& v, const bool is_const = false) +{ +return add_impl&> +(symbol_name, v, is_const); +} + +inline bool add(const std::string& symbol_name, RawType& t_, const bool is_const = false) +{ +struct tie +{ +static inline std::pair make(T& t, const bool is_constant = false) +{ +return std::make_pair(is_constant, new variable_node_t(t)); +} + +#ifndef exprtk_disable_string_capabilities +static inline std::pair make(std::string& t, const bool is_constant = false) +{ +return std::make_pair(is_constant, new stringvar_node_t(t)); +} +#endif + +static inline std::pair make(function_t& t, const bool is_constant = false) +{ +return std::make_pair(is_constant,&t); +} + +static inline std::pair make(vararg_function_t& t, const bool is_constant = false) +{ +return std::make_pair(is_constant,&t); +} + +static inline std::pair make(generic_function_t& t, const bool is_constant = false) +{ +return std::make_pair(is_constant,&t); +} +}; + +const tm_itr_t itr = map.find(symbol_name); + +if (map.end() == itr) +{ +map[symbol_name] = tie::make(t_,is_const); +++size; +} + +return true; +} + +inline type_ptr get(const std::string& symbol_name) const +{ +const tm_const_itr_t itr = map.find(symbol_name); + +if (map.end() == itr) +return reinterpret_cast(0); +else +return itr->second.second; +} + +template +struct ptr_match +{ +static inline bool test(const PtrType, const void*) +{ +return false; +} +}; + +template +struct ptr_match +{ +static inline bool test(const variable_node_t* p, const void* ptr) +{ +exprtk_debug(("ptr_match::test() - %p <--> %p\n",(void*)(&(p->ref())),ptr)); +return (&(p->ref()) == ptr); +} +}; + +inline type_ptr get_from_varptr(const void* ptr) const +{ +tm_const_itr_t itr = map.begin(); + +while (map.end() != itr) +{ +type_ptr ret_ptr = itr->second.second; + +if (ptr_match::test(ret_ptr,ptr)) +{ +return ret_ptr; +} + +++itr; +} + +return type_ptr(0); +} + +inline bool remove(const std::string& symbol_name, const bool delete_node = true) +{ +const tm_itr_t itr = map.find(symbol_name); + +if (map.end() != itr) +{ +if (delete_node) +{ +deleter::process((*itr).second); +} + +map.erase(itr); +--size; + +return true; +} +else +return false; +} + +inline RawType& type_ref(const std::string& symbol_name) +{ +struct init_type +{ +static inline double set(double) { return (0.0); } +static inline double set(long double) { return (0.0); } +static inline float set(float) { return (0.0f); } +static inline std::string set(std::string) { return std::string(""); } +}; + +static RawType null_type = init_type::set(RawType()); + +const tm_const_itr_t itr = map.find(symbol_name); + +if (map.end() == itr) +return null_type; +else +return itr->second.second->ref(); +} + +inline void clear(const bool delete_node = true) +{ +if (!map.empty()) +{ +if (delete_node) +{ +tm_itr_t itr = map.begin(); +tm_itr_t end = map.end (); + +while (end != itr) +{ +deleter::process((*itr).second); +++itr; +} +} + +map.clear(); +} + +size = 0; +} + +template class Sequence> +inline std::size_t get_list(Sequence,Allocator>& list) const +{ +std::size_t count = 0; + +if (!map.empty()) +{ +tm_const_itr_t itr = map.begin(); +tm_const_itr_t end = map.end (); + +while (end != itr) +{ +list.push_back(std::make_pair((*itr).first,itr->second.second->ref())); +++itr; +++count; +} +} + +return count; +} + +template class Sequence> +inline std::size_t get_list(Sequence& vlist) const +{ +std::size_t count = 0; + +if (!map.empty()) +{ +tm_const_itr_t itr = map.begin(); +tm_const_itr_t end = map.end (); + +while (end != itr) +{ +vlist.push_back((*itr).first); +++itr; +++count; +} +} + +return count; +} +}; + +typedef details::expression_node* expression_ptr; +typedef typename details::variable_node variable_t; +typedef typename details::vector_holder vector_holder_t; +typedef variable_t* variable_ptr; +#ifndef exprtk_disable_string_capabilities +typedef typename details::stringvar_node stringvar_t; +typedef stringvar_t* stringvar_ptr; +#endif +typedef ifunction function_t; +typedef ivararg_function vararg_function_t; +typedef igeneric_function generic_function_t; +typedef function_t* function_ptr; +typedef vararg_function_t* vararg_function_ptr; +typedef generic_function_t* generic_function_ptr; + +static const std::size_t lut_size = 256; + +// Symbol Table Holder +struct control_block +{ +struct st_data +{ +type_store variable_store; +type_store function_store; +type_store vararg_function_store; +type_store generic_function_store; +type_store string_function_store; +type_store overload_function_store; +type_store vector_store; +#ifndef exprtk_disable_string_capabilities +type_store stringvar_store; +#endif + +st_data() +{ +for (std::size_t i = 0; i < details::reserved_words_size; ++i) +{ +reserved_symbol_table_.insert(details::reserved_words[i]); +} + +for (std::size_t i = 0; i < details::reserved_symbols_size; ++i) +{ +reserved_symbol_table_.insert(details::reserved_symbols[i]); +} +} + +~st_data() +{ +for (std::size_t i = 0; i < free_function_list_.size(); ++i) +{ +delete free_function_list_[i]; +} +} + +inline bool is_reserved_symbol(const std::string& symbol) const +{ +return (reserved_symbol_table_.end() != reserved_symbol_table_.find(symbol)); +} + +static inline st_data* create() +{ +return (new st_data); +} + +static inline void destroy(st_data*& sd) +{ +delete sd; +sd = reinterpret_cast(0); +} + +std::list local_symbol_list_; +std::list local_stringvar_list_; +std::set reserved_symbol_table_; +std::vector*> free_function_list_; +}; + +control_block() +: ref_count(1) +, data_(st_data::create()) +, mutability_(e_mutable) +{} + +explicit control_block(st_data* data) +: ref_count(1) +, data_(data) +, mutability_(e_mutable) +{} + +~control_block() +{ +if (data_ && (0 == ref_count)) +{ +st_data::destroy(data_); +} +} + +static inline control_block* create() +{ +return (new control_block); +} + +template +static inline void destroy(control_block*& cntrl_blck, SymTab* sym_tab) +{ +if (cntrl_blck) +{ +if ( +(0 != cntrl_blck->ref_count) && +(0 == --cntrl_blck->ref_count) +) +{ +if (sym_tab) +sym_tab->clear(); + +delete cntrl_blck; +} + +cntrl_blck = 0; +} +} + +void set_mutability(const symtab_mutability_type mutability) +{ +mutability_ = mutability; +} + +std::size_t ref_count; +st_data* data_; +symtab_mutability_type mutability_; +}; + +public: + +symbol_table(const symtab_mutability_type mutability = e_mutable) +: control_block_(control_block::create()) +{ +control_block_->set_mutability(mutability); +clear(); +} + +~symbol_table() +{ +exprtk::details::dump_ptr("~symbol_table", this); +control_block::destroy(control_block_, this); +} + +symbol_table(const symbol_table& st) +{ +control_block_ = st.control_block_; +control_block_->ref_count++; +} + +inline symbol_table& operator=(const symbol_table& st) +{ +if (this != &st) +{ +control_block::destroy(control_block_,reinterpret_cast*>(0)); + +control_block_ = st.control_block_; +control_block_->ref_count++; +} + +return (*this); +} + +inline bool operator==(const symbol_table& st) const +{ +return (this == &st) || (control_block_ == st.control_block_); +} + +inline symtab_mutability_type mutability() const +{ +return valid() ? control_block_->mutability_ : e_unknown; +} + +inline void clear_variables(const bool delete_node = true) +{ +local_data().variable_store.clear(delete_node); +} + +inline void clear_functions() +{ +local_data().function_store.clear(); +} + +inline void clear_strings() +{ +#ifndef exprtk_disable_string_capabilities +local_data().stringvar_store.clear(); +#endif +} + +inline void clear_vectors() +{ +local_data().vector_store.clear(); +} + +inline void clear_local_constants() +{ +local_data().local_symbol_list_.clear(); +} + +inline void clear() +{ +if (!valid()) return; +clear_variables (); +clear_functions (); +clear_strings (); +clear_vectors (); +clear_local_constants(); +} + +inline std::size_t variable_count() const +{ +if (valid()) +return local_data().variable_store.size; +else +return 0; +} + +#ifndef exprtk_disable_string_capabilities +inline std::size_t stringvar_count() const +{ +if (valid()) +return local_data().stringvar_store.size; +else +return 0; +} +#endif + +inline std::size_t function_count() const +{ +if (valid()) +return local_data().function_store.size; +else +return 0; +} + +inline std::size_t vector_count() const +{ +if (valid()) +return local_data().vector_store.size; +else +return 0; +} + +inline variable_ptr get_variable(const std::string& variable_name) const +{ +if (!valid()) +return reinterpret_cast(0); +else if (!valid_symbol(variable_name)) +return reinterpret_cast(0); +else +return local_data().variable_store.get(variable_name); +} + +inline variable_ptr get_variable(const T& var_ref) const +{ +if (!valid()) +return reinterpret_cast(0); +else +return local_data().variable_store.get_from_varptr( +reinterpret_cast(&var_ref)); +} + +#ifndef exprtk_disable_string_capabilities +inline stringvar_ptr get_stringvar(const std::string& string_name) const +{ +if (!valid()) +return reinterpret_cast(0); +else if (!valid_symbol(string_name)) +return reinterpret_cast(0); +else +return local_data().stringvar_store.get(string_name); +} + +inline stringvar_base get_stringvar_base(const std::string& string_name) const +{ +static stringvar_base null_stringvar_base("",reinterpret_cast(0)); +if (!valid()) +return null_stringvar_base; +else if (!valid_symbol(string_name)) +return null_stringvar_base; + +stringvar_ptr stringvar = local_data().stringvar_store.get(string_name); + +if (0 == stringvar) +{ +return null_stringvar_base; +} + +return stringvar_base(string_name,stringvar); +} +#endif + +inline function_ptr get_function(const std::string& function_name) const +{ +if (!valid()) +return reinterpret_cast(0); +else if (!valid_symbol(function_name)) +return reinterpret_cast(0); +else +return local_data().function_store.get(function_name); +} + +inline vararg_function_ptr get_vararg_function(const std::string& vararg_function_name) const +{ +if (!valid()) +return reinterpret_cast(0); +else if (!valid_symbol(vararg_function_name)) +return reinterpret_cast(0); +else +return local_data().vararg_function_store.get(vararg_function_name); +} + +inline generic_function_ptr get_generic_function(const std::string& function_name) const +{ +if (!valid()) +return reinterpret_cast(0); +else if (!valid_symbol(function_name)) +return reinterpret_cast(0); +else +return local_data().generic_function_store.get(function_name); +} + +inline generic_function_ptr get_string_function(const std::string& function_name) const +{ +if (!valid()) +return reinterpret_cast(0); +else if (!valid_symbol(function_name)) +return reinterpret_cast(0); +else +return local_data().string_function_store.get(function_name); +} + +inline generic_function_ptr get_overload_function(const std::string& function_name) const +{ +if (!valid()) +return reinterpret_cast(0); +else if (!valid_symbol(function_name)) +return reinterpret_cast(0); +else +return local_data().overload_function_store.get(function_name); +} + +typedef vector_holder_t* vector_holder_ptr; + +inline vector_holder_ptr get_vector(const std::string& vector_name) const +{ +if (!valid()) +return reinterpret_cast(0); +else if (!valid_symbol(vector_name)) +return reinterpret_cast(0); +else +return local_data().vector_store.get(vector_name); +} + +inline T& variable_ref(const std::string& symbol_name) +{ +static T null_var = T(0); +if (!valid()) +return null_var; +else if (!valid_symbol(symbol_name)) +return null_var; +else +return local_data().variable_store.type_ref(symbol_name); +} + +#ifndef exprtk_disable_string_capabilities +inline std::string& stringvar_ref(const std::string& symbol_name) +{ +static std::string null_stringvar; +if (!valid()) +return null_stringvar; +else if (!valid_symbol(symbol_name)) +return null_stringvar; +else +return local_data().stringvar_store.type_ref(symbol_name); +} +#endif + +inline bool is_constant_node(const std::string& symbol_name) const +{ +if (!valid()) +return false; +else if (!valid_symbol(symbol_name)) +return false; +else +return local_data().variable_store.is_constant(symbol_name); +} + +#ifndef exprtk_disable_string_capabilities +inline bool is_constant_string(const std::string& symbol_name) const +{ +if (!valid()) +return false; +else if (!valid_symbol(symbol_name)) +return false; +else if (!local_data().stringvar_store.symbol_exists(symbol_name)) +return false; +else +return local_data().stringvar_store.is_constant(symbol_name); +} +#endif + +inline bool create_variable(const std::string& variable_name, const T& value = T(0)) +{ +if (!valid()) +return false; +else if (!valid_symbol(variable_name)) +return false; +else if (symbol_exists(variable_name)) +return false; + +local_data().local_symbol_list_.push_back(value); +T& t = local_data().local_symbol_list_.back(); + +return add_variable(variable_name,t); +} + +#ifndef exprtk_disable_string_capabilities +inline bool create_stringvar(const std::string& stringvar_name, const std::string& value = std::string("")) +{ +if (!valid()) +return false; +else if (!valid_symbol(stringvar_name)) +return false; +else if (symbol_exists(stringvar_name)) +return false; + +local_data().local_stringvar_list_.push_back(value); +std::string& s = local_data().local_stringvar_list_.back(); + +return add_stringvar(stringvar_name,s); +} +#endif + +inline bool add_variable(const std::string& variable_name, T& t, const bool is_constant = false) +{ +if (!valid()) +return false; +else if (!valid_symbol(variable_name)) +return false; +else if (symbol_exists(variable_name)) +return false; +else +return local_data().variable_store.add(variable_name, t, is_constant); +} + +inline bool add_constant(const std::string& constant_name, const T& value) +{ +if (!valid()) +return false; +else if (!valid_symbol(constant_name)) +return false; +else if (symbol_exists(constant_name)) +return false; + +local_data().local_symbol_list_.push_back(value); +T& t = local_data().local_symbol_list_.back(); + +return add_variable(constant_name, t, true); +} + +#ifndef exprtk_disable_string_capabilities +inline bool add_stringvar(const std::string& stringvar_name, std::string& s, const bool is_constant = false) +{ +if (!valid()) +return false; +else if (!valid_symbol(stringvar_name)) +return false; +else if (symbol_exists(stringvar_name)) +return false; +else +return local_data().stringvar_store.add(stringvar_name, s, is_constant); +} +#endif + +inline bool add_function(const std::string& function_name, function_t& function) +{ +if (!valid()) +return false; +else if (!valid_symbol(function_name)) +return false; +else if (symbol_exists(function_name)) +return false; +else +return local_data().function_store.add(function_name,function); +} + +inline bool add_function(const std::string& vararg_function_name, vararg_function_t& vararg_function) +{ +if (!valid()) +return false; +else if (!valid_symbol(vararg_function_name)) +return false; +else if (symbol_exists(vararg_function_name)) +return false; +else +return local_data().vararg_function_store.add(vararg_function_name,vararg_function); +} + +inline bool add_function(const std::string& function_name, generic_function_t& function) +{ +if (!valid()) +return false; +else if (!valid_symbol(function_name)) +return false; +else if (symbol_exists(function_name)) +return false; +else +{ +switch (function.rtrn_type) +{ +case generic_function_t::e_rtrn_scalar : +return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|")) ? +local_data().generic_function_store.add(function_name,function) : false; + +case generic_function_t::e_rtrn_string : +return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|")) ? +local_data().string_function_store.add(function_name,function) : false; + +case generic_function_t::e_rtrn_overload : +return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|:")) ? +local_data().overload_function_store.add(function_name,function) : false; +} +} + +return false; +} + +#define exprtk_define_freefunction(NN) \ + inline bool add_function(const std::string& function_name, ff##NN##_functor function) \ + { \ + if (!valid()) \ + { return false; } \ + if (!valid_symbol(function_name)) \ + { return false; } \ + if (symbol_exists(function_name)) \ + { return false; } \ + \ + exprtk::ifunction* ifunc = new freefunc##NN(function); \ + \ + local_data().free_function_list_.push_back(ifunc); \ + \ + return add_function(function_name,(*local_data().free_function_list_.back())); \ + } \ + +exprtk_define_freefunction(00) exprtk_define_freefunction(01) +exprtk_define_freefunction(02) exprtk_define_freefunction(03) +exprtk_define_freefunction(04) exprtk_define_freefunction(05) +exprtk_define_freefunction(06) exprtk_define_freefunction(07) +exprtk_define_freefunction(08) exprtk_define_freefunction(09) +exprtk_define_freefunction(10) exprtk_define_freefunction(11) +exprtk_define_freefunction(12) exprtk_define_freefunction(13) +exprtk_define_freefunction(14) exprtk_define_freefunction(15) + +#undef exprtk_define_freefunction + +inline bool add_reserved_function(const std::string& function_name, function_t& function) +{ +if (!valid()) +return false; +else if (!valid_symbol(function_name,false)) +return false; +else if (symbol_exists(function_name,false)) +return false; +else +return local_data().function_store.add(function_name,function); +} + +inline bool add_reserved_function(const std::string& vararg_function_name, vararg_function_t& vararg_function) +{ +if (!valid()) +return false; +else if (!valid_symbol(vararg_function_name,false)) +return false; +else if (symbol_exists(vararg_function_name,false)) +return false; +else +return local_data().vararg_function_store.add(vararg_function_name,vararg_function); +} + +inline bool add_reserved_function(const std::string& function_name, generic_function_t& function) +{ +if (!valid()) +return false; +else if (!valid_symbol(function_name,false)) +return false; +else if (symbol_exists(function_name,false)) +return false; +else +{ +switch (function.rtrn_type) +{ +case generic_function_t::e_rtrn_scalar : +return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|")) ? +local_data().generic_function_store.add(function_name,function) : false; + +case generic_function_t::e_rtrn_string : +return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|")) ? +local_data().string_function_store.add(function_name,function) : false; + +case generic_function_t::e_rtrn_overload : +return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|:")) ? +local_data().overload_function_store.add(function_name,function) : false; +} +} + +return false; +} + +template +inline bool add_vector(const std::string& vector_name, T (&v)[N]) +{ +if (!valid()) +return false; +else if (!valid_symbol(vector_name)) +return false; +else if (symbol_exists(vector_name)) +return false; +else +return local_data().vector_store.add(vector_name,v); +} + +inline bool add_vector(const std::string& vector_name, T* v, const std::size_t& v_size) +{ +if (!valid()) +return false; +else if (!valid_symbol(vector_name)) +return false; +else if (symbol_exists(vector_name)) +return false; +else if (0 == v_size) +return false; +else +return local_data().vector_store.add(vector_name, v, v_size); +} + +template +inline bool add_vector(const std::string& vector_name, std::vector& v) +{ +if (!valid()) +return false; +else if (!valid_symbol(vector_name)) +return false; +else if (symbol_exists(vector_name)) +return false; +else if (0 == v.size()) +return false; +else +return local_data().vector_store.add(vector_name,v); +} + +inline bool add_vector(const std::string& vector_name, exprtk::vector_view& v) +{ +if (!valid()) +return false; +else if (!valid_symbol(vector_name)) +return false; +else if (symbol_exists(vector_name)) +return false; +else if (0 == v.size()) +return false; +else +return local_data().vector_store.add(vector_name,v); +} + +inline bool remove_variable(const std::string& variable_name, const bool delete_node = true) +{ +if (!valid()) +return false; +else +return local_data().variable_store.remove(variable_name, delete_node); +} + +#ifndef exprtk_disable_string_capabilities +inline bool remove_stringvar(const std::string& string_name) +{ +if (!valid()) +return false; +else +return local_data().stringvar_store.remove(string_name); +} +#endif + +inline bool remove_function(const std::string& function_name) +{ +if (!valid()) +return false; +else +return local_data().function_store.remove(function_name); +} + +inline bool remove_vararg_function(const std::string& vararg_function_name) +{ +if (!valid()) +return false; +else +return local_data().vararg_function_store.remove(vararg_function_name); +} + +inline bool remove_vector(const std::string& vector_name) +{ +if (!valid()) +return false; +else +return local_data().vector_store.remove(vector_name); +} + +inline bool add_constants() +{ +return add_pi () && +add_epsilon () && +add_infinity() ; +} + +inline bool add_pi() +{ +const typename details::numeric::details::number_type::type num_type; +static const T local_pi = details::numeric::details::const_pi_impl(num_type); +return add_constant("pi",local_pi); +} + +inline bool add_epsilon() +{ +static const T local_epsilon = details::numeric::details::epsilon_type::value(); +return add_constant("epsilon",local_epsilon); +} + +inline bool add_infinity() +{ +static const T local_infinity = std::numeric_limits::infinity(); +return add_constant("inf",local_infinity); +} + +template +inline bool add_package(Package& package) +{ +return package.register_package(*this); +} + +template class Sequence> +inline std::size_t get_variable_list(Sequence,Allocator>& vlist) const +{ +if (!valid()) +return 0; +else +return local_data().variable_store.get_list(vlist); +} + +template class Sequence> +inline std::size_t get_variable_list(Sequence& vlist) const +{ +if (!valid()) +return 0; +else +return local_data().variable_store.get_list(vlist); +} + +#ifndef exprtk_disable_string_capabilities +template class Sequence> +inline std::size_t get_stringvar_list(Sequence,Allocator>& svlist) const +{ +if (!valid()) +return 0; +else +return local_data().stringvar_store.get_list(svlist); +} + +template class Sequence> +inline std::size_t get_stringvar_list(Sequence& svlist) const +{ +if (!valid()) +return 0; +else +return local_data().stringvar_store.get_list(svlist); +} +#endif + +template class Sequence> +inline std::size_t get_vector_list(Sequence& vlist) const +{ +if (!valid()) +return 0; +else +return local_data().vector_store.get_list(vlist); +} + +inline bool symbol_exists(const std::string& symbol_name, const bool check_reserved_symb = true) const +{ +/* + Function will return true if symbol_name exists as either a + reserved symbol, variable, stringvar, vector or function name + in any of the type stores. + */ +if (!valid()) +return false; +else if (local_data().variable_store.symbol_exists(symbol_name)) +return true; +#ifndef exprtk_disable_string_capabilities +else if (local_data().stringvar_store.symbol_exists(symbol_name)) +return true; +#endif +else if (local_data().vector_store.symbol_exists(symbol_name)) +return true; +else if (local_data().function_store.symbol_exists(symbol_name)) +return true; +else if (check_reserved_symb && local_data().is_reserved_symbol(symbol_name)) +return true; +else +return false; +} + +inline bool is_variable(const std::string& variable_name) const +{ +if (!valid()) +return false; +else +return local_data().variable_store.symbol_exists(variable_name); +} + +#ifndef exprtk_disable_string_capabilities +inline bool is_stringvar(const std::string& stringvar_name) const +{ +if (!valid()) +return false; +else +return local_data().stringvar_store.symbol_exists(stringvar_name); +} + +inline bool is_conststr_stringvar(const std::string& symbol_name) const +{ +if (!valid()) +return false; +else if (!valid_symbol(symbol_name)) +return false; +else if (!local_data().stringvar_store.symbol_exists(symbol_name)) +return false; + +return ( +local_data().stringvar_store.symbol_exists(symbol_name) || +local_data().stringvar_store.is_constant (symbol_name) +); +} +#endif + +inline bool is_function(const std::string& function_name) const +{ +if (!valid()) +return false; +else +return local_data().function_store.symbol_exists(function_name); +} + +inline bool is_vararg_function(const std::string& vararg_function_name) const +{ +if (!valid()) +return false; +else +return local_data().vararg_function_store.symbol_exists(vararg_function_name); +} + +inline bool is_vector(const std::string& vector_name) const +{ +if (!valid()) +return false; +else +return local_data().vector_store.symbol_exists(vector_name); +} + +inline std::string get_variable_name(const expression_ptr& ptr) const +{ +return local_data().variable_store.entity_name(ptr); +} + +inline std::string get_vector_name(const vector_holder_ptr& ptr) const +{ +return local_data().vector_store.entity_name(ptr); +} + +#ifndef exprtk_disable_string_capabilities +inline std::string get_stringvar_name(const expression_ptr& ptr) const +{ +return local_data().stringvar_store.entity_name(ptr); +} + +inline std::string get_conststr_stringvar_name(const expression_ptr& ptr) const +{ +return local_data().stringvar_store.entity_name(ptr); +} +#endif + +inline bool valid() const +{ +// Symbol table sanity check. +return control_block_ && control_block_->data_; +} + +inline void load_from(const symbol_table& st) +{ +{ +std::vector name_list; + +st.local_data().function_store.get_list(name_list); + +if (!name_list.empty()) +{ +for (std::size_t i = 0; i < name_list.size(); ++i) +{ +exprtk::ifunction& ifunc = *st.get_function(name_list[i]); +add_function(name_list[i],ifunc); +} +} +} + +{ +std::vector name_list; + +st.local_data().vararg_function_store.get_list(name_list); + +if (!name_list.empty()) +{ +for (std::size_t i = 0; i < name_list.size(); ++i) +{ +exprtk::ivararg_function& ivafunc = *st.get_vararg_function(name_list[i]); +add_function(name_list[i],ivafunc); +} +} +} + +{ +std::vector name_list; + +st.local_data().generic_function_store.get_list(name_list); + +if (!name_list.empty()) +{ +for (std::size_t i = 0; i < name_list.size(); ++i) +{ +exprtk::igeneric_function& ifunc = *st.get_generic_function(name_list[i]); +add_function(name_list[i],ifunc); +} +} +} + +{ +std::vector name_list; + +st.local_data().string_function_store.get_list(name_list); + +if (!name_list.empty()) +{ +for (std::size_t i = 0; i < name_list.size(); ++i) +{ +exprtk::igeneric_function& ifunc = *st.get_string_function(name_list[i]); +add_function(name_list[i],ifunc); +} +} +} + +{ +std::vector name_list; + +st.local_data().overload_function_store.get_list(name_list); + +if (!name_list.empty()) +{ +for (std::size_t i = 0; i < name_list.size(); ++i) +{ +exprtk::igeneric_function& ifunc = *st.get_overload_function(name_list[i]); +add_function(name_list[i],ifunc); +} +} +} +} + +private: + +inline bool valid_symbol(const std::string& symbol, const bool check_reserved_symb = true) const +{ +if (symbol.empty()) +return false; +else if (!details::is_letter(symbol[0])) +return false; +else if (symbol.size() > 1) +{ +for (std::size_t i = 1; i < symbol.size(); ++i) +{ +if ( +!details::is_letter_or_digit(symbol[i]) && +('_' != symbol[i]) +) +{ +if ((i < (symbol.size() - 1)) && ('.' == symbol[i])) +continue; +else +return false; +} +} +} + +return (check_reserved_symb) ? (!local_data().is_reserved_symbol(symbol)) : true; +} + +inline bool valid_function(const std::string& symbol) const +{ +if (symbol.empty()) +return false; +else if (!details::is_letter(symbol[0])) +return false; +else if (symbol.size() > 1) +{ +for (std::size_t i = 1; i < symbol.size(); ++i) +{ +if ( +!details::is_letter_or_digit(symbol[i]) && +('_' != symbol[i]) +) +{ +if ((i < (symbol.size() - 1)) && ('.' == symbol[i])) +continue; +else +return false; +} +} +} + +return true; +} + +typedef typename control_block::st_data local_data_t; + +inline local_data_t& local_data() +{ +return *(control_block_->data_); +} + +inline const local_data_t& local_data() const +{ +return *(control_block_->data_); +} + +control_block* control_block_; + +friend class parser; +}; // class symbol_table + +template +class function_compositor; + +template +class expression +{ +private: + +typedef details::expression_node* expression_ptr; +typedef details::vector_holder* vector_holder_ptr; +typedef std::vector > symtab_list_t; + +struct control_block +{ +enum data_type +{ +e_unknown , +e_expr , +e_vecholder, +e_data , +e_vecdata , +e_string +}; + +struct data_pack +{ +data_pack() +: pointer(0) +, type(e_unknown) +, size(0) +{} + +data_pack(void* ptr, const data_type dt, const std::size_t sz = 0) +: pointer(ptr) +, type(dt) +, size(sz) +{} + +void* pointer; +data_type type; +std::size_t size; +}; + +typedef std::vector local_data_list_t; +typedef results_context results_context_t; +typedef control_block* cntrl_blck_ptr_t; + +control_block() +: ref_count(0) +, expr (0) +, results (0) +, retinv_null(false) +, return_invoked(&retinv_null) +{} + +explicit control_block(expression_ptr e) +: ref_count(1) +, expr (e) +, results (0) +, retinv_null(false) +, return_invoked(&retinv_null) +{} + +~control_block() +{ +if (expr && details::branch_deletable(expr)) +{ +destroy_node(expr); +} + +if (!local_data_list.empty()) +{ +for (std::size_t i = 0; i < local_data_list.size(); ++i) +{ +switch (local_data_list[i].type) +{ +case e_expr : delete reinterpret_cast(local_data_list[i].pointer); +break; + +case e_vecholder : delete reinterpret_cast(local_data_list[i].pointer); +break; + +case e_data : delete reinterpret_cast(local_data_list[i].pointer); +break; + +case e_vecdata : delete [] reinterpret_cast(local_data_list[i].pointer); +break; + +case e_string : delete reinterpret_cast(local_data_list[i].pointer); +break; + +default : break; +} +} +} + +if (results) +{ +delete results; +} +} + +static inline cntrl_blck_ptr_t create(expression_ptr e) +{ +return new control_block(e); +} + +static inline void destroy(cntrl_blck_ptr_t& cntrl_blck) +{ +if (cntrl_blck) +{ +if ( +(0 != cntrl_blck->ref_count) && +(0 == --cntrl_blck->ref_count) +) +{ +delete cntrl_blck; +} + +cntrl_blck = 0; +} +} + +std::size_t ref_count; +expression_ptr expr; +local_data_list_t local_data_list; +results_context_t* results; +bool retinv_null; +bool* return_invoked; + +friend class function_compositor; +}; + +public: + +expression() +: control_block_(0) +{ +set_expression(new details::null_node()); +} + +expression(const expression& e) +: control_block_ (e.control_block_ ) +, symbol_table_list_(e.symbol_table_list_) +{ +control_block_->ref_count++; +} + +explicit expression(const symbol_table& symbol_table) +: control_block_(0) +{ +set_expression(new details::null_node()); +symbol_table_list_.push_back(symbol_table); +} + +inline expression& operator=(const expression& e) +{ +if (this != &e) +{ +if (control_block_) +{ +if ( +(0 != control_block_->ref_count) && +(0 == --control_block_->ref_count) +) +{ +delete control_block_; +} + +control_block_ = 0; +} + +control_block_ = e.control_block_; +control_block_->ref_count++; +symbol_table_list_ = e.symbol_table_list_; +} + +return *this; +} + +inline bool operator==(const expression& e) const +{ +return (this == &e); +} + +inline bool operator!() const +{ +return ( +(0 == control_block_ ) || +(0 == control_block_->expr) +); +} + +inline expression& release() +{ +exprtk::details::dump_ptr("expression::release", this); +control_block::destroy(control_block_); + +return (*this); +} + +~expression() +{ +control_block::destroy(control_block_); +} + +inline T value() const +{ +assert(control_block_ ); +assert(control_block_->expr); + +return control_block_->expr->value(); +} + +inline T operator() () const +{ +return value(); +} + +inline operator T() const +{ +return value(); +} + +inline operator bool() const +{ +return details::is_true(value()); +} + +inline void register_symbol_table(symbol_table& st) +{ +for (std::size_t i = 0; i < symbol_table_list_.size(); ++i) +{ +if (&st == &symbol_table_list_[i]) +{ +return; +} +} + +symbol_table_list_.push_back(st); +} + +inline const symbol_table& get_symbol_table(const std::size_t& index = 0) const +{ +return symbol_table_list_[index]; +} + +inline symbol_table& get_symbol_table(const std::size_t& index = 0) +{ +return symbol_table_list_[index]; +} + +typedef results_context results_context_t; + +inline const results_context_t& results() const +{ +if (control_block_->results) +return (*control_block_->results); +else +{ +static const results_context_t null_results; +return null_results; +} +} + +inline bool return_invoked() const +{ +return (*control_block_->return_invoked); +} + +private: + +inline symtab_list_t get_symbol_table_list() const +{ +return symbol_table_list_; +} + +inline void set_expression(const expression_ptr expr) +{ +if (expr) +{ +if (control_block_) +{ +if (0 == --control_block_->ref_count) +{ +delete control_block_; +} +} + +control_block_ = control_block::create(expr); +} +} + +inline void register_local_var(expression_ptr expr) +{ +if (expr) +{ +if (control_block_) +{ +control_block_-> +local_data_list.push_back( +typename expression::control_block:: +data_pack(reinterpret_cast(expr), +control_block::e_expr)); +} +} +} + +inline void register_local_var(vector_holder_ptr vec_holder) +{ +if (vec_holder) +{ +if (control_block_) +{ +control_block_-> +local_data_list.push_back( +typename expression::control_block:: +data_pack(reinterpret_cast(vec_holder), +control_block::e_vecholder)); +} +} +} + +inline void register_local_data(void* data, const std::size_t& size = 0, const std::size_t data_mode = 0) +{ +if (data) +{ +if (control_block_) +{ +typename control_block::data_type dt = control_block::e_data; + +switch (data_mode) +{ +case 0 : dt = control_block::e_data; break; +case 1 : dt = control_block::e_vecdata; break; +case 2 : dt = control_block::e_string; break; +} + +control_block_-> +local_data_list.push_back( +typename expression::control_block:: +data_pack(reinterpret_cast(data), dt, size)); +} +} +} + +inline const typename control_block::local_data_list_t& local_data_list() +{ +if (control_block_) +{ +return control_block_->local_data_list; +} +else +{ +static typename control_block::local_data_list_t null_local_data_list; +return null_local_data_list; +} +} + +inline void register_return_results(results_context_t* rc) +{ +if (control_block_ && rc) +{ +control_block_->results = rc; +} +} + +inline void set_retinvk(bool* retinvk_ptr) +{ +if (control_block_) +{ +control_block_->return_invoked = retinvk_ptr; +} +} + +control_block* control_block_; +symtab_list_t symbol_table_list_; + +friend class parser; +friend class expression_helper; +friend class function_compositor; +}; // class expression + +template +class expression_helper +{ +public: + +static inline bool is_constant(const expression& expr) +{ +return details::is_constant_node(expr.control_block_->expr); +} + +static inline bool is_variable(const expression& expr) +{ +return details::is_variable_node(expr.control_block_->expr); +} + +static inline bool is_unary(const expression& expr) +{ +return details::is_unary_node(expr.control_block_->expr); +} + +static inline bool is_binary(const expression& expr) +{ +return details::is_binary_node(expr.control_block_->expr); +} + +static inline bool is_function(const expression& expr) +{ +return details::is_function(expr.control_block_->expr); +} + +static inline bool is_null(const expression& expr) +{ +return details::is_null_node(expr.control_block_->expr); +} +}; + +template +inline bool is_valid(const expression& expr) +{ +return !expression_helper::is_null(expr); +} + +namespace parser_error +{ +enum error_mode +{ +e_unknown = 0, +e_syntax = 1, +e_token = 2, +e_numeric = 4, +e_symtab = 5, +e_lexer = 6, +e_helper = 7, +e_parser = 8 +}; + +struct type +{ +type() +: mode(parser_error::e_unknown) +, line_no (0) +, column_no(0) +{} + +lexer::token token; +error_mode mode; +std::string diagnostic; +std::string src_location; +std::string error_line; +std::size_t line_no; +std::size_t column_no; +}; + +inline type make_error(const error_mode mode, +const std::string& diagnostic = "", +const std::string& src_location = "") +{ +type t; +t.mode = mode; +t.token.type = lexer::token::e_error; +t.diagnostic = diagnostic; +t.src_location = src_location; +exprtk_debug(("%s\n",diagnostic .c_str())); +return t; +} + +inline type make_error(const error_mode mode, +const lexer::token& tk, +const std::string& diagnostic = "", +const std::string& src_location = "") +{ +type t; +t.mode = mode; +t.token = tk; +t.diagnostic = diagnostic; +t.src_location = src_location; +exprtk_debug(("%s\n",diagnostic .c_str())); +return t; +} + +inline std::string to_str(error_mode mode) +{ +switch (mode) +{ +case e_unknown : return std::string("Unknown Error"); +case e_syntax : return std::string("Syntax Error" ); +case e_token : return std::string("Token Error" ); +case e_numeric : return std::string("Numeric Error"); +case e_symtab : return std::string("Symbol Error" ); +case e_lexer : return std::string("Lexer Error" ); +case e_helper : return std::string("Helper Error" ); +case e_parser : return std::string("Parser Error" ); +default : return std::string("Unknown Error"); +} +} + +inline bool update_error(type& error, const std::string& expression) +{ +if ( +expression.empty() || +(error.token.position > expression.size()) || +(std::numeric_limits::max() == error.token.position) +) +{ +return false; +} + +std::size_t error_line_start = 0; + +for (std::size_t i = error.token.position; i > 0; --i) +{ +const details::char_t c = expression[i]; + +if (('\n' == c) || ('\r' == c)) +{ +error_line_start = i + 1; +break; +} +} + +std::size_t next_nl_position = std::min(expression.size(), +expression.find_first_of('\n',error.token.position + 1)); + +error.column_no = error.token.position - error_line_start; +error.error_line = expression.substr(error_line_start, +next_nl_position - error_line_start); + +error.line_no = 0; + +for (std::size_t i = 0; i < next_nl_position; ++i) +{ +if ('\n' == expression[i]) +++error.line_no; +} + +return true; +} + +inline void dump_error(const type& error) +{ +printf("Position: %02d Type: [%s] Msg: %s\n", +static_cast(error.token.position), +exprtk::parser_error::to_str(error.mode).c_str(), +error.diagnostic.c_str()); +} +} + +namespace details +{ +template +inline void disable_type_checking(Parser& p) +{ +p.state_.type_check_enabled = false; +} +} + +template +class parser : public lexer::parser_helper +{ +private: + +enum precedence_level +{ +e_level00, e_level01, e_level02, e_level03, e_level04, +e_level05, e_level06, e_level07, e_level08, e_level09, +e_level10, e_level11, e_level12, e_level13, e_level14 +}; + +typedef const T& cref_t; +typedef const T const_t; +typedef ifunction F; +typedef ivararg_function VAF; +typedef igeneric_function GF; +typedef ifunction ifunction_t; +typedef ivararg_function ivararg_function_t; +typedef igeneric_function igeneric_function_t; +typedef details::expression_node expression_node_t; +typedef details::literal_node literal_node_t; +typedef details::unary_node unary_node_t; +typedef details::binary_node binary_node_t; +typedef details::trinary_node trinary_node_t; +typedef details::quaternary_node quaternary_node_t; +typedef details::conditional_node conditional_node_t; +typedef details::cons_conditional_node cons_conditional_node_t; +typedef details::while_loop_node while_loop_node_t; +typedef details::repeat_until_loop_node repeat_until_loop_node_t; +typedef details::for_loop_node for_loop_node_t; +typedef details::while_loop_rtc_node while_loop_rtc_node_t; +typedef details::repeat_until_loop_rtc_node repeat_until_loop_rtc_node_t; +typedef details::for_loop_rtc_node for_loop_rtc_node_t; +#ifndef exprtk_disable_break_continue +typedef details::while_loop_bc_node while_loop_bc_node_t; +typedef details::repeat_until_loop_bc_node repeat_until_loop_bc_node_t; +typedef details::for_loop_bc_node for_loop_bc_node_t; +typedef details::while_loop_bc_rtc_node while_loop_bc_rtc_node_t; +typedef details::repeat_until_loop_bc_rtc_node repeat_until_loop_bc_rtc_node_t; +typedef details::for_loop_bc_rtc_node for_loop_bc_rtc_node_t; +#endif +typedef details::switch_node switch_node_t; +typedef details::variable_node variable_node_t; +typedef details::vector_elem_node vector_elem_node_t; +typedef details::rebasevector_elem_node rebasevector_elem_node_t; +typedef details::rebasevector_celem_node rebasevector_celem_node_t; +typedef details::vector_node vector_node_t; +typedef details::range_pack range_t; +#ifndef exprtk_disable_string_capabilities +typedef details::stringvar_node stringvar_node_t; +typedef details::string_literal_node string_literal_node_t; +typedef details::string_range_node string_range_node_t; +typedef details::const_string_range_node const_string_range_node_t; +typedef details::generic_string_range_node generic_string_range_node_t; +typedef details::string_concat_node string_concat_node_t; +typedef details::assignment_string_node assignment_string_node_t; +typedef details::assignment_string_range_node assignment_string_range_node_t; +typedef details::conditional_string_node conditional_string_node_t; +typedef details::cons_conditional_str_node cons_conditional_str_node_t; +#endif +typedef details::assignment_node assignment_node_t; +typedef details::assignment_vec_elem_node assignment_vec_elem_node_t; +typedef details::assignment_rebasevec_elem_node assignment_rebasevec_elem_node_t; +typedef details::assignment_rebasevec_celem_node assignment_rebasevec_celem_node_t; +typedef details::assignment_vec_node assignment_vec_node_t; +typedef details::assignment_vecvec_node assignment_vecvec_node_t; +typedef details::conditional_vector_node conditional_vector_node_t; +typedef details::scand_node scand_node_t; +typedef details::scor_node scor_node_t; +typedef lexer::token token_t; +typedef expression_node_t* expression_node_ptr; +typedef expression expression_t; +typedef symbol_table symbol_table_t; +typedef typename expression::symtab_list_t symbol_table_list_t; +typedef details::vector_holder* vector_holder_ptr; + +typedef typename details::functor_t functor_t; +typedef typename functor_t::qfunc_t quaternary_functor_t; +typedef typename functor_t::tfunc_t trinary_functor_t; +typedef typename functor_t::bfunc_t binary_functor_t; +typedef typename functor_t::ufunc_t unary_functor_t; + +typedef details::operator_type operator_t; + +typedef std::map unary_op_map_t; +typedef std::map binary_op_map_t; +typedef std::map trinary_op_map_t; + +typedef std::map > sf3_map_t; +typedef std::map > sf4_map_t; + +typedef std::map inv_binary_op_map_t; +typedef std::multimap base_ops_map_t; +typedef std::set disabled_func_set_t; + +typedef details::T0oT1_define vov_t; +typedef details::T0oT1_define cov_t; +typedef details::T0oT1_define voc_t; + +typedef details::T0oT1oT2_define vovov_t; +typedef details::T0oT1oT2_define vovoc_t; +typedef details::T0oT1oT2_define vocov_t; +typedef details::T0oT1oT2_define covov_t; +typedef details::T0oT1oT2_define covoc_t; +typedef details::T0oT1oT2_define cocov_t; +typedef details::T0oT1oT2_define vococ_t; + +typedef details::T0oT1oT2oT3_define vovovov_t; +typedef details::T0oT1oT2oT3_define vovovoc_t; +typedef details::T0oT1oT2oT3_define vovocov_t; +typedef details::T0oT1oT2oT3_define vocovov_t; +typedef details::T0oT1oT2oT3_define covovov_t; + +typedef details::T0oT1oT2oT3_define covocov_t; +typedef details::T0oT1oT2oT3_define vocovoc_t; +typedef details::T0oT1oT2oT3_define covovoc_t; +typedef details::T0oT1oT2oT3_define vococov_t; + +typedef results_context results_context_t; + +typedef parser_helper prsrhlpr_t; + +struct scope_element +{ +enum element_type +{ +e_none , +e_variable, +e_vector , +e_vecelem , +e_string +}; + +typedef details::vector_holder vector_holder_t; +typedef variable_node_t* variable_node_ptr; +typedef vector_holder_t* vector_holder_ptr; +typedef expression_node_t* expression_node_ptr; +#ifndef exprtk_disable_string_capabilities +typedef stringvar_node_t* stringvar_node_ptr; +#endif + +scope_element() +: name("???") +, size (std::numeric_limits::max()) +, index(std::numeric_limits::max()) +, depth(std::numeric_limits::max()) +, ref_count(0) +, ip_index (0) +, type (e_none) +, active(false) +, data (0) +, var_node (0) +, vec_node (0) +#ifndef exprtk_disable_string_capabilities +, str_node(0) +#endif +{} + +bool operator < (const scope_element& se) const +{ +if (ip_index < se.ip_index) +return true; +else if (ip_index > se.ip_index) +return false; +else if (depth < se.depth) +return true; +else if (depth > se.depth) +return false; +else if (index < se.index) +return true; +else if (index > se.index) +return false; +else +return (name < se.name); +} + +void clear() +{ +name = "???"; +size = std::numeric_limits::max(); +index = std::numeric_limits::max(); +depth = std::numeric_limits::max(); +type = e_none; +active = false; +ref_count = 0; +ip_index = 0; +data = 0; +var_node = 0; +vec_node = 0; +#ifndef exprtk_disable_string_capabilities +str_node = 0; +#endif +} + +std::string name; +std::size_t size; +std::size_t index; +std::size_t depth; +std::size_t ref_count; +std::size_t ip_index; +element_type type; +bool active; +void* data; +expression_node_ptr var_node; +vector_holder_ptr vec_node; +#ifndef exprtk_disable_string_capabilities +stringvar_node_ptr str_node; +#endif +}; + +class scope_element_manager +{ +public: + +typedef expression_node_t* expression_node_ptr; +typedef variable_node_t* variable_node_ptr; +typedef parser parser_t; + +explicit scope_element_manager(parser& p) +: parser_(p) +, input_param_cnt_(0) +{} + +inline std::size_t size() const +{ +return element_.size(); +} + +inline bool empty() const +{ +return element_.empty(); +} + +inline scope_element& get_element(const std::size_t& index) +{ +if (index < element_.size()) +return element_[index]; +else +return null_element_; +} + +inline scope_element& get_element(const std::string& var_name, +const std::size_t index = std::numeric_limits::max()) +{ +const std::size_t current_depth = parser_.state_.scope_depth; + +for (std::size_t i = 0; i < element_.size(); ++i) +{ +scope_element& se = element_[i]; + +if (se.depth > current_depth) +continue; +else if ( +details::imatch(se.name, var_name) && +(se.index == index) +) +return se; +} + +return null_element_; +} + +inline scope_element& get_active_element(const std::string& var_name, +const std::size_t index = std::numeric_limits::max()) +{ +const std::size_t current_depth = parser_.state_.scope_depth; + +for (std::size_t i = 0; i < element_.size(); ++i) +{ +scope_element& se = element_[i]; + +if (se.depth > current_depth) +continue; +else if ( +details::imatch(se.name, var_name) && +(se.index == index) && +(se.active) +) +return se; +} + +return null_element_; +} + +inline bool add_element(const scope_element& se) +{ +for (std::size_t i = 0; i < element_.size(); ++i) +{ +scope_element& cse = element_[i]; + +if ( +details::imatch(cse.name, se.name) && +(cse.depth <= se.depth) && +(cse.index == se.index) && +(cse.size == se.size ) && +(cse.type == se.type ) && +(cse.active) +) +return false; +} + +element_.push_back(se); +std::sort(element_.begin(),element_.end()); + +return true; +} + +inline void deactivate(const std::size_t& scope_depth) +{ +exprtk_debug(("deactivate() - Scope depth: %d\n", +static_cast(parser_.state_.scope_depth))); + +for (std::size_t i = 0; i < element_.size(); ++i) +{ +scope_element& se = element_[i]; + +if (se.active && (se.depth >= scope_depth)) +{ +exprtk_debug(("deactivate() - element[%02d] '%s'\n", +static_cast(i), +se.name.c_str())); + +se.active = false; +} +} +} + +inline void free_element(scope_element& se) +{ +exprtk_debug(("free_element() - se[%s]\n", se.name.c_str())); + +switch (se.type) +{ +case scope_element::e_variable : delete reinterpret_cast(se.data); +delete se.var_node; +break; + +case scope_element::e_vector : delete[] reinterpret_cast(se.data); +delete se.vec_node; +break; + +case scope_element::e_vecelem : delete se.var_node; +break; + +#ifndef exprtk_disable_string_capabilities +case scope_element::e_string : delete reinterpret_cast(se.data); +delete se.str_node; +break; +#endif + +default : return; +} + +se.clear(); +} + +inline void cleanup() +{ +for (std::size_t i = 0; i < element_.size(); ++i) +{ +free_element(element_[i]); +} + +element_.clear(); + +input_param_cnt_ = 0; +} + +inline std::size_t next_ip_index() +{ +return ++input_param_cnt_; +} + +inline expression_node_ptr get_variable(const T& v) +{ +for (std::size_t i = 0; i < element_.size(); ++i) +{ +scope_element& se = element_[i]; + +if ( +se.active && +se.var_node && +details::is_variable_node(se.var_node) +) +{ +variable_node_ptr vn = reinterpret_cast(se.var_node); + +if (&(vn->ref()) == (&v)) +{ +return se.var_node; +} +} +} + +return expression_node_ptr(0); +} + +private: + +scope_element_manager(const scope_element_manager&) exprtk_delete; +scope_element_manager& operator=(const scope_element_manager&) exprtk_delete; + +parser_t& parser_; +std::vector element_; +scope_element null_element_; +std::size_t input_param_cnt_; +}; + +class scope_handler +{ +public: + +typedef parser parser_t; + +explicit scope_handler(parser& p) +: parser_(p) +{ +parser_.state_.scope_depth++; +#ifdef exprtk_enable_debugging +const std::string depth(2 * parser_.state_.scope_depth,'-'); +exprtk_debug(("%s> Scope Depth: %02d\n", +depth.c_str(), +static_cast(parser_.state_.scope_depth))); +#endif +} + +~scope_handler() +{ +parser_.sem_.deactivate(parser_.state_.scope_depth); +parser_.state_.scope_depth--; +#ifdef exprtk_enable_debugging +const std::string depth(2 * parser_.state_.scope_depth,'-'); +exprtk_debug(("<%s Scope Depth: %02d\n", +depth.c_str(), +static_cast(parser_.state_.scope_depth))); +#endif +} + +private: + +scope_handler(const scope_handler&) exprtk_delete; +scope_handler& operator=(const scope_handler&) exprtk_delete; + +parser_t& parser_; +}; + +template +struct halfopen_range_policy +{ +static inline bool is_within(const T_& v, const T_& begin, const T_& end) +{ +assert(begin <= end); +return (begin <= v) && (v < end); +} + +static inline bool is_less(const T_& v, const T_& begin) +{ +return (v < begin); +} + +static inline bool is_greater(const T_& v, const T_& end) +{ +return (end <= v); +} + +static inline bool end_inclusive() +{ +return false; +} +}; + +template +struct closed_range_policy +{ +static inline bool is_within(const T_& v, const T_& begin, const T_& end) +{ +assert(begin <= end); +return (begin <= v) && (v <= end); +} + +static inline bool is_less(const T_& v, const T_& begin) +{ +return (v < begin); +} + +static inline bool is_greater(const T_& v, const T_& end) +{ +return (end < v); +} + +static inline bool end_inclusive() +{ +return true; +} +}; + +template > +class interval_container_t +{ +public: + +typedef IntervalPointType interval_point_t; +typedef std::pair interval_t; +typedef std::map interval_map_t; +typedef typename interval_map_t::const_iterator interval_map_citr_t; + +std::size_t size() const +{ +return interval_map_.size(); +} + +void reset() +{ +interval_map_.clear(); +} + +bool in_interval(const interval_point_t point, interval_t& interval) const +{ +interval_map_citr_t itr = RangePolicy::end_inclusive() ? +interval_map_.lower_bound(point): +interval_map_.upper_bound(point); + +for (; itr != interval_map_.end(); ++itr) +{ +const interval_point_t& begin = itr->second.first; +const interval_point_t& end = itr->second.second; + +if (RangePolicy::is_within(point, begin, end)) +{ +interval = interval_t(begin,end); +return true; +} +else if (RangePolicy::is_greater(point, end)) +{ +break; +} +} + +return false; +} + +bool in_interval(const interval_point_t point) const +{ +interval_t interval; +return in_interval(point,interval); +} + +bool add_interval(const interval_point_t begin, const interval_point_t end) +{ +if ((end <= begin) || in_interval(begin) || in_interval(end)) +{ +return false; +} + +interval_map_[end] = std::make_pair(begin, end); + +return true; +} + +bool add_interval(const interval_t interval) +{ +return add_interval(interval.first, interval.second); +} + +private: + +interval_map_t interval_map_; +}; + +class stack_limit_handler +{ +public: + +typedef parser parser_t; + +explicit stack_limit_handler(parser& p) +: parser_(p) +, limit_exceeded_(false) +{ +if (++parser_.state_.stack_depth > parser_.settings_.max_stack_depth_) +{ +limit_exceeded_ = true; +parser_.set_error( +make_error(parser_error::e_parser, +"ERR000 - Current stack depth " + details::to_str(parser_.state_.stack_depth) + +" exceeds maximum allowed stack depth of " + details::to_str(parser_.settings_.max_stack_depth_), +exprtk_error_location)); +} +} + +~stack_limit_handler() +{ +parser_.state_.stack_depth--; +} + +bool operator!() +{ +return limit_exceeded_; +} + +private: + +stack_limit_handler(const stack_limit_handler&) exprtk_delete; +stack_limit_handler& operator=(const stack_limit_handler&) exprtk_delete; + +parser_t& parser_; +bool limit_exceeded_; +}; + +struct symtab_store +{ +symbol_table_list_t symtab_list_; + +typedef typename symbol_table_t::local_data_t local_data_t; +typedef typename symbol_table_t::variable_ptr variable_ptr; +typedef typename symbol_table_t::function_ptr function_ptr; +#ifndef exprtk_disable_string_capabilities +typedef typename symbol_table_t::stringvar_ptr stringvar_ptr; +#endif +typedef typename symbol_table_t::vector_holder_ptr vector_holder_ptr; +typedef typename symbol_table_t::vararg_function_ptr vararg_function_ptr; +typedef typename symbol_table_t::generic_function_ptr generic_function_ptr; + +struct variable_context +{ +variable_context() +: symbol_table(0) +, variable(0) +{} + +const symbol_table_t* symbol_table; +variable_ptr variable; +}; + +struct vector_context +{ +vector_context() +: symbol_table(0) +, vector_holder(0) +{} + +const symbol_table_t* symbol_table; +vector_holder_ptr vector_holder; +}; + +#ifndef exprtk_disable_string_capabilities +struct string_context +{ +string_context() +: symbol_table(0) +, str_var(0) +{} + +const symbol_table_t* symbol_table; +stringvar_ptr str_var; +}; +#endif + +inline bool empty() const +{ +return symtab_list_.empty(); +} + +inline void clear() +{ +symtab_list_.clear(); +} + +inline bool valid() const +{ +if (!empty()) +{ +for (std::size_t i = 0; i < symtab_list_.size(); ++i) +{ +if (symtab_list_[i].valid()) +return true; +} +} + +return false; +} + +inline bool valid_symbol(const std::string& symbol) const +{ +if (!symtab_list_.empty()) +return symtab_list_[0].valid_symbol(symbol); +else +return false; +} + +inline bool valid_function_name(const std::string& symbol) const +{ +if (!symtab_list_.empty()) +return symtab_list_[0].valid_function(symbol); +else +return false; +} + +inline variable_context get_variable_context(const std::string& variable_name) const +{ +variable_context result; +if (!valid_symbol(variable_name)) +return result; + +for (std::size_t i = 0; i < symtab_list_.size(); ++i) +{ +if (!symtab_list_[i].valid()) +{ +continue; +} + +result.variable = local_data(i) +.variable_store.get(variable_name); +if (result.variable) +{ +result.symbol_table = &symtab_list_[i]; +break; +} +} + +return result; +} + +inline variable_ptr get_variable(const std::string& variable_name) const +{ +if (!valid_symbol(variable_name)) +return reinterpret_cast(0); + +variable_ptr result = reinterpret_cast(0); + +for (std::size_t i = 0; i < symtab_list_.size(); ++i) +{ +if (!symtab_list_[i].valid()) +continue; +else +result = local_data(i) +.variable_store.get(variable_name); + +if (result) break; +} + +return result; +} + +inline variable_ptr get_variable(const T& var_ref) const +{ +variable_ptr result = reinterpret_cast(0); + +for (std::size_t i = 0; i < symtab_list_.size(); ++i) +{ +if (!symtab_list_[i].valid()) +continue; +else +result = local_data(i).variable_store +.get_from_varptr(reinterpret_cast(&var_ref)); + +if (result) break; +} + +return result; +} + +#ifndef exprtk_disable_string_capabilities +inline string_context get_string_context(const std::string& string_name) const +{ +string_context result; + +if (!valid_symbol(string_name)) +return result; + +for (std::size_t i = 0; i < symtab_list_.size(); ++i) +{ +if (!symtab_list_[i].valid()) +{ +continue; +} + +result.str_var = local_data(i).stringvar_store.get(string_name); + +if (result.str_var) +{ +result.symbol_table = &symtab_list_[i]; +break; +} +} + +return result; +} + +inline stringvar_ptr get_stringvar(const std::string& string_name) const +{ +if (!valid_symbol(string_name)) +return reinterpret_cast(0); + +stringvar_ptr result = reinterpret_cast(0); + +for (std::size_t i = 0; i < symtab_list_.size(); ++i) +{ +if (!symtab_list_[i].valid()) +continue; +else +result = local_data(i) +.stringvar_store.get(string_name); + +if (result) break; +} + +return result; +} +#endif + +inline function_ptr get_function(const std::string& function_name) const +{ +if (!valid_function_name(function_name)) +return reinterpret_cast(0); + +function_ptr result = reinterpret_cast(0); + +for (std::size_t i = 0; i < symtab_list_.size(); ++i) +{ +if (!symtab_list_[i].valid()) +continue; +else +result = local_data(i) +.function_store.get(function_name); + +if (result) break; +} + +return result; +} + +inline vararg_function_ptr get_vararg_function(const std::string& vararg_function_name) const +{ +if (!valid_function_name(vararg_function_name)) +return reinterpret_cast(0); + +vararg_function_ptr result = reinterpret_cast(0); + +for (std::size_t i = 0; i < symtab_list_.size(); ++i) +{ +if (!symtab_list_[i].valid()) +continue; +else +result = local_data(i) +.vararg_function_store.get(vararg_function_name); + +if (result) break; +} + +return result; +} + +inline generic_function_ptr get_generic_function(const std::string& function_name) const +{ +if (!valid_function_name(function_name)) +return reinterpret_cast(0); + +generic_function_ptr result = reinterpret_cast(0); + +for (std::size_t i = 0; i < symtab_list_.size(); ++i) +{ +if (!symtab_list_[i].valid()) +continue; +else +result = local_data(i) +.generic_function_store.get(function_name); + +if (result) break; +} + +return result; +} + +inline generic_function_ptr get_string_function(const std::string& function_name) const +{ +if (!valid_function_name(function_name)) +return reinterpret_cast(0); + +generic_function_ptr result = reinterpret_cast(0); + +for (std::size_t i = 0; i < symtab_list_.size(); ++i) +{ +if (!symtab_list_[i].valid()) +continue; +else +result = +local_data(i).string_function_store.get(function_name); + +if (result) break; +} + +return result; +} + +inline generic_function_ptr get_overload_function(const std::string& function_name) const +{ +if (!valid_function_name(function_name)) +return reinterpret_cast(0); + +generic_function_ptr result = reinterpret_cast(0); + +for (std::size_t i = 0; i < symtab_list_.size(); ++i) +{ +if (!symtab_list_[i].valid()) +continue; +else +result = +local_data(i).overload_function_store.get(function_name); + +if (result) break; +} + +return result; +} + +inline vector_context get_vector_context(const std::string& vector_name) const +{ +vector_context result; +if (!valid_symbol(vector_name)) +return result; + +for (std::size_t i = 0; i < symtab_list_.size(); ++i) +{ +if (!symtab_list_[i].valid()) +{ +continue; +} + +result.vector_holder = local_data(i).vector_store.get(vector_name); + +if (result.vector_holder) +{ +result.symbol_table = &symtab_list_[i]; +break; +} +} + +return result; +} + +inline vector_holder_ptr get_vector(const std::string& vector_name) const +{ +if (!valid_symbol(vector_name)) +return reinterpret_cast(0); + +vector_holder_ptr result = reinterpret_cast(0); + +for (std::size_t i = 0; i < symtab_list_.size(); ++i) +{ +if (!symtab_list_[i].valid()) +continue; +else +result = +local_data(i).vector_store.get(vector_name); + +if (result) break; +} + +return result; +} + +inline bool is_constant_node(const std::string& symbol_name) const +{ +if (!valid_symbol(symbol_name)) +return false; + +for (std::size_t i = 0; i < symtab_list_.size(); ++i) +{ +if (!symtab_list_[i].valid()) +continue; +else if (local_data(i).variable_store.is_constant(symbol_name)) +return true; +} + +return false; +} + +#ifndef exprtk_disable_string_capabilities +inline bool is_constant_string(const std::string& symbol_name) const +{ +if (!valid_symbol(symbol_name)) +return false; + +for (std::size_t i = 0; i < symtab_list_.size(); ++i) +{ +if (!symtab_list_[i].valid()) +continue; +else if (!local_data(i).stringvar_store.symbol_exists(symbol_name)) +continue; +else if (local_data(i).stringvar_store.is_constant(symbol_name)) +return true; +} + +return false; +} +#endif + +inline bool symbol_exists(const std::string& symbol) const +{ +for (std::size_t i = 0; i < symtab_list_.size(); ++i) +{ +if (!symtab_list_[i].valid()) +continue; +else if (symtab_list_[i].symbol_exists(symbol)) +return true; +} + +return false; +} + +inline bool is_variable(const std::string& variable_name) const +{ +for (std::size_t i = 0; i < symtab_list_.size(); ++i) +{ +if (!symtab_list_[i].valid()) +continue; +else if ( +symtab_list_[i].local_data().variable_store +.symbol_exists(variable_name) +) +return true; +} + +return false; +} + +#ifndef exprtk_disable_string_capabilities +inline bool is_stringvar(const std::string& stringvar_name) const +{ +for (std::size_t i = 0; i < symtab_list_.size(); ++i) +{ +if (!symtab_list_[i].valid()) +continue; +else if ( +symtab_list_[i].local_data().stringvar_store +.symbol_exists(stringvar_name) +) +return true; +} + +return false; +} + +inline bool is_conststr_stringvar(const std::string& symbol_name) const +{ +for (std::size_t i = 0; i < symtab_list_.size(); ++i) +{ +if (!symtab_list_[i].valid()) +continue; +else if ( +symtab_list_[i].local_data().stringvar_store +.symbol_exists(symbol_name) +) +{ +return ( +local_data(i).stringvar_store.symbol_exists(symbol_name) || +local_data(i).stringvar_store.is_constant (symbol_name) +); + +} +} + +return false; +} +#endif + +inline bool is_function(const std::string& function_name) const +{ +for (std::size_t i = 0; i < symtab_list_.size(); ++i) +{ +if (!symtab_list_[i].valid()) +continue; +else if ( +local_data(i).vararg_function_store +.symbol_exists(function_name) +) +return true; +} + +return false; +} + +inline bool is_vararg_function(const std::string& vararg_function_name) const +{ +for (std::size_t i = 0; i < symtab_list_.size(); ++i) +{ +if (!symtab_list_[i].valid()) +continue; +else if ( +local_data(i).vararg_function_store +.symbol_exists(vararg_function_name) +) +return true; +} + +return false; +} + +inline bool is_vector(const std::string& vector_name) const +{ +for (std::size_t i = 0; i < symtab_list_.size(); ++i) +{ +if (!symtab_list_[i].valid()) +continue; +else if ( +local_data(i).vector_store +.symbol_exists(vector_name) +) +return true; +} + +return false; +} + +inline std::string get_variable_name(const expression_node_ptr& ptr) const +{ +return local_data().variable_store.entity_name(ptr); +} + +inline std::string get_vector_name(const vector_holder_ptr& ptr) const +{ +return local_data().vector_store.entity_name(ptr); +} + +#ifndef exprtk_disable_string_capabilities +inline std::string get_stringvar_name(const expression_node_ptr& ptr) const +{ +return local_data().stringvar_store.entity_name(ptr); +} + +inline std::string get_conststr_stringvar_name(const expression_node_ptr& ptr) const +{ +return local_data().stringvar_store.entity_name(ptr); +} +#endif + +inline local_data_t& local_data(const std::size_t& index = 0) +{ +return symtab_list_[index].local_data(); +} + +inline const local_data_t& local_data(const std::size_t& index = 0) const +{ +return symtab_list_[index].local_data(); +} + +inline symbol_table_t& get_symbol_table(const std::size_t& index = 0) +{ +return symtab_list_[index]; +} +}; + +struct parser_state +{ +parser_state() +: type_check_enabled(true) +{ +reset(); +} + +void reset() +{ +parsing_return_stmt = false; +parsing_break_stmt = false; +return_stmt_present = false; +side_effect_present = false; +scope_depth = 0; +stack_depth = 0; +parsing_loop_stmt_count = 0; +} + +#ifndef exprtk_enable_debugging +void activate_side_effect(const std::string&) +#else +void activate_side_effect(const std::string& source) +#endif +{ +if (!side_effect_present) +{ +side_effect_present = true; + +exprtk_debug(("activate_side_effect() - caller: %s\n",source.c_str())); +} +} + +bool parsing_return_stmt; +bool parsing_break_stmt; +bool return_stmt_present; +bool side_effect_present; +bool type_check_enabled; +std::size_t scope_depth; +std::size_t stack_depth; +std::size_t parsing_loop_stmt_count; +}; + +public: + +struct unknown_symbol_resolver +{ + +enum usr_symbol_type +{ +e_usr_unknown_type = 0, +e_usr_variable_type = 1, +e_usr_constant_type = 2 +}; + +enum usr_mode +{ +e_usrmode_default = 0, +e_usrmode_extended = 1 +}; + +usr_mode mode; + +unknown_symbol_resolver(const usr_mode m = e_usrmode_default) +: mode(m) +{} + +virtual ~unknown_symbol_resolver() {} + +virtual bool process(const std::string& /*unknown_symbol*/, +usr_symbol_type& st, +T& default_value, +std::string& error_message) +{ +if (e_usrmode_default != mode) +return false; + +st = e_usr_variable_type; +default_value = T(0); +error_message.clear(); + +return true; +} + +virtual bool process(const std::string& /* unknown_symbol */, +symbol_table_t& /* symbol_table */, +std::string& /* error_message */) +{ +return false; +} +}; + +enum collect_type +{ +e_ct_none = 0, +e_ct_variables = 1, +e_ct_functions = 2, +e_ct_assignments = 4 +}; + +enum symbol_type +{ +e_st_unknown = 0, +e_st_variable = 1, +e_st_vector = 2, +e_st_vecelem = 3, +e_st_string = 4, +e_st_function = 5, +e_st_local_variable = 6, +e_st_local_vector = 7, +e_st_local_string = 8 +}; + +class dependent_entity_collector +{ +public: + +typedef std::pair symbol_t; +typedef std::vector symbol_list_t; + +dependent_entity_collector(const std::size_t options = e_ct_none) +: options_(options) +, collect_variables_ ((options_ & e_ct_variables ) == e_ct_variables ) +, collect_functions_ ((options_ & e_ct_functions ) == e_ct_functions ) +, collect_assignments_((options_ & e_ct_assignments) == e_ct_assignments) +, return_present_ (false) +, final_stmt_return_(false) +{} + +template class Sequence> +inline std::size_t symbols(Sequence& symbols_list) +{ +if (!collect_variables_ && !collect_functions_) +return 0; +else if (symbol_name_list_.empty()) +return 0; + +for (std::size_t i = 0; i < symbol_name_list_.size(); ++i) +{ +details::case_normalise(symbol_name_list_[i].first); +} + +std::sort(symbol_name_list_.begin(),symbol_name_list_.end()); + +std::unique_copy(symbol_name_list_.begin(), +symbol_name_list_.end (), +std::back_inserter(symbols_list)); + +return symbols_list.size(); +} + +template class Sequence> +inline std::size_t assignment_symbols(Sequence& assignment_list) +{ +if (!collect_assignments_) +return 0; +else if (assignment_name_list_.empty()) +return 0; + +for (std::size_t i = 0; i < assignment_name_list_.size(); ++i) +{ +details::case_normalise(assignment_name_list_[i].first); +} + +std::sort(assignment_name_list_.begin(),assignment_name_list_.end()); + +std::unique_copy(assignment_name_list_.begin(), +assignment_name_list_.end (), +std::back_inserter(assignment_list)); + +return assignment_list.size(); +} + +void clear() +{ +symbol_name_list_ .clear(); +assignment_name_list_.clear(); +retparam_list_ .clear(); +return_present_ = false; +final_stmt_return_ = false; +} + +bool& collect_variables() +{ +return collect_variables_; +} + +bool& collect_functions() +{ +return collect_functions_; +} + +bool& collect_assignments() +{ +return collect_assignments_; +} + +bool return_present() const +{ +return return_present_; +} + +bool final_stmt_return() const +{ +return final_stmt_return_; +} + +typedef std::vector retparam_list_t; + +retparam_list_t return_param_type_list() const +{ +return retparam_list_; +} + +private: + +inline void add_symbol(const std::string& symbol, const symbol_type st) +{ +switch (st) +{ +case e_st_variable : +case e_st_vector : +case e_st_string : +case e_st_local_variable : +case e_st_local_vector : +case e_st_local_string : if (collect_variables_) +symbol_name_list_ +.push_back(std::make_pair(symbol, st)); +break; + +case e_st_function : if (collect_functions_) +symbol_name_list_ +.push_back(std::make_pair(symbol, st)); +break; + +default : return; +} +} + +inline void add_assignment(const std::string& symbol, const symbol_type st) +{ +switch (st) +{ +case e_st_variable : +case e_st_vector : +case e_st_string : if (collect_assignments_) +assignment_name_list_ +.push_back(std::make_pair(symbol, st)); +break; + +default : return; +} +} + +std::size_t options_; +bool collect_variables_; +bool collect_functions_; +bool collect_assignments_; +bool return_present_; +bool final_stmt_return_; +symbol_list_t symbol_name_list_; +symbol_list_t assignment_name_list_; +retparam_list_t retparam_list_; + +friend class parser; +}; + +class settings_store +{ +private: + +typedef std::set disabled_entity_set_t; +typedef disabled_entity_set_t::iterator des_itr_t; + +public: + +enum settings_compilation_options +{ +e_unknown = 0, +e_replacer = 1, +e_joiner = 2, +e_numeric_check = 4, +e_bracket_check = 8, +e_sequence_check = 16, +e_commutative_check = 32, +e_strength_reduction = 64, +e_disable_vardef = 128, +e_collect_vars = 256, +e_collect_funcs = 512, +e_collect_assings = 1024, +e_disable_usr_on_rsrvd = 2048, +e_disable_zero_return = 4096 +}; + +enum settings_base_funcs +{ +e_bf_unknown = 0, +e_bf_abs , e_bf_acos , e_bf_acosh , e_bf_asin , +e_bf_asinh , e_bf_atan , e_bf_atan2 , e_bf_atanh , +e_bf_avg , e_bf_ceil , e_bf_clamp , e_bf_cos , +e_bf_cosh , e_bf_cot , e_bf_csc , e_bf_equal , +e_bf_erf , e_bf_erfc , e_bf_exp , e_bf_expm1 , +e_bf_floor , e_bf_frac , e_bf_hypot , e_bf_iclamp , +e_bf_like , e_bf_log , e_bf_log10 , e_bf_log1p , +e_bf_log2 , e_bf_logn , e_bf_mand , e_bf_max , +e_bf_min , e_bf_mod , e_bf_mor , e_bf_mul , +e_bf_ncdf , e_bf_pow , e_bf_root , e_bf_round , +e_bf_roundn , e_bf_sec , e_bf_sgn , e_bf_sin , +e_bf_sinc , e_bf_sinh , e_bf_sqrt , e_bf_sum , +e_bf_swap , e_bf_tan , e_bf_tanh , e_bf_trunc , +e_bf_not_equal , e_bf_inrange , e_bf_deg2grad , e_bf_deg2rad , +e_bf_rad2deg , e_bf_grad2deg +}; + +enum settings_control_structs +{ +e_ctrl_unknown = 0, +e_ctrl_ifelse, +e_ctrl_switch, +e_ctrl_for_loop, +e_ctrl_while_loop, +e_ctrl_repeat_loop, +e_ctrl_return +}; + +enum settings_logic_opr +{ +e_logic_unknown = 0, +e_logic_and, e_logic_nand , e_logic_nor , +e_logic_not, e_logic_or , e_logic_xnor, +e_logic_xor, e_logic_scand, e_logic_scor +}; + +enum settings_arithmetic_opr +{ +e_arith_unknown = 0, +e_arith_add, e_arith_sub, e_arith_mul, +e_arith_div, e_arith_mod, e_arith_pow +}; + +enum settings_assignment_opr +{ +e_assign_unknown = 0, +e_assign_assign, e_assign_addass, e_assign_subass, +e_assign_mulass, e_assign_divass, e_assign_modass +}; + +enum settings_inequality_opr +{ +e_ineq_unknown = 0, +e_ineq_lt , e_ineq_lte, e_ineq_eq , +e_ineq_equal, e_ineq_ne , e_ineq_nequal, +e_ineq_gte , e_ineq_gt +}; + +static const std::size_t compile_all_opts = +e_replacer + +e_joiner + +e_numeric_check + +e_bracket_check + +e_sequence_check + +e_commutative_check + +e_strength_reduction; + +settings_store(const std::size_t compile_options = compile_all_opts) +: max_stack_depth_(400) +, max_node_depth_(10000) +{ +load_compile_options(compile_options); +} + +settings_store& enable_all_base_functions() +{ +disabled_func_set_.clear(); +return (*this); +} + +settings_store& enable_all_control_structures() +{ +disabled_ctrl_set_.clear(); +return (*this); +} + +settings_store& enable_all_logic_ops() +{ +disabled_logic_set_.clear(); +return (*this); +} + +settings_store& enable_all_arithmetic_ops() +{ +disabled_arithmetic_set_.clear(); +return (*this); +} + +settings_store& enable_all_assignment_ops() +{ +disabled_assignment_set_.clear(); +return (*this); +} + +settings_store& enable_all_inequality_ops() +{ +disabled_inequality_set_.clear(); +return (*this); +} + +settings_store& enable_local_vardef() +{ +disable_vardef_ = false; +return (*this); +} + +settings_store& disable_all_base_functions() +{ +std::copy(details::base_function_list, +details::base_function_list + details::base_function_list_size, +std::insert_iterator +(disabled_func_set_, disabled_func_set_.begin())); +return (*this); +} + +settings_store& disable_all_control_structures() +{ +std::copy(details::cntrl_struct_list, +details::cntrl_struct_list + details::cntrl_struct_list_size, +std::insert_iterator +(disabled_ctrl_set_, disabled_ctrl_set_.begin())); +return (*this); +} + +settings_store& disable_all_logic_ops() +{ +std::copy(details::logic_ops_list, +details::logic_ops_list + details::logic_ops_list_size, +std::insert_iterator +(disabled_logic_set_, disabled_logic_set_.begin())); +return (*this); +} + +settings_store& disable_all_arithmetic_ops() +{ +std::copy(details::arithmetic_ops_list, +details::arithmetic_ops_list + details::arithmetic_ops_list_size, +std::insert_iterator +(disabled_arithmetic_set_, disabled_arithmetic_set_.begin())); +return (*this); +} + +settings_store& disable_all_assignment_ops() +{ +std::copy(details::assignment_ops_list, +details::assignment_ops_list + details::assignment_ops_list_size, +std::insert_iterator +(disabled_assignment_set_, disabled_assignment_set_.begin())); +return (*this); +} + +settings_store& disable_all_inequality_ops() +{ +std::copy(details::inequality_ops_list, +details::inequality_ops_list + details::inequality_ops_list_size, +std::insert_iterator +(disabled_inequality_set_, disabled_inequality_set_.begin())); +return (*this); +} + +settings_store& disable_local_vardef() +{ +disable_vardef_ = true; +return (*this); +} + +bool replacer_enabled () const { return enable_replacer_; } +bool commutative_check_enabled () const { return enable_commutative_check_; } +bool joiner_enabled () const { return enable_joiner_; } +bool numeric_check_enabled () const { return enable_numeric_check_; } +bool bracket_check_enabled () const { return enable_bracket_check_; } +bool sequence_check_enabled () const { return enable_sequence_check_; } +bool strength_reduction_enabled () const { return enable_strength_reduction_; } +bool collect_variables_enabled () const { return enable_collect_vars_; } +bool collect_functions_enabled () const { return enable_collect_funcs_; } +bool collect_assignments_enabled() const { return enable_collect_assings_; } +bool vardef_disabled () const { return disable_vardef_; } +bool rsrvd_sym_usr_disabled () const { return disable_rsrvd_sym_usr_; } +bool zero_return_disabled () const { return disable_zero_return_; } + +bool function_enabled(const std::string& function_name) const +{ +if (disabled_func_set_.empty()) +return true; +else +return (disabled_func_set_.end() == disabled_func_set_.find(function_name)); +} + +bool control_struct_enabled(const std::string& control_struct) const +{ +if (disabled_ctrl_set_.empty()) +return true; +else +return (disabled_ctrl_set_.end() == disabled_ctrl_set_.find(control_struct)); +} + +bool logic_enabled(const std::string& logic_operation) const +{ +if (disabled_logic_set_.empty()) +return true; +else +return (disabled_logic_set_.end() == disabled_logic_set_.find(logic_operation)); +} + +bool arithmetic_enabled(const details::operator_type& arithmetic_operation) const +{ +if (disabled_logic_set_.empty()) +return true; +else +return disabled_arithmetic_set_.end() == disabled_arithmetic_set_ +.find(arith_opr_to_string(arithmetic_operation)); +} + +bool assignment_enabled(const details::operator_type& assignment) const +{ +if (disabled_assignment_set_.empty()) +return true; +else +return disabled_assignment_set_.end() == disabled_assignment_set_ +.find(assign_opr_to_string(assignment)); +} + +bool inequality_enabled(const details::operator_type& inequality) const +{ +if (disabled_inequality_set_.empty()) +return true; +else +return disabled_inequality_set_.end() == disabled_inequality_set_ +.find(inequality_opr_to_string(inequality)); +} + +bool function_disabled(const std::string& function_name) const +{ +if (disabled_func_set_.empty()) +return false; +else +return (disabled_func_set_.end() != disabled_func_set_.find(function_name)); +} + +bool control_struct_disabled(const std::string& control_struct) const +{ +if (disabled_ctrl_set_.empty()) +return false; +else +return (disabled_ctrl_set_.end() != disabled_ctrl_set_.find(control_struct)); +} + +bool logic_disabled(const std::string& logic_operation) const +{ +if (disabled_logic_set_.empty()) +return false; +else +return (disabled_logic_set_.end() != disabled_logic_set_.find(logic_operation)); +} + +bool assignment_disabled(const details::operator_type assignment_operation) const +{ +if (disabled_assignment_set_.empty()) +return false; +else +return disabled_assignment_set_.end() != disabled_assignment_set_ +.find(assign_opr_to_string(assignment_operation)); +} + +bool logic_disabled(const details::operator_type logic_operation) const +{ +if (disabled_logic_set_.empty()) +return false; +else +return disabled_logic_set_.end() != disabled_logic_set_ +.find(logic_opr_to_string(logic_operation)); +} + +bool arithmetic_disabled(const details::operator_type arithmetic_operation) const +{ +if (disabled_arithmetic_set_.empty()) +return false; +else +return disabled_arithmetic_set_.end() != disabled_arithmetic_set_ +.find(arith_opr_to_string(arithmetic_operation)); +} + +bool inequality_disabled(const details::operator_type& inequality) const +{ +if (disabled_inequality_set_.empty()) +return false; +else +return disabled_inequality_set_.end() != disabled_inequality_set_ +.find(inequality_opr_to_string(inequality)); +} + +settings_store& disable_base_function(settings_base_funcs bf) +{ +if ( +(e_bf_unknown != bf) && +(static_cast(bf) < (details::base_function_list_size + 1)) +) +{ +disabled_func_set_.insert(details::base_function_list[bf - 1]); +} + +return (*this); +} + +settings_store& disable_control_structure(settings_control_structs ctrl_struct) +{ +if ( +(e_ctrl_unknown != ctrl_struct) && +(static_cast(ctrl_struct) < (details::cntrl_struct_list_size + 1)) +) +{ +disabled_ctrl_set_.insert(details::cntrl_struct_list[ctrl_struct - 1]); +} + +return (*this); +} + +settings_store& disable_logic_operation(settings_logic_opr logic) +{ +if ( +(e_logic_unknown != logic) && +(static_cast(logic) < (details::logic_ops_list_size + 1)) +) +{ +disabled_logic_set_.insert(details::logic_ops_list[logic - 1]); +} + +return (*this); +} + +settings_store& disable_arithmetic_operation(settings_arithmetic_opr arithmetic) +{ +if ( +(e_arith_unknown != arithmetic) && +(static_cast(arithmetic) < (details::arithmetic_ops_list_size + 1)) +) +{ +disabled_arithmetic_set_.insert(details::arithmetic_ops_list[arithmetic - 1]); +} + +return (*this); +} + +settings_store& disable_assignment_operation(settings_assignment_opr assignment) +{ +if ( +(e_assign_unknown != assignment) && +(static_cast(assignment) < (details::assignment_ops_list_size + 1)) +) +{ +disabled_assignment_set_.insert(details::assignment_ops_list[assignment - 1]); +} + +return (*this); +} + +settings_store& disable_inequality_operation(settings_inequality_opr inequality) +{ +if ( +(e_ineq_unknown != inequality) && +(static_cast(inequality) < (details::inequality_ops_list_size + 1)) +) +{ +disabled_inequality_set_.insert(details::inequality_ops_list[inequality - 1]); +} + +return (*this); +} + +settings_store& enable_base_function(settings_base_funcs bf) +{ +if ( +(e_bf_unknown != bf) && +(static_cast(bf) < (details::base_function_list_size + 1)) +) +{ +const des_itr_t itr = disabled_func_set_.find(details::base_function_list[bf - 1]); + +if (disabled_func_set_.end() != itr) +{ +disabled_func_set_.erase(itr); +} +} + +return (*this); +} + +settings_store& enable_control_structure(settings_control_structs ctrl_struct) +{ +if ( +(e_ctrl_unknown != ctrl_struct) && +(static_cast(ctrl_struct) < (details::cntrl_struct_list_size + 1)) +) +{ +const des_itr_t itr = disabled_ctrl_set_.find(details::cntrl_struct_list[ctrl_struct - 1]); + +if (disabled_ctrl_set_.end() != itr) +{ +disabled_ctrl_set_.erase(itr); +} +} + +return (*this); +} + +settings_store& enable_logic_operation(settings_logic_opr logic) +{ +if ( +(e_logic_unknown != logic) && +(static_cast(logic) < (details::logic_ops_list_size + 1)) +) +{ +const des_itr_t itr = disabled_logic_set_.find(details::logic_ops_list[logic - 1]); + +if (disabled_logic_set_.end() != itr) +{ +disabled_logic_set_.erase(itr); +} +} + +return (*this); +} + +settings_store& enable_arithmetic_operation(settings_arithmetic_opr arithmetic) +{ +if ( +(e_arith_unknown != arithmetic) && +(static_cast(arithmetic) < (details::arithmetic_ops_list_size + 1)) +) +{ +const des_itr_t itr = disabled_arithmetic_set_.find(details::arithmetic_ops_list[arithmetic - 1]); + +if (disabled_arithmetic_set_.end() != itr) +{ +disabled_arithmetic_set_.erase(itr); +} +} + +return (*this); +} + +settings_store& enable_assignment_operation(settings_assignment_opr assignment) +{ +if ( +(e_assign_unknown != assignment) && +(static_cast(assignment) < (details::assignment_ops_list_size + 1)) +) +{ +const des_itr_t itr = disabled_assignment_set_.find(details::assignment_ops_list[assignment - 1]); + +if (disabled_assignment_set_.end() != itr) +{ +disabled_assignment_set_.erase(itr); +} +} + +return (*this); +} + +settings_store& enable_inequality_operation(settings_inequality_opr inequality) +{ +if ( +(e_ineq_unknown != inequality) && +(static_cast(inequality) < (details::inequality_ops_list_size + 1)) +) +{ +const des_itr_t itr = disabled_inequality_set_.find(details::inequality_ops_list[inequality - 1]); + +if (disabled_inequality_set_.end() != itr) +{ +disabled_inequality_set_.erase(itr); +} +} + +return (*this); +} + +void set_max_stack_depth(const std::size_t max_stack_depth) +{ +max_stack_depth_ = max_stack_depth; +} + +void set_max_node_depth(const std::size_t max_node_depth) +{ +max_node_depth_ = max_node_depth; +} + +private: + +void load_compile_options(const std::size_t compile_options) +{ +enable_replacer_ = (compile_options & e_replacer ) == e_replacer; +enable_joiner_ = (compile_options & e_joiner ) == e_joiner; +enable_numeric_check_ = (compile_options & e_numeric_check ) == e_numeric_check; +enable_bracket_check_ = (compile_options & e_bracket_check ) == e_bracket_check; +enable_sequence_check_ = (compile_options & e_sequence_check ) == e_sequence_check; +enable_commutative_check_ = (compile_options & e_commutative_check ) == e_commutative_check; +enable_strength_reduction_ = (compile_options & e_strength_reduction ) == e_strength_reduction; +enable_collect_vars_ = (compile_options & e_collect_vars ) == e_collect_vars; +enable_collect_funcs_ = (compile_options & e_collect_funcs ) == e_collect_funcs; +enable_collect_assings_ = (compile_options & e_collect_assings ) == e_collect_assings; +disable_vardef_ = (compile_options & e_disable_vardef ) == e_disable_vardef; +disable_rsrvd_sym_usr_ = (compile_options & e_disable_usr_on_rsrvd) == e_disable_usr_on_rsrvd; +disable_zero_return_ = (compile_options & e_disable_zero_return ) == e_disable_zero_return; +} + +std::string assign_opr_to_string(details::operator_type opr) const +{ +switch (opr) +{ +case details::e_assign : return ":="; +case details::e_addass : return "+="; +case details::e_subass : return "-="; +case details::e_mulass : return "*="; +case details::e_divass : return "/="; +case details::e_modass : return "%="; +default : return "" ; +} +} + +std::string arith_opr_to_string(details::operator_type opr) const +{ +switch (opr) +{ +case details::e_add : return "+"; +case details::e_sub : return "-"; +case details::e_mul : return "*"; +case details::e_div : return "/"; +case details::e_mod : return "%"; +default : return "" ; +} +} + +std::string inequality_opr_to_string(details::operator_type opr) const +{ +switch (opr) +{ +case details::e_lt : return "<" ; +case details::e_lte : return "<="; +case details::e_eq : return "=="; +case details::e_equal : return "=" ; +case details::e_ne : return "!="; +case details::e_nequal: return "<>"; +case details::e_gte : return ">="; +case details::e_gt : return ">" ; +default : return "" ; +} +} + +std::string logic_opr_to_string(details::operator_type opr) const +{ +switch (opr) +{ +case details::e_and : return "and" ; +case details::e_or : return "or" ; +case details::e_xor : return "xor" ; +case details::e_nand : return "nand"; +case details::e_nor : return "nor" ; +case details::e_xnor : return "xnor"; +case details::e_notl : return "not" ; +default : return "" ; +} +} + +bool enable_replacer_; +bool enable_joiner_; +bool enable_numeric_check_; +bool enable_bracket_check_; +bool enable_sequence_check_; +bool enable_commutative_check_; +bool enable_strength_reduction_; +bool enable_collect_vars_; +bool enable_collect_funcs_; +bool enable_collect_assings_; +bool disable_vardef_; +bool disable_rsrvd_sym_usr_; +bool disable_zero_return_; + +disabled_entity_set_t disabled_func_set_ ; +disabled_entity_set_t disabled_ctrl_set_ ; +disabled_entity_set_t disabled_logic_set_; +disabled_entity_set_t disabled_arithmetic_set_; +disabled_entity_set_t disabled_assignment_set_; +disabled_entity_set_t disabled_inequality_set_; + +std::size_t max_stack_depth_; +std::size_t max_node_depth_; + +friend class parser; +}; + +typedef settings_store settings_t; + +parser(const settings_t& settings = settings_t()) +: settings_(settings) +, resolve_unknown_symbol_(false) +, results_context_(0) +, unknown_symbol_resolver_(reinterpret_cast(0)) +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning (disable:4355) +#endif +, sem_(*this) +#ifdef _MSC_VER +#pragma warning(pop) +#endif +, operator_joiner_2_(2) +, operator_joiner_3_(3) +, loop_runtime_check_(0) +{ +init_precompilation(); + +load_operations_map (base_ops_map_ ); +load_unary_operations_map (unary_op_map_ ); +load_binary_operations_map (binary_op_map_ ); +load_inv_binary_operations_map(inv_binary_op_map_); +load_sf3_map (sf3_map_ ); +load_sf4_map (sf4_map_ ); + +expression_generator_.init_synthesize_map(); +expression_generator_.set_parser(*this); +expression_generator_.set_uom(unary_op_map_); +expression_generator_.set_bom(binary_op_map_); +expression_generator_.set_ibom(inv_binary_op_map_); +expression_generator_.set_sf3m(sf3_map_); +expression_generator_.set_sf4m(sf4_map_); +expression_generator_.set_strength_reduction_state(settings_.strength_reduction_enabled()); +} + +~parser() {} + +inline void init_precompilation() +{ +dec_.collect_variables() = +settings_.collect_variables_enabled(); + +dec_.collect_functions() = +settings_.collect_functions_enabled(); + +dec_.collect_assignments() = +settings_.collect_assignments_enabled(); + +if (settings_.replacer_enabled()) +{ +symbol_replacer_.clear(); +symbol_replacer_.add_replace("true" , "1", lexer::token::e_number); +symbol_replacer_.add_replace("false", "0", lexer::token::e_number); +helper_assembly_.token_modifier_list.clear(); +helper_assembly_.register_modifier(&symbol_replacer_); +} + +if (settings_.commutative_check_enabled()) +{ +for (std::size_t i = 0; i < details::reserved_words_size; ++i) +{ +commutative_inserter_.ignore_symbol(details::reserved_words[i]); +} + +helper_assembly_.token_inserter_list.clear(); +helper_assembly_.register_inserter(&commutative_inserter_); +} + +if (settings_.joiner_enabled()) +{ +helper_assembly_.token_joiner_list.clear(); +helper_assembly_.register_joiner(&operator_joiner_2_); +helper_assembly_.register_joiner(&operator_joiner_3_); +} + +if ( +settings_.numeric_check_enabled () || +settings_.bracket_check_enabled () || +settings_.sequence_check_enabled() +) +{ +helper_assembly_.token_scanner_list.clear(); + +if (settings_.numeric_check_enabled()) +{ +helper_assembly_.register_scanner(&numeric_checker_); +} + +if (settings_.bracket_check_enabled()) +{ +helper_assembly_.register_scanner(&bracket_checker_); +} + +if (settings_.sequence_check_enabled()) +{ +helper_assembly_.register_scanner(&sequence_validator_ ); +helper_assembly_.register_scanner(&sequence_validator_3tkns_); +} +} +} + +inline bool compile(const std::string& expression_string, expression& expr) +{ +state_ .reset(); +error_list_ .clear(); +brkcnt_list_ .clear(); +synthesis_error_.clear(); +sem_ .cleanup(); + +return_cleanup(); + +expression_generator_.set_allocator(node_allocator_); + +if (expression_string.empty()) +{ +set_error( +make_error(parser_error::e_syntax, +"ERR001 - Empty expression!", +exprtk_error_location)); + +return false; +} + +if (!init(expression_string)) +{ +process_lexer_errors(); +return false; +} + +if (lexer().empty()) +{ +set_error( +make_error(parser_error::e_syntax, +"ERR002 - Empty expression!", +exprtk_error_location)); + +return false; +} + +if (!run_assemblies()) +{ +return false; +} + +symtab_store_.symtab_list_ = expr.get_symbol_table_list(); +dec_.clear(); + +lexer().begin(); + +next_token(); + +expression_node_ptr e = parse_corpus(); + +if ((0 != e) && (token_t::e_eof == current_token().type)) +{ +bool* retinvk_ptr = 0; + +if (state_.return_stmt_present) +{ +dec_.return_present_ = true; + +e = expression_generator_ +.return_envelope(e, results_context_, retinvk_ptr); +} + +expr.set_expression(e); +expr.set_retinvk(retinvk_ptr); + +register_local_vars(expr); +register_return_results(expr); + +return !(!expr); +} +else +{ +if (error_list_.empty()) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR003 - Invalid expression encountered", +exprtk_error_location)); +} + +if ((0 != e) && branch_deletable(e)) +{ +destroy_node(e); +} + +dec_.clear (); +sem_.cleanup (); +return_cleanup(); + +return false; +} +} + +inline expression_t compile(const std::string& expression_string, symbol_table_t& symtab) +{ +expression_t expression; +expression.register_symbol_table(symtab); +compile(expression_string,expression); +return expression; +} + +void process_lexer_errors() +{ +for (std::size_t i = 0; i < lexer().size(); ++i) +{ +if (lexer()[i].is_error()) +{ +std::string diagnostic = "ERR004 - "; + +switch (lexer()[i].type) +{ +case lexer::token::e_error : diagnostic += "General token error"; +break; + +case lexer::token::e_err_symbol : diagnostic += "Symbol error"; +break; + +case lexer::token::e_err_number : diagnostic += "Invalid numeric token"; +break; + +case lexer::token::e_err_string : diagnostic += "Invalid string token"; +break; + +case lexer::token::e_err_sfunc : diagnostic += "Invalid special function token"; +break; + +default : diagnostic += "Unknown compiler error"; +} + +set_error( +make_error(parser_error::e_lexer, +lexer()[i], +diagnostic + ": " + lexer()[i].value, +exprtk_error_location)); +} +} +} + +inline bool run_assemblies() +{ +if (settings_.commutative_check_enabled()) +{ +helper_assembly_.run_inserters(lexer()); +} + +if (settings_.joiner_enabled()) +{ +helper_assembly_.run_joiners(lexer()); +} + +if (settings_.replacer_enabled()) +{ +helper_assembly_.run_modifiers(lexer()); +} + +if ( +settings_.numeric_check_enabled () || +settings_.bracket_check_enabled () || +settings_.sequence_check_enabled() +) +{ +if (!helper_assembly_.run_scanners(lexer())) +{ +if (helper_assembly_.error_token_scanner) +{ +lexer::helper::bracket_checker* bracket_checker_ptr = 0; +lexer::helper::numeric_checker* numeric_checker_ptr = 0; +lexer::helper::sequence_validator* sequence_validator_ptr = 0; +lexer::helper::sequence_validator_3tokens* sequence_validator3_ptr = 0; + +if (0 != (bracket_checker_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) +{ +set_error( +make_error(parser_error::e_token, +bracket_checker_ptr->error_token(), +"ERR005 - Mismatched brackets: '" + bracket_checker_ptr->error_token().value + "'", +exprtk_error_location)); +} +else if (0 != (numeric_checker_ptr = dynamic_cast*>(helper_assembly_.error_token_scanner))) +{ +for (std::size_t i = 0; i < numeric_checker_ptr->error_count(); ++i) +{ +lexer::token error_token = lexer()[numeric_checker_ptr->error_index(i)]; + +set_error( +make_error(parser_error::e_token, +error_token, +"ERR006 - Invalid numeric token: '" + error_token.value + "'", +exprtk_error_location)); +} + +if (numeric_checker_ptr->error_count()) +{ +numeric_checker_ptr->clear_errors(); +} +} +else if (0 != (sequence_validator_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) +{ +for (std::size_t i = 0; i < sequence_validator_ptr->error_count(); ++i) +{ +std::pair error_token = sequence_validator_ptr->error(i); + +set_error( +make_error(parser_error::e_token, +error_token.first, +"ERR007 - Invalid token sequence: '" + +error_token.first.value + "' and '" + +error_token.second.value + "'", +exprtk_error_location)); +} + +if (sequence_validator_ptr->error_count()) +{ +sequence_validator_ptr->clear_errors(); +} +} +else if (0 != (sequence_validator3_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) +{ +for (std::size_t i = 0; i < sequence_validator3_ptr->error_count(); ++i) +{ +std::pair error_token = sequence_validator3_ptr->error(i); + +set_error( +make_error(parser_error::e_token, +error_token.first, +"ERR008 - Invalid token sequence: '" + +error_token.first.value + "' and '" + +error_token.second.value + "'", +exprtk_error_location)); +} + +if (sequence_validator3_ptr->error_count()) +{ +sequence_validator3_ptr->clear_errors(); +} +} +} + +return false; +} +} + +return true; +} + +inline settings_store& settings() +{ +return settings_; +} + +inline parser_error::type get_error(const std::size_t& index) const +{ +if (index < error_list_.size()) +return error_list_[index]; +else +throw std::invalid_argument("parser::get_error() - Invalid error index specificed"); +} + +inline std::string error() const +{ +if (!error_list_.empty()) +{ +return error_list_[0].diagnostic; +} +else +return std::string("No Error"); +} + +inline std::size_t error_count() const +{ +return error_list_.size(); +} + +inline dependent_entity_collector& dec() +{ +return dec_; +} + +inline bool replace_symbol(const std::string& old_symbol, const std::string& new_symbol) +{ +if (!settings_.replacer_enabled()) +return false; +else if (details::is_reserved_word(old_symbol)) +return false; +else +return symbol_replacer_.add_replace(old_symbol,new_symbol,lexer::token::e_symbol); +} + +inline bool remove_replace_symbol(const std::string& symbol) +{ +if (!settings_.replacer_enabled()) +return false; +else if (details::is_reserved_word(symbol)) +return false; +else +return symbol_replacer_.remove(symbol); +} + +inline void enable_unknown_symbol_resolver(unknown_symbol_resolver* usr = reinterpret_cast(0)) +{ +resolve_unknown_symbol_ = true; + +if (usr) +unknown_symbol_resolver_ = usr; +else +unknown_symbol_resolver_ = &default_usr_; +} + +inline void enable_unknown_symbol_resolver(unknown_symbol_resolver& usr) +{ +enable_unknown_symbol_resolver(&usr); +} + +inline void disable_unknown_symbol_resolver() +{ +resolve_unknown_symbol_ = false; +unknown_symbol_resolver_ = &default_usr_; +} + +inline void register_loop_runtime_check(loop_runtime_check& lrtchk) +{ +loop_runtime_check_ = &lrtchk; +} + +inline void clear_loop_runtime_check() +{ +loop_runtime_check_ = loop_runtime_check_ptr(0); +} + +private: + +inline bool valid_base_operation(const std::string& symbol) const +{ +const std::size_t length = symbol.size(); + +if ( +(length < 3) || // Shortest base op symbol length +(length > 9) // Longest base op symbol length +) +return false; +else +return settings_.function_enabled(symbol) && +(base_ops_map_.end() != base_ops_map_.find(symbol)); +} + +inline bool valid_vararg_operation(const std::string& symbol) const +{ +static const std::string s_sum = "sum" ; +static const std::string s_mul = "mul" ; +static const std::string s_avg = "avg" ; +static const std::string s_min = "min" ; +static const std::string s_max = "max" ; +static const std::string s_mand = "mand"; +static const std::string s_mor = "mor" ; +static const std::string s_multi = "~" ; +static const std::string s_mswitch = "[*]" ; + +return +( +details::imatch(symbol,s_sum ) || +details::imatch(symbol,s_mul ) || +details::imatch(symbol,s_avg ) || +details::imatch(symbol,s_min ) || +details::imatch(symbol,s_max ) || +details::imatch(symbol,s_mand ) || +details::imatch(symbol,s_mor ) || +details::imatch(symbol,s_multi ) || +details::imatch(symbol,s_mswitch) +) && +settings_.function_enabled(symbol); +} + +bool is_invalid_logic_operation(const details::operator_type operation) const +{ +return settings_.logic_disabled(operation); +} + +bool is_invalid_arithmetic_operation(const details::operator_type operation) const +{ +return settings_.arithmetic_disabled(operation); +} + +bool is_invalid_assignment_operation(const details::operator_type operation) const +{ +return settings_.assignment_disabled(operation); +} + +bool is_invalid_inequality_operation(const details::operator_type operation) const +{ +return settings_.inequality_disabled(operation); +} + +#ifdef exprtk_enable_debugging +inline void next_token() +{ +const std::string ct_str = current_token().value; +const std::size_t ct_pos = current_token().position; +parser_helper::next_token(); +const std::string depth(2 * state_.scope_depth,' '); +exprtk_debug(("%s" +"prev[%s | %04d] --> curr[%s | %04d] stack_level: %3d\n", +depth.c_str(), +ct_str.c_str(), +static_cast(ct_pos), +current_token().value.c_str(), +static_cast(current_token().position), +static_cast(state_.stack_depth))); +} +#endif + +inline expression_node_ptr parse_corpus() +{ +std::vector arg_list; +std::vector side_effect_list; + +scoped_vec_delete sdd((*this),arg_list); + +lexer::token begin_token; +lexer::token end_token; + +for ( ; ; ) +{ +state_.side_effect_present = false; + +begin_token = current_token(); + +expression_node_ptr arg = parse_expression(); + +if (0 == arg) +{ +if (error_list_.empty()) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR009 - Invalid expression encountered", +exprtk_error_location)); +} + +return error_node(); +} +else +{ +arg_list.push_back(arg); + +side_effect_list.push_back(state_.side_effect_present); + +end_token = current_token(); + +const std::string sub_expr = construct_subexpr(begin_token, end_token); + +exprtk_debug(("parse_corpus(%02d) Subexpr: %s\n", +static_cast(arg_list.size() - 1), +sub_expr.c_str())); + +exprtk_debug(("parse_corpus(%02d) - Side effect present: %s\n", +static_cast(arg_list.size() - 1), +state_.side_effect_present ? "true" : "false")); + +exprtk_debug(("-------------------------------------------------\n")); +} + +if (lexer().finished()) +break; +else if (token_is(token_t::e_eof,prsrhlpr_t::e_hold)) +{ +if (lexer().finished()) +break; +else +next_token(); +} +} + +if ( +!arg_list.empty() && +is_return_node(arg_list.back()) +) +{ +dec_.final_stmt_return_ = true; +} + +const expression_node_ptr result = simplify(arg_list,side_effect_list); + +sdd.delete_ptr = (0 == result); + +return result; +} + +std::string construct_subexpr(lexer::token& begin_token, lexer::token& end_token) +{ +std::string result = lexer().substr(begin_token.position,end_token.position); + +for (std::size_t i = 0; i < result.size(); ++i) +{ +if (details::is_whitespace(result[i])) result[i] = ' '; +} + +return result; +} + +static const precedence_level default_precedence = e_level00; + +struct state_t +{ +inline void set(const precedence_level& l, +const precedence_level& r, +const details::operator_type& o) +{ +left = l; +right = r; +operation = o; +} + +inline void reset() +{ +left = e_level00; +right = e_level00; +operation = details::e_default; +} + +precedence_level left; +precedence_level right; +details::operator_type operation; +}; + +inline expression_node_ptr parse_expression(precedence_level precedence = e_level00) +{ +stack_limit_handler slh(*this); + +if (!slh) +{ +return error_node(); +} + +expression_node_ptr expression = parse_branch(precedence); + +if (0 == expression) +{ +return error_node(); +} + +bool break_loop = false; + +state_t current_state; + +for ( ; ; ) +{ +current_state.reset(); + +switch (current_token().type) +{ +case token_t::e_assign : current_state.set(e_level00, e_level00, details::e_assign); break; +case token_t::e_addass : current_state.set(e_level00, e_level00, details::e_addass); break; +case token_t::e_subass : current_state.set(e_level00, e_level00, details::e_subass); break; +case token_t::e_mulass : current_state.set(e_level00, e_level00, details::e_mulass); break; +case token_t::e_divass : current_state.set(e_level00, e_level00, details::e_divass); break; +case token_t::e_modass : current_state.set(e_level00, e_level00, details::e_modass); break; +case token_t::e_swap : current_state.set(e_level00, e_level00, details::e_swap ); break; +case token_t::e_lt : current_state.set(e_level05, e_level06, details::e_lt ); break; +case token_t::e_lte : current_state.set(e_level05, e_level06, details::e_lte ); break; +case token_t::e_eq : current_state.set(e_level05, e_level06, details::e_eq ); break; +case token_t::e_ne : current_state.set(e_level05, e_level06, details::e_ne ); break; +case token_t::e_gte : current_state.set(e_level05, e_level06, details::e_gte ); break; +case token_t::e_gt : current_state.set(e_level05, e_level06, details::e_gt ); break; +case token_t::e_add : current_state.set(e_level07, e_level08, details::e_add ); break; +case token_t::e_sub : current_state.set(e_level07, e_level08, details::e_sub ); break; +case token_t::e_div : current_state.set(e_level10, e_level11, details::e_div ); break; +case token_t::e_mul : current_state.set(e_level10, e_level11, details::e_mul ); break; +case token_t::e_mod : current_state.set(e_level10, e_level11, details::e_mod ); break; +case token_t::e_pow : current_state.set(e_level12, e_level12, details::e_pow ); break; +default : if (token_t::e_symbol == current_token().type) +{ +static const std::string s_and = "and" ; +static const std::string s_nand = "nand" ; +static const std::string s_or = "or" ; +static const std::string s_nor = "nor" ; +static const std::string s_xor = "xor" ; +static const std::string s_xnor = "xnor" ; +static const std::string s_in = "in" ; +static const std::string s_like = "like" ; +static const std::string s_ilike = "ilike"; +static const std::string s_and1 = "&" ; +static const std::string s_or1 = "|" ; +static const std::string s_not = "not" ; + +if (details::imatch(current_token().value,s_and)) +{ +current_state.set(e_level03, e_level04, details::e_and); +break; +} +else if (details::imatch(current_token().value,s_and1)) +{ +#ifndef exprtk_disable_sc_andor +current_state.set(e_level03, e_level04, details::e_scand); +#else +current_state.set(e_level03, e_level04, details::e_and); +#endif +break; +} +else if (details::imatch(current_token().value,s_nand)) +{ +current_state.set(e_level03, e_level04, details::e_nand); +break; +} +else if (details::imatch(current_token().value,s_or)) +{ +current_state.set(e_level01, e_level02, details::e_or); +break; +} +else if (details::imatch(current_token().value,s_or1)) +{ +#ifndef exprtk_disable_sc_andor +current_state.set(e_level01, e_level02, details::e_scor); +#else +current_state.set(e_level01, e_level02, details::e_or); +#endif +break; +} +else if (details::imatch(current_token().value,s_nor)) +{ +current_state.set(e_level01, e_level02, details::e_nor); +break; +} +else if (details::imatch(current_token().value,s_xor)) +{ +current_state.set(e_level01, e_level02, details::e_xor); +break; +} +else if (details::imatch(current_token().value,s_xnor)) +{ +current_state.set(e_level01, e_level02, details::e_xnor); +break; +} +else if (details::imatch(current_token().value,s_in)) +{ +current_state.set(e_level04, e_level04, details::e_in); +break; +} +else if (details::imatch(current_token().value,s_like)) +{ +current_state.set(e_level04, e_level04, details::e_like); +break; +} +else if (details::imatch(current_token().value,s_ilike)) +{ +current_state.set(e_level04, e_level04, details::e_ilike); +break; +} +else if (details::imatch(current_token().value,s_not)) +{ +break; +} +} + +break_loop = true; +} + +if (break_loop) +{ +parse_pending_string_rangesize(expression); +break; +} +else if (current_state.left < precedence) +break; + +const lexer::token prev_token = current_token(); + +next_token(); + +expression_node_ptr right_branch = error_node(); +expression_node_ptr new_expression = error_node(); + +if (is_invalid_logic_operation(current_state.operation)) +{ +free_node(node_allocator_,expression); + +set_error( +make_error(parser_error::e_syntax, +prev_token, +"ERR010 - Invalid or disabled logic operation '" + details::to_str(current_state.operation) + "'", +exprtk_error_location)); + +return error_node(); +} +else if (is_invalid_arithmetic_operation(current_state.operation)) +{ +free_node(node_allocator_,expression); + +set_error( +make_error(parser_error::e_syntax, +prev_token, +"ERR011 - Invalid or disabled arithmetic operation '" + details::to_str(current_state.operation) + "'", +exprtk_error_location)); + +return error_node(); +} +else if (is_invalid_inequality_operation(current_state.operation)) +{ +free_node(node_allocator_,expression); + +set_error( +make_error(parser_error::e_syntax, +prev_token, +"ERR012 - Invalid inequality operation '" + details::to_str(current_state.operation) + "'", +exprtk_error_location)); + +return error_node(); +} +else if (is_invalid_assignment_operation(current_state.operation)) +{ +free_node(node_allocator_,expression); + +set_error( +make_error(parser_error::e_syntax, +prev_token, +"ERR013 - Invalid or disabled assignment operation '" + details::to_str(current_state.operation) + "'", +exprtk_error_location)); + +return error_node(); +} + +if (0 != (right_branch = parse_expression(current_state.right))) +{ +if ( +details::is_return_node(expression ) || +details::is_return_node(right_branch) +) +{ +free_node(node_allocator_, expression ); +free_node(node_allocator_, right_branch); + +set_error( +make_error(parser_error::e_syntax, +prev_token, +"ERR014 - Return statements cannot be part of sub-expressions", +exprtk_error_location)); + +return error_node(); +} + +new_expression = expression_generator_ +( +current_state.operation, +expression, +right_branch +); +} + +if (0 == new_expression) +{ +if (error_list_.empty()) +{ +set_error( +make_error(parser_error::e_syntax, +prev_token, +!synthesis_error_.empty() ? +synthesis_error_ : +"ERR015 - General parsing error at token: '" + prev_token.value + "'", +exprtk_error_location)); +} + +free_node(node_allocator_, expression ); +free_node(node_allocator_, right_branch); + +return error_node(); +} +else +{ +if ( +token_is(token_t::e_ternary,prsrhlpr_t::e_hold) && +(e_level00 == precedence) +) +{ +expression = parse_ternary_conditional_statement(new_expression); +} +else +expression = new_expression; + +parse_pending_string_rangesize(expression); +} +} + +if ((0 != expression) && (expression->node_depth() > settings_.max_node_depth_)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR016 - Expression depth of " + details::to_str(static_cast(expression->node_depth())) + +" exceeds maximum allowed expression depth of " + details::to_str(static_cast(settings_.max_node_depth_)), +exprtk_error_location)); + +free_node(node_allocator_,expression); + +return error_node(); +} + +return expression; +} + +bool simplify_unary_negation_branch(expression_node_ptr& node) +{ +{ +typedef details::unary_branch_node > ubn_t; +ubn_t* n = dynamic_cast(node); + +if (n) +{ +expression_node_ptr un_r = n->branch(0); +n->release(); +free_node(node_allocator_,node); +node = un_r; + +return true; +} +} + +{ +typedef details::unary_variable_node > uvn_t; + +uvn_t* n = dynamic_cast(node); + +if (n) +{ +const T& v = n->v(); +expression_node_ptr return_node = error_node(); + +if ( +(0 != (return_node = symtab_store_.get_variable(v))) || +(0 != (return_node = sem_ .get_variable(v))) +) +{ +free_node(node_allocator_,node); +node = return_node; + +return true; +} +else +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR017 - Failed to find variable node in symbol table", +exprtk_error_location)); + +free_node(node_allocator_,node); + +return false; +} +} +} + +return false; +} + +static inline expression_node_ptr error_node() +{ +return reinterpret_cast(0); +} + +struct scoped_expression_delete +{ +scoped_expression_delete(parser& pr, expression_node_ptr& expression) +: delete_ptr(true) +, parser_(pr) +, expression_(expression) +{} + +~scoped_expression_delete() +{ +if (delete_ptr) +{ +free_node(parser_.node_allocator_, expression_); +} +} + +bool delete_ptr; +parser& parser_; +expression_node_ptr& expression_; + +private: + +scoped_expression_delete(const scoped_expression_delete&) exprtk_delete; +scoped_expression_delete& operator=(const scoped_expression_delete&) exprtk_delete; +}; + +template +struct scoped_delete +{ +typedef Type* ptr_t; + +scoped_delete(parser& pr, ptr_t& p) +: delete_ptr(true) +, parser_(pr) +, p_(&p) +{} + +scoped_delete(parser& pr, ptr_t (&p)[N]) +: delete_ptr(true) +, parser_(pr) +, p_(&p[0]) +{} + +~scoped_delete() +{ +if (delete_ptr) +{ +for (std::size_t i = 0; i < N; ++i) +{ +free_node(parser_.node_allocator_, p_[i]); +} +} +} + +bool delete_ptr; +parser& parser_; +ptr_t* p_; + +private: + +scoped_delete(const scoped_delete&) exprtk_delete; +scoped_delete& operator=(const scoped_delete&) exprtk_delete; +}; + +template +struct scoped_deq_delete +{ +typedef Type* ptr_t; + +scoped_deq_delete(parser& pr, std::deque& deq) +: delete_ptr(true) +, parser_(pr) +, deq_(deq) +{} + +~scoped_deq_delete() +{ +if (delete_ptr && !deq_.empty()) +{ +for (std::size_t i = 0; i < deq_.size(); ++i) +{ +free_node(parser_.node_allocator_,deq_[i]); +} + +deq_.clear(); +} +} + +bool delete_ptr; +parser& parser_; +std::deque& deq_; + +private: + +scoped_deq_delete(const scoped_deq_delete&) exprtk_delete; +scoped_deq_delete& operator=(const scoped_deq_delete&) exprtk_delete; +}; + +template +struct scoped_vec_delete +{ +typedef Type* ptr_t; + +scoped_vec_delete(parser& pr, std::vector& vec) +: delete_ptr(true) +, parser_(pr) +, vec_(vec) +{} + +~scoped_vec_delete() +{ +if (delete_ptr && !vec_.empty()) +{ +for (std::size_t i = 0; i < vec_.size(); ++i) +{ +free_node(parser_.node_allocator_,vec_[i]); +} + +vec_.clear(); +} +} + +bool delete_ptr; +parser& parser_; +std::vector& vec_; + +private: + +scoped_vec_delete(const scoped_vec_delete&) exprtk_delete; +scoped_vec_delete& operator=(const scoped_vec_delete&) exprtk_delete; +}; + +struct scoped_bool_negator +{ +explicit scoped_bool_negator(bool& bb) +: b(bb) +{ b = !b; } + +~scoped_bool_negator() +{ b = !b; } + +bool& b; +}; + +struct scoped_bool_or_restorer +{ +explicit scoped_bool_or_restorer(bool& bb) +: b(bb) +, original_value_(bb) +{} + +~scoped_bool_or_restorer() +{ +b = b || original_value_; +} + +bool& b; +bool original_value_; +}; + +struct scoped_inc_dec +{ +explicit scoped_inc_dec(std::size_t& v) +: v_(v) +{ ++v_; } + +~scoped_inc_dec() +{ +assert(v_ > 0); +--v_; +} + +std::size_t& v_; +}; + +inline expression_node_ptr parse_function_invocation(ifunction* function, const std::string& function_name) +{ +expression_node_ptr func_node = reinterpret_cast(0); + +switch (function->param_count) +{ +case 0 : func_node = parse_function_call_0 (function,function_name); break; +case 1 : func_node = parse_function_call< 1>(function,function_name); break; +case 2 : func_node = parse_function_call< 2>(function,function_name); break; +case 3 : func_node = parse_function_call< 3>(function,function_name); break; +case 4 : func_node = parse_function_call< 4>(function,function_name); break; +case 5 : func_node = parse_function_call< 5>(function,function_name); break; +case 6 : func_node = parse_function_call< 6>(function,function_name); break; +case 7 : func_node = parse_function_call< 7>(function,function_name); break; +case 8 : func_node = parse_function_call< 8>(function,function_name); break; +case 9 : func_node = parse_function_call< 9>(function,function_name); break; +case 10 : func_node = parse_function_call<10>(function,function_name); break; +case 11 : func_node = parse_function_call<11>(function,function_name); break; +case 12 : func_node = parse_function_call<12>(function,function_name); break; +case 13 : func_node = parse_function_call<13>(function,function_name); break; +case 14 : func_node = parse_function_call<14>(function,function_name); break; +case 15 : func_node = parse_function_call<15>(function,function_name); break; +case 16 : func_node = parse_function_call<16>(function,function_name); break; +case 17 : func_node = parse_function_call<17>(function,function_name); break; +case 18 : func_node = parse_function_call<18>(function,function_name); break; +case 19 : func_node = parse_function_call<19>(function,function_name); break; +case 20 : func_node = parse_function_call<20>(function,function_name); break; +default : { +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR018 - Invalid number of parameters for function: '" + function_name + "'", +exprtk_error_location)); + +return error_node(); +} +} + +if (func_node) +return func_node; +else +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR019 - Failed to generate call to function: '" + function_name + "'", +exprtk_error_location)); + +return error_node(); +} +} + +template +inline expression_node_ptr parse_function_call(ifunction* function, const std::string& function_name) +{ +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif +if (0 == NumberofParameters) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR020 - Expecting ifunction '" + function_name + "' to have non-zero parameter count", +exprtk_error_location)); + +return error_node(); +} +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +expression_node_ptr branch[NumberofParameters]; +expression_node_ptr result = error_node(); + +std::fill_n(branch, NumberofParameters, reinterpret_cast(0)); + +scoped_delete sd((*this),branch); + +next_token(); + +if (!token_is(token_t::e_lbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR021 - Expecting argument list for function: '" + function_name + "'", +exprtk_error_location)); + +return error_node(); +} + +for (int i = 0; i < static_cast(NumberofParameters); ++i) +{ +branch[i] = parse_expression(); + +if (0 == branch[i]) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR022 - Failed to parse argument " + details::to_str(i) + " for function: '" + function_name + "'", +exprtk_error_location)); + +return error_node(); +} +else if (i < static_cast(NumberofParameters - 1)) +{ +if (!token_is(token_t::e_comma)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR023 - Invalid number of arguments for function: '" + function_name + "'", +exprtk_error_location)); + +return error_node(); +} +} +} + +if (!token_is(token_t::e_rbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR024 - Invalid number of arguments for function: '" + function_name + "'", +exprtk_error_location)); + +return error_node(); +} +else +result = expression_generator_.function(function,branch); + +sd.delete_ptr = (0 == result); + +return result; +} + +inline expression_node_ptr parse_function_call_0(ifunction* function, const std::string& function_name) +{ +expression_node_ptr result = expression_generator_.function(function); + +state_.side_effect_present = function->has_side_effects(); + +next_token(); + +if ( +token_is(token_t::e_lbracket) && +!token_is(token_t::e_rbracket) +) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR025 - Expecting '()' to proceed call to function: '" + function_name + "'", +exprtk_error_location)); + +free_node(node_allocator_,result); + +return error_node(); +} +else +return result; +} + +template +inline std::size_t parse_base_function_call(expression_node_ptr (¶m_list)[MaxNumberofParameters], const std::string& function_name = "") +{ +std::fill_n(param_list, MaxNumberofParameters, reinterpret_cast(0)); + +scoped_delete sd((*this),param_list); + +next_token(); + +if (!token_is(token_t::e_lbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR026 - Expected a '(' at start of function call to '" + function_name + +"', instead got: '" + current_token().value + "'", +exprtk_error_location)); + +return 0; +} + +if (token_is(token_t::e_rbracket, e_hold)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR027 - Expected at least one input parameter for function call '" + function_name + "'", +exprtk_error_location)); + +return 0; +} + +std::size_t param_index = 0; + +for (; param_index < MaxNumberofParameters; ++param_index) +{ +param_list[param_index] = parse_expression(); + +if (0 == param_list[param_index]) +return 0; +else if (token_is(token_t::e_rbracket)) +{ +sd.delete_ptr = false; +break; +} +else if (token_is(token_t::e_comma)) +continue; +else +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR028 - Expected a ',' between function input parameters, instead got: '" + current_token().value + "'", +exprtk_error_location)); + +return 0; +} +} + +if (sd.delete_ptr) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR029 - Invalid number of input parameters passed to function '" + function_name + "'", +exprtk_error_location)); + +return 0; +} + +return (param_index + 1); +} + +inline expression_node_ptr parse_base_operation() +{ +typedef std::pair map_range_t; + +const std::string operation_name = current_token().value; +const token_t diagnostic_token = current_token(); + +map_range_t itr_range = base_ops_map_.equal_range(operation_name); + +if (0 == std::distance(itr_range.first,itr_range.second)) +{ +set_error( +make_error(parser_error::e_syntax, +diagnostic_token, +"ERR030 - No entry found for base operation: " + operation_name, +exprtk_error_location)); + +return error_node(); +} + +static const std::size_t MaxNumberofParameters = 4; +expression_node_ptr param_list[MaxNumberofParameters] = {0}; + +const std::size_t parameter_count = parse_base_function_call(param_list, operation_name); + +if ((parameter_count > 0) && (parameter_count <= MaxNumberofParameters)) +{ +for (base_ops_map_t::iterator itr = itr_range.first; itr != itr_range.second; ++itr) +{ +const details::base_operation_t& operation = itr->second; + +if (operation.num_params == parameter_count) +{ +switch (parameter_count) +{ +#define base_opr_case(N) \ + case N : { \ + expression_node_ptr pl##N[N] = {0}; \ + std::copy(param_list, param_list + N, pl##N); \ + lodge_symbol(operation_name, e_st_function); \ + return expression_generator_(operation.type, pl##N); \ + } \ + +base_opr_case(1) +base_opr_case(2) +base_opr_case(3) +base_opr_case(4) +#undef base_opr_case +} +} +} +} + +for (std::size_t i = 0; i < MaxNumberofParameters; ++i) +{ +free_node(node_allocator_, param_list[i]); +} + +set_error( +make_error(parser_error::e_syntax, +diagnostic_token, +"ERR031 - Invalid number of input parameters for call to function: '" + operation_name + "'", +exprtk_error_location)); + +return error_node(); +} + +inline expression_node_ptr parse_conditional_statement_01(expression_node_ptr condition) +{ +// Parse: [if][(][condition][,][consequent][,][alternative][)] + +expression_node_ptr consequent = error_node(); +expression_node_ptr alternative = error_node(); + +bool result = true; + +if (!token_is(token_t::e_comma)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR032 - Expected ',' between if-statement condition and consequent", +exprtk_error_location)); +result = false; +} +else if (0 == (consequent = parse_expression())) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR033 - Failed to parse consequent for if-statement", +exprtk_error_location)); +result = false; +} +else if (!token_is(token_t::e_comma)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR034 - Expected ',' between if-statement consequent and alternative", +exprtk_error_location)); +result = false; +} +else if (0 == (alternative = parse_expression())) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR035 - Failed to parse alternative for if-statement", +exprtk_error_location)); +result = false; +} +else if (!token_is(token_t::e_rbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR036 - Expected ')' at the end of if-statement", +exprtk_error_location)); +result = false; +} + +#ifndef exprtk_disable_string_capabilities +if (result) +{ +const bool consq_is_str = is_generally_string_node(consequent ); +const bool alter_is_str = is_generally_string_node(alternative); + +if (consq_is_str || alter_is_str) +{ +if (consq_is_str && alter_is_str) +{ +return expression_generator_ +.conditional_string(condition, consequent, alternative); +} + +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR037 - Return types of if-statement differ: string/non-string", +exprtk_error_location)); + +result = false; +} +} +#endif + +if (result) +{ +const bool consq_is_vec = is_ivector_node(consequent ); +const bool alter_is_vec = is_ivector_node(alternative); + +if (consq_is_vec || alter_is_vec) +{ +if (consq_is_vec && alter_is_vec) +{ +return expression_generator_ +.conditional_vector(condition, consequent, alternative); +} + +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR038 - Return types of if-statement differ: vector/non-vector", +exprtk_error_location)); + +result = false; +} +} + +if (!result) +{ +free_node(node_allocator_, condition ); +free_node(node_allocator_, consequent ); +free_node(node_allocator_, alternative); + +return error_node(); +} +else +return expression_generator_ +.conditional(condition, consequent, alternative); +} + +inline expression_node_ptr parse_conditional_statement_02(expression_node_ptr condition) +{ +expression_node_ptr consequent = error_node(); +expression_node_ptr alternative = error_node(); + +bool result = true; + +if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) +{ +if (0 == (consequent = parse_multi_sequence("if-statement-01"))) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR039 - Failed to parse body of consequent for if-statement", +exprtk_error_location)); + +result = false; +} +} +else +{ +if ( +settings_.commutative_check_enabled() && +token_is(token_t::e_mul,prsrhlpr_t::e_hold) +) +{ +next_token(); +} + +if (0 != (consequent = parse_expression())) +{ +if (!token_is(token_t::e_eof)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR040 - Expected ';' at the end of the consequent for if-statement", +exprtk_error_location)); + +result = false; +} +} +else +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR041 - Failed to parse body of consequent for if-statement", +exprtk_error_location)); + +result = false; +} +} + +if (result) +{ +if (details::imatch(current_token().value,"else")) +{ +next_token(); + +if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) +{ +if (0 == (alternative = parse_multi_sequence("else-statement-01"))) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR042 - Failed to parse body of the 'else' for if-statement", +exprtk_error_location)); + +result = false; +} +} +else if (details::imatch(current_token().value,"if")) +{ +if (0 == (alternative = parse_conditional_statement())) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR043 - Failed to parse body of if-else statement", +exprtk_error_location)); + +result = false; +} +} +else if (0 != (alternative = parse_expression())) +{ +if (!token_is(token_t::e_eof)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR044 - Expected ';' at the end of the 'else-if' for the if-statement", +exprtk_error_location)); + +result = false; +} +} +else +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR045 - Failed to parse body of the 'else' for if-statement", +exprtk_error_location)); + +result = false; +} +} +} + +#ifndef exprtk_disable_string_capabilities +if (result) +{ +const bool consq_is_str = is_generally_string_node(consequent ); +const bool alter_is_str = is_generally_string_node(alternative); + +if (consq_is_str || alter_is_str) +{ +if (consq_is_str && alter_is_str) +{ +return expression_generator_ +.conditional_string(condition, consequent, alternative); +} + +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR046 - Return types of if-statement differ: string/non-string", +exprtk_error_location)); + +result = false; +} +} +#endif + +if (result) +{ +const bool consq_is_vec = is_ivector_node(consequent ); +const bool alter_is_vec = is_ivector_node(alternative); + +if (consq_is_vec || alter_is_vec) +{ +if (consq_is_vec && alter_is_vec) +{ +return expression_generator_ +.conditional_vector(condition, consequent, alternative); +} + +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR047 - Return types of if-statement differ: vector/non-vector", +exprtk_error_location)); + +result = false; +} +} + +if (!result) +{ +free_node(node_allocator_, condition ); +free_node(node_allocator_, consequent ); +free_node(node_allocator_, alternative); + +return error_node(); +} +else +return expression_generator_ +.conditional(condition, consequent, alternative); +} + +inline expression_node_ptr parse_conditional_statement() +{ +expression_node_ptr condition = error_node(); + +next_token(); + +if (!token_is(token_t::e_lbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR048 - Expected '(' at start of if-statement, instead got: '" + current_token().value + "'", +exprtk_error_location)); + +return error_node(); +} +else if (0 == (condition = parse_expression())) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR049 - Failed to parse condition for if-statement", +exprtk_error_location)); + +return error_node(); +} +else if (token_is(token_t::e_comma,prsrhlpr_t::e_hold)) +{ +// if (x,y,z) +return parse_conditional_statement_01(condition); +} +else if (token_is(token_t::e_rbracket)) +{ +/* + 00. if (x) y; + 01. if (x) y; else z; + 02. if (x) y; else {z0; ... zn;} + 03. if (x) y; else if (z) w; + 04. if (x) y; else if (z) w; else u; + 05. if (x) y; else if (z) w; else {u0; ... un;} + 06. if (x) y; else if (z) {w0; ... wn;} + 07. if (x) {y0; ... yn;} + 08. if (x) {y0; ... yn;} else z; + 09. if (x) {y0; ... yn;} else {z0; ... zn;}; + 10. if (x) {y0; ... yn;} else if (z) w; + 11. if (x) {y0; ... yn;} else if (z) w; else u; + 12. if (x) {y0; ... nex;} else if (z) w; else {u0 ... un;} + 13. if (x) {y0; ... yn;} else if (z) {w0; ... wn;} + */ +return parse_conditional_statement_02(condition); +} + +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR050 - Invalid if-statement", +exprtk_error_location)); + +free_node(node_allocator_,condition); + +return error_node(); +} + +inline expression_node_ptr parse_ternary_conditional_statement(expression_node_ptr condition) +{ +// Parse: [condition][?][consequent][:][alternative] +expression_node_ptr consequent = error_node(); +expression_node_ptr alternative = error_node(); + +bool result = true; + +if (0 == condition) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR051 - Encountered invalid condition branch for ternary if-statement", +exprtk_error_location)); + +return error_node(); +} +else if (!token_is(token_t::e_ternary)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR052 - Expected '?' after condition of ternary if-statement", +exprtk_error_location)); + +result = false; +} +else if (0 == (consequent = parse_expression())) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR053 - Failed to parse consequent for ternary if-statement", +exprtk_error_location)); + +result = false; +} +else if (!token_is(token_t::e_colon)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR054 - Expected ':' between ternary if-statement consequent and alternative", +exprtk_error_location)); + +result = false; +} +else if (0 == (alternative = parse_expression())) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR055 - Failed to parse alternative for ternary if-statement", +exprtk_error_location)); + +result = false; +} + +#ifndef exprtk_disable_string_capabilities +if (result) +{ +const bool consq_is_str = is_generally_string_node(consequent ); +const bool alter_is_str = is_generally_string_node(alternative); + +if (consq_is_str || alter_is_str) +{ +if (consq_is_str && alter_is_str) +{ +return expression_generator_ +.conditional_string(condition, consequent, alternative); +} + +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR056 - Return types of ternary differ: string/non-string", +exprtk_error_location)); + +result = false; +} +} +#endif + +if (result) +{ +const bool consq_is_vec = is_ivector_node(consequent ); +const bool alter_is_vec = is_ivector_node(alternative); + +if (consq_is_vec || alter_is_vec) +{ +if (consq_is_vec && alter_is_vec) +{ +return expression_generator_ +.conditional_vector(condition, consequent, alternative); +} + +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR057 - Return types of ternary differ: vector/non-vector", +exprtk_error_location)); + +result = false; +} +} + +if (!result) +{ +free_node(node_allocator_, condition ); +free_node(node_allocator_, consequent ); +free_node(node_allocator_, alternative); + +return error_node(); +} +else +return expression_generator_ +.conditional(condition, consequent, alternative); +} + +inline expression_node_ptr parse_not_statement() +{ +if (settings_.logic_disabled("not")) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR058 - Invalid or disabled logic operation 'not'", +exprtk_error_location)); + +return error_node(); +} + +return parse_base_operation(); +} + +void handle_brkcnt_scope_exit() +{ +assert(!brkcnt_list_.empty()); +brkcnt_list_.pop_front(); +} + +inline expression_node_ptr parse_while_loop() +{ +// Parse: [while][(][test expr][)][{][expression][}] +expression_node_ptr condition = error_node(); +expression_node_ptr branch = error_node(); +expression_node_ptr result_node = error_node(); + +bool result = true; + +next_token(); + +if (!token_is(token_t::e_lbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR059 - Expected '(' at start of while-loop condition statement", +exprtk_error_location)); + +return error_node(); +} +else if (0 == (condition = parse_expression())) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR060 - Failed to parse condition for while-loop", +exprtk_error_location)); + +return error_node(); +} +else if (!token_is(token_t::e_rbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR061 - Expected ')' at end of while-loop condition statement", +exprtk_error_location)); + +result = false; +} + +brkcnt_list_.push_front(false); + +if (result) +{ +scoped_inc_dec sid(state_.parsing_loop_stmt_count); + +if (0 == (branch = parse_multi_sequence("while-loop", true))) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR062 - Failed to parse body of while-loop")); +result = false; +} +else if (0 == (result_node = expression_generator_.while_loop(condition, +branch, +brkcnt_list_.front()))) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR063 - Failed to synthesize while-loop", +exprtk_error_location)); + +result = false; +} +} + +handle_brkcnt_scope_exit(); + +if (!result) +{ +free_node(node_allocator_, branch ); +free_node(node_allocator_, condition ); +free_node(node_allocator_, result_node); + +return error_node(); +} + +return result_node; +} + +inline expression_node_ptr parse_repeat_until_loop() +{ +// Parse: [repeat][{][expression][}][until][(][test expr][)] +expression_node_ptr condition = error_node(); +expression_node_ptr branch = error_node(); +next_token(); + +std::vector arg_list; +std::vector side_effect_list; + +scoped_vec_delete sdd((*this),arg_list); + +brkcnt_list_.push_front(false); + +if (details::imatch(current_token().value,"until")) +{ +next_token(); +branch = node_allocator_.allocate >(); +} +else +{ +const token_t::token_type seperator = token_t::e_eof; + +scope_handler sh(*this); + +scoped_bool_or_restorer sbr(state_.side_effect_present); + +scoped_inc_dec sid(state_.parsing_loop_stmt_count); + +for ( ; ; ) +{ +state_.side_effect_present = false; + +expression_node_ptr arg = parse_expression(); + +if (0 == arg) +return error_node(); +else +{ +arg_list.push_back(arg); +side_effect_list.push_back(state_.side_effect_present); +} + +if (details::imatch(current_token().value,"until")) +{ +next_token(); +break; +} + +const bool is_next_until = peek_token_is(token_t::e_symbol) && +peek_token_is("until"); + +if (!token_is(seperator) && is_next_until) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR064 - Expected '" + token_t::to_str(seperator) + "' in body of repeat until loop", +exprtk_error_location)); + +return error_node(); +} + +if (details::imatch(current_token().value,"until")) +{ +next_token(); +break; +} +} + +branch = simplify(arg_list,side_effect_list); + +sdd.delete_ptr = (0 == branch); + +if (sdd.delete_ptr) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR065 - Failed to parse body of repeat until loop", +exprtk_error_location)); + +return error_node(); +} +} + +if (!token_is(token_t::e_lbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR066 - Expected '(' before condition statement of repeat until loop", +exprtk_error_location)); + +free_node(node_allocator_,branch); +return error_node(); +} +else if (0 == (condition = parse_expression())) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR067 - Failed to parse condition for repeat until loop", +exprtk_error_location)); + +free_node(node_allocator_,branch); +return error_node(); +} +else if (!token_is(token_t::e_rbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR068 - Expected ')' after condition of repeat until loop", +exprtk_error_location)); + +free_node(node_allocator_, branch ); +free_node(node_allocator_, condition); + +return error_node(); +} + +expression_node_ptr result; + +result = expression_generator_ +.repeat_until_loop(condition, branch, brkcnt_list_.front()); + +if (0 == result) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR069 - Failed to synthesize repeat until loop", +exprtk_error_location)); + +free_node(node_allocator_,condition); + +return error_node(); +} + +handle_brkcnt_scope_exit(); + +return result; +} + +inline expression_node_ptr parse_for_loop() +{ +expression_node_ptr initialiser = error_node(); +expression_node_ptr condition = error_node(); +expression_node_ptr incrementor = error_node(); +expression_node_ptr loop_body = error_node(); + +scope_element* se = 0; +bool result = true; + +next_token(); + +scope_handler sh(*this); + +if (!token_is(token_t::e_lbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR070 - Expected '(' at start of for-loop", +exprtk_error_location)); + +return error_node(); +} + +if (!token_is(token_t::e_eof)) +{ +if ( +!token_is(token_t::e_symbol,prsrhlpr_t::e_hold) && +details::imatch(current_token().value,"var") +) +{ +next_token(); + +if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR071 - Expected a variable at the start of initialiser section of for-loop", +exprtk_error_location)); + +return error_node(); +} +else if (!peek_token_is(token_t::e_assign)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR072 - Expected variable assignment of initialiser section of for-loop", +exprtk_error_location)); + +return error_node(); +} + +const std::string loop_counter_symbol = current_token().value; + +se = &sem_.get_element(loop_counter_symbol); + +if ((se->name == loop_counter_symbol) && se->active) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR073 - For-loop variable '" + loop_counter_symbol+ "' is being shadowed by a previous declaration", +exprtk_error_location)); + +return error_node(); +} +else if (!symtab_store_.is_variable(loop_counter_symbol)) +{ +if ( +!se->active && +(se->name == loop_counter_symbol) && +(se->type == scope_element::e_variable) +) +{ +se->active = true; +se->ref_count++; +} +else +{ +scope_element nse; +nse.name = loop_counter_symbol; +nse.active = true; +nse.ref_count = 1; +nse.type = scope_element::e_variable; +nse.depth = state_.scope_depth; +nse.data = new T(T(0)); +nse.var_node = node_allocator_.allocate(*reinterpret_cast(nse.data)); + +if (!sem_.add_element(nse)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR074 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM", +exprtk_error_location)); + +sem_.free_element(nse); + +result = false; +} +else +{ +exprtk_debug(("parse_for_loop() - INFO - Added new local variable: %s\n",nse.name.c_str())); + +state_.activate_side_effect("parse_for_loop()"); +} +} +} +} + +if (0 == (initialiser = parse_expression())) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR075 - Failed to parse initialiser of for-loop", +exprtk_error_location)); + +result = false; +} +else if (!token_is(token_t::e_eof)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR076 - Expected ';' after initialiser of for-loop", +exprtk_error_location)); + +result = false; +} +} + +if (!token_is(token_t::e_eof)) +{ +if (0 == (condition = parse_expression())) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR077 - Failed to parse condition of for-loop", +exprtk_error_location)); + +result = false; +} +else if (!token_is(token_t::e_eof)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR078 - Expected ';' after condition section of for-loop", +exprtk_error_location)); + +result = false; +} +} + +if (!token_is(token_t::e_rbracket)) +{ +if (0 == (incrementor = parse_expression())) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR079 - Failed to parse incrementor of for-loop", +exprtk_error_location)); + +result = false; +} +else if (!token_is(token_t::e_rbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR080 - Expected ')' after incrementor section of for-loop", +exprtk_error_location)); + +result = false; +} +} + +if (result) +{ +brkcnt_list_.push_front(false); + +scoped_inc_dec sid(state_.parsing_loop_stmt_count); + +if (0 == (loop_body = parse_multi_sequence("for-loop", true))) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR081 - Failed to parse body of for-loop", +exprtk_error_location)); + +result = false; +} +} + +if (!result) +{ +if (se) +{ +se->ref_count--; +} + +free_node(node_allocator_, initialiser); +free_node(node_allocator_, condition ); +free_node(node_allocator_, incrementor); +free_node(node_allocator_, loop_body ); +return error_node(); +} + +expression_node_ptr result_node = +expression_generator_.for_loop(initialiser, +condition, +incrementor, +loop_body, +brkcnt_list_.front()); +handle_brkcnt_scope_exit(); + +return result_node; +} + +inline expression_node_ptr parse_switch_statement() +{ +std::vector arg_list; +expression_node_ptr result = error_node(); + +if (!details::imatch(current_token().value,"switch")) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR082 - Expected keyword 'switch'", +exprtk_error_location)); + +return error_node(); +} + +scoped_vec_delete svd((*this),arg_list); + +next_token(); + +if (!token_is(token_t::e_lcrlbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR083 - Expected '{' for call to switch statement", +exprtk_error_location)); + +return error_node(); +} + +expression_node_ptr default_statement = error_node(); + +scoped_expression_delete defstmt_delete((*this), default_statement); + +for ( ; ; ) +{ +if (details::imatch("case",current_token().value)) +{ +next_token(); + +expression_node_ptr condition = parse_expression(); + +if (0 == condition) +return error_node(); +else if (!token_is(token_t::e_colon)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR084 - Expected ':' for case of switch statement", +exprtk_error_location)); + +free_node(node_allocator_, condition); + +return error_node(); +} + +expression_node_ptr consequent = parse_expression(); + +if (0 == consequent) +{ +free_node(node_allocator_, condition); + +return error_node(); +} +else if (!token_is(token_t::e_eof)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR085 - Expected ';' at end of case for switch statement", +exprtk_error_location)); + +free_node(node_allocator_, condition ); +free_node(node_allocator_, consequent); + +return error_node(); +} + +// Can we optimise away the case statement? +if (is_constant_node(condition) && is_false(condition)) +{ +free_node(node_allocator_, condition ); +free_node(node_allocator_, consequent); +} +else +{ +arg_list.push_back(condition ); +arg_list.push_back(consequent); +} + +} +else if (details::imatch("default",current_token().value)) +{ +if (0 != default_statement) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR086 - Multiple default cases for switch statement", +exprtk_error_location)); + +return error_node(); +} + +next_token(); + +if (!token_is(token_t::e_colon)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR087 - Expected ':' for default of switch statement", +exprtk_error_location)); + +return error_node(); +} + +if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) +default_statement = parse_multi_sequence("switch-default"); +else +default_statement = parse_expression(); + +if (0 == default_statement) +return error_node(); +else if (!token_is(token_t::e_eof)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR088 - Expected ';' at end of default for switch statement", +exprtk_error_location)); + +return error_node(); +} +} +else if (token_is(token_t::e_rcrlbracket)) +break; +else +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR089 - Expected '}' at end of switch statement", +exprtk_error_location)); + +return error_node(); +} +} + +const bool default_statement_present = (0 != default_statement); + +if (default_statement_present) +{ +arg_list.push_back(default_statement); +} + +result = expression_generator_.switch_statement(arg_list, (0 != default_statement)); + +svd.delete_ptr = (0 == result); +defstmt_delete.delete_ptr = (0 == result); + +return result; +} + +inline expression_node_ptr parse_multi_switch_statement() +{ +std::vector arg_list; + +if (!details::imatch(current_token().value,"[*]")) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR090 - Expected token '[*]'", +exprtk_error_location)); + +return error_node(); +} + +scoped_vec_delete svd((*this),arg_list); + +next_token(); + +if (!token_is(token_t::e_lcrlbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR091 - Expected '{' for call to [*] statement", +exprtk_error_location)); + +return error_node(); +} + +for ( ; ; ) +{ +if (!details::imatch("case",current_token().value)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR092 - Expected a 'case' statement for multi-switch", +exprtk_error_location)); + +return error_node(); +} + +next_token(); + +expression_node_ptr condition = parse_expression(); + +if (0 == condition) +return error_node(); + +if (!token_is(token_t::e_colon)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR093 - Expected ':' for case of [*] statement", +exprtk_error_location)); + +return error_node(); +} + +expression_node_ptr consequent = parse_expression(); + +if (0 == consequent) +return error_node(); + +if (!token_is(token_t::e_eof)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR094 - Expected ';' at end of case for [*] statement", +exprtk_error_location)); + +return error_node(); +} + +// Can we optimise away the case statement? +if (is_constant_node(condition) && is_false(condition)) +{ +free_node(node_allocator_, condition ); +free_node(node_allocator_, consequent); +} +else +{ +arg_list.push_back(condition ); +arg_list.push_back(consequent); +} + +if (token_is(token_t::e_rcrlbracket,prsrhlpr_t::e_hold)) +{ +break; +} +} + +if (!token_is(token_t::e_rcrlbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR095 - Expected '}' at end of [*] statement", +exprtk_error_location)); + +return error_node(); +} + +const expression_node_ptr result = expression_generator_.multi_switch_statement(arg_list); + +svd.delete_ptr = (0 == result); + +return result; +} + +inline expression_node_ptr parse_vararg_function() +{ +std::vector arg_list; + +details::operator_type opt_type = details::e_default; +const std::string symbol = current_token().value; + +if (details::imatch(symbol,"~")) +{ +next_token(); +return parse_multi_sequence(); +} +else if (details::imatch(symbol,"[*]")) +{ +return parse_multi_switch_statement(); +} +else if (details::imatch(symbol, "avg" )) opt_type = details::e_avg ; +else if (details::imatch(symbol, "mand")) opt_type = details::e_mand; +else if (details::imatch(symbol, "max" )) opt_type = details::e_max ; +else if (details::imatch(symbol, "min" )) opt_type = details::e_min ; +else if (details::imatch(symbol, "mor" )) opt_type = details::e_mor ; +else if (details::imatch(symbol, "mul" )) opt_type = details::e_prod; +else if (details::imatch(symbol, "sum" )) opt_type = details::e_sum ; +else +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR096 - Unsupported built-in vararg function: " + symbol, +exprtk_error_location)); + +return error_node(); +} + +scoped_vec_delete sdd((*this),arg_list); + +lodge_symbol(symbol, e_st_function); + +next_token(); + +if (!token_is(token_t::e_lbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR097 - Expected '(' for call to vararg function: " + symbol, +exprtk_error_location)); + +return error_node(); +} + +if (token_is(token_t::e_rbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR098 - vararg function: " + symbol + +" requires at least one input parameter", +exprtk_error_location)); + +return error_node(); +} + +for ( ; ; ) +{ +expression_node_ptr arg = parse_expression(); + +if (0 == arg) +return error_node(); +else +arg_list.push_back(arg); + +if (token_is(token_t::e_rbracket)) +break; +else if (!token_is(token_t::e_comma)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR099 - Expected ',' for call to vararg function: " + symbol, +exprtk_error_location)); + +return error_node(); +} +} + +const expression_node_ptr result = expression_generator_.vararg_function(opt_type,arg_list); + +sdd.delete_ptr = (0 == result); +return result; +} + +#ifndef exprtk_disable_string_capabilities +inline expression_node_ptr parse_string_range_statement(expression_node_ptr& expression) +{ +if (!token_is(token_t::e_lsqrbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR100 - Expected '[' as start of string range definition", +exprtk_error_location)); + +free_node(node_allocator_,expression); + +return error_node(); +} +else if (token_is(token_t::e_rsqrbracket)) +{ +return node_allocator_.allocate >(expression); +} + +range_t rp; + +if (!parse_range(rp,true)) +{ +free_node(node_allocator_,expression); + +return error_node(); +} + +expression_node_ptr result = expression_generator_(expression,rp); + +if (0 == result) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR101 - Failed to generate string range node", +exprtk_error_location)); + +free_node(node_allocator_,expression); +rp.free(); +} + +rp.clear(); + +return result; +} +#else +inline expression_node_ptr parse_string_range_statement(expression_node_ptr&) +{ +return error_node(); +} +#endif + +inline void parse_pending_string_rangesize(expression_node_ptr& expression) +{ +// Allow no more than 100 range calls, eg: s[][][]...[][] +const std::size_t max_rangesize_parses = 100; + +std::size_t i = 0; + +while +( +(0 != expression) && +(i++ < max_rangesize_parses) && +error_list_.empty() && +is_generally_string_node(expression) && +token_is(token_t::e_lsqrbracket,prsrhlpr_t::e_hold) +) +{ +expression = parse_string_range_statement(expression); +} +} + +template class Sequence> +inline expression_node_ptr simplify(Sequence& expression_list, +Sequence& side_effect_list, +const bool specialise_on_final_type = false) +{ +if (expression_list.empty()) +return error_node(); +else if (1 == expression_list.size()) +return expression_list[0]; + +Sequence tmp_expression_list; + +bool return_node_present = false; + +for (std::size_t i = 0; i < (expression_list.size() - 1); ++i) +{ +if (is_variable_node(expression_list[i])) +continue; +else if ( +is_return_node (expression_list[i]) || +is_break_node (expression_list[i]) || +is_continue_node(expression_list[i]) +) +{ +tmp_expression_list.push_back(expression_list[i]); + +// Remove all subexpressions after first short-circuit +// node has been encountered. + +for (std::size_t j = i + 1; j < expression_list.size(); ++j) +{ +free_node(node_allocator_,expression_list[j]); +} + +return_node_present = true; + +break; +} +else if ( +is_constant_node(expression_list[i]) || +is_null_node (expression_list[i]) || +!side_effect_list[i] +) +{ +free_node(node_allocator_,expression_list[i]); +continue; +} +else +tmp_expression_list.push_back(expression_list[i]); +} + +if (!return_node_present) +{ +tmp_expression_list.push_back(expression_list.back()); +} + +expression_list.swap(tmp_expression_list); + +if (tmp_expression_list.size() > expression_list.size()) +{ +exprtk_debug(("simplify() - Reduced subexpressions from %d to %d\n", +static_cast(tmp_expression_list.size()), +static_cast(expression_list .size()))); +} + +if ( +return_node_present || +side_effect_list.back() || +(expression_list.size() > 1) +) +state_.activate_side_effect("simplify()"); + +if (1 == expression_list.size()) +return expression_list[0]; +else if (specialise_on_final_type && is_generally_string_node(expression_list.back())) +return expression_generator_.vararg_function(details::e_smulti,expression_list); +else +return expression_generator_.vararg_function(details::e_multi,expression_list); +} + +inline expression_node_ptr parse_multi_sequence(const std::string& source = "", +const bool enforce_crlbrackets = false) +{ +token_t::token_type open_bracket = token_t::e_lcrlbracket; +token_t::token_type close_bracket = token_t::e_rcrlbracket; +token_t::token_type seperator = token_t::e_eof; + +if (!token_is(open_bracket)) +{ +if (!enforce_crlbrackets && token_is(token_t::e_lbracket)) +{ +open_bracket = token_t::e_lbracket; +close_bracket = token_t::e_rbracket; +seperator = token_t::e_comma; +} +else +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR102 - Expected '" + token_t::to_str(open_bracket) + "' for call to multi-sequence" + +((!source.empty()) ? std::string(" section of " + source): ""), +exprtk_error_location)); + +return error_node(); +} +} +else if (token_is(close_bracket)) +{ +return node_allocator_.allocate >(); +} + +std::vector arg_list; +std::vector side_effect_list; + +expression_node_ptr result = error_node(); + +scoped_vec_delete sdd((*this),arg_list); + +scope_handler sh(*this); + +scoped_bool_or_restorer sbr(state_.side_effect_present); + +for ( ; ; ) +{ +state_.side_effect_present = false; + +expression_node_ptr arg = parse_expression(); + +if (0 == arg) +return error_node(); +else +{ +arg_list.push_back(arg); +side_effect_list.push_back(state_.side_effect_present); +} + +if (token_is(close_bracket)) +break; + +const bool is_next_close = peek_token_is(close_bracket); + +if (!token_is(seperator) && is_next_close) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR103 - Expected '" + details::to_str(seperator) + "' for call to multi-sequence section of " + source, +exprtk_error_location)); + +return error_node(); +} + +if (token_is(close_bracket)) +break; +} + +result = simplify(arg_list, side_effect_list, source.empty()); + +sdd.delete_ptr = (0 == result); +return result; +} + +inline bool parse_range(range_t& rp, const bool skip_lsqr = false) +{ +// Examples of valid ranges: +// 1. [1:5] -> 1..5 +// 2. [ :5] -> 0..5 +// 3. [1: ] -> 1..end +// 4. [x:y] -> x..y where x <= y +// 5. [x+1:y/2] -> x+1..y/2 where x+1 <= y/2 +// 6. [ :y] -> 0..y where 0 <= y +// 7. [x: ] -> x..end where x <= end + +rp.clear(); + +if (!skip_lsqr && !token_is(token_t::e_lsqrbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR104 - Expected '[' for start of range", +exprtk_error_location)); + +return false; +} + +if (token_is(token_t::e_colon)) +{ +rp.n0_c.first = true; +rp.n0_c.second = 0; +rp.cache.first = 0; +} +else +{ +expression_node_ptr r0 = parse_expression(); + +if (0 == r0) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR105 - Failed parse begin section of range", +exprtk_error_location)); + +return false; +} +else if (is_constant_node(r0)) +{ +const T r0_value = r0->value(); + +if (r0_value >= T(0)) +{ +rp.n0_c.first = true; +rp.n0_c.second = static_cast(details::numeric::to_int64(r0_value)); +rp.cache.first = rp.n0_c.second; +} + +free_node(node_allocator_,r0); + +if (r0_value < T(0)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR106 - Range lower bound less than zero! Constraint: r0 >= 0", +exprtk_error_location)); + +return false; +} +} +else +{ +rp.n0_e.first = true; +rp.n0_e.second = r0; +} + +if (!token_is(token_t::e_colon)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR107 - Expected ':' for break in range", +exprtk_error_location)); + +rp.free(); + +return false; +} +} + +if (token_is(token_t::e_rsqrbracket)) +{ +rp.n1_c.first = true; +rp.n1_c.second = std::numeric_limits::max(); +} +else +{ +expression_node_ptr r1 = parse_expression(); + +if (0 == r1) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR108 - Failed parse end section of range", +exprtk_error_location)); + +rp.free(); + +return false; +} +else if (is_constant_node(r1)) +{ +const T r1_value = r1->value(); + +if (r1_value >= T(0)) +{ +rp.n1_c.first = true; +rp.n1_c.second = static_cast(details::numeric::to_int64(r1_value)); +rp.cache.second = rp.n1_c.second; +} + +free_node(node_allocator_,r1); + +if (r1_value < T(0)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR109 - Range upper bound less than zero! Constraint: r1 >= 0", +exprtk_error_location)); + +rp.free(); + +return false; +} +} +else +{ +rp.n1_e.first = true; +rp.n1_e.second = r1; +} + +if (!token_is(token_t::e_rsqrbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR110 - Expected ']' for start of range", +exprtk_error_location)); + +rp.free(); + +return false; +} +} + +if (rp.const_range()) +{ +std::size_t r0 = 0; +std::size_t r1 = 0; + +bool rp_result = false; + +try +{ +rp_result = rp(r0, r1); +} +catch (std::runtime_error&) +{} + +if (!rp_result || (r0 > r1)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR111 - Invalid range, Constraint: r0 <= r1", +exprtk_error_location)); + +return false; +} +} + +return true; +} + +inline void lodge_symbol(const std::string& symbol, +const symbol_type st) +{ +dec_.add_symbol(symbol,st); +} + +#ifndef exprtk_disable_string_capabilities +inline expression_node_ptr parse_string() +{ +const std::string symbol = current_token().value; + +typedef details::stringvar_node* strvar_node_t; + +expression_node_ptr result = error_node(); +strvar_node_t const_str_node = static_cast(0); + +scope_element& se = sem_.get_active_element(symbol); + +if (scope_element::e_string == se.type) +{ +se.active = true; +result = se.str_node; +lodge_symbol(symbol, e_st_local_string); +} +else +{ +typedef typename symtab_store::string_context str_ctxt_t; +str_ctxt_t str_ctx = symtab_store_.get_string_context(symbol); + +if ((0 == str_ctx.str_var) || !symtab_store_.is_conststr_stringvar(symbol)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR112 - Unknown string symbol", +exprtk_error_location)); + +return error_node(); +} + +assert(str_ctx.str_var != 0); +assert(str_ctx.symbol_table != 0); + +result = str_ctx.str_var; + +if (symtab_store_.is_constant_string(symbol)) +{ +const_str_node = static_cast(result); +result = expression_generator_(const_str_node->str()); +} +else if (symbol_table_t::e_immutable == str_ctx.symbol_table->mutability()) +{ +lodge_immutable_symbol( +current_token(), +make_memory_range(str_ctx.str_var->base(), str_ctx.str_var->size())); +} + +lodge_symbol(symbol, e_st_string); +} + +if (peek_token_is(token_t::e_lsqrbracket)) +{ +next_token(); + +if (peek_token_is(token_t::e_rsqrbracket)) +{ +next_token(); +next_token(); + +if (const_str_node) +{ +free_node(node_allocator_,result); + +return expression_generator_(T(const_str_node->size())); +} +else +return node_allocator_.allocate > +(static_cast*>(result)->ref()); +} + +range_t rp; + +if (!parse_range(rp)) +{ +free_node(node_allocator_,result); + +return error_node(); +} +else if (const_str_node) +{ +free_node(node_allocator_,result); +result = expression_generator_(const_str_node->ref(),rp); +} +else +result = expression_generator_(static_cast*> +(result)->ref(), rp); + +if (result) +rp.clear(); +} +else +next_token(); + +return result; +} +#else +inline expression_node_ptr parse_string() +{ +return error_node(); +} +#endif + +#ifndef exprtk_disable_string_capabilities +inline expression_node_ptr parse_const_string() +{ +const std::string const_str = current_token().value; +expression_node_ptr result = expression_generator_(const_str); + +if (peek_token_is(token_t::e_lsqrbracket)) +{ +next_token(); + +if (peek_token_is(token_t::e_rsqrbracket)) +{ +next_token(); +next_token(); + +free_node(node_allocator_,result); + +return expression_generator_(T(const_str.size())); +} + +range_t rp; + +if (!parse_range(rp)) +{ +free_node(node_allocator_,result); +rp.free(); + +return error_node(); +} + +free_node(node_allocator_,result); + +if (rp.n1_c.first && (rp.n1_c.second == std::numeric_limits::max())) +{ +rp.n1_c.second = const_str.size() - 1; +rp.cache.second = rp.n1_c.second; +} + +if ( +(rp.n0_c.first && (rp.n0_c.second >= const_str.size())) || +(rp.n1_c.first && (rp.n1_c.second >= const_str.size())) +) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR113 - Overflow in range for string: '" + const_str + "'[" + +(rp.n0_c.first ? details::to_str(static_cast(rp.n0_c.second)) : "?") + ":" + +(rp.n1_c.first ? details::to_str(static_cast(rp.n1_c.second)) : "?") + "]", +exprtk_error_location)); + +rp.free(); + +return error_node(); +} + +result = expression_generator_(const_str,rp); + +if (result) +rp.clear(); +} +else +next_token(); + +return result; +} +#else +inline expression_node_ptr parse_const_string() +{ +return error_node(); +} +#endif + +inline expression_node_ptr parse_vector() +{ +const std::string symbol = current_token().value; + +vector_holder_ptr vec = vector_holder_ptr(0); + +const scope_element& se = sem_.get_active_element(symbol); + +if ( +!details::imatch(se.name, symbol) || +(se.depth > state_.scope_depth) || +(scope_element::e_vector != se.type) +) +{ +typedef typename symtab_store::vector_context vec_ctxt_t; +vec_ctxt_t vec_ctx = symtab_store_.get_vector_context(symbol); + +if (0 == vec_ctx.vector_holder) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR114 - Symbol '" + symbol+ " not a vector", +exprtk_error_location)); + +return error_node(); +} + +assert(0 != vec_ctx.vector_holder); +assert(0 != vec_ctx.symbol_table ); + +vec = vec_ctx.vector_holder; + +if (symbol_table_t::e_immutable == vec_ctx.symbol_table->mutability()) +{ +lodge_immutable_symbol( +current_token(), +make_memory_range(vec->data(), vec->size())); +} +} +else +vec = se.vec_node; + +assert(0 != vec); + +expression_node_ptr index_expr = error_node(); + +next_token(); + +if (!token_is(token_t::e_lsqrbracket)) +{ +return node_allocator_.allocate(vec); +} +else if (token_is(token_t::e_rsqrbracket)) +{ +return expression_generator_(T(vec->size())); +} +else if (0 == (index_expr = parse_expression())) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR115 - Failed to parse index for vector: '" + symbol + "'", +exprtk_error_location)); + +return error_node(); +} +else if (!token_is(token_t::e_rsqrbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR116 - Expected ']' for index of vector: '" + symbol + "'", +exprtk_error_location)); + +free_node(node_allocator_,index_expr); + +return error_node(); +} + +// Perform compile-time range check +if (details::is_constant_node(index_expr)) +{ +const std::size_t index = static_cast(details::numeric::to_int32(index_expr->value())); +const std::size_t vec_size = vec->size(); + +if (index >= vec_size) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR117 - Index of " + details::to_str(index) + " out of range for " +"vector '" + symbol + "' of size " + details::to_str(vec_size), +exprtk_error_location)); + +free_node(node_allocator_,index_expr); + +return error_node(); +} +} + +return expression_generator_.vector_element(symbol, vec, index_expr); +} + +inline expression_node_ptr parse_vararg_function_call(ivararg_function* vararg_function, const std::string& vararg_function_name) +{ +std::vector arg_list; + +expression_node_ptr result = error_node(); + +scoped_vec_delete sdd((*this),arg_list); + +next_token(); + +if (token_is(token_t::e_lbracket)) +{ +if (token_is(token_t::e_rbracket)) +{ +if (!vararg_function->allow_zero_parameters()) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR118 - Zero parameter call to vararg function: " ++ vararg_function_name + " not allowed", +exprtk_error_location)); + +return error_node(); +} +} +else +{ +for ( ; ; ) +{ +expression_node_ptr arg = parse_expression(); + +if (0 == arg) +return error_node(); +else +arg_list.push_back(arg); + +if (token_is(token_t::e_rbracket)) +break; +else if (!token_is(token_t::e_comma)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR119 - Expected ',' for call to vararg function: " ++ vararg_function_name, +exprtk_error_location)); + +return error_node(); +} +} +} +} +else if (!vararg_function->allow_zero_parameters()) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR120 - Zero parameter call to vararg function: " ++ vararg_function_name + " not allowed", +exprtk_error_location)); + +return error_node(); +} + +if (arg_list.size() < vararg_function->min_num_args()) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR121 - Invalid number of parameters to call to vararg function: " ++ vararg_function_name + ", require at least " ++ details::to_str(static_cast(vararg_function->min_num_args())) + " parameters", +exprtk_error_location)); + +return error_node(); +} +else if (arg_list.size() > vararg_function->max_num_args()) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR122 - Invalid number of parameters to call to vararg function: " ++ vararg_function_name + ", require no more than " ++ details::to_str(static_cast(vararg_function->max_num_args())) + " parameters", +exprtk_error_location)); + +return error_node(); +} + +result = expression_generator_.vararg_function_call(vararg_function,arg_list); + +sdd.delete_ptr = (0 == result); + +return result; +} + +class type_checker +{ +public: + +enum return_type_t +{ +e_overload = ' ', +e_numeric = 'T', +e_string = 'S' +}; + +struct function_prototype_t +{ +return_type_t return_type; +std::string param_seq; +}; + +typedef parser parser_t; +typedef std::vector function_definition_list_t; + +type_checker(parser_t& p, +const std::string& func_name, +const std::string& func_prototypes, +const return_type_t default_return_type) +: invalid_state_(true) +, parser_(p) +, function_name_(func_name) +, default_return_type_(default_return_type) +{ +parse_function_prototypes(func_prototypes); +} + +bool verify(const std::string& param_seq, std::size_t& pseq_index) +{ +if (function_definition_list_.empty()) +return true; + +std::vector > error_list; + +for (std::size_t i = 0; i < function_definition_list_.size(); ++i) +{ +details::char_t diff_value = 0; +std::size_t diff_index = 0; + +const bool result = details::sequence_match(function_definition_list_[i].param_seq, +param_seq, +diff_index, diff_value); + +if (result) +{ +pseq_index = i; +return true; +} +else +error_list.push_back(std::make_pair(diff_index, diff_value)); +} + +if (1 == error_list.size()) +{ +parser_. +set_error( +make_error(parser_error::e_syntax, +parser_.current_token(), +"ERR123 - Failed parameter type check for function '" + function_name_ + "', " +"Expected '" + function_definition_list_[0].param_seq + +"' call set: '" + param_seq + "'", +exprtk_error_location)); +} +else +{ +// find first with largest diff_index; +std::size_t max_diff_index = 0; + +for (std::size_t i = 1; i < error_list.size(); ++i) +{ +if (error_list[i].first > error_list[max_diff_index].first) +{ +max_diff_index = i; +} +} + +parser_. +set_error( +make_error(parser_error::e_syntax, +parser_.current_token(), +"ERR124 - Failed parameter type check for function '" + function_name_ + "', " +"Best match: '" + function_definition_list_[max_diff_index].param_seq + +"' call set: '" + param_seq + "'", +exprtk_error_location)); +} + +return false; +} + +std::size_t paramseq_count() const +{ +return function_definition_list_.size(); +} + +std::string paramseq(const std::size_t& index) const +{ +return function_definition_list_[index].param_seq; +} + +return_type_t return_type(const std::size_t& index) const +{ +return function_definition_list_[index].return_type; +} + +bool invalid() const +{ +return !invalid_state_; +} + +bool allow_zero_parameters() const +{ + +for (std::size_t i = 0; i < function_definition_list_.size(); ++i) +{ +if (std::string::npos != function_definition_list_[i].param_seq.find("Z")) +{ +return true; +} +} + +return false; +} + +private: + +std::vector split_param_seq(const std::string& param_seq, const details::char_t delimiter = '|') const +{ +std::string::const_iterator current_begin = param_seq.begin(); +std::string::const_iterator iter = param_seq.begin(); + +std::vector result; + +while (iter != param_seq.end()) +{ +if (*iter == delimiter) +{ +result.push_back(std::string(current_begin, iter)); +current_begin = ++iter; +} +else +++iter; +} + +if (current_begin != iter) +{ +result.push_back(std::string(current_begin, iter)); +} + +return result; +} + +inline bool is_valid_token(std::string param_seq, +function_prototype_t& funcproto) const +{ +// Determine return type +funcproto.return_type = default_return_type_; + +if (param_seq.size() > 2) +{ +if (':' == param_seq[1]) +{ +// Note: Only overloaded igeneric functions can have return +// type definitions. +if (type_checker::e_overload != default_return_type_) +return false; + +switch (param_seq[0]) +{ +case 'T' : funcproto.return_type = type_checker::e_numeric; +break; + +case 'S' : funcproto.return_type = type_checker::e_string; +break; + +default : return false; +} + +param_seq.erase(0,2); +} +} + +if ( +(std::string::npos != param_seq.find("?*")) || +(std::string::npos != param_seq.find("**")) +) +{ +return false; +} +else if ( +(std::string::npos == param_seq.find_first_not_of("STV*?|")) || +("Z" == param_seq) +) +{ +funcproto.param_seq = param_seq; +return true; +} + +return false; +} + +void parse_function_prototypes(const std::string& func_prototypes) +{ +if (func_prototypes.empty()) +return; + +std::vector param_seq_list = split_param_seq(func_prototypes); + +typedef std::map param_seq_map_t; +param_seq_map_t param_seq_map; + +for (std::size_t i = 0; i < param_seq_list.size(); ++i) +{ +function_prototype_t func_proto; + +if (!is_valid_token(param_seq_list[i], func_proto)) +{ +invalid_state_ = false; + +parser_. +set_error( +make_error(parser_error::e_syntax, +parser_.current_token(), +"ERR125 - Invalid parameter sequence of '" + param_seq_list[i] + +"' for function: " + function_name_, +exprtk_error_location)); +return; +} + +param_seq_map_t::const_iterator seq_itr = param_seq_map.find(param_seq_list[i]); + +if (param_seq_map.end() != seq_itr) +{ +invalid_state_ = false; + +parser_. +set_error( +make_error(parser_error::e_syntax, +parser_.current_token(), +"ERR126 - Function '" + function_name_ + "' has a parameter sequence conflict between " + +"pseq_idx[" + details::to_str(seq_itr->second) + "] and" + +"pseq_idx[" + details::to_str(i) + "] " + +"param seq: " + param_seq_list[i], +exprtk_error_location)); +return; +} + +function_definition_list_.push_back(func_proto); +} +} + +type_checker(const type_checker&) exprtk_delete; +type_checker& operator=(const type_checker&) exprtk_delete; + +bool invalid_state_; +parser_t& parser_; +std::string function_name_; +const return_type_t default_return_type_; +function_definition_list_t function_definition_list_; +}; + +inline expression_node_ptr parse_generic_function_call(igeneric_function* function, const std::string& function_name) +{ +std::vector arg_list; + +scoped_vec_delete sdd((*this),arg_list); + +next_token(); + +std::string param_type_list; + +type_checker tc( +(*this), +function_name, +function->parameter_sequence, +type_checker::e_string); + +if (tc.invalid()) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR127 - Type checker instantiation failure for generic function: " + function_name, +exprtk_error_location)); + +return error_node(); +} + +if (token_is(token_t::e_lbracket)) +{ +if (token_is(token_t::e_rbracket)) +{ +if ( +!function->allow_zero_parameters() && +!tc .allow_zero_parameters() +) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR128 - Zero parameter call to generic function: " ++ function_name + " not allowed", +exprtk_error_location)); + +return error_node(); +} +} +else +{ +for ( ; ; ) +{ +expression_node_ptr arg = parse_expression(); + +if (0 == arg) +return error_node(); + +if (is_ivector_node(arg)) +param_type_list += 'V'; +else if (is_generally_string_node(arg)) +param_type_list += 'S'; +else // Everything else is assumed to be a scalar returning expression +param_type_list += 'T'; + +arg_list.push_back(arg); + +if (token_is(token_t::e_rbracket)) +break; +else if (!token_is(token_t::e_comma)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR129 - Expected ',' for call to generic function: " + function_name, +exprtk_error_location)); + +return error_node(); +} +} +} +} +else if ( +!function->parameter_sequence.empty() && +function->allow_zero_parameters () && +!tc .allow_zero_parameters () +) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR130 - Zero parameter call to generic function: " ++ function_name + " not allowed", +exprtk_error_location)); + +return error_node(); +} + +std::size_t param_seq_index = 0; + +if ( +state_.type_check_enabled && +!tc.verify(param_type_list, param_seq_index) +) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR131 - Invalid input parameter sequence for call to generic function: " + function_name, +exprtk_error_location)); + +return error_node(); +} + +expression_node_ptr result = error_node(); + +if (tc.paramseq_count() <= 1) +result = expression_generator_ +.generic_function_call(function, arg_list); +else +result = expression_generator_ +.generic_function_call(function, arg_list, param_seq_index); + +sdd.delete_ptr = (0 == result); + +return result; +} + +inline bool parse_igeneric_function_params(std::string& param_type_list, +std::vector& arg_list, +const std::string& function_name, +igeneric_function* function, +const type_checker& tc) +{ +if (token_is(token_t::e_lbracket)) +{ +if (token_is(token_t::e_rbracket)) +{ +if ( +!function->allow_zero_parameters() && +!tc .allow_zero_parameters() +) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR132 - Zero parameter call to generic function: " ++ function_name + " not allowed", +exprtk_error_location)); + +return false; +} +} +else +{ +for ( ; ; ) +{ +expression_node_ptr arg = parse_expression(); + +if (0 == arg) +return false; + +if (is_ivector_node(arg)) +param_type_list += 'V'; +else if (is_generally_string_node(arg)) +param_type_list += 'S'; +else // Everything else is a scalar returning expression +param_type_list += 'T'; + +arg_list.push_back(arg); + +if (token_is(token_t::e_rbracket)) +break; +else if (!token_is(token_t::e_comma)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR133 - Expected ',' for call to string function: " + function_name, +exprtk_error_location)); + +return false; +} +} +} + +return true; +} +else +return false; +} + +#ifndef exprtk_disable_string_capabilities +inline expression_node_ptr parse_string_function_call(igeneric_function* function, const std::string& function_name) +{ +// Move pass the function name +next_token(); + +std::string param_type_list; + +type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_string); + +if ( +(!function->parameter_sequence.empty()) && +(0 == tc.paramseq_count()) +) +{ +return error_node(); +} + +std::vector arg_list; +scoped_vec_delete sdd((*this),arg_list); + +if (!parse_igeneric_function_params(param_type_list, arg_list, function_name, function, tc)) +{ +return error_node(); +} + +std::size_t param_seq_index = 0; + +if (!tc.verify(param_type_list, param_seq_index)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR134 - Invalid input parameter sequence for call to string function: " + function_name, +exprtk_error_location)); + +return error_node(); +} + +expression_node_ptr result = error_node(); + +if (tc.paramseq_count() <= 1) +result = expression_generator_ +.string_function_call(function, arg_list); +else +result = expression_generator_ +.string_function_call(function, arg_list, param_seq_index); + +sdd.delete_ptr = (0 == result); + +return result; +} + +inline expression_node_ptr parse_overload_function_call(igeneric_function* function, const std::string& function_name) +{ +// Move pass the function name +next_token(); + +std::string param_type_list; + +type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_overload); + +if ( +(!function->parameter_sequence.empty()) && +(0 == tc.paramseq_count()) +) +{ +return error_node(); +} + +std::vector arg_list; +scoped_vec_delete sdd((*this),arg_list); + +if (!parse_igeneric_function_params(param_type_list, arg_list, function_name, function, tc)) +{ +return error_node(); +} + +std::size_t param_seq_index = 0; + +if (!tc.verify(param_type_list, param_seq_index)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR135 - Invalid input parameter sequence for call to overloaded function: " + function_name, +exprtk_error_location)); + +return error_node(); +} + +expression_node_ptr result = error_node(); + +if (type_checker::e_numeric == tc.return_type(param_seq_index)) +{ +if (tc.paramseq_count() <= 1) +result = expression_generator_ +.generic_function_call(function, arg_list); +else +result = expression_generator_ +.generic_function_call(function, arg_list, param_seq_index); +} +else if (type_checker::e_string == tc.return_type(param_seq_index)) +{ +if (tc.paramseq_count() <= 1) +result = expression_generator_ +.string_function_call(function, arg_list); +else +result = expression_generator_ +.string_function_call(function, arg_list, param_seq_index); +} +else +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR136 - Invalid return type for call to overloaded function: " + function_name, +exprtk_error_location)); +} + +sdd.delete_ptr = (0 == result); +return result; +} +#endif + +template +struct parse_special_function_impl +{ +static inline expression_node_ptr process(parser& p, const details::operator_type opt_type, const std::string& sf_name) +{ +expression_node_ptr branch[NumberOfParameters]; +expression_node_ptr result = error_node(); + +std::fill_n(branch, NumberOfParameters, reinterpret_cast(0)); + +scoped_delete sd(p,branch); + +p.next_token(); + +if (!p.token_is(token_t::e_lbracket)) +{ +p.set_error( +make_error(parser_error::e_syntax, +p.current_token(), +"ERR137 - Expected '(' for special function '" + sf_name + "'", +exprtk_error_location)); + +return error_node(); +} + +for (std::size_t i = 0; i < NumberOfParameters; ++i) +{ +branch[i] = p.parse_expression(); + +if (0 == branch[i]) +{ +return p.error_node(); +} +else if (i < (NumberOfParameters - 1)) +{ +if (!p.token_is(token_t::e_comma)) +{ +p.set_error( +make_error(parser_error::e_syntax, +p.current_token(), +"ERR138 - Expected ',' before next parameter of special function '" + sf_name + "'", +exprtk_error_location)); + +return p.error_node(); +} +} +} + +if (!p.token_is(token_t::e_rbracket)) +{ +p.set_error( +make_error(parser_error::e_syntax, +p.current_token(), +"ERR139 - Invalid number of parameters for special function '" + sf_name + "'", +exprtk_error_location)); + +return p.error_node(); +} +else +result = p.expression_generator_.special_function(opt_type,branch); + +sd.delete_ptr = (0 == result); + +return result; +} +}; + +inline expression_node_ptr parse_special_function() +{ +const std::string sf_name = current_token().value; + +// Expect: $fDD(expr0,expr1,expr2) or $fDD(expr0,expr1,expr2,expr3) +if ( +!details::is_digit(sf_name[2]) || +!details::is_digit(sf_name[3]) +) +{ +set_error( +make_error(parser_error::e_token, +current_token(), +"ERR140 - Invalid special function[1]: " + sf_name, +exprtk_error_location)); + +return error_node(); +} + +const int id = (sf_name[2] - '0') * 10 + +(sf_name[3] - '0'); + +if (id >= details::e_sffinal) +{ +set_error( +make_error(parser_error::e_token, +current_token(), +"ERR141 - Invalid special function[2]: " + sf_name, +exprtk_error_location)); + +return error_node(); +} + +const int sf_3_to_4 = details::e_sf48; +const details::operator_type opt_type = details::operator_type(id + 1000); +const std::size_t NumberOfParameters = (id < (sf_3_to_4 - 1000)) ? 3U : 4U; + +switch (NumberOfParameters) +{ +case 3 : return parse_special_function_impl::process((*this), opt_type, sf_name); +case 4 : return parse_special_function_impl::process((*this), opt_type, sf_name); +default : return error_node(); +} +} + +inline expression_node_ptr parse_null_statement() +{ +next_token(); +return node_allocator_.allocate >(); +} + +#ifndef exprtk_disable_break_continue +inline expression_node_ptr parse_break_statement() +{ +if (state_.parsing_break_stmt) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR142 - Invoking 'break' within a break call is not allowed", +exprtk_error_location)); + +return error_node(); +} +else if (0 == state_.parsing_loop_stmt_count) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR143 - Invalid use of 'break', allowed only in the scope of a loop", +exprtk_error_location)); + +return error_node(); +} + +scoped_bool_negator sbn(state_.parsing_break_stmt); + +if (!brkcnt_list_.empty()) +{ +next_token(); + +brkcnt_list_.front() = true; + +expression_node_ptr return_expr = error_node(); + +if (token_is(token_t::e_lsqrbracket)) +{ +if (0 == (return_expr = parse_expression())) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR144 - Failed to parse return expression for 'break' statement", +exprtk_error_location)); + +return error_node(); +} +else if (!token_is(token_t::e_rsqrbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR145 - Expected ']' at the completion of break's return expression", +exprtk_error_location)); + +free_node(node_allocator_,return_expr); + +return error_node(); +} +} + +state_.activate_side_effect("parse_break_statement()"); + +return node_allocator_.allocate >(return_expr); +} +else +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR146 - Invalid use of 'break', allowed only in the scope of a loop", +exprtk_error_location)); +} + +return error_node(); +} + +inline expression_node_ptr parse_continue_statement() +{ +if (0 == state_.parsing_loop_stmt_count) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR147 - Invalid use of 'continue', allowed only in the scope of a loop", +exprtk_error_location)); + +return error_node(); +} +else +{ +next_token(); + +brkcnt_list_.front() = true; +state_.activate_side_effect("parse_continue_statement()"); + +return node_allocator_.allocate >(); +} +} +#endif + +inline expression_node_ptr parse_define_vector_statement(const std::string& vec_name) +{ +expression_node_ptr size_expr = error_node(); + +if (!token_is(token_t::e_lsqrbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR148 - Expected '[' as part of vector size definition", +exprtk_error_location)); + +return error_node(); +} +else if (0 == (size_expr = parse_expression())) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR149 - Failed to determine size of vector '" + vec_name + "'", +exprtk_error_location)); + +return error_node(); +} +else if (!is_constant_node(size_expr)) +{ +free_node(node_allocator_,size_expr); + +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR150 - Expected a literal number as size of vector '" + vec_name + "'", +exprtk_error_location)); + +return error_node(); +} + +const T vector_size = size_expr->value(); + +free_node(node_allocator_,size_expr); + +const T max_vector_size = T(2000000000.0); + +if ( +(vector_size <= T(0)) || +std::not_equal_to() +(T(0),vector_size - details::numeric::trunc(vector_size)) || +(vector_size > max_vector_size) +) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR151 - Invalid vector size. Must be an integer in the range [0,2e9], size: " + +details::to_str(details::numeric::to_int32(vector_size)), +exprtk_error_location)); + +return error_node(); +} + +std::vector vec_initilizer_list; + +scoped_vec_delete svd((*this),vec_initilizer_list); + +bool single_value_initialiser = false; +bool vec_to_vec_initialiser = false; +bool null_initialisation = false; + +if (!token_is(token_t::e_rsqrbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR152 - Expected ']' as part of vector size definition", +exprtk_error_location)); + +return error_node(); +} +else if (!token_is(token_t::e_eof)) +{ +if (!token_is(token_t::e_assign)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR153 - Expected ':=' as part of vector definition", +exprtk_error_location)); + +return error_node(); +} +else if (token_is(token_t::e_lsqrbracket)) +{ +expression_node_ptr initialiser = parse_expression(); + +if (0 == initialiser) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR154 - Failed to parse single vector initialiser", +exprtk_error_location)); + +return error_node(); +} + +vec_initilizer_list.push_back(initialiser); + +if (!token_is(token_t::e_rsqrbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR155 - Expected ']' to close single value vector initialiser", +exprtk_error_location)); + +return error_node(); +} + +single_value_initialiser = true; +} +else if (!token_is(token_t::e_lcrlbracket)) +{ +expression_node_ptr initialiser = error_node(); + +// Is this a vector to vector assignment and initialisation? +if (token_t::e_symbol == current_token().type) +{ +// Is it a locally defined vector? +const scope_element& se = sem_.get_active_element(current_token().value); + +if (scope_element::e_vector == se.type) +{ +if (0 != (initialiser = parse_expression())) +vec_initilizer_list.push_back(initialiser); +else +return error_node(); +} +// Are we dealing with a user defined vector? +else if (symtab_store_.is_vector(current_token().value)) +{ +lodge_symbol(current_token().value, e_st_vector); + +if (0 != (initialiser = parse_expression())) +vec_initilizer_list.push_back(initialiser); +else +return error_node(); +} +// Are we dealing with a null initialisation vector definition? +else if (token_is(token_t::e_symbol,"null")) +null_initialisation = true; +} + +if (!null_initialisation) +{ +if (0 == initialiser) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR156 - Expected '{' as part of vector initialiser list", +exprtk_error_location)); + +return error_node(); +} +else +vec_to_vec_initialiser = true; +} +} +else if (!token_is(token_t::e_rcrlbracket)) +{ +for ( ; ; ) +{ +expression_node_ptr initialiser = parse_expression(); + +if (0 == initialiser) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR157 - Expected '{' as part of vector initialiser list", +exprtk_error_location)); + +return error_node(); +} +else +vec_initilizer_list.push_back(initialiser); + +if (token_is(token_t::e_rcrlbracket)) +break; + +const bool is_next_close = peek_token_is(token_t::e_rcrlbracket); + +if (!token_is(token_t::e_comma) && is_next_close) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR158 - Expected ',' between vector initialisers", +exprtk_error_location)); + +return error_node(); +} + +if (token_is(token_t::e_rcrlbracket)) +break; +} +} + +if ( +!token_is(token_t::e_rbracket , prsrhlpr_t::e_hold) && +!token_is(token_t::e_rcrlbracket, prsrhlpr_t::e_hold) && +!token_is(token_t::e_rsqrbracket, prsrhlpr_t::e_hold) +) +{ +if (!token_is(token_t::e_eof)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR159 - Expected ';' at end of vector definition", +exprtk_error_location)); + +return error_node(); +} +} + +if (T(vec_initilizer_list.size()) > vector_size) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR160 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'", +exprtk_error_location)); + +return error_node(); +} +} + +typename symbol_table_t::vector_holder_ptr vec_holder = typename symbol_table_t::vector_holder_ptr(0); + +const std::size_t vec_size = static_cast(details::numeric::to_int32(vector_size)); + +scope_element& se = sem_.get_element(vec_name); + +if (se.name == vec_name) +{ +if (se.active) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR161 - Illegal redefinition of local vector: '" + vec_name + "'", +exprtk_error_location)); + +return error_node(); +} +else if ( +(se.size == vec_size) && +(scope_element::e_vector == se.type) +) +{ +vec_holder = se.vec_node; +se.active = true; +se.depth = state_.scope_depth; +se.ref_count++; +} +} + +if (0 == vec_holder) +{ +scope_element nse; +nse.name = vec_name; +nse.active = true; +nse.ref_count = 1; +nse.type = scope_element::e_vector; +nse.depth = state_.scope_depth; +nse.size = vec_size; +nse.data = new T[vec_size]; +nse.vec_node = new typename scope_element::vector_holder_t(reinterpret_cast(nse.data),nse.size); + +if (!sem_.add_element(nse)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR162 - Failed to add new local vector '" + vec_name + "' to SEM", +exprtk_error_location)); + +sem_.free_element(nse); + +return error_node(); +} + +vec_holder = nse.vec_node; + +exprtk_debug(("parse_define_vector_statement() - INFO - Added new local vector: %s[%d]\n", +nse.name.c_str(), +static_cast(nse.size))); +} + +state_.activate_side_effect("parse_define_vector_statement()"); + +lodge_symbol(vec_name, e_st_local_vector); + +expression_node_ptr result = error_node(); + +if (null_initialisation) +result = expression_generator_(T(0.0)); +else if (vec_to_vec_initialiser) +{ +expression_node_ptr vec_node = node_allocator_.allocate(vec_holder); + +result = expression_generator_( +details::e_assign, +vec_node, +vec_initilizer_list[0]); +} +else +result = node_allocator_ +.allocate >( +(*vec_holder)[0], +vec_size, +vec_initilizer_list, +single_value_initialiser); + +svd.delete_ptr = (0 == result); + +return result; +} + +#ifndef exprtk_disable_string_capabilities +inline expression_node_ptr parse_define_string_statement(const std::string& str_name, expression_node_ptr initialisation_expression) +{ +stringvar_node_t* str_node = reinterpret_cast(0); + +scope_element& se = sem_.get_element(str_name); + +if (se.name == str_name) +{ +if (se.active) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR163 - Illegal redefinition of local variable: '" + str_name + "'", +exprtk_error_location)); + +free_node(node_allocator_,initialisation_expression); + +return error_node(); +} +else if (scope_element::e_string == se.type) +{ +str_node = se.str_node; +se.active = true; +se.depth = state_.scope_depth; +se.ref_count++; +} +} + +if (0 == str_node) +{ +scope_element nse; +nse.name = str_name; +nse.active = true; +nse.ref_count = 1; +nse.type = scope_element::e_string; +nse.depth = state_.scope_depth; +nse.data = new std::string; +nse.str_node = new stringvar_node_t(*reinterpret_cast(nse.data)); + +if (!sem_.add_element(nse)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR164 - Failed to add new local string variable '" + str_name + "' to SEM", +exprtk_error_location)); + +free_node(node_allocator_,initialisation_expression); + +sem_.free_element(nse); + +return error_node(); +} + +str_node = nse.str_node; + +exprtk_debug(("parse_define_string_statement() - INFO - Added new local string variable: %s\n",nse.name.c_str())); +} + +lodge_symbol(str_name, e_st_local_string); + +state_.activate_side_effect("parse_define_string_statement()"); + +expression_node_ptr branch[2] = {0}; + +branch[0] = str_node; +branch[1] = initialisation_expression; + +return expression_generator_(details::e_assign,branch); +} +#else +inline expression_node_ptr parse_define_string_statement(const std::string&, expression_node_ptr) +{ +return error_node(); +} +#endif + +inline bool local_variable_is_shadowed(const std::string& symbol) +{ +const scope_element& se = sem_.get_element(symbol); +return (se.name == symbol) && se.active; +} + +inline expression_node_ptr parse_define_var_statement() +{ +if (settings_.vardef_disabled()) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR165 - Illegal variable definition", +exprtk_error_location)); + +return error_node(); +} +else if (!details::imatch(current_token().value,"var")) +{ +return error_node(); +} +else +next_token(); + +const std::string var_name = current_token().value; + +expression_node_ptr initialisation_expression = error_node(); + +if (!token_is(token_t::e_symbol)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR166 - Expected a symbol for variable definition", +exprtk_error_location)); + +return error_node(); +} +else if (details::is_reserved_symbol(var_name)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR167 - Illegal redefinition of reserved keyword: '" + var_name + "'", +exprtk_error_location)); + +return error_node(); +} +else if (symtab_store_.symbol_exists(var_name)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR168 - Illegal redefinition of variable '" + var_name + "'", +exprtk_error_location)); + +return error_node(); +} +else if (local_variable_is_shadowed(var_name)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR169 - Illegal redefinition of local variable: '" + var_name + "'", +exprtk_error_location)); + +return error_node(); +} +else if (token_is(token_t::e_lsqrbracket,prsrhlpr_t::e_hold)) +{ +return parse_define_vector_statement(var_name); +} +else if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) +{ +return parse_uninitialised_var_statement(var_name); +} +else if (token_is(token_t::e_assign)) +{ +if (0 == (initialisation_expression = parse_expression())) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR170 - Failed to parse initialisation expression", +exprtk_error_location)); + +return error_node(); +} +} + +if ( +!token_is(token_t::e_rbracket , prsrhlpr_t::e_hold) && +!token_is(token_t::e_rcrlbracket, prsrhlpr_t::e_hold) && +!token_is(token_t::e_rsqrbracket, prsrhlpr_t::e_hold) +) +{ +if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR171 - Expected ';' after variable definition", +exprtk_error_location)); + +free_node(node_allocator_,initialisation_expression); + +return error_node(); +} +} + +if ( +(0 != initialisation_expression) && +details::is_generally_string_node(initialisation_expression) +) +{ +return parse_define_string_statement(var_name,initialisation_expression); +} + +expression_node_ptr var_node = reinterpret_cast(0); + +scope_element& se = sem_.get_element(var_name); + +if (se.name == var_name) +{ +if (se.active) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR172 - Illegal redefinition of local variable: '" + var_name + "'", +exprtk_error_location)); + +free_node(node_allocator_, initialisation_expression); + +return error_node(); +} +else if (scope_element::e_variable == se.type) +{ +var_node = se.var_node; +se.active = true; +se.depth = state_.scope_depth; +se.ref_count++; +} +} + +if (0 == var_node) +{ +scope_element nse; +nse.name = var_name; +nse.active = true; +nse.ref_count = 1; +nse.type = scope_element::e_variable; +nse.depth = state_.scope_depth; +nse.data = new T(T(0)); +nse.var_node = node_allocator_.allocate(*reinterpret_cast(nse.data)); + +if (!sem_.add_element(nse)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR173 - Failed to add new local variable '" + var_name + "' to SEM", +exprtk_error_location)); + +free_node(node_allocator_, initialisation_expression); + +sem_.free_element(nse); + +return error_node(); +} + +var_node = nse.var_node; + +exprtk_debug(("parse_define_var_statement() - INFO - Added new local variable: %s\n",nse.name.c_str())); +} + +state_.activate_side_effect("parse_define_var_statement()"); + +lodge_symbol(var_name, e_st_local_variable); + +expression_node_ptr branch[2] = {0}; + +branch[0] = var_node; +branch[1] = initialisation_expression ? initialisation_expression : expression_generator_(T(0)); + +return expression_generator_(details::e_assign,branch); +} + +inline expression_node_ptr parse_uninitialised_var_statement(const std::string& var_name) +{ +if ( +!token_is(token_t::e_lcrlbracket) || +!token_is(token_t::e_rcrlbracket) +) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR174 - Expected a '{}' for uninitialised var definition", +exprtk_error_location)); + +return error_node(); +} +else if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR175 - Expected ';' after uninitialised variable definition", +exprtk_error_location)); + +return error_node(); +} + +expression_node_ptr var_node = reinterpret_cast(0); + +scope_element& se = sem_.get_element(var_name); + +if (se.name == var_name) +{ +if (se.active) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR176 - Illegal redefinition of local variable: '" + var_name + "'", +exprtk_error_location)); + +return error_node(); +} +else if (scope_element::e_variable == se.type) +{ +var_node = se.var_node; +se.active = true; +se.ref_count++; +} +} + +if (0 == var_node) +{ +scope_element nse; +nse.name = var_name; +nse.active = true; +nse.ref_count = 1; +nse.type = scope_element::e_variable; +nse.depth = state_.scope_depth; +nse.ip_index = sem_.next_ip_index(); +nse.data = new T(T(0)); +nse.var_node = node_allocator_.allocate(*reinterpret_cast(nse.data)); + +if (!sem_.add_element(nse)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR177 - Failed to add new local variable '" + var_name + "' to SEM", +exprtk_error_location)); + +sem_.free_element(nse); + +return error_node(); +} + +exprtk_debug(("parse_uninitialised_var_statement() - INFO - Added new local variable: %s\n", +nse.name.c_str())); +} + +lodge_symbol(var_name, e_st_local_variable); + +state_.activate_side_effect("parse_uninitialised_var_statement()"); + +return expression_generator_(T(0)); +} + +inline expression_node_ptr parse_swap_statement() +{ +if (!details::imatch(current_token().value,"swap")) +{ +return error_node(); +} +else +next_token(); + +if (!token_is(token_t::e_lbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR178 - Expected '(' at start of swap statement", +exprtk_error_location)); + +return error_node(); +} + +expression_node_ptr variable0 = error_node(); +expression_node_ptr variable1 = error_node(); + +bool variable0_generated = false; +bool variable1_generated = false; + +const std::string var0_name = current_token().value; + +if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR179 - Expected a symbol for variable or vector element definition", +exprtk_error_location)); + +return error_node(); +} +else if (peek_token_is(token_t::e_lsqrbracket)) +{ +if (0 == (variable0 = parse_vector())) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR180 - First parameter to swap is an invalid vector element: '" + var0_name + "'", +exprtk_error_location)); + +return error_node(); +} + +variable0_generated = true; +} +else +{ +if (symtab_store_.is_variable(var0_name)) +{ +variable0 = symtab_store_.get_variable(var0_name); +} + +const scope_element& se = sem_.get_element(var0_name); + +if ( +(se.active) && +(se.name == var0_name) && +(scope_element::e_variable == se.type) +) +{ +variable0 = se.var_node; +} + +lodge_symbol(var0_name, e_st_variable); + +if (0 == variable0) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR181 - First parameter to swap is an invalid variable: '" + var0_name + "'", +exprtk_error_location)); + +return error_node(); +} +else +next_token(); +} + +if (!token_is(token_t::e_comma)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR182 - Expected ',' between parameters to swap", +exprtk_error_location)); + +if (variable0_generated) +{ +free_node(node_allocator_,variable0); +} + +return error_node(); +} + +const std::string var1_name = current_token().value; + +if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR183 - Expected a symbol for variable or vector element definition", +exprtk_error_location)); + +if (variable0_generated) +{ +free_node(node_allocator_,variable0); +} + +return error_node(); +} +else if (peek_token_is(token_t::e_lsqrbracket)) +{ +if (0 == (variable1 = parse_vector())) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR184 - Second parameter to swap is an invalid vector element: '" + var1_name + "'", +exprtk_error_location)); + +if (variable0_generated) +{ +free_node(node_allocator_,variable0); +} + +return error_node(); +} + +variable1_generated = true; +} +else +{ +if (symtab_store_.is_variable(var1_name)) +{ +variable1 = symtab_store_.get_variable(var1_name); +} + +const scope_element& se = sem_.get_element(var1_name); + +if ( +(se.active) && +(se.name == var1_name) && +(scope_element::e_variable == se.type) +) +{ +variable1 = se.var_node; +} + +lodge_symbol(var1_name, e_st_variable); + +if (0 == variable1) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR185 - Second parameter to swap is an invalid variable: '" + var1_name + "'", +exprtk_error_location)); + +if (variable0_generated) +{ +free_node(node_allocator_,variable0); +} + +return error_node(); +} +else +next_token(); +} + +if (!token_is(token_t::e_rbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR186 - Expected ')' at end of swap statement", +exprtk_error_location)); + +if (variable0_generated) +{ +free_node(node_allocator_,variable0); +} + +if (variable1_generated) +{ +free_node(node_allocator_,variable1); +} + +return error_node(); +} + +typedef details::variable_node* variable_node_ptr; + +variable_node_ptr v0 = variable_node_ptr(0); +variable_node_ptr v1 = variable_node_ptr(0); + +expression_node_ptr result = error_node(); + +if ( +(0 != (v0 = dynamic_cast(variable0))) && +(0 != (v1 = dynamic_cast(variable1))) +) +{ +result = node_allocator_.allocate >(v0, v1); + +if (variable0_generated) +{ +free_node(node_allocator_,variable0); +} + +if (variable1_generated) +{ +free_node(node_allocator_,variable1); +} +} +else +result = node_allocator_.allocate > +(variable0, variable1); + +state_.activate_side_effect("parse_swap_statement()"); + +return result; +} + +#ifndef exprtk_disable_return_statement +inline expression_node_ptr parse_return_statement() +{ +if (state_.parsing_return_stmt) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR187 - Return call within a return call is not allowed", +exprtk_error_location)); + +return error_node(); +} + +scoped_bool_negator sbn(state_.parsing_return_stmt); + +std::vector arg_list; + +scoped_vec_delete sdd((*this),arg_list); + +if (!details::imatch(current_token().value,"return")) +{ +return error_node(); +} +else +next_token(); + +if (!token_is(token_t::e_lsqrbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR188 - Expected '[' at start of return statement", +exprtk_error_location)); + +return error_node(); +} +else if (!token_is(token_t::e_rsqrbracket)) +{ +for ( ; ; ) +{ +expression_node_ptr arg = parse_expression(); + +if (0 == arg) +return error_node(); + +arg_list.push_back(arg); + +if (token_is(token_t::e_rsqrbracket)) +break; +else if (!token_is(token_t::e_comma)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR189 - Expected ',' between values during call to return", +exprtk_error_location)); + +return error_node(); +} +} +} +else if (settings_.zero_return_disabled()) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR190 - Zero parameter return statement not allowed", +exprtk_error_location)); + +return error_node(); +} + +const lexer::token prev_token = current_token(); + +if (token_is(token_t::e_rsqrbracket)) +{ +if (!arg_list.empty()) +{ +set_error( +make_error(parser_error::e_syntax, +prev_token, +"ERR191 - Invalid ']' found during return call", +exprtk_error_location)); + +return error_node(); +} +} + +std::string ret_param_type_list; + +for (std::size_t i = 0; i < arg_list.size(); ++i) +{ +if (0 == arg_list[i]) +return error_node(); +else if (is_ivector_node(arg_list[i])) +ret_param_type_list += 'V'; +else if (is_generally_string_node(arg_list[i])) +ret_param_type_list += 'S'; +else +ret_param_type_list += 'T'; +} + +dec_.retparam_list_.push_back(ret_param_type_list); + +expression_node_ptr result = expression_generator_.return_call(arg_list); + +sdd.delete_ptr = (0 == result); + +state_.return_stmt_present = true; + +state_.activate_side_effect("parse_return_statement()"); + +return result; +} +#else +inline expression_node_ptr parse_return_statement() +{ +return error_node(); +} +#endif + +inline bool post_variable_process(const std::string& symbol) +{ +if ( +peek_token_is(token_t::e_lbracket ) || +peek_token_is(token_t::e_lcrlbracket) || +peek_token_is(token_t::e_lsqrbracket) +) +{ +if (!settings_.commutative_check_enabled()) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR192 - Invalid sequence of variable '" + symbol + "' and bracket", +exprtk_error_location)); + +return false; +} + +lexer().insert_front(token_t::e_mul); +} + +return true; +} + +inline bool post_bracket_process(const typename token_t::token_type& token, expression_node_ptr& branch) +{ +bool implied_mul = false; + +if (details::is_generally_string_node(branch)) +return true; + +const lexer::parser_helper::token_advance_mode hold = prsrhlpr_t::e_hold; + +switch (token) +{ +case token_t::e_lcrlbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || +token_is(token_t::e_lcrlbracket,hold) || +token_is(token_t::e_lsqrbracket,hold) ; +break; + +case token_t::e_lbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || +token_is(token_t::e_lcrlbracket,hold) || +token_is(token_t::e_lsqrbracket,hold) ; +break; + +case token_t::e_lsqrbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || +token_is(token_t::e_lcrlbracket,hold) || +token_is(token_t::e_lsqrbracket,hold) ; +break; + +default : return true; +} + +if (implied_mul) +{ +if (!settings_.commutative_check_enabled()) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR193 - Invalid sequence of brackets", +exprtk_error_location)); + +return false; +} +else if (token_t::e_eof != current_token().type) +{ +lexer().insert_front(current_token().type); +lexer().insert_front(token_t::e_mul); +next_token(); +} +} + +return true; +} + +typedef typename interval_container_t::interval_t interval_t; +typedef interval_container_t immutable_memory_map_t; +typedef std::map immutable_symtok_map_t; + +inline interval_t make_memory_range(const T& t) +{ +const T* begin = reinterpret_cast(&t); +const T* end = begin + 1; +return interval_t(begin, end); +} + +inline interval_t make_memory_range(const T* begin, const std::size_t size) +{ +return interval_t(begin, begin + size); +} + +inline interval_t make_memory_range(details::char_cptr begin, const std::size_t size) +{ +return interval_t(begin, begin + size); +} + +void lodge_immutable_symbol(const lexer::token& token, const interval_t interval) +{ +immutable_memory_map_.add_interval(interval); +immutable_symtok_map_[interval] = token; +} + +inline expression_node_ptr parse_symtab_symbol() +{ +const std::string symbol = current_token().value; + +// Are we dealing with a variable or a special constant? +typedef typename symtab_store::variable_context var_ctxt_t; +var_ctxt_t var_ctx = symtab_store_.get_variable_context(symbol); + +if (var_ctx.variable) +{ +assert(var_ctx.symbol_table); + +expression_node_ptr result_variable = var_ctx.variable; + +if (symtab_store_.is_constant_node(symbol)) +{ +result_variable = expression_generator_(var_ctx.variable->value()); +} +else if (symbol_table_t::e_immutable == var_ctx.symbol_table->mutability()) +{ +lodge_immutable_symbol(current_token(), make_memory_range(var_ctx.variable->ref())); +result_variable = var_ctx.variable; +} + +if (!post_variable_process(symbol)) +return error_node(); + +lodge_symbol(symbol, e_st_variable); + +next_token(); + +return result_variable; +} + +// Are we dealing with a locally defined variable, vector or string? +if (!sem_.empty()) +{ +scope_element& se = sem_.get_active_element(symbol); + +if (se.active && details::imatch(se.name, symbol)) +{ +if (scope_element::e_variable == se.type) +{ +se.active = true; +lodge_symbol(symbol, e_st_local_variable); + +if (!post_variable_process(symbol)) +return error_node(); + +next_token(); + +return se.var_node; +} +else if (scope_element::e_vector == se.type) +{ +return parse_vector(); +} +#ifndef exprtk_disable_string_capabilities +else if (scope_element::e_string == se.type) +{ +return parse_string(); +} +#endif +} +} + +#ifndef exprtk_disable_string_capabilities +// Are we dealing with a string variable? +if (symtab_store_.is_stringvar(symbol)) +{ +return parse_string(); +} +#endif + +{ +// Are we dealing with a function? +ifunction* function = symtab_store_.get_function(symbol); + +if (function) +{ +lodge_symbol(symbol, e_st_function); + +expression_node_ptr func_node = +parse_function_invocation(function,symbol); + +if (func_node) +return func_node; +else +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR194 - Failed to generate node for function: '" + symbol + "'", +exprtk_error_location)); + +return error_node(); +} +} +} + +{ +// Are we dealing with a vararg function? +ivararg_function* vararg_function = symtab_store_.get_vararg_function(symbol); + +if (vararg_function) +{ +lodge_symbol(symbol, e_st_function); + +expression_node_ptr vararg_func_node = +parse_vararg_function_call(vararg_function, symbol); + +if (vararg_func_node) +return vararg_func_node; +else +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR195 - Failed to generate node for vararg function: '" + symbol + "'", +exprtk_error_location)); + +return error_node(); +} +} +} + +{ +// Are we dealing with a vararg generic function? +igeneric_function* generic_function = symtab_store_.get_generic_function(symbol); + +if (generic_function) +{ +lodge_symbol(symbol, e_st_function); + +expression_node_ptr genericfunc_node = +parse_generic_function_call(generic_function, symbol); + +if (genericfunc_node) +return genericfunc_node; +else +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR196 - Failed to generate node for generic function: '" + symbol + "'", +exprtk_error_location)); + +return error_node(); +} +} +} + +#ifndef exprtk_disable_string_capabilities +{ +// Are we dealing with a vararg string returning function? +igeneric_function* string_function = symtab_store_.get_string_function(symbol); + +if (string_function) +{ +lodge_symbol(symbol, e_st_function); + +expression_node_ptr stringfunc_node = +parse_string_function_call(string_function, symbol); + +if (stringfunc_node) +return stringfunc_node; +else +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR197 - Failed to generate node for string function: '" + symbol + "'", +exprtk_error_location)); + +return error_node(); +} +} +} + +{ +// Are we dealing with a vararg overloaded scalar/string returning function? +igeneric_function* overload_function = symtab_store_.get_overload_function(symbol); + +if (overload_function) +{ +lodge_symbol(symbol, e_st_function); + +expression_node_ptr overloadfunc_node = +parse_overload_function_call(overload_function, symbol); + +if (overloadfunc_node) +return overloadfunc_node; +else +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR198 - Failed to generate node for overload function: '" + symbol + "'", +exprtk_error_location)); + +return error_node(); +} +} +} +#endif + +// Are we dealing with a vector? +if (symtab_store_.is_vector(symbol)) +{ +lodge_symbol(symbol, e_st_vector); +return parse_vector(); +} + +if (details::is_reserved_symbol(symbol)) +{ +if ( +settings_.function_enabled(symbol) || +!details::is_base_function(symbol) +) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR199 - Invalid use of reserved symbol '" + symbol + "'", +exprtk_error_location)); + +return error_node(); +} +} + +// Should we handle unknown symbols? +if (resolve_unknown_symbol_ && unknown_symbol_resolver_) +{ +if (!(settings_.rsrvd_sym_usr_disabled() && details::is_reserved_symbol(symbol))) +{ +symbol_table_t& symtab = symtab_store_.get_symbol_table(); + +std::string error_message; + +if (unknown_symbol_resolver::e_usrmode_default == unknown_symbol_resolver_->mode) +{ +T default_value = T(0); + +typename unknown_symbol_resolver::usr_symbol_type usr_symbol_type = unknown_symbol_resolver::e_usr_unknown_type; + +if (unknown_symbol_resolver_->process(symbol, usr_symbol_type, default_value, error_message)) +{ +bool create_result = false; + +switch (usr_symbol_type) +{ +case unknown_symbol_resolver::e_usr_variable_type : create_result = symtab.create_variable(symbol, default_value); +break; + +case unknown_symbol_resolver::e_usr_constant_type : create_result = symtab.add_constant(symbol, default_value); +break; + +default : create_result = false; +} + +if (create_result) +{ +expression_node_ptr var = symtab_store_.get_variable(symbol); + +if (var) +{ +if (symtab_store_.is_constant_node(symbol)) +{ +var = expression_generator_(var->value()); +} + +lodge_symbol(symbol, e_st_variable); + +if (!post_variable_process(symbol)) +return error_node(); + +next_token(); + +return var; +} +} +} + +set_error( +make_error(parser_error::e_symtab, +current_token(), +"ERR200 - Failed to create variable: '" + symbol + "'" + +(error_message.empty() ? "" : " - " + error_message), +exprtk_error_location)); + +} +else if (unknown_symbol_resolver::e_usrmode_extended == unknown_symbol_resolver_->mode) +{ +if (unknown_symbol_resolver_->process(symbol, symtab, error_message)) +{ +expression_node_ptr result = parse_symtab_symbol(); + +if (result) +{ +return result; +} +} + +set_error( +make_error(parser_error::e_symtab, +current_token(), +"ERR201 - Failed to resolve symbol: '" + symbol + "'" + +(error_message.empty() ? "" : " - " + error_message), +exprtk_error_location)); +} + +return error_node(); +} +} + +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR202 - Undefined symbol: '" + symbol + "'", +exprtk_error_location)); + +return error_node(); +} + +inline expression_node_ptr parse_symbol() +{ +static const std::string symbol_if = "if" ; +static const std::string symbol_while = "while" ; +static const std::string symbol_repeat = "repeat" ; +static const std::string symbol_for = "for" ; +static const std::string symbol_switch = "switch" ; +static const std::string symbol_null = "null" ; +static const std::string symbol_break = "break" ; +static const std::string symbol_continue = "continue"; +static const std::string symbol_var = "var" ; +static const std::string symbol_swap = "swap" ; +static const std::string symbol_return = "return" ; +static const std::string symbol_not = "not" ; + +const std::string symbol = current_token().value; + +if (valid_vararg_operation(symbol)) +{ +return parse_vararg_function(); +} +else if (details::imatch(symbol, symbol_not)) +{ +return parse_not_statement(); +} +else if (valid_base_operation(symbol)) +{ +return parse_base_operation(); +} +else if ( +details::imatch(symbol, symbol_if) && +settings_.control_struct_enabled(symbol) +) +{ +return parse_conditional_statement(); +} +else if ( +details::imatch(symbol, symbol_while) && +settings_.control_struct_enabled(symbol) +) +{ +return parse_while_loop(); +} +else if ( +details::imatch(symbol, symbol_repeat) && +settings_.control_struct_enabled(symbol) +) +{ +return parse_repeat_until_loop(); +} +else if ( +details::imatch(symbol, symbol_for) && +settings_.control_struct_enabled(symbol) +) +{ +return parse_for_loop(); +} +else if ( +details::imatch(symbol, symbol_switch) && +settings_.control_struct_enabled(symbol) +) +{ +return parse_switch_statement(); +} +else if (details::is_valid_sf_symbol(symbol)) +{ +return parse_special_function(); +} +else if (details::imatch(symbol, symbol_null)) +{ +return parse_null_statement(); +} +#ifndef exprtk_disable_break_continue +else if (details::imatch(symbol, symbol_break)) +{ +return parse_break_statement(); +} +else if (details::imatch(symbol, symbol_continue)) +{ +return parse_continue_statement(); +} +#endif +else if (details::imatch(symbol, symbol_var)) +{ +return parse_define_var_statement(); +} +else if (details::imatch(symbol, symbol_swap)) +{ +return parse_swap_statement(); +} +#ifndef exprtk_disable_return_statement +else if ( +details::imatch(symbol, symbol_return) && +settings_.control_struct_enabled(symbol) +) +{ +return parse_return_statement(); +} +#endif +else if (symtab_store_.valid() || !sem_.empty()) +{ +return parse_symtab_symbol(); +} +else +{ +set_error( +make_error(parser_error::e_symtab, +current_token(), +"ERR203 - Variable or function detected, yet symbol-table is invalid, Symbol: " + symbol, +exprtk_error_location)); + +return error_node(); +} +} + +inline expression_node_ptr parse_branch(precedence_level precedence = e_level00) +{ +stack_limit_handler slh(*this); + +if (!slh) +{ +return error_node(); +} + +expression_node_ptr branch = error_node(); + +if (token_t::e_number == current_token().type) +{ +T numeric_value = T(0); + +if (details::string_to_real(current_token().value, numeric_value)) +{ +expression_node_ptr literal_exp = expression_generator_(numeric_value); + +if (0 == literal_exp) +{ +set_error( +make_error(parser_error::e_numeric, +current_token(), +"ERR204 - Failed generate node for scalar: '" + current_token().value + "'", +exprtk_error_location)); + +return error_node(); +} + +next_token(); +branch = literal_exp; +} +else +{ +set_error( +make_error(parser_error::e_numeric, +current_token(), +"ERR205 - Failed to convert '" + current_token().value + "' to a number", +exprtk_error_location)); + +return error_node(); +} +} +else if (token_t::e_symbol == current_token().type) +{ +branch = parse_symbol(); +} +#ifndef exprtk_disable_string_capabilities +else if (token_t::e_string == current_token().type) +{ +branch = parse_const_string(); +} +#endif +else if (token_t::e_lbracket == current_token().type) +{ +next_token(); + +if (0 == (branch = parse_expression())) +return error_node(); +else if (!token_is(token_t::e_rbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR206 - Expected ')' instead of: '" + current_token().value + "'", +exprtk_error_location)); + +details::free_node(node_allocator_,branch); + +return error_node(); +} +else if (!post_bracket_process(token_t::e_lbracket,branch)) +{ +details::free_node(node_allocator_,branch); + +return error_node(); +} +} +else if (token_t::e_lsqrbracket == current_token().type) +{ +next_token(); + +if (0 == (branch = parse_expression())) +return error_node(); +else if (!token_is(token_t::e_rsqrbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR207 - Expected ']' instead of: '" + current_token().value + "'", +exprtk_error_location)); + +details::free_node(node_allocator_,branch); + +return error_node(); +} +else if (!post_bracket_process(token_t::e_lsqrbracket,branch)) +{ +details::free_node(node_allocator_,branch); + +return error_node(); +} +} +else if (token_t::e_lcrlbracket == current_token().type) +{ +next_token(); + +if (0 == (branch = parse_expression())) +return error_node(); +else if (!token_is(token_t::e_rcrlbracket)) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR208 - Expected '}' instead of: '" + current_token().value + "'", +exprtk_error_location)); + +details::free_node(node_allocator_,branch); + +return error_node(); +} +else if (!post_bracket_process(token_t::e_lcrlbracket,branch)) +{ +details::free_node(node_allocator_,branch); + +return error_node(); +} +} +else if (token_t::e_sub == current_token().type) +{ +next_token(); +branch = parse_expression(e_level11); + +if ( +branch && +!( +details::is_neg_unary_node (branch) && +simplify_unary_negation_branch(branch) +) +) +{ +expression_node_ptr result = expression_generator_(details::e_neg,branch); + +if (0 == result) +{ +details::free_node(node_allocator_,branch); + +return error_node(); +} +else +branch = result; +} +} +else if (token_t::e_add == current_token().type) +{ +next_token(); +branch = parse_expression(e_level13); +} +else if (token_t::e_eof == current_token().type) +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR209 - Premature end of expression[1]", +exprtk_error_location)); + +return error_node(); +} +else +{ +set_error( +make_error(parser_error::e_syntax, +current_token(), +"ERR210 - Premature end of expression[2]", +exprtk_error_location)); + +return error_node(); +} + +if ( +branch && +(e_level00 == precedence) && +token_is(token_t::e_ternary,prsrhlpr_t::e_hold) +) +{ +branch = parse_ternary_conditional_statement(branch); +} + +parse_pending_string_rangesize(branch); + +return branch; +} + +template +class expression_generator +{ +public: + +typedef details::expression_node* expression_node_ptr; +typedef expression_node_ptr (*synthesize_functor_t)(expression_generator&, const details::operator_type& operation, expression_node_ptr (&branch)[2]); +typedef std::map synthesize_map_t; +typedef typename exprtk::parser parser_t; +typedef const Type& vtype; +typedef const Type ctype; + +inline void init_synthesize_map() +{ +#ifndef exprtk_disable_enhanced_features +synthesize_map_["(v)o(v)"] = synthesize_vov_expression::process; +synthesize_map_["(c)o(v)"] = synthesize_cov_expression::process; +synthesize_map_["(v)o(c)"] = synthesize_voc_expression::process; + +#define register_synthezier(S) \ + synthesize_map_[S ::node_type::id()] = S ::process; \ + +register_synthezier(synthesize_vovov_expression0) +register_synthezier(synthesize_vovov_expression1) +register_synthezier(synthesize_vovoc_expression0) +register_synthezier(synthesize_vovoc_expression1) +register_synthezier(synthesize_vocov_expression0) +register_synthezier(synthesize_vocov_expression1) +register_synthezier(synthesize_covov_expression0) +register_synthezier(synthesize_covov_expression1) +register_synthezier(synthesize_covoc_expression0) +register_synthezier(synthesize_covoc_expression1) +register_synthezier(synthesize_cocov_expression1) +register_synthezier(synthesize_vococ_expression0) + +register_synthezier(synthesize_vovovov_expression0) +register_synthezier(synthesize_vovovoc_expression0) +register_synthezier(synthesize_vovocov_expression0) +register_synthezier(synthesize_vocovov_expression0) +register_synthezier(synthesize_covovov_expression0) +register_synthezier(synthesize_covocov_expression0) +register_synthezier(synthesize_vocovoc_expression0) +register_synthezier(synthesize_covovoc_expression0) +register_synthezier(synthesize_vococov_expression0) + +register_synthezier(synthesize_vovovov_expression1) +register_synthezier(synthesize_vovovoc_expression1) +register_synthezier(synthesize_vovocov_expression1) +register_synthezier(synthesize_vocovov_expression1) +register_synthezier(synthesize_covovov_expression1) +register_synthezier(synthesize_covocov_expression1) +register_synthezier(synthesize_vocovoc_expression1) +register_synthezier(synthesize_covovoc_expression1) +register_synthezier(synthesize_vococov_expression1) + +register_synthezier(synthesize_vovovov_expression2) +register_synthezier(synthesize_vovovoc_expression2) +register_synthezier(synthesize_vovocov_expression2) +register_synthezier(synthesize_vocovov_expression2) +register_synthezier(synthesize_covovov_expression2) +register_synthezier(synthesize_covocov_expression2) +register_synthezier(synthesize_vocovoc_expression2) +register_synthezier(synthesize_covovoc_expression2) + +register_synthezier(synthesize_vovovov_expression3) +register_synthezier(synthesize_vovovoc_expression3) +register_synthezier(synthesize_vovocov_expression3) +register_synthezier(synthesize_vocovov_expression3) +register_synthezier(synthesize_covovov_expression3) +register_synthezier(synthesize_covocov_expression3) +register_synthezier(synthesize_vocovoc_expression3) +register_synthezier(synthesize_covovoc_expression3) +register_synthezier(synthesize_vococov_expression3) + +register_synthezier(synthesize_vovovov_expression4) +register_synthezier(synthesize_vovovoc_expression4) +register_synthezier(synthesize_vovocov_expression4) +register_synthezier(synthesize_vocovov_expression4) +register_synthezier(synthesize_covovov_expression4) +register_synthezier(synthesize_covocov_expression4) +register_synthezier(synthesize_vocovoc_expression4) +register_synthezier(synthesize_covovoc_expression4) +#endif +} + +inline void set_parser(parser_t& p) +{ +parser_ = &p; +} + +inline void set_uom(unary_op_map_t& unary_op_map) +{ +unary_op_map_ = &unary_op_map; +} + +inline void set_bom(binary_op_map_t& binary_op_map) +{ +binary_op_map_ = &binary_op_map; +} + +inline void set_ibom(inv_binary_op_map_t& inv_binary_op_map) +{ +inv_binary_op_map_ = &inv_binary_op_map; +} + +inline void set_sf3m(sf3_map_t& sf3_map) +{ +sf3_map_ = &sf3_map; +} + +inline void set_sf4m(sf4_map_t& sf4_map) +{ +sf4_map_ = &sf4_map; +} + +inline void set_allocator(details::node_allocator& na) +{ +node_allocator_ = &na; +} + +inline void set_strength_reduction_state(const bool enabled) +{ +strength_reduction_enabled_ = enabled; +} + +inline bool strength_reduction_enabled() const +{ +return strength_reduction_enabled_; +} + +inline bool valid_operator(const details::operator_type& operation, binary_functor_t& bop) +{ +typename binary_op_map_t::iterator bop_itr = binary_op_map_->find(operation); + +if ((*binary_op_map_).end() == bop_itr) +return false; + +bop = bop_itr->second; + +return true; +} + +inline bool valid_operator(const details::operator_type& operation, unary_functor_t& uop) +{ +typename unary_op_map_t::iterator uop_itr = unary_op_map_->find(operation); + +if ((*unary_op_map_).end() == uop_itr) +return false; + +uop = uop_itr->second; + +return true; +} + +inline details::operator_type get_operator(const binary_functor_t& bop) const +{ +return (*inv_binary_op_map_).find(bop)->second; +} + +inline expression_node_ptr operator() (const Type& v) const +{ +return node_allocator_->allocate(v); +} + +#ifndef exprtk_disable_string_capabilities +inline expression_node_ptr operator() (const std::string& s) const +{ +return node_allocator_->allocate(s); +} + +inline expression_node_ptr operator() (std::string& s, range_t& rp) const +{ +return node_allocator_->allocate_rr(s,rp); +} + +inline expression_node_ptr operator() (const std::string& s, range_t& rp) const +{ +return node_allocator_->allocate_tt(s,rp); +} + +inline expression_node_ptr operator() (expression_node_ptr branch, range_t& rp) const +{ +if (is_generally_string_node(branch)) +return node_allocator_->allocate_tt(branch,rp); +else +return error_node(); +} +#endif + +inline bool unary_optimisable(const details::operator_type& operation) const +{ +return (details::e_abs == operation) || (details::e_acos == operation) || +(details::e_acosh == operation) || (details::e_asin == operation) || +(details::e_asinh == operation) || (details::e_atan == operation) || +(details::e_atanh == operation) || (details::e_ceil == operation) || +(details::e_cos == operation) || (details::e_cosh == operation) || +(details::e_exp == operation) || (details::e_expm1 == operation) || +(details::e_floor == operation) || (details::e_log == operation) || +(details::e_log10 == operation) || (details::e_log2 == operation) || +(details::e_log1p == operation) || (details::e_neg == operation) || +(details::e_pos == operation) || (details::e_round == operation) || +(details::e_sin == operation) || (details::e_sinc == operation) || +(details::e_sinh == operation) || (details::e_sqrt == operation) || +(details::e_tan == operation) || (details::e_tanh == operation) || +(details::e_cot == operation) || (details::e_sec == operation) || +(details::e_csc == operation) || (details::e_r2d == operation) || +(details::e_d2r == operation) || (details::e_d2g == operation) || +(details::e_g2d == operation) || (details::e_notl == operation) || +(details::e_sgn == operation) || (details::e_erf == operation) || +(details::e_erfc == operation) || (details::e_ncdf == operation) || +(details::e_frac == operation) || (details::e_trunc == operation) ; +} + +inline bool sf3_optimisable(const std::string& sf3id, trinary_functor_t& tfunc) const +{ +typename sf3_map_t::const_iterator itr = sf3_map_->find(sf3id); + +if (sf3_map_->end() == itr) +return false; +else +tfunc = itr->second.first; + +return true; +} + +inline bool sf4_optimisable(const std::string& sf4id, quaternary_functor_t& qfunc) const +{ +typename sf4_map_t::const_iterator itr = sf4_map_->find(sf4id); + +if (sf4_map_->end() == itr) +return false; +else +qfunc = itr->second.first; + +return true; +} + +inline bool sf3_optimisable(const std::string& sf3id, details::operator_type& operation) const +{ +typename sf3_map_t::const_iterator itr = sf3_map_->find(sf3id); + +if (sf3_map_->end() == itr) +return false; +else +operation = itr->second.second; + +return true; +} + +inline bool sf4_optimisable(const std::string& sf4id, details::operator_type& operation) const +{ +typename sf4_map_t::const_iterator itr = sf4_map_->find(sf4id); + +if (sf4_map_->end() == itr) +return false; +else +operation = itr->second.second; + +return true; +} + +inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr (&branch)[1]) +{ +if (0 == branch[0]) +{ +return error_node(); +} +else if (details::is_null_node(branch[0])) +{ +return branch[0]; +} +else if (details::is_break_node(branch[0])) +{ +return error_node(); +} +else if (details::is_continue_node(branch[0])) +{ +return error_node(); +} +else if (details::is_constant_node(branch[0])) +{ +return synthesize_expression(operation,branch); +} +else if (unary_optimisable(operation) && details::is_variable_node(branch[0])) +{ +return synthesize_uv_expression(operation,branch); +} +else if (unary_optimisable(operation) && details::is_ivector_node(branch[0])) +{ +return synthesize_uvec_expression(operation,branch); +} +else +return synthesize_unary_expression(operation,branch); +} + +inline bool is_assignment_operation(const details::operator_type& operation) const +{ +return ( +(details::e_addass == operation) || +(details::e_subass == operation) || +(details::e_mulass == operation) || +(details::e_divass == operation) || +(details::e_modass == operation) +) && +parser_->settings_.assignment_enabled(operation); +} + +#ifndef exprtk_disable_string_capabilities +inline bool valid_string_operation(const details::operator_type& operation) const +{ +return (details::e_add == operation) || +(details::e_lt == operation) || +(details::e_lte == operation) || +(details::e_gt == operation) || +(details::e_gte == operation) || +(details::e_eq == operation) || +(details::e_ne == operation) || +(details::e_in == operation) || +(details::e_like == operation) || +(details::e_ilike == operation) || +(details::e_assign == operation) || +(details::e_addass == operation) || +(details::e_swap == operation) ; +} +#else +inline bool valid_string_operation(const details::operator_type&) const +{ +return false; +} +#endif + +inline std::string to_str(const details::operator_type& operation) const +{ +switch (operation) +{ +case details::e_add : return "+" ; +case details::e_sub : return "-" ; +case details::e_mul : return "*" ; +case details::e_div : return "/" ; +case details::e_mod : return "%" ; +case details::e_pow : return "^" ; +case details::e_lt : return "<" ; +case details::e_lte : return "<=" ; +case details::e_gt : return ">" ; +case details::e_gte : return ">=" ; +case details::e_eq : return "==" ; +case details::e_ne : return "!=" ; +case details::e_and : return "and" ; +case details::e_nand : return "nand" ; +case details::e_or : return "or" ; +case details::e_nor : return "nor" ; +case details::e_xor : return "xor" ; +case details::e_xnor : return "xnor" ; +default : return "UNKNOWN"; +} +} + +inline bool operation_optimisable(const details::operator_type& operation) const +{ +return (details::e_add == operation) || +(details::e_sub == operation) || +(details::e_mul == operation) || +(details::e_div == operation) || +(details::e_mod == operation) || +(details::e_pow == operation) || +(details::e_lt == operation) || +(details::e_lte == operation) || +(details::e_gt == operation) || +(details::e_gte == operation) || +(details::e_eq == operation) || +(details::e_ne == operation) || +(details::e_and == operation) || +(details::e_nand == operation) || +(details::e_or == operation) || +(details::e_nor == operation) || +(details::e_xor == operation) || +(details::e_xnor == operation) ; +} + +inline std::string branch_to_id(expression_node_ptr branch) const +{ +static const std::string null_str ("(null)" ); +static const std::string const_str ("(c)" ); +static const std::string var_str ("(v)" ); +static const std::string vov_str ("(vov)" ); +static const std::string cov_str ("(cov)" ); +static const std::string voc_str ("(voc)" ); +static const std::string str_str ("(s)" ); +static const std::string strrng_str ("(rngs)" ); +static const std::string cs_str ("(cs)" ); +static const std::string cstrrng_str("(crngs)"); + +if (details::is_null_node(branch)) +return null_str; +else if (details::is_constant_node(branch)) +return const_str; +else if (details::is_variable_node(branch)) +return var_str; +else if (details::is_vov_node(branch)) +return vov_str; +else if (details::is_cov_node(branch)) +return cov_str; +else if (details::is_voc_node(branch)) +return voc_str; +else if (details::is_string_node(branch)) +return str_str; +else if (details::is_const_string_node(branch)) +return cs_str; +else if (details::is_string_range_node(branch)) +return strrng_str; +else if (details::is_const_string_range_node(branch)) +return cstrrng_str; +else if (details::is_t0ot1ot2_node(branch)) +return "(" + dynamic_cast*>(branch)->type_id() + ")"; +else if (details::is_t0ot1ot2ot3_node(branch)) +return "(" + dynamic_cast*>(branch)->type_id() + ")"; +else +return "ERROR"; +} + +inline std::string branch_to_id(expression_node_ptr (&branch)[2]) const +{ +return branch_to_id(branch[0]) + std::string("o") + branch_to_id(branch[1]); +} + +inline bool cov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const +{ +if (!operation_optimisable(operation)) +return false; +else +return details::is_constant_node(branch[0]) && +details::is_variable_node(branch[1]) ; +} + +inline bool voc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const +{ +if (!operation_optimisable(operation)) +return false; +else +return details::is_variable_node(branch[0]) && +details::is_constant_node(branch[1]) ; +} + +inline bool vov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const +{ +if (!operation_optimisable(operation)) +return false; +else +return details::is_variable_node(branch[0]) && +details::is_variable_node(branch[1]) ; +} + +inline bool cob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const +{ +if (!operation_optimisable(operation)) +return false; +else +return details::is_constant_node(branch[0]) && +!details::is_constant_node(branch[1]) ; +} + +inline bool boc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const +{ +if (!operation_optimisable(operation)) +return false; +else +return !details::is_constant_node(branch[0]) && +details::is_constant_node(branch[1]) ; +} + +inline bool cocob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const +{ +if ( +(details::e_add == operation) || +(details::e_sub == operation) || +(details::e_mul == operation) || +(details::e_div == operation) +) +{ +return (details::is_constant_node(branch[0]) && details::is_cob_node(branch[1])) || +(details::is_constant_node(branch[1]) && details::is_cob_node(branch[0])) ; +} +else +return false; +} + +inline bool coboc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const +{ +if ( +(details::e_add == operation) || +(details::e_sub == operation) || +(details::e_mul == operation) || +(details::e_div == operation) +) +{ +return (details::is_constant_node(branch[0]) && details::is_boc_node(branch[1])) || +(details::is_constant_node(branch[1]) && details::is_boc_node(branch[0])) ; +} +else +return false; +} + +inline bool uvouv_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const +{ +if (!operation_optimisable(operation)) +return false; +else +return details::is_uv_node(branch[0]) && +details::is_uv_node(branch[1]) ; +} + +inline bool vob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const +{ +if (!operation_optimisable(operation)) +return false; +else +return details::is_variable_node(branch[0]) && +!details::is_variable_node(branch[1]) ; +} + +inline bool bov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const +{ +if (!operation_optimisable(operation)) +return false; +else +return !details::is_variable_node(branch[0]) && +details::is_variable_node(branch[1]) ; +} + +inline bool binext_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const +{ +if (!operation_optimisable(operation)) +return false; +else +return !details::is_constant_node(branch[0]) || +!details::is_constant_node(branch[1]) ; +} + +inline bool is_invalid_assignment_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const +{ +if (is_assignment_operation(operation)) +{ +const bool b1_is_genstring = details::is_generally_string_node(branch[1]); + +if (details::is_string_node(branch[0])) +return !b1_is_genstring; +else +return ( +!details::is_variable_node (branch[0]) && +!details::is_vector_elem_node (branch[0]) && +!details::is_rebasevector_elem_node (branch[0]) && +!details::is_rebasevector_celem_node(branch[0]) && +!details::is_vector_node (branch[0]) +) +|| b1_is_genstring; +} +else +return false; +} + +inline bool is_constpow_operation(const details::operator_type& operation, expression_node_ptr(&branch)[2]) const +{ +if ( +!details::is_constant_node(branch[1]) || +details::is_constant_node(branch[0]) || +details::is_variable_node(branch[0]) || +details::is_vector_node (branch[0]) || +details::is_generally_string_node(branch[0]) +) +return false; + +const Type c = static_cast*>(branch[1])->value(); + +return cardinal_pow_optimisable(operation, c); +} + +inline bool is_invalid_break_continue_op(expression_node_ptr (&branch)[2]) const +{ +return ( +details::is_break_node (branch[0]) || +details::is_break_node (branch[1]) || +details::is_continue_node(branch[0]) || +details::is_continue_node(branch[1]) +); +} + +inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const +{ +const bool b0_string = is_generally_string_node(branch[0]); +const bool b1_string = is_generally_string_node(branch[1]); + +bool result = false; + +if (b0_string != b1_string) +result = true; +else if (!valid_string_operation(operation) && b0_string && b1_string) +result = true; + +if (result) +{ +parser_->set_synthesis_error("Invalid string operation"); +} + +return result; +} + +inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[3]) const +{ +const bool b0_string = is_generally_string_node(branch[0]); +const bool b1_string = is_generally_string_node(branch[1]); +const bool b2_string = is_generally_string_node(branch[2]); + +bool result = false; + +if ((b0_string != b1_string) || (b1_string != b2_string)) +result = true; +else if ((details::e_inrange != operation) && b0_string && b1_string && b2_string) +result = true; + +if (result) +{ +parser_->set_synthesis_error("Invalid string operation"); +} + +return result; +} + +inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const +{ +const bool b0_string = is_generally_string_node(branch[0]); +const bool b1_string = is_generally_string_node(branch[1]); + +return (b0_string && b1_string && valid_string_operation(operation)); +} + +inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[3]) const +{ +const bool b0_string = is_generally_string_node(branch[0]); +const bool b1_string = is_generally_string_node(branch[1]); +const bool b2_string = is_generally_string_node(branch[2]); + +return (b0_string && b1_string && b2_string && (details::e_inrange == operation)); +} + +#ifndef exprtk_disable_sc_andor +inline bool is_shortcircuit_expression(const details::operator_type& operation) const +{ +return ( +(details::e_scand == operation) || +(details::e_scor == operation) +); +} +#else +inline bool is_shortcircuit_expression(const details::operator_type&) const +{ +return false; +} +#endif + +inline bool is_null_present(expression_node_ptr (&branch)[2]) const +{ +return ( +details::is_null_node(branch[0]) || +details::is_null_node(branch[1]) +); +} + +inline bool is_vector_eqineq_logic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const +{ +if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1])) +return false; +else +return ( +(details::e_lt == operation) || +(details::e_lte == operation) || +(details::e_gt == operation) || +(details::e_gte == operation) || +(details::e_eq == operation) || +(details::e_ne == operation) || +(details::e_equal == operation) || +(details::e_and == operation) || +(details::e_nand == operation) || +(details::e_or == operation) || +(details::e_nor == operation) || +(details::e_xor == operation) || +(details::e_xnor == operation) +); +} + +inline bool is_vector_arithmetic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const +{ +if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1])) +return false; +else +return ( +(details::e_add == operation) || +(details::e_sub == operation) || +(details::e_mul == operation) || +(details::e_div == operation) || +(details::e_pow == operation) +); +} + +inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr (&branch)[2]) +{ +if ((0 == branch[0]) || (0 == branch[1])) +{ +return error_node(); +} +else if (is_invalid_string_op(operation,branch)) +{ +return error_node(); +} +else if (is_invalid_assignment_op(operation,branch)) +{ +return error_node(); +} +else if (is_invalid_break_continue_op(branch)) +{ +return error_node(); +} +else if (details::e_assign == operation) +{ +return synthesize_assignment_expression(operation, branch); +} +else if (details::e_swap == operation) +{ +return synthesize_swap_expression(branch); +} +else if (is_assignment_operation(operation)) +{ +return synthesize_assignment_operation_expression(operation, branch); +} +else if (is_vector_eqineq_logic_operation(operation, branch)) +{ +return synthesize_veceqineqlogic_operation_expression(operation, branch); +} +else if (is_vector_arithmetic_operation(operation, branch)) +{ +return synthesize_vecarithmetic_operation_expression(operation, branch); +} +else if (is_shortcircuit_expression(operation)) +{ +return synthesize_shortcircuit_expression(operation, branch); +} +else if (is_string_operation(operation, branch)) +{ +return synthesize_string_expression(operation, branch); +} +else if (is_null_present(branch)) +{ +return synthesize_null_expression(operation, branch); +} +#ifndef exprtk_disable_cardinal_pow_optimisation +else if (is_constpow_operation(operation, branch)) +{ +return cardinal_pow_optimisation(branch); +} +#endif + +expression_node_ptr result = error_node(); + +#ifndef exprtk_disable_enhanced_features +if (synthesize_expression(operation, branch, result)) +{ +return result; +} +else +#endif + +{ +/* + Possible reductions: + 1. c o cob -> cob + 2. cob o c -> cob + 3. c o boc -> boc + 4. boc o c -> boc + */ +result = error_node(); + +if (cocob_optimisable(operation, branch)) +{ +result = synthesize_cocob_expression::process((*this), operation, branch); +} +else if (coboc_optimisable(operation, branch) && (0 == result)) +{ +result = synthesize_coboc_expression::process((*this), operation, branch); +} + +if (result) +return result; +} + +if (uvouv_optimisable(operation, branch)) +{ +return synthesize_uvouv_expression(operation, branch); +} +else if (vob_optimisable(operation, branch)) +{ +return synthesize_vob_expression::process((*this), operation, branch); +} +else if (bov_optimisable(operation, branch)) +{ +return synthesize_bov_expression::process((*this), operation, branch); +} +else if (cob_optimisable(operation, branch)) +{ +return synthesize_cob_expression::process((*this), operation, branch); +} +else if (boc_optimisable(operation, branch)) +{ +return synthesize_boc_expression::process((*this), operation, branch); +} +#ifndef exprtk_disable_enhanced_features +else if (cov_optimisable(operation, branch)) +{ +return synthesize_cov_expression::process((*this), operation, branch); +} +#endif +else if (binext_optimisable(operation, branch)) +{ +return synthesize_binary_ext_expression::process((*this), operation, branch); +} +else +return synthesize_expression(operation, branch); +} + +inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr (&branch)[3]) +{ +if ( +(0 == branch[0]) || +(0 == branch[1]) || +(0 == branch[2]) +) +{ +details::free_all_nodes(*node_allocator_,branch); + +return error_node(); +} +else if (is_invalid_string_op(operation, branch)) +{ +return error_node(); +} +else if (is_string_operation(operation, branch)) +{ +return synthesize_string_expression(operation, branch); +} +else +return synthesize_expression(operation, branch); +} + +inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr (&branch)[4]) +{ +return synthesize_expression(operation,branch); +} + +inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr b0) +{ +expression_node_ptr branch[1] = { b0 }; +return (*this)(operation,branch); +} + +inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr& b0, expression_node_ptr& b1) +{ +expression_node_ptr result = error_node(); + +if ((0 != b0) && (0 != b1)) +{ +expression_node_ptr branch[2] = { b0, b1 }; +result = expression_generator::operator()(operation, branch); +b0 = branch[0]; +b1 = branch[1]; +} + +return result; +} + +inline expression_node_ptr conditional(expression_node_ptr condition, +expression_node_ptr consequent, +expression_node_ptr alternative) const +{ +if ((0 == condition) || (0 == consequent)) +{ +details::free_node(*node_allocator_, condition ); +details::free_node(*node_allocator_, consequent ); +details::free_node(*node_allocator_, alternative); + +return error_node(); +} +// Can the condition be immediately evaluated? if so optimise. +else if (details::is_constant_node(condition)) +{ +// True branch +if (details::is_true(condition)) +{ +details::free_node(*node_allocator_, condition ); +details::free_node(*node_allocator_, alternative); + +return consequent; +} +// False branch +else +{ +details::free_node(*node_allocator_, condition ); +details::free_node(*node_allocator_, consequent); + +if (alternative) +return alternative; +else +return node_allocator_->allocate >(); +} +} +else if ((0 != consequent) && (0 != alternative)) +{ +return node_allocator_-> +allocate(condition, consequent, alternative); +} +else +return node_allocator_-> +allocate(condition, consequent); +} + +#ifndef exprtk_disable_string_capabilities +inline expression_node_ptr conditional_string(expression_node_ptr condition, +expression_node_ptr consequent, +expression_node_ptr alternative) const +{ +if ((0 == condition) || (0 == consequent)) +{ +details::free_node(*node_allocator_, condition ); +details::free_node(*node_allocator_, consequent ); +details::free_node(*node_allocator_, alternative); + +return error_node(); +} +// Can the condition be immediately evaluated? if so optimise. +else if (details::is_constant_node(condition)) +{ +// True branch +if (details::is_true(condition)) +{ +details::free_node(*node_allocator_, condition ); +details::free_node(*node_allocator_, alternative); + +return consequent; +} +// False branch +else +{ +details::free_node(*node_allocator_, condition ); +details::free_node(*node_allocator_, consequent); + +if (alternative) +return alternative; +else +return node_allocator_-> +allocate_c >(""); +} +} +else if ((0 != consequent) && (0 != alternative)) +return node_allocator_-> +allocate(condition, consequent, alternative); +else +return error_node(); +} +#else +inline expression_node_ptr conditional_string(expression_node_ptr, +expression_node_ptr, +expression_node_ptr) const +{ +return error_node(); +} +#endif + +inline expression_node_ptr conditional_vector(expression_node_ptr condition, +expression_node_ptr consequent, +expression_node_ptr alternative) const +{ +if ((0 == condition) || (0 == consequent)) +{ +details::free_node(*node_allocator_, condition ); +details::free_node(*node_allocator_, consequent ); +details::free_node(*node_allocator_, alternative); + +return error_node(); +} +// Can the condition be immediately evaluated? if so optimise. +else if (details::is_constant_node(condition)) +{ +// True branch +if (details::is_true(condition)) +{ +details::free_node(*node_allocator_, condition ); +details::free_node(*node_allocator_, alternative); + +return consequent; +} +// False branch +else +{ +details::free_node(*node_allocator_, condition ); +details::free_node(*node_allocator_, consequent); + +if (alternative) +return alternative; +else +return node_allocator_->allocate >(); + +} +} +else if ((0 != consequent) && (0 != alternative)) +{ +return node_allocator_-> +allocate(condition, consequent, alternative); +} +else +return error_node(); +} + +inline loop_runtime_check_ptr get_loop_runtime_check(const loop_runtime_check::loop_types loop_type) const +{ +if ( +parser_->loop_runtime_check_ && +(loop_type == (parser_->loop_runtime_check_->loop_set & loop_type)) +) +{ +return parser_->loop_runtime_check_; +} + +return loop_runtime_check_ptr(0); +} + +inline expression_node_ptr while_loop(expression_node_ptr& condition, +expression_node_ptr& branch, +const bool break_continue_present = false) const +{ +if (!break_continue_present && details::is_constant_node(condition)) +{ +expression_node_ptr result = error_node(); +if (details::is_true(condition)) +// Infinite loops are not allowed. +result = error_node(); +else +result = node_allocator_->allocate >(); + +details::free_node(*node_allocator_, condition); +details::free_node(*node_allocator_, branch ); + +return result; +} +else if (details::is_null_node(condition)) +{ +details::free_node(*node_allocator_,condition); + +return branch; +} + +loop_runtime_check_ptr rtc = get_loop_runtime_check(loop_runtime_check::e_while_loop); + +if (!break_continue_present) +{ +if (rtc) +return node_allocator_->allocate +(condition, branch, rtc); +else +return node_allocator_->allocate +(condition, branch); +} +#ifndef exprtk_disable_break_continue +else +{ +if (rtc) +return node_allocator_->allocate +(condition, branch, rtc); +else +return node_allocator_->allocate +(condition, branch); +} +#else +return error_node(); +#endif +} + +inline expression_node_ptr repeat_until_loop(expression_node_ptr& condition, +expression_node_ptr& branch, +const bool break_continue_present = false) const +{ +if (!break_continue_present && details::is_constant_node(condition)) +{ +if ( +details::is_true(condition) && +details::is_constant_node(branch) +) +{ +free_node(*node_allocator_,condition); + +return branch; +} + +details::free_node(*node_allocator_, condition); +details::free_node(*node_allocator_, branch ); + +return error_node(); +} +else if (details::is_null_node(condition)) +{ +details::free_node(*node_allocator_,condition); + +return branch; +} + +loop_runtime_check_ptr rtc = get_loop_runtime_check(loop_runtime_check::e_repeat_until_loop); + +if (!break_continue_present) +{ +if (rtc) +return node_allocator_->allocate +(condition, branch, rtc); +else +return node_allocator_->allocate +(condition, branch); +} +#ifndef exprtk_disable_break_continue +else +{ +if (rtc) +return node_allocator_->allocate +(condition, branch, rtc); +else +return node_allocator_->allocate +(condition, branch); +} +#else +return error_node(); +#endif +} + +inline expression_node_ptr for_loop(expression_node_ptr& initialiser, +expression_node_ptr& condition, +expression_node_ptr& incrementor, +expression_node_ptr& loop_body, +bool break_continue_present = false) const +{ +if (!break_continue_present && details::is_constant_node(condition)) +{ +expression_node_ptr result = error_node(); + +if (details::is_true(condition)) +// Infinite loops are not allowed. +result = error_node(); +else +result = node_allocator_->allocate >(); + +details::free_node(*node_allocator_, initialiser); +details::free_node(*node_allocator_, condition ); +details::free_node(*node_allocator_, incrementor); +details::free_node(*node_allocator_, loop_body ); + +return result; +} +else if (details::is_null_node(condition) || (0 == condition)) +{ +details::free_node(*node_allocator_, initialiser); +details::free_node(*node_allocator_, condition ); +details::free_node(*node_allocator_, incrementor); + +return loop_body; +} + +loop_runtime_check_ptr rtc = get_loop_runtime_check(loop_runtime_check::e_for_loop); + +if (!break_continue_present) +{ +if (rtc) +return node_allocator_->allocate +( +initialiser, +condition, +incrementor, +loop_body, +rtc +); +else +return node_allocator_->allocate +( +initialiser, +condition, +incrementor, +loop_body +); +} +#ifndef exprtk_disable_break_continue +else +{ +if (rtc) +return node_allocator_->allocate +( +initialiser, +condition, +incrementor, +loop_body, +rtc +); +else +return node_allocator_->allocate +( +initialiser, +condition, +incrementor, +loop_body +); +} +#else +return error_node(); +#endif +} + +template class Sequence> +inline expression_node_ptr const_optimise_switch(Sequence& arg_list) +{ +expression_node_ptr result = error_node(); + +for (std::size_t i = 0; i < (arg_list.size() / 2); ++i) +{ +expression_node_ptr condition = arg_list[(2 * i) ]; +expression_node_ptr consequent = arg_list[(2 * i) + 1]; + +if ((0 == result) && details::is_true(condition)) +{ +result = consequent; +break; +} +} + +if (0 == result) +{ +result = arg_list.back(); +} + +for (std::size_t i = 0; i < arg_list.size(); ++i) +{ +expression_node_ptr current_expr = arg_list[i]; + +if (current_expr && (current_expr != result)) +{ +free_node(*node_allocator_,current_expr); +} +} + +return result; +} + +template class Sequence> +inline expression_node_ptr const_optimise_mswitch(Sequence& arg_list) +{ +expression_node_ptr result = error_node(); + +for (std::size_t i = 0; i < (arg_list.size() / 2); ++i) +{ +expression_node_ptr condition = arg_list[(2 * i) ]; +expression_node_ptr consequent = arg_list[(2 * i) + 1]; + +if (details::is_true(condition)) +{ +result = consequent; +} +} + +if (0 == result) +{ +T zero = T(0); +result = node_allocator_->allocate(zero); +} + +for (std::size_t i = 0; i < arg_list.size(); ++i) +{ +expression_node_ptr& current_expr = arg_list[i]; + +if (current_expr && (current_expr != result)) +{ +details::free_node(*node_allocator_,current_expr); +} +} + +return result; +} + +struct switch_nodes +{ +typedef std::vector > arg_list_t; + +#define case_stmt(N) \ + if (is_true(arg[(2 * N)].first)) { return arg[(2 * N) + 1].first->value(); } \ + +struct switch_impl_1 +{ +static inline T process(const arg_list_t& arg) +{ +case_stmt(0) + +assert(arg.size() == ((2 * 1) + 1)); + +return arg.back().first->value(); +} +}; + +struct switch_impl_2 +{ +static inline T process(const arg_list_t& arg) +{ +case_stmt(0) case_stmt(1) + +assert(arg.size() == ((2 * 2) + 1)); + +return arg.back().first->value(); +} +}; + +struct switch_impl_3 +{ +static inline T process(const arg_list_t& arg) +{ +case_stmt(0) case_stmt(1) +case_stmt(2) + +assert(arg.size() == ((2 * 3) + 1)); + +return arg.back().first->value(); +} +}; + +struct switch_impl_4 +{ +static inline T process(const arg_list_t& arg) +{ +case_stmt(0) case_stmt(1) +case_stmt(2) case_stmt(3) + +assert(arg.size() == ((2 * 4) + 1)); + +return arg.back().first->value(); +} +}; + +struct switch_impl_5 +{ +static inline T process(const arg_list_t& arg) +{ +case_stmt(0) case_stmt(1) +case_stmt(2) case_stmt(3) +case_stmt(4) + +assert(arg.size() == ((2 * 5) + 1)); + +return arg.back().first->value(); +} +}; + +struct switch_impl_6 +{ +static inline T process(const arg_list_t& arg) +{ +case_stmt(0) case_stmt(1) +case_stmt(2) case_stmt(3) +case_stmt(4) case_stmt(5) + +assert(arg.size() == ((2 * 6) + 1)); + +return arg.back().first->value(); +} +}; + +struct switch_impl_7 +{ +static inline T process(const arg_list_t& arg) +{ +case_stmt(0) case_stmt(1) +case_stmt(2) case_stmt(3) +case_stmt(4) case_stmt(5) +case_stmt(6) + +assert(arg.size() == ((2 * 7) + 1)); + +return arg.back().first->value(); +} +}; + +#undef case_stmt +}; + +template class Sequence> +inline expression_node_ptr switch_statement(Sequence& arg_list, const bool default_statement_present) +{ +if (arg_list.empty()) +return error_node(); +else if ( +!all_nodes_valid(arg_list) || +(!default_statement_present && (arg_list.size() < 2)) +) +{ +details::free_all_nodes(*node_allocator_,arg_list); + +return error_node(); +} +else if (is_constant_foldable(arg_list)) +return const_optimise_switch(arg_list); + +switch ((arg_list.size() - 1) / 2) +{ +#define case_stmt(N) \ + case N : \ + return node_allocator_-> \ + allocate >(arg_list); \ + +case_stmt(1) +case_stmt(2) +case_stmt(3) +case_stmt(4) +case_stmt(5) +case_stmt(6) +case_stmt(7) +#undef case_stmt + +default : return node_allocator_->allocate >(arg_list); +} +} + +template class Sequence> +inline expression_node_ptr multi_switch_statement(Sequence& arg_list) +{ +if (!all_nodes_valid(arg_list)) +{ +details::free_all_nodes(*node_allocator_,arg_list); + +return error_node(); +} +else if (is_constant_foldable(arg_list)) +return const_optimise_mswitch(arg_list); +else +return node_allocator_->allocate >(arg_list); +} + +#define unary_opr_switch_statements \ + case_stmt(details::e_abs , details::abs_op ) \ + case_stmt(details::e_acos , details::acos_op ) \ + case_stmt(details::e_acosh , details::acosh_op) \ + case_stmt(details::e_asin , details::asin_op ) \ + case_stmt(details::e_asinh , details::asinh_op) \ + case_stmt(details::e_atan , details::atan_op ) \ + case_stmt(details::e_atanh , details::atanh_op) \ + case_stmt(details::e_ceil , details::ceil_op ) \ + case_stmt(details::e_cos , details::cos_op ) \ + case_stmt(details::e_cosh , details::cosh_op ) \ + case_stmt(details::e_exp , details::exp_op ) \ + case_stmt(details::e_expm1 , details::expm1_op) \ + case_stmt(details::e_floor , details::floor_op) \ + case_stmt(details::e_log , details::log_op ) \ + case_stmt(details::e_log10 , details::log10_op) \ + case_stmt(details::e_log2 , details::log2_op ) \ + case_stmt(details::e_log1p , details::log1p_op) \ + case_stmt(details::e_neg , details::neg_op ) \ + case_stmt(details::e_pos , details::pos_op ) \ + case_stmt(details::e_round , details::round_op) \ + case_stmt(details::e_sin , details::sin_op ) \ + case_stmt(details::e_sinc , details::sinc_op ) \ + case_stmt(details::e_sinh , details::sinh_op ) \ + case_stmt(details::e_sqrt , details::sqrt_op ) \ + case_stmt(details::e_tan , details::tan_op ) \ + case_stmt(details::e_tanh , details::tanh_op ) \ + case_stmt(details::e_cot , details::cot_op ) \ + case_stmt(details::e_sec , details::sec_op ) \ + case_stmt(details::e_csc , details::csc_op ) \ + case_stmt(details::e_r2d , details::r2d_op ) \ + case_stmt(details::e_d2r , details::d2r_op ) \ + case_stmt(details::e_d2g , details::d2g_op ) \ + case_stmt(details::e_g2d , details::g2d_op ) \ + case_stmt(details::e_notl , details::notl_op ) \ + case_stmt(details::e_sgn , details::sgn_op ) \ + case_stmt(details::e_erf , details::erf_op ) \ + case_stmt(details::e_erfc , details::erfc_op ) \ + case_stmt(details::e_ncdf , details::ncdf_op ) \ + case_stmt(details::e_frac , details::frac_op ) \ + case_stmt(details::e_trunc , details::trunc_op) \ + +inline expression_node_ptr synthesize_uv_expression(const details::operator_type& operation, +expression_node_ptr (&branch)[1]) +{ +T& v = static_cast*>(branch[0])->ref(); + +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + allocate > >(v); \ + +unary_opr_switch_statements +#undef case_stmt +default : return error_node(); +} +} + +inline expression_node_ptr synthesize_uvec_expression(const details::operator_type& operation, +expression_node_ptr (&branch)[1]) +{ +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + allocate > > \ + (operation, branch[0]); \ + +unary_opr_switch_statements +#undef case_stmt +default : return error_node(); +} +} + +inline expression_node_ptr synthesize_unary_expression(const details::operator_type& operation, +expression_node_ptr (&branch)[1]) +{ +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + allocate > >(branch[0]); \ + +unary_opr_switch_statements +#undef case_stmt +default : return error_node(); +} +} + +inline expression_node_ptr const_optimise_sf3(const details::operator_type& operation, +expression_node_ptr (&branch)[3]) +{ +expression_node_ptr temp_node = error_node(); + +switch (operation) +{ +#define case_stmt(op) \ + case details::e_sf##op : temp_node = node_allocator_-> \ + allocate > > \ + (operation, branch); \ + break; \ + +case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) +case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) +case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) +case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) +case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) +case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) +case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) +case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) +case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) +case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) +case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) +case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) +#undef case_stmt +default : return error_node(); +} + +const T v = temp_node->value(); + +details::free_node(*node_allocator_,temp_node); + +return node_allocator_->allocate(v); +} + +inline expression_node_ptr varnode_optimise_sf3(const details::operator_type& operation, expression_node_ptr (&branch)[3]) +{ +typedef details::variable_node* variable_ptr; + +const Type& v0 = static_cast(branch[0])->ref(); +const Type& v1 = static_cast(branch[1])->ref(); +const Type& v2 = static_cast(branch[2])->ref(); + +switch (operation) +{ +#define case_stmt(op) \ + case details::e_sf##op : return node_allocator_-> \ + allocate_rrr > > \ + (v0, v1, v2); \ + +case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) +case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) +case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) +case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) +case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) +case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) +case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) +case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) +case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) +case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) +case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) +case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) +#undef case_stmt +default : return error_node(); +} +} + +inline expression_node_ptr special_function(const details::operator_type& operation, expression_node_ptr (&branch)[3]) +{ +if (!all_nodes_valid(branch)) +return error_node(); +else if (is_constant_foldable(branch)) +return const_optimise_sf3(operation,branch); +else if (all_nodes_variables(branch)) +return varnode_optimise_sf3(operation,branch); +else +{ +switch (operation) +{ +#define case_stmt(op) \ + case details::e_sf##op : return node_allocator_-> \ + allocate > > \ + (operation, branch); \ + +case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) +case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) +case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) +case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) +case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) +case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) +case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) +case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) +case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) +case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) +case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) +case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) +#undef case_stmt +default : return error_node(); +} +} +} + +inline expression_node_ptr const_optimise_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) +{ +expression_node_ptr temp_node = error_node(); + +switch (operation) +{ +#define case_stmt(op) \ + case details::e_sf##op : temp_node = node_allocator_-> \ + allocate > > \ + (operation, branch); \ + break; \ + +case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) +case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) +case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) +case_stmt(60) case_stmt(61) case_stmt(62) case_stmt(63) +case_stmt(64) case_stmt(65) case_stmt(66) case_stmt(67) +case_stmt(68) case_stmt(69) case_stmt(70) case_stmt(71) +case_stmt(72) case_stmt(73) case_stmt(74) case_stmt(75) +case_stmt(76) case_stmt(77) case_stmt(78) case_stmt(79) +case_stmt(80) case_stmt(81) case_stmt(82) case_stmt(83) +case_stmt(84) case_stmt(85) case_stmt(86) case_stmt(87) +case_stmt(88) case_stmt(89) case_stmt(90) case_stmt(91) +case_stmt(92) case_stmt(93) case_stmt(94) case_stmt(95) +case_stmt(96) case_stmt(97) case_stmt(98) case_stmt(99) +#undef case_stmt +default : return error_node(); +} + +const T v = temp_node->value(); + +details::free_node(*node_allocator_,temp_node); + +return node_allocator_->allocate(v); +} + +inline expression_node_ptr varnode_optimise_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) +{ +typedef details::variable_node* variable_ptr; + +const Type& v0 = static_cast(branch[0])->ref(); +const Type& v1 = static_cast(branch[1])->ref(); +const Type& v2 = static_cast(branch[2])->ref(); +const Type& v3 = static_cast(branch[3])->ref(); + +switch (operation) +{ +#define case_stmt(op) \ + case details::e_sf##op : return node_allocator_-> \ + allocate_rrrr > > \ + (v0, v1, v2, v3); \ + +case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) +case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) +case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) +case_stmt(60) case_stmt(61) case_stmt(62) case_stmt(63) +case_stmt(64) case_stmt(65) case_stmt(66) case_stmt(67) +case_stmt(68) case_stmt(69) case_stmt(70) case_stmt(71) +case_stmt(72) case_stmt(73) case_stmt(74) case_stmt(75) +case_stmt(76) case_stmt(77) case_stmt(78) case_stmt(79) +case_stmt(80) case_stmt(81) case_stmt(82) case_stmt(83) +case_stmt(84) case_stmt(85) case_stmt(86) case_stmt(87) +case_stmt(88) case_stmt(89) case_stmt(90) case_stmt(91) +case_stmt(92) case_stmt(93) case_stmt(94) case_stmt(95) +case_stmt(96) case_stmt(97) case_stmt(98) case_stmt(99) +#undef case_stmt +default : return error_node(); +} +} + +inline expression_node_ptr special_function(const details::operator_type& operation, expression_node_ptr (&branch)[4]) +{ +if (!all_nodes_valid(branch)) +return error_node(); +else if (is_constant_foldable(branch)) +return const_optimise_sf4(operation,branch); +else if (all_nodes_variables(branch)) +return varnode_optimise_sf4(operation,branch); +switch (operation) +{ +#define case_stmt(op) \ + case details::e_sf##op : return node_allocator_-> \ + allocate > > \ + (operation, branch); \ + +case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) +case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) +case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) +case_stmt(60) case_stmt(61) case_stmt(62) case_stmt(63) +case_stmt(64) case_stmt(65) case_stmt(66) case_stmt(67) +case_stmt(68) case_stmt(69) case_stmt(70) case_stmt(71) +case_stmt(72) case_stmt(73) case_stmt(74) case_stmt(75) +case_stmt(76) case_stmt(77) case_stmt(78) case_stmt(79) +case_stmt(80) case_stmt(81) case_stmt(82) case_stmt(83) +case_stmt(84) case_stmt(85) case_stmt(86) case_stmt(87) +case_stmt(88) case_stmt(89) case_stmt(90) case_stmt(91) +case_stmt(92) case_stmt(93) case_stmt(94) case_stmt(95) +case_stmt(96) case_stmt(97) case_stmt(98) case_stmt(99) +#undef case_stmt +default : return error_node(); +} +} + +template class Sequence> +inline expression_node_ptr const_optimise_varargfunc(const details::operator_type& operation, Sequence& arg_list) +{ +expression_node_ptr temp_node = error_node(); + +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : temp_node = node_allocator_-> \ + allocate > > \ + (arg_list); \ + break; \ + +case_stmt(details::e_sum , details::vararg_add_op ) +case_stmt(details::e_prod , details::vararg_mul_op ) +case_stmt(details::e_avg , details::vararg_avg_op ) +case_stmt(details::e_min , details::vararg_min_op ) +case_stmt(details::e_max , details::vararg_max_op ) +case_stmt(details::e_mand , details::vararg_mand_op ) +case_stmt(details::e_mor , details::vararg_mor_op ) +case_stmt(details::e_multi , details::vararg_multi_op) +#undef case_stmt +default : return error_node(); +} + +const T v = temp_node->value(); + +details::free_node(*node_allocator_,temp_node); + +return node_allocator_->allocate(v); +} + +inline bool special_one_parameter_vararg(const details::operator_type& operation) const +{ +return ( +(details::e_sum == operation) || +(details::e_prod == operation) || +(details::e_avg == operation) || +(details::e_min == operation) || +(details::e_max == operation) +); +} + +template class Sequence> +inline expression_node_ptr varnode_optimise_varargfunc(const details::operator_type& operation, Sequence& arg_list) +{ +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + allocate > >(arg_list); \ + +case_stmt(details::e_sum , details::vararg_add_op ) +case_stmt(details::e_prod , details::vararg_mul_op ) +case_stmt(details::e_avg , details::vararg_avg_op ) +case_stmt(details::e_min , details::vararg_min_op ) +case_stmt(details::e_max , details::vararg_max_op ) +case_stmt(details::e_mand , details::vararg_mand_op ) +case_stmt(details::e_mor , details::vararg_mor_op ) +case_stmt(details::e_multi , details::vararg_multi_op) +#undef case_stmt +default : return error_node(); +} +} + +template class Sequence> +inline expression_node_ptr vectorize_func(const details::operator_type& operation, Sequence& arg_list) +{ +if (1 == arg_list.size()) +{ +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + allocate > >(arg_list[0]); \ + +case_stmt(details::e_sum , details::vec_add_op) +case_stmt(details::e_prod , details::vec_mul_op) +case_stmt(details::e_avg , details::vec_avg_op) +case_stmt(details::e_min , details::vec_min_op) +case_stmt(details::e_max , details::vec_max_op) +#undef case_stmt +default : return error_node(); +} +} +else +return error_node(); +} + +template class Sequence> +inline expression_node_ptr vararg_function(const details::operator_type& operation, Sequence& arg_list) +{ +if (!all_nodes_valid(arg_list)) +{ +details::free_all_nodes(*node_allocator_,arg_list); + +return error_node(); +} +else if (is_constant_foldable(arg_list)) +return const_optimise_varargfunc(operation,arg_list); +else if ((arg_list.size() == 1) && details::is_ivector_node(arg_list[0])) +return vectorize_func(operation,arg_list); +else if ((arg_list.size() == 1) && special_one_parameter_vararg(operation)) +return arg_list[0]; +else if (all_nodes_variables(arg_list)) +return varnode_optimise_varargfunc(operation,arg_list); + +#ifndef exprtk_disable_string_capabilities +if (details::e_smulti == operation) +{ +return node_allocator_-> +allocate > >(arg_list); +} +else +#endif +{ +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + allocate > >(arg_list); \ + +case_stmt(details::e_sum , details::vararg_add_op ) +case_stmt(details::e_prod , details::vararg_mul_op ) +case_stmt(details::e_avg , details::vararg_avg_op ) +case_stmt(details::e_min , details::vararg_min_op ) +case_stmt(details::e_max , details::vararg_max_op ) +case_stmt(details::e_mand , details::vararg_mand_op ) +case_stmt(details::e_mor , details::vararg_mor_op ) +case_stmt(details::e_multi , details::vararg_multi_op) +#undef case_stmt +default : return error_node(); +} +} +} + +template +inline expression_node_ptr function(ifunction_t* f, expression_node_ptr (&b)[N]) +{ +typedef typename details::function_N_node function_N_node_t; +expression_node_ptr result = synthesize_expression(f,b); + +if (0 == result) +return error_node(); +else +{ +// Can the function call be completely optimised? +if (details::is_constant_node(result)) +return result; +else if (!all_nodes_valid(b)) +{ +details::free_node(*node_allocator_,result); +std::fill_n(b, N, reinterpret_cast(0)); + +return error_node(); +} +else if (N != f->param_count) +{ +details::free_node(*node_allocator_,result); +std::fill_n(b, N, reinterpret_cast(0)); + +return error_node(); +} + +function_N_node_t* func_node_ptr = reinterpret_cast(result); + +if (!func_node_ptr->init_branches(b)) +{ +details::free_node(*node_allocator_,result); +std::fill_n(b, N, reinterpret_cast(0)); + +return error_node(); +} + +return result; +} +} + +inline expression_node_ptr function(ifunction_t* f) +{ +typedef typename details::function_N_node function_N_node_t; +return node_allocator_->allocate(f); +} + +inline expression_node_ptr vararg_function_call(ivararg_function_t* vaf, +std::vector& arg_list) +{ +if (!all_nodes_valid(arg_list)) +{ +details::free_all_nodes(*node_allocator_,arg_list); + +return error_node(); +} + +typedef details::vararg_function_node alloc_type; + +expression_node_ptr result = node_allocator_->allocate(vaf,arg_list); + +if ( +!arg_list.empty() && +!vaf->has_side_effects() && +is_constant_foldable(arg_list) +) +{ +const Type v = result->value(); +details::free_node(*node_allocator_,result); +result = node_allocator_->allocate(v); +} + +parser_->state_.activate_side_effect("vararg_function_call()"); + +return result; +} + +inline expression_node_ptr generic_function_call(igeneric_function_t* gf, +std::vector& arg_list, +const std::size_t& param_seq_index = std::numeric_limits::max()) +{ +if (!all_nodes_valid(arg_list)) +{ +details::free_all_nodes(*node_allocator_,arg_list); +return error_node(); +} + +typedef details::generic_function_node alloc_type1; +typedef details::multimode_genfunction_node alloc_type2; + +const std::size_t no_psi = std::numeric_limits::max(); + +expression_node_ptr result = error_node(); + +if (no_psi == param_seq_index) +result = node_allocator_->allocate(arg_list,gf); +else +result = node_allocator_->allocate(gf, param_seq_index, arg_list); + +alloc_type1* genfunc_node_ptr = static_cast(result); + +if ( +!arg_list.empty() && +!gf->has_side_effects() && +parser_->state_.type_check_enabled && +is_constant_foldable(arg_list) +) +{ +genfunc_node_ptr->init_branches(); + +const Type v = result->value(); + +details::free_node(*node_allocator_,result); + +return node_allocator_->allocate(v); +} +else if (genfunc_node_ptr->init_branches()) +{ +parser_->state_.activate_side_effect("generic_function_call()"); + +return result; +} +else +{ +details::free_node(*node_allocator_, result); +details::free_all_nodes(*node_allocator_, arg_list); + +return error_node(); +} +} + +#ifndef exprtk_disable_string_capabilities +inline expression_node_ptr string_function_call(igeneric_function_t* gf, +std::vector& arg_list, +const std::size_t& param_seq_index = std::numeric_limits::max()) +{ +if (!all_nodes_valid(arg_list)) +{ +details::free_all_nodes(*node_allocator_,arg_list); +return error_node(); +} + +typedef details::string_function_node alloc_type1; +typedef details::multimode_strfunction_node alloc_type2; + +const std::size_t no_psi = std::numeric_limits::max(); + +expression_node_ptr result = error_node(); + +if (no_psi == param_seq_index) +result = node_allocator_->allocate(gf,arg_list); +else +result = node_allocator_->allocate(gf, param_seq_index, arg_list); + +alloc_type1* strfunc_node_ptr = static_cast(result); + +if ( +!arg_list.empty() && +!gf->has_side_effects() && +is_constant_foldable(arg_list) +) +{ +strfunc_node_ptr->init_branches(); + +const Type v = result->value(); + +details::free_node(*node_allocator_,result); + +return node_allocator_->allocate(v); +} +else if (strfunc_node_ptr->init_branches()) +{ +parser_->state_.activate_side_effect("string_function_call()"); + +return result; +} +else +{ +details::free_node (*node_allocator_,result ); +details::free_all_nodes(*node_allocator_,arg_list); + +return error_node(); +} +} +#endif + +#ifndef exprtk_disable_return_statement +inline expression_node_ptr return_call(std::vector& arg_list) +{ +if (!all_nodes_valid(arg_list)) +{ +details::free_all_nodes(*node_allocator_,arg_list); +return error_node(); +} + +typedef details::return_node alloc_type; + +expression_node_ptr result = node_allocator_-> +allocate_rr(arg_list,parser_->results_ctx()); + +alloc_type* return_node_ptr = static_cast(result); + +if (return_node_ptr->init_branches()) +{ +parser_->state_.activate_side_effect("return_call()"); + +return result; +} +else +{ +details::free_node (*node_allocator_, result ); +details::free_all_nodes(*node_allocator_, arg_list); + +return error_node(); +} +} + +inline expression_node_ptr return_envelope(expression_node_ptr body, +results_context_t* rc, +bool*& return_invoked) +{ +typedef details::return_envelope_node alloc_type; + +expression_node_ptr result = node_allocator_-> +allocate_cr(body,(*rc)); + +return_invoked = static_cast(result)->retinvk_ptr(); + +return result; +} +#else +inline expression_node_ptr return_call(std::vector&) +{ +return error_node(); +} + +inline expression_node_ptr return_envelope(expression_node_ptr, +results_context_t*, +bool*&) +{ +return error_node(); +} +#endif + +inline expression_node_ptr vector_element(const std::string& symbol, +vector_holder_ptr vector_base, +expression_node_ptr index) +{ +expression_node_ptr result = error_node(); + +if (details::is_constant_node(index)) +{ +std::size_t i = static_cast(details::numeric::to_int64(index->value())); + +details::free_node(*node_allocator_,index); + +if (vector_base->rebaseable()) +{ +return node_allocator_->allocate(i,vector_base); +} + +const scope_element& se = parser_->sem_.get_element(symbol,i); + +if (se.index == i) +{ +result = se.var_node; +} +else +{ +scope_element nse; +nse.name = symbol; +nse.active = true; +nse.ref_count = 1; +nse.type = scope_element::e_vecelem; +nse.index = i; +nse.depth = parser_->state_.scope_depth; +nse.data = 0; +nse.var_node = node_allocator_->allocate((*(*vector_base)[i])); + +if (!parser_->sem_.add_element(nse)) +{ +parser_->set_synthesis_error("Failed to add new local vector element to SEM [1]"); + +parser_->sem_.free_element(nse); + +result = error_node(); +} + +exprtk_debug(("vector_element() - INFO - Added new local vector element: %s\n",nse.name.c_str())); + +parser_->state_.activate_side_effect("vector_element()"); + +result = nse.var_node; +} +} +else if (vector_base->rebaseable()) +result = node_allocator_->allocate(index,vector_base); +else +result = node_allocator_->allocate(index,vector_base); + +return result; +} + +private: + +template +inline bool is_constant_foldable(NodePtr (&b)[N]) const +{ +for (std::size_t i = 0; i < N; ++i) +{ +if (0 == b[i]) +return false; +else if (!details::is_constant_node(b[i])) +return false; +} + +return true; +} + +template class Sequence> +inline bool is_constant_foldable(const Sequence& b) const +{ +for (std::size_t i = 0; i < b.size(); ++i) +{ +if (0 == b[i]) +return false; +else if (!details::is_constant_node(b[i])) +return false; +} + +return true; +} + +void lodge_assignment(symbol_type cst, expression_node_ptr node) +{ +parser_->state_.activate_side_effect("lodge_assignment()"); + +if (!parser_->dec_.collect_assignments()) +return; + +std::string symbol_name; + +switch (cst) +{ +case e_st_variable : symbol_name = parser_->symtab_store_ +.get_variable_name(node); +break; + +#ifndef exprtk_disable_string_capabilities +case e_st_string : symbol_name = parser_->symtab_store_ +.get_stringvar_name(node); +break; +#endif + +case e_st_vector : { +typedef details::vector_holder vector_holder_t; + +vector_holder_t& vh = static_cast(node)->vec_holder(); + +symbol_name = parser_->symtab_store_.get_vector_name(&vh); +} +break; + +case e_st_vecelem : { +typedef details::vector_holder vector_holder_t; + +vector_holder_t& vh = static_cast(node)->vec_holder(); + +symbol_name = parser_->symtab_store_.get_vector_name(&vh); + +cst = e_st_vector; +} +break; + +default : return; +} + +if (!symbol_name.empty()) +{ +parser_->dec_.add_assignment(symbol_name,cst); +} +} + +const void* base_ptr(expression_node_ptr node) +{ +if (node) +{ +switch(node->type()) +{ +case details::expression_node::e_variable: +return reinterpret_cast(&static_cast(node)->ref()); + +case details::expression_node::e_vecelem: +return reinterpret_cast(&static_cast(node)->ref()); + +case details::expression_node::e_rbvecelem: +return reinterpret_cast(&static_cast(node)->ref()); + +case details::expression_node::e_rbveccelem: +return reinterpret_cast(&static_cast(node)->ref()); + +case details::expression_node::e_vector: +return reinterpret_cast(static_cast(node)->vec_holder().data()); + +#ifndef exprtk_disable_string_capabilities +case details::expression_node::e_stringvar: +return reinterpret_cast((static_cast(node)->base())); + +case details::expression_node::e_stringvarrng: +return reinterpret_cast((static_cast(node)->base())); +#endif +default : return reinterpret_cast(0); +} +} + +return reinterpret_cast(0); +} + +bool assign_immutable_symbol(expression_node_ptr node) +{ +interval_t interval; +const void* baseptr_addr = base_ptr(node); + +exprtk_debug(("assign_immutable_symbol - base ptr addr: %p\n", baseptr_addr)); + +if (parser_->immutable_memory_map_.in_interval(baseptr_addr,interval)) +{ +typename immutable_symtok_map_t::iterator itr = parser_->immutable_symtok_map_.find(interval); + +if (parser_->immutable_symtok_map_.end() != itr) +{ +token_t& token = itr->second; +parser_->set_error( +parser_error::make_error(parser_error::e_parser, +token, +"ERR211 - Symbol '" + token.value + "' cannot be assigned-to as it is immutable.", +exprtk_error_location)); +} +else +parser_->set_synthesis_error("Unable to assign symbol is immutable."); + +return true; +} + +return false; +} + +inline expression_node_ptr synthesize_assignment_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) +{ +if (assign_immutable_symbol(branch[0])) +{ +return error_node(); +} +else if (details::is_variable_node(branch[0])) +{ +lodge_assignment(e_st_variable,branch[0]); +return synthesize_expression(operation,branch); +} +else if (details::is_vector_elem_node(branch[0])) +{ +lodge_assignment(e_st_vecelem,branch[0]); +return synthesize_expression(operation, branch); +} +else if (details::is_rebasevector_elem_node(branch[0])) +{ +lodge_assignment(e_st_vecelem,branch[0]); +return synthesize_expression(operation, branch); +} +else if (details::is_rebasevector_celem_node(branch[0])) +{ +lodge_assignment(e_st_vecelem,branch[0]); +return synthesize_expression(operation, branch); +} +#ifndef exprtk_disable_string_capabilities +else if (details::is_string_node(branch[0])) +{ +lodge_assignment(e_st_string,branch[0]); +return synthesize_expression(operation, branch); +} +else if (details::is_string_range_node(branch[0])) +{ +lodge_assignment(e_st_string,branch[0]); +return synthesize_expression(operation, branch); +} +#endif +else if (details::is_vector_node(branch[0])) +{ +lodge_assignment(e_st_vector,branch[0]); + +if (details::is_ivector_node(branch[1])) +return synthesize_expression(operation, branch); +else +return synthesize_expression(operation, branch); +} +else +{ +parser_->set_synthesis_error("Invalid assignment operation.[1]"); + +return error_node(); +} +} + +inline expression_node_ptr synthesize_assignment_operation_expression(const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +if (assign_immutable_symbol(branch[0])) +{ +return error_node(); +} + +if (details::is_variable_node(branch[0])) +{ +lodge_assignment(e_st_variable,branch[0]); + +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + +case_stmt(details::e_addass , details::add_op) +case_stmt(details::e_subass , details::sub_op) +case_stmt(details::e_mulass , details::mul_op) +case_stmt(details::e_divass , details::div_op) +case_stmt(details::e_modass , details::mod_op) +#undef case_stmt +default : return error_node(); +} +} +else if (details::is_vector_elem_node(branch[0])) +{ +lodge_assignment(e_st_vecelem,branch[0]); + +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + +case_stmt(details::e_addass , details::add_op) +case_stmt(details::e_subass , details::sub_op) +case_stmt(details::e_mulass , details::mul_op) +case_stmt(details::e_divass , details::div_op) +case_stmt(details::e_modass , details::mod_op) +#undef case_stmt +default : return error_node(); +} +} +else if (details::is_rebasevector_elem_node(branch[0])) +{ +lodge_assignment(e_st_vecelem,branch[0]); + +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + +case_stmt(details::e_addass , details::add_op) +case_stmt(details::e_subass , details::sub_op) +case_stmt(details::e_mulass , details::mul_op) +case_stmt(details::e_divass , details::div_op) +case_stmt(details::e_modass , details::mod_op) +#undef case_stmt +default : return error_node(); +} +} +else if (details::is_rebasevector_celem_node(branch[0])) +{ +lodge_assignment(e_st_vecelem,branch[0]); + +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + +case_stmt(details::e_addass , details::add_op) +case_stmt(details::e_subass , details::sub_op) +case_stmt(details::e_mulass , details::mul_op) +case_stmt(details::e_divass , details::div_op) +case_stmt(details::e_modass , details::mod_op) +#undef case_stmt +default : return error_node(); +} +} +else if (details::is_vector_node(branch[0])) +{ +lodge_assignment(e_st_vector,branch[0]); + +if (details::is_ivector_node(branch[1])) +{ +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + +case_stmt(details::e_addass , details::add_op) +case_stmt(details::e_subass , details::sub_op) +case_stmt(details::e_mulass , details::mul_op) +case_stmt(details::e_divass , details::div_op) +case_stmt(details::e_modass , details::mod_op) +#undef case_stmt +default : return error_node(); +} +} +else +{ +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + +case_stmt(details::e_addass , details::add_op) +case_stmt(details::e_subass , details::sub_op) +case_stmt(details::e_mulass , details::mul_op) +case_stmt(details::e_divass , details::div_op) +case_stmt(details::e_modass , details::mod_op) +#undef case_stmt +default : return error_node(); +} +} +} +#ifndef exprtk_disable_string_capabilities +else if ( +(details::e_addass == operation) && +details::is_string_node(branch[0]) +) +{ +typedef details::assignment_string_node addass_t; + +lodge_assignment(e_st_string,branch[0]); + +return synthesize_expression(operation,branch); +} +#endif +else +{ +parser_->set_synthesis_error("Invalid assignment operation[2]"); + +return error_node(); +} +} + +inline expression_node_ptr synthesize_veceqineqlogic_operation_expression(const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +const bool is_b0_ivec = details::is_ivector_node(branch[0]); +const bool is_b1_ivec = details::is_ivector_node(branch[1]); + +#define batch_eqineq_logic_case \ + case_stmt(details::e_lt , details::lt_op ) \ + case_stmt(details::e_lte , details::lte_op ) \ + case_stmt(details::e_gt , details::gt_op ) \ + case_stmt(details::e_gte , details::gte_op ) \ + case_stmt(details::e_eq , details::eq_op ) \ + case_stmt(details::e_ne , details::ne_op ) \ + case_stmt(details::e_equal , details::equal_op) \ + case_stmt(details::e_and , details::and_op ) \ + case_stmt(details::e_nand , details::nand_op ) \ + case_stmt(details::e_or , details::or_op ) \ + case_stmt(details::e_nor , details::nor_op ) \ + case_stmt(details::e_xor , details::xor_op ) \ + case_stmt(details::e_xnor , details::xnor_op ) \ + +if (is_b0_ivec && is_b1_ivec) +{ +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + +batch_eqineq_logic_case +#undef case_stmt +default : return error_node(); +} +} +else if (is_b0_ivec && !is_b1_ivec) +{ +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + +batch_eqineq_logic_case +#undef case_stmt +default : return error_node(); +} +} +else if (!is_b0_ivec && is_b1_ivec) +{ +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + +batch_eqineq_logic_case +#undef case_stmt +default : return error_node(); +} +} +else +return error_node(); + +#undef batch_eqineq_logic_case +} + +inline expression_node_ptr synthesize_vecarithmetic_operation_expression(const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +const bool is_b0_ivec = details::is_ivector_node(branch[0]); +const bool is_b1_ivec = details::is_ivector_node(branch[1]); + +#define vector_ops \ + case_stmt(details::e_add , details::add_op) \ + case_stmt(details::e_sub , details::sub_op) \ + case_stmt(details::e_mul , details::mul_op) \ + case_stmt(details::e_div , details::div_op) \ + case_stmt(details::e_mod , details::mod_op) \ + +if (is_b0_ivec && is_b1_ivec) +{ +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + +vector_ops +case_stmt(details::e_pow,details:: pow_op) +#undef case_stmt +default : return error_node(); +} +} +else if (is_b0_ivec && !is_b1_ivec) +{ +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + +vector_ops +case_stmt(details::e_pow,details:: pow_op) +#undef case_stmt +default : return error_node(); +} +} +else if (!is_b0_ivec && is_b1_ivec) +{ +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + +vector_ops +#undef case_stmt +default : return error_node(); +} +} +else +return error_node(); + +#undef vector_ops +} + +inline expression_node_ptr synthesize_swap_expression(expression_node_ptr (&branch)[2]) +{ +const bool v0_is_ivar = details::is_ivariable_node(branch[0]); +const bool v1_is_ivar = details::is_ivariable_node(branch[1]); + +const bool v0_is_ivec = details::is_ivector_node (branch[0]); +const bool v1_is_ivec = details::is_ivector_node (branch[1]); + +#ifndef exprtk_disable_string_capabilities +const bool v0_is_str = details::is_generally_string_node(branch[0]); +const bool v1_is_str = details::is_generally_string_node(branch[1]); +#endif + +expression_node_ptr result = error_node(); + +if (v0_is_ivar && v1_is_ivar) +{ +typedef details::variable_node* variable_node_ptr; + +variable_node_ptr v0 = variable_node_ptr(0); +variable_node_ptr v1 = variable_node_ptr(0); + +if ( +(0 != (v0 = dynamic_cast(branch[0]))) && +(0 != (v1 = dynamic_cast(branch[1]))) +) +{ +result = node_allocator_->allocate >(v0,v1); +} +else +result = node_allocator_->allocate >(branch[0],branch[1]); +} +else if (v0_is_ivec && v1_is_ivec) +{ +result = node_allocator_->allocate >(branch[0],branch[1]); +} +#ifndef exprtk_disable_string_capabilities +else if (v0_is_str && v1_is_str) +{ +if (is_string_node(branch[0]) && is_string_node(branch[1])) +result = node_allocator_->allocate > +(branch[0], branch[1]); +else +result = node_allocator_->allocate > +(branch[0], branch[1]); +} +#endif +else +{ +parser_->set_synthesis_error("Only variables, strings, vectors or vector elements can be swapped"); + +return error_node(); +} + +parser_->state_.activate_side_effect("synthesize_swap_expression()"); + +return result; +} + +#ifndef exprtk_disable_sc_andor +inline expression_node_ptr synthesize_shortcircuit_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) +{ +expression_node_ptr result = error_node(); + +if (details::is_constant_node(branch[0])) +{ +if ( +(details::e_scand == operation) && +std::equal_to()(T(0),branch[0]->value()) +) +result = node_allocator_->allocate_c(T(0)); +else if ( +(details::e_scor == operation) && +std::not_equal_to()(T(0),branch[0]->value()) +) +result = node_allocator_->allocate_c(T(1)); +} + +if (details::is_constant_node(branch[1]) && (0 == result)) +{ +if ( +(details::e_scand == operation) && +std::equal_to()(T(0),branch[1]->value()) +) +result = node_allocator_->allocate_c(T(0)); +else if ( +(details::e_scor == operation) && +std::not_equal_to()(T(0),branch[1]->value()) +) +result = node_allocator_->allocate_c(T(1)); +} + +if (result) +{ +details::free_node(*node_allocator_, branch[0]); +details::free_node(*node_allocator_, branch[1]); + +return result; +} +else if (details::e_scand == operation) +{ +return synthesize_expression(operation, branch); +} +else if (details::e_scor == operation) +{ +return synthesize_expression(operation, branch); +} +else +return error_node(); +} +#else +inline expression_node_ptr synthesize_shortcircuit_expression(const details::operator_type&, expression_node_ptr (&)[2]) +{ +return error_node(); +} +#endif + +#define basic_opr_switch_statements \ + case_stmt(details::e_add , details::add_op) \ + case_stmt(details::e_sub , details::sub_op) \ + case_stmt(details::e_mul , details::mul_op) \ + case_stmt(details::e_div , details::div_op) \ + case_stmt(details::e_mod , details::mod_op) \ + case_stmt(details::e_pow , details::pow_op) \ + +#define extended_opr_switch_statements \ + case_stmt(details::e_lt , details::lt_op ) \ + case_stmt(details::e_lte , details::lte_op ) \ + case_stmt(details::e_gt , details::gt_op ) \ + case_stmt(details::e_gte , details::gte_op ) \ + case_stmt(details::e_eq , details::eq_op ) \ + case_stmt(details::e_ne , details::ne_op ) \ + case_stmt(details::e_and , details::and_op ) \ + case_stmt(details::e_nand , details::nand_op) \ + case_stmt(details::e_or , details::or_op ) \ + case_stmt(details::e_nor , details::nor_op ) \ + case_stmt(details::e_xor , details::xor_op ) \ + case_stmt(details::e_xnor , details::xnor_op) \ + +#ifndef exprtk_disable_cardinal_pow_optimisation +template class IPowNode> +inline expression_node_ptr cardinal_pow_optimisation_impl(const TType& v, const unsigned int& p) +{ +switch (p) +{ +#define case_stmt(cp) \ + case cp : return node_allocator_-> \ + allocate > >(v); \ + +case_stmt( 1) case_stmt( 2) case_stmt( 3) case_stmt( 4) +case_stmt( 5) case_stmt( 6) case_stmt( 7) case_stmt( 8) +case_stmt( 9) case_stmt(10) case_stmt(11) case_stmt(12) +case_stmt(13) case_stmt(14) case_stmt(15) case_stmt(16) +case_stmt(17) case_stmt(18) case_stmt(19) case_stmt(20) +case_stmt(21) case_stmt(22) case_stmt(23) case_stmt(24) +case_stmt(25) case_stmt(26) case_stmt(27) case_stmt(28) +case_stmt(29) case_stmt(30) case_stmt(31) case_stmt(32) +case_stmt(33) case_stmt(34) case_stmt(35) case_stmt(36) +case_stmt(37) case_stmt(38) case_stmt(39) case_stmt(40) +case_stmt(41) case_stmt(42) case_stmt(43) case_stmt(44) +case_stmt(45) case_stmt(46) case_stmt(47) case_stmt(48) +case_stmt(49) case_stmt(50) case_stmt(51) case_stmt(52) +case_stmt(53) case_stmt(54) case_stmt(55) case_stmt(56) +case_stmt(57) case_stmt(58) case_stmt(59) case_stmt(60) +#undef case_stmt +default : return error_node(); +} +} + +inline expression_node_ptr cardinal_pow_optimisation(const T& v, const T& c) +{ +const bool not_recipricol = (c >= T(0)); +const unsigned int p = static_cast(details::numeric::to_int32(details::numeric::abs(c))); + +if (0 == p) +return node_allocator_->allocate_c(T(1)); +else if (std::equal_to()(T(2),c)) +{ +return node_allocator_-> +template allocate_rr > >(v,v); +} +else +{ +if (not_recipricol) +return cardinal_pow_optimisation_impl(v,p); +else +return cardinal_pow_optimisation_impl(v,p); +} +} + +inline bool cardinal_pow_optimisable(const details::operator_type& operation, const T& c) const +{ +return (details::e_pow == operation) && (details::numeric::abs(c) <= T(60)) && details::numeric::is_integer(c); +} + +inline expression_node_ptr cardinal_pow_optimisation(expression_node_ptr (&branch)[2]) +{ +const Type c = static_cast*>(branch[1])->value(); +const bool not_recipricol = (c >= T(0)); +const unsigned int p = static_cast(details::numeric::to_int32(details::numeric::abs(c))); + +node_allocator_->free(branch[1]); + +if (0 == p) +{ +details::free_all_nodes(*node_allocator_, branch); + +return node_allocator_->allocate_c(T(1)); +} +else if (not_recipricol) +return cardinal_pow_optimisation_impl(branch[0],p); +else +return cardinal_pow_optimisation_impl(branch[0],p); +} +#else +inline expression_node_ptr cardinal_pow_optimisation(T&, const T&) +{ +return error_node(); +} + +inline bool cardinal_pow_optimisable(const details::operator_type&, const T&) +{ +return false; +} + +inline expression_node_ptr cardinal_pow_optimisation(expression_node_ptr(&)[2]) +{ +return error_node(); +} +#endif + +struct synthesize_binary_ext_expression +{ +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +const bool left_neg = is_neg_unary_node(branch[0]); +const bool right_neg = is_neg_unary_node(branch[1]); + +if (left_neg && right_neg) +{ +if ( +(details::e_add == operation) || +(details::e_sub == operation) || +(details::e_mul == operation) || +(details::e_div == operation) +) +{ +if ( +!expr_gen.parser_->simplify_unary_negation_branch(branch[0]) || +!expr_gen.parser_->simplify_unary_negation_branch(branch[1]) +) +{ +details::free_all_nodes(*expr_gen.node_allocator_,branch); + +return error_node(); +} +} + +switch (operation) +{ +// -f(x + 1) + -g(y + 1) --> -(f(x + 1) + g(y + 1)) +case details::e_add : return expr_gen(details::e_neg, +expr_gen.node_allocator_-> +template allocate > > +(branch[0],branch[1])); + +// -f(x + 1) - -g(y + 1) --> g(y + 1) - f(x + 1) +case details::e_sub : return expr_gen.node_allocator_-> +template allocate > > +(branch[1],branch[0]); + +default : break; +} +} +else if (left_neg && !right_neg) +{ +if ( +(details::e_add == operation) || +(details::e_sub == operation) || +(details::e_mul == operation) || +(details::e_div == operation) +) +{ +if (!expr_gen.parser_->simplify_unary_negation_branch(branch[0])) +{ +details::free_all_nodes(*expr_gen.node_allocator_,branch); + +return error_node(); +} + +switch (operation) +{ +// -f(x + 1) + g(y + 1) --> g(y + 1) - f(x + 1) +case details::e_add : return expr_gen.node_allocator_-> +template allocate > > +(branch[1], branch[0]); + +// -f(x + 1) - g(y + 1) --> -(f(x + 1) + g(y + 1)) +case details::e_sub : return expr_gen(details::e_neg, +expr_gen.node_allocator_-> +template allocate > > +(branch[0], branch[1])); + +// -f(x + 1) * g(y + 1) --> -(f(x + 1) * g(y + 1)) +case details::e_mul : return expr_gen(details::e_neg, +expr_gen.node_allocator_-> +template allocate > > +(branch[0], branch[1])); + +// -f(x + 1) / g(y + 1) --> -(f(x + 1) / g(y + 1)) +case details::e_div : return expr_gen(details::e_neg, +expr_gen.node_allocator_-> +template allocate > > +(branch[0], branch[1])); + +default : return error_node(); +} +} +} +else if (!left_neg && right_neg) +{ +if ( +(details::e_add == operation) || +(details::e_sub == operation) || +(details::e_mul == operation) || +(details::e_div == operation) +) +{ +if (!expr_gen.parser_->simplify_unary_negation_branch(branch[1])) +{ +details::free_all_nodes(*expr_gen.node_allocator_,branch); + +return error_node(); +} + +switch (operation) +{ +// f(x + 1) + -g(y + 1) --> f(x + 1) - g(y + 1) +case details::e_add : return expr_gen.node_allocator_-> +template allocate > > +(branch[0], branch[1]); + +// f(x + 1) - - g(y + 1) --> f(x + 1) + g(y + 1) +case details::e_sub : return expr_gen.node_allocator_-> +template allocate > > +(branch[0], branch[1]); + +// f(x + 1) * -g(y + 1) --> -(f(x + 1) * g(y + 1)) +case details::e_mul : return expr_gen(details::e_neg, +expr_gen.node_allocator_-> +template allocate > > +(branch[0], branch[1])); + +// f(x + 1) / -g(y + 1) --> -(f(x + 1) / g(y + 1)) +case details::e_div : return expr_gen(details::e_neg, +expr_gen.node_allocator_-> +template allocate > > +(branch[0], branch[1])); + +default : return error_node(); +} +} +} + +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate > > \ + (branch[0], branch[1]); \ + +basic_opr_switch_statements +extended_opr_switch_statements +#undef case_stmt +default : return error_node(); +} +} +}; + +struct synthesize_vob_expression +{ +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +const Type& v = static_cast*>(branch[0])->ref(); + +#ifndef exprtk_disable_enhanced_features +if (details::is_sf3ext_node(branch[1])) +{ +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile_right +(expr_gen, v, operation, branch[1], result); + +if (synthesis_result) +{ +details::free_node(*expr_gen.node_allocator_,branch[1]); +return result; +} +} +#endif + +if ( +(details::e_mul == operation) || +(details::e_div == operation) +) +{ +if (details::is_uv_node(branch[1])) +{ +typedef details::uv_base_node* uvbn_ptr_t; + +details::operator_type o = static_cast(branch[1])->operation(); + +if (details::e_neg == o) +{ +const Type& v1 = static_cast(branch[1])->v(); + +details::free_node(*expr_gen.node_allocator_,branch[1]); + +switch (operation) +{ +case details::e_mul : return expr_gen(details::e_neg, +expr_gen.node_allocator_-> +template allocate_rr > >(v,v1)); + +case details::e_div : return expr_gen(details::e_neg, +expr_gen.node_allocator_-> +template allocate_rr > >(v,v1)); + +default : break; +} +} +} +} + +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_rc > > \ + (v, branch[1]); \ + +basic_opr_switch_statements +extended_opr_switch_statements +#undef case_stmt +default : return error_node(); +} +} +}; + +struct synthesize_bov_expression +{ +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +const Type& v = static_cast*>(branch[1])->ref(); + +#ifndef exprtk_disable_enhanced_features +if (details::is_sf3ext_node(branch[0])) +{ +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile_left +(expr_gen, v, operation, branch[0], result); + +if (synthesis_result) +{ +details::free_node(*expr_gen.node_allocator_, branch[0]); + +return result; +} +} +#endif + +if ( +(details::e_add == operation) || +(details::e_sub == operation) || +(details::e_mul == operation) || +(details::e_div == operation) +) +{ +if (details::is_uv_node(branch[0])) +{ +typedef details::uv_base_node* uvbn_ptr_t; + +details::operator_type o = static_cast(branch[0])->operation(); + +if (details::e_neg == o) +{ +const Type& v0 = static_cast(branch[0])->v(); + +details::free_node(*expr_gen.node_allocator_,branch[0]); + +switch (operation) +{ +case details::e_add : return expr_gen.node_allocator_-> +template allocate_rr > >(v,v0); + +case details::e_sub : return expr_gen(details::e_neg, +expr_gen.node_allocator_-> +template allocate_rr > >(v0,v)); + +case details::e_mul : return expr_gen(details::e_neg, +expr_gen.node_allocator_-> +template allocate_rr > >(v0,v)); + +case details::e_div : return expr_gen(details::e_neg, +expr_gen.node_allocator_-> +template allocate_rr > >(v0,v)); +default : break; +} +} +} +} + +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_cr > > \ + (branch[0], v); \ + +basic_opr_switch_statements +extended_opr_switch_statements +#undef case_stmt +default : return error_node(); +} +} +}; + +struct synthesize_cob_expression +{ +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +const Type c = static_cast*>(branch[0])->value(); + +details::free_node(*expr_gen.node_allocator_,branch[0]); + +if (std::equal_to()(T(0),c) && (details::e_mul == operation)) +{ +details::free_node(*expr_gen.node_allocator_,branch[1]); + +return expr_gen(T(0)); +} +else if (std::equal_to()(T(0),c) && (details::e_div == operation)) +{ +details::free_node(*expr_gen.node_allocator_, branch[1]); + +return expr_gen(T(0)); +} +else if (std::equal_to()(T(0),c) && (details::e_add == operation)) +return branch[1]; +else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) +return branch[1]; + +if (details::is_cob_node(branch[1])) +{ +// Simplify expressions of the form: +// 1. (1 * (2 * (3 * (4 * (5 * (6 * (7 * (8 * (9 + x))))))))) --> 40320 * (9 + x) +// 2. (1 + (2 + (3 + (4 + (5 + (6 + (7 + (8 + (9 + x))))))))) --> 45 + x +if ( +(details::e_mul == operation) || +(details::e_add == operation) +) +{ +details::cob_base_node* cobnode = static_cast*>(branch[1]); + +if (operation == cobnode->operation()) +{ +switch (operation) +{ +case details::e_add : cobnode->set_c(c + cobnode->c()); break; +case details::e_mul : cobnode->set_c(c * cobnode->c()); break; +default : return error_node(); +} + +return cobnode; +} +} + +if (operation == details::e_mul) +{ +details::cob_base_node* cobnode = static_cast*>(branch[1]); +details::operator_type cob_opr = cobnode->operation(); + +if ( +(details::e_div == cob_opr) || +(details::e_mul == cob_opr) +) +{ +switch (cob_opr) +{ +case details::e_div : cobnode->set_c(c * cobnode->c()); break; +case details::e_mul : cobnode->set_c(cobnode->c() / c); break; +default : return error_node(); +} + +return cobnode; +} +} +else if (operation == details::e_div) +{ +details::cob_base_node* cobnode = static_cast*>(branch[1]); +details::operator_type cob_opr = cobnode->operation(); + +if ( +(details::e_div == cob_opr) || +(details::e_mul == cob_opr) +) +{ +details::expression_node* new_cobnode = error_node(); + +switch (cob_opr) +{ +case details::e_div : new_cobnode = expr_gen.node_allocator_-> +template allocate_tt > > +(c / cobnode->c(), cobnode->move_branch(0)); +break; + +case details::e_mul : new_cobnode = expr_gen.node_allocator_-> +template allocate_tt > > +(c / cobnode->c(), cobnode->move_branch(0)); +break; + +default : return error_node(); +} + +details::free_node(*expr_gen.node_allocator_,branch[1]); + +return new_cobnode; +} +} +} +#ifndef exprtk_disable_enhanced_features +else if (details::is_sf3ext_node(branch[1])) +{ +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile_right +(expr_gen, c, operation, branch[1], result); + +if (synthesis_result) +{ +details::free_node(*expr_gen.node_allocator_,branch[1]); + +return result; +} +} +#endif + +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_tt > > \ + (c, branch[1]); \ + +basic_opr_switch_statements +extended_opr_switch_statements +#undef case_stmt +default : return error_node(); +} +} +}; + +struct synthesize_boc_expression +{ +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +const Type c = static_cast*>(branch[1])->value(); + +details::free_node(*(expr_gen.node_allocator_), branch[1]); + +if (std::equal_to()(T(0),c) && (details::e_mul == operation)) +{ +details::free_node(*expr_gen.node_allocator_, branch[0]); + +return expr_gen(T(0)); +} +else if (std::equal_to()(T(0),c) && (details::e_div == operation)) +{ +details::free_node(*expr_gen.node_allocator_, branch[0]); + +return expr_gen(std::numeric_limits::quiet_NaN()); +} +else if (std::equal_to()(T(0),c) && (details::e_add == operation)) +return branch[0]; +else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) +return branch[0]; + +if (details::is_boc_node(branch[0])) +{ +// Simplify expressions of the form: +// 1. (((((((((x + 9) * 8) * 7) * 6) * 5) * 4) * 3) * 2) * 1) --> (x + 9) * 40320 +// 2. (((((((((x + 9) + 8) + 7) + 6) + 5) + 4) + 3) + 2) + 1) --> x + 45 +if ( +(details::e_mul == operation) || +(details::e_add == operation) +) +{ +details::boc_base_node* bocnode = static_cast*>(branch[0]); + +if (operation == bocnode->operation()) +{ +switch (operation) +{ +case details::e_add : bocnode->set_c(c + bocnode->c()); break; +case details::e_mul : bocnode->set_c(c * bocnode->c()); break; +default : return error_node(); +} + +return bocnode; +} +} +else if (operation == details::e_div) +{ +details::boc_base_node* bocnode = static_cast*>(branch[0]); +details::operator_type boc_opr = bocnode->operation(); + +if ( +(details::e_div == boc_opr) || +(details::e_mul == boc_opr) +) +{ +switch (boc_opr) +{ +case details::e_div : bocnode->set_c(c * bocnode->c()); break; +case details::e_mul : bocnode->set_c(bocnode->c() / c); break; +default : return error_node(); +} + +return bocnode; +} +} +else if (operation == details::e_pow) +{ +// (v ^ c0) ^ c1 --> v ^(c0 * c1) +details::boc_base_node* bocnode = static_cast*>(branch[0]); +details::operator_type boc_opr = bocnode->operation(); + +if (details::e_pow == boc_opr) +{ +bocnode->set_c(bocnode->c() * c); + +return bocnode; +} +} +} + +#ifndef exprtk_disable_enhanced_features +if (details::is_sf3ext_node(branch[0])) +{ +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile_left +(expr_gen, c, operation, branch[0], result); + +if (synthesis_result) +{ +free_node(*expr_gen.node_allocator_, branch[0]); + +return result; +} +} +#endif + +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_cr > > \ + (branch[0], c); \ + +basic_opr_switch_statements +extended_opr_switch_statements +#undef case_stmt +default : return error_node(); +} +} +}; + +struct synthesize_cocob_expression +{ +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +expression_node_ptr result = error_node(); + +// (cob) o c --> cob +if (details::is_cob_node(branch[0])) +{ +details::cob_base_node* cobnode = static_cast*>(branch[0]); + +const Type c = static_cast*>(branch[1])->value(); + +if (std::equal_to()(T(0),c) && (details::e_mul == operation)) +{ +details::free_node(*expr_gen.node_allocator_, branch[0]); +details::free_node(*expr_gen.node_allocator_, branch[1]); + +return expr_gen(T(0)); +} +else if (std::equal_to()(T(0),c) && (details::e_div == operation)) +{ +details::free_node(*expr_gen.node_allocator_, branch[0]); +details::free_node(*expr_gen.node_allocator_, branch[1]); + +return expr_gen(T(std::numeric_limits::quiet_NaN())); +} +else if (std::equal_to()(T(0),c) && (details::e_add == operation)) +{ +details::free_node(*expr_gen.node_allocator_, branch[1]); + +return branch[0]; +} +else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) +{ +details::free_node(*expr_gen.node_allocator_, branch[1]); + +return branch[0]; +} +else if (std::equal_to()(T(1),c) && (details::e_div == operation)) +{ +details::free_node(*expr_gen.node_allocator_, branch[1]); + +return branch[0]; +} + +const bool op_addsub = (details::e_add == cobnode->operation()) || +(details::e_sub == cobnode->operation()) ; + +if (op_addsub) +{ +switch (operation) +{ +case details::e_add : cobnode->set_c(cobnode->c() + c); break; +case details::e_sub : cobnode->set_c(cobnode->c() - c); break; +default : return error_node(); +} + +result = cobnode; +} +else if (details::e_mul == cobnode->operation()) +{ +switch (operation) +{ +case details::e_mul : cobnode->set_c(cobnode->c() * c); break; +case details::e_div : cobnode->set_c(cobnode->c() / c); break; +default : return error_node(); +} + +result = cobnode; +} +else if (details::e_div == cobnode->operation()) +{ +if (details::e_mul == operation) +{ +cobnode->set_c(cobnode->c() * c); +result = cobnode; +} +else if (details::e_div == operation) +{ +result = expr_gen.node_allocator_-> +template allocate_tt > > +(cobnode->c() / c, cobnode->move_branch(0)); + +details::free_node(*expr_gen.node_allocator_, branch[0]); +} +} + +if (result) +{ +details::free_node(*expr_gen.node_allocator_,branch[1]); +} +} + +// c o (cob) --> cob +else if (details::is_cob_node(branch[1])) +{ +details::cob_base_node* cobnode = static_cast*>(branch[1]); + +const Type c = static_cast*>(branch[0])->value(); + +if (std::equal_to()(T(0),c) && (details::e_mul == operation)) +{ +details::free_node(*expr_gen.node_allocator_, branch[0]); +details::free_node(*expr_gen.node_allocator_, branch[1]); + +return expr_gen(T(0)); +} +else if (std::equal_to()(T(0),c) && (details::e_div == operation)) +{ +details::free_node(*expr_gen.node_allocator_, branch[0]); +details::free_node(*expr_gen.node_allocator_, branch[1]); + +return expr_gen(T(0)); +} +else if (std::equal_to()(T(0),c) && (details::e_add == operation)) +{ +details::free_node(*expr_gen.node_allocator_, branch[0]); + +return branch[1]; +} +else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) +{ +details::free_node(*expr_gen.node_allocator_, branch[0]); + +return branch[1]; +} + +if (details::e_add == cobnode->operation()) +{ +if (details::e_add == operation) +{ +cobnode->set_c(c + cobnode->c()); +result = cobnode; +} +else if (details::e_sub == operation) +{ +result = expr_gen.node_allocator_-> +template allocate_tt > > +(c - cobnode->c(), cobnode->move_branch(0)); + +details::free_node(*expr_gen.node_allocator_,branch[1]); +} +} +else if (details::e_sub == cobnode->operation()) +{ +if (details::e_add == operation) +{ +cobnode->set_c(c + cobnode->c()); +result = cobnode; +} +else if (details::e_sub == operation) +{ +result = expr_gen.node_allocator_-> +template allocate_tt > > +(c - cobnode->c(), cobnode->move_branch(0)); + +details::free_node(*expr_gen.node_allocator_,branch[1]); +} +} +else if (details::e_mul == cobnode->operation()) +{ +if (details::e_mul == operation) +{ +cobnode->set_c(c * cobnode->c()); +result = cobnode; +} +else if (details::e_div == operation) +{ +result = expr_gen.node_allocator_-> +template allocate_tt > > +(c / cobnode->c(), cobnode->move_branch(0)); + +details::free_node(*expr_gen.node_allocator_,branch[1]); +} +} +else if (details::e_div == cobnode->operation()) +{ +if (details::e_mul == operation) +{ +cobnode->set_c(c * cobnode->c()); +result = cobnode; +} +else if (details::e_div == operation) +{ +result = expr_gen.node_allocator_-> +template allocate_tt > > +(c / cobnode->c(), cobnode->move_branch(0)); + +details::free_node(*expr_gen.node_allocator_,branch[1]); +} +} + +if (result) +{ +details::free_node(*expr_gen.node_allocator_,branch[0]); +} +} + +return result; +} +}; + +struct synthesize_coboc_expression +{ +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +expression_node_ptr result = error_node(); + +// (boc) o c --> boc +if (details::is_boc_node(branch[0])) +{ +details::boc_base_node* bocnode = static_cast*>(branch[0]); + +const Type c = static_cast*>(branch[1])->value(); + +if (details::e_add == bocnode->operation()) +{ +switch (operation) +{ +case details::e_add : bocnode->set_c(bocnode->c() + c); break; +case details::e_sub : bocnode->set_c(bocnode->c() - c); break; +default : return error_node(); +} + +result = bocnode; +} +else if (details::e_mul == bocnode->operation()) +{ +switch (operation) +{ +case details::e_mul : bocnode->set_c(bocnode->c() * c); break; +case details::e_div : bocnode->set_c(bocnode->c() / c); break; +default : return error_node(); +} + +result = bocnode; +} +else if (details::e_sub == bocnode->operation()) +{ +if (details::e_add == operation) +{ +result = expr_gen.node_allocator_-> +template allocate_tt > > +(bocnode->move_branch(0), c - bocnode->c()); + +details::free_node(*expr_gen.node_allocator_,branch[0]); +} +else if (details::e_sub == operation) +{ +bocnode->set_c(bocnode->c() + c); +result = bocnode; +} +} +else if (details::e_div == bocnode->operation()) +{ +switch (operation) +{ +case details::e_div : bocnode->set_c(bocnode->c() * c); break; +case details::e_mul : bocnode->set_c(bocnode->c() / c); break; +default : return error_node(); +} + +result = bocnode; +} + +if (result) +{ +details::free_node(*expr_gen.node_allocator_, branch[1]); +} +} + +// c o (boc) --> boc +else if (details::is_boc_node(branch[1])) +{ +details::boc_base_node* bocnode = static_cast*>(branch[1]); + +const Type c = static_cast*>(branch[0])->value(); + +if (details::e_add == bocnode->operation()) +{ +if (details::e_add == operation) +{ +bocnode->set_c(c + bocnode->c()); +result = bocnode; +} +else if (details::e_sub == operation) +{ +result = expr_gen.node_allocator_-> +template allocate_tt > > +(c - bocnode->c(), bocnode->move_branch(0)); + +details::free_node(*expr_gen.node_allocator_,branch[1]); +} +} +else if (details::e_sub == bocnode->operation()) +{ +if (details::e_add == operation) +{ +result = expr_gen.node_allocator_-> +template allocate_tt > > +(bocnode->move_branch(0), c - bocnode->c()); + +details::free_node(*expr_gen.node_allocator_,branch[1]); +} +else if (details::e_sub == operation) +{ +result = expr_gen.node_allocator_-> +template allocate_tt > > +(c + bocnode->c(), bocnode->move_branch(0)); + +details::free_node(*expr_gen.node_allocator_,branch[1]); +} +} +else if (details::e_mul == bocnode->operation()) +{ +if (details::e_mul == operation) +{ +bocnode->set_c(c * bocnode->c()); +result = bocnode; +} +else if (details::e_div == operation) +{ +result = expr_gen.node_allocator_-> +template allocate_tt > > +(c / bocnode->c(), bocnode->move_branch(0)); + +details::free_node(*expr_gen.node_allocator_,branch[1]); +} +} +else if (details::e_div == bocnode->operation()) +{ +if (details::e_mul == operation) +{ +bocnode->set_c(bocnode->c() / c); +result = bocnode; +} +else if (details::e_div == operation) +{ +result = expr_gen.node_allocator_-> +template allocate_tt > > +(c * bocnode->c(), bocnode->move_branch(0)); + +details::free_node(*expr_gen.node_allocator_,branch[1]); +} +} + +if (result) +{ +details::free_node(*expr_gen.node_allocator_,branch[0]); +} +} + +return result; +} +}; + +#ifndef exprtk_disable_enhanced_features +inline bool synthesize_expression(const details::operator_type& operation, +expression_node_ptr (&branch)[2], +expression_node_ptr& result) +{ +result = error_node(); + +if (!operation_optimisable(operation)) +return false; + +const std::string node_id = branch_to_id(branch); + +const typename synthesize_map_t::iterator itr = synthesize_map_.find(node_id); + +if (synthesize_map_.end() != itr) +{ +result = itr->second((*this), operation, branch); + +return true; +} +else +return false; +} + +struct synthesize_vov_expression +{ +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +const Type& v1 = static_cast*>(branch[0])->ref(); +const Type& v2 = static_cast*>(branch[1])->ref(); + +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_rr > > \ + (v1, v2); \ + +basic_opr_switch_statements +extended_opr_switch_statements +#undef case_stmt +default : return error_node(); +} +} +}; + +struct synthesize_cov_expression +{ +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +const Type c = static_cast*> (branch[0])->value(); +const Type& v = static_cast*>(branch[1])->ref (); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); + +if (std::equal_to()(T(0),c) && (details::e_mul == operation)) +return expr_gen(T(0)); +else if (std::equal_to()(T(0),c) && (details::e_div == operation)) +return expr_gen(T(0)); +else if (std::equal_to()(T(0),c) && (details::e_add == operation)) +return static_cast*>(branch[1]); +else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) +return static_cast*>(branch[1]); + +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_cr > > \ + (c, v); \ + +basic_opr_switch_statements +extended_opr_switch_statements +#undef case_stmt +default : return error_node(); +} +} +}; + +struct synthesize_voc_expression +{ +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +const Type& v = static_cast*>(branch[0])->ref (); +const Type c = static_cast*> (branch[1])->value(); + +details::free_node(*(expr_gen.node_allocator_), branch[1]); + +if (expr_gen.cardinal_pow_optimisable(operation,c)) +{ +if (std::equal_to()(T(1),c)) +return branch[0]; +else +return expr_gen.cardinal_pow_optimisation(v,c); +} +else if (std::equal_to()(T(0),c) && (details::e_mul == operation)) +return expr_gen(T(0)); +else if (std::equal_to()(T(0),c) && (details::e_div == operation)) +return expr_gen(std::numeric_limits::quiet_NaN()); +else if (std::equal_to()(T(0),c) && (details::e_add == operation)) +return static_cast*>(branch[0]); +else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) +return static_cast*>(branch[0]); +else if (std::equal_to()(T(1),c) && (details::e_div == operation)) +return static_cast*>(branch[0]); + +switch (operation) +{ +#define case_stmt(op0, op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_rc > > \ + (v, c); \ + +basic_opr_switch_statements +extended_opr_switch_statements +#undef case_stmt +default : return error_node(); +} +} +}; + +struct synthesize_sf3ext_expression +{ +template +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& sf3opr, +T0 t0, T1 t1, T2 t2) +{ +switch (sf3opr) +{ +#define case_stmt(op) \ + case details::e_sf##op : return details::T0oT1oT2_sf3ext >:: \ + allocate(*(expr_gen.node_allocator_), t0, t1, t2); \ + +case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) +case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) +case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) +case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) +case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) +case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) +case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) +case_stmt(28) case_stmt(29) case_stmt(30) +#undef case_stmt +default : return error_node(); +} +} + +template +static inline bool compile(expression_generator& expr_gen, const std::string& id, +T0 t0, T1 t1, T2 t2, +expression_node_ptr& result) +{ +details::operator_type sf3opr; + +if (!expr_gen.sf3_optimisable(id,sf3opr)) +return false; +else +result = synthesize_sf3ext_expression::template process +(expr_gen, sf3opr, t0, t1, t2); + +return true; +} +}; + +struct synthesize_sf4ext_expression +{ +template +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& sf4opr, +T0 t0, T1 t1, T2 t2, T3 t3) +{ +switch (sf4opr) +{ +#define case_stmt0(op) \ + case details::e_sf##op : return details::T0oT1oT2oT3_sf4ext >:: \ + allocate(*(expr_gen.node_allocator_), t0, t1, t2, t3); \ + +#define case_stmt1(op) \ + case details::e_sf4ext##op : return details::T0oT1oT2oT3_sf4ext >:: \ + allocate(*(expr_gen.node_allocator_), t0, t1, t2, t3); \ + +case_stmt0(48) case_stmt0(49) case_stmt0(50) case_stmt0(51) +case_stmt0(52) case_stmt0(53) case_stmt0(54) case_stmt0(55) +case_stmt0(56) case_stmt0(57) case_stmt0(58) case_stmt0(59) +case_stmt0(60) case_stmt0(61) case_stmt0(62) case_stmt0(63) +case_stmt0(64) case_stmt0(65) case_stmt0(66) case_stmt0(67) +case_stmt0(68) case_stmt0(69) case_stmt0(70) case_stmt0(71) +case_stmt0(72) case_stmt0(73) case_stmt0(74) case_stmt0(75) +case_stmt0(76) case_stmt0(77) case_stmt0(78) case_stmt0(79) +case_stmt0(80) case_stmt0(81) case_stmt0(82) case_stmt0(83) + +case_stmt1(00) case_stmt1(01) case_stmt1(02) case_stmt1(03) +case_stmt1(04) case_stmt1(05) case_stmt1(06) case_stmt1(07) +case_stmt1(08) case_stmt1(09) case_stmt1(10) case_stmt1(11) +case_stmt1(12) case_stmt1(13) case_stmt1(14) case_stmt1(15) +case_stmt1(16) case_stmt1(17) case_stmt1(18) case_stmt1(19) +case_stmt1(20) case_stmt1(21) case_stmt1(22) case_stmt1(23) +case_stmt1(24) case_stmt1(25) case_stmt1(26) case_stmt1(27) +case_stmt1(28) case_stmt1(29) case_stmt1(30) case_stmt1(31) +case_stmt1(32) case_stmt1(33) case_stmt1(34) case_stmt1(35) +case_stmt1(36) case_stmt1(37) case_stmt1(38) case_stmt1(39) +case_stmt1(40) case_stmt1(41) case_stmt1(42) case_stmt1(43) +case_stmt1(44) case_stmt1(45) case_stmt1(46) case_stmt1(47) +case_stmt1(48) case_stmt1(49) case_stmt1(50) case_stmt1(51) +case_stmt1(52) case_stmt1(53) case_stmt1(54) case_stmt1(55) +case_stmt1(56) case_stmt1(57) case_stmt1(58) case_stmt1(59) +case_stmt1(60) case_stmt1(61) + +#undef case_stmt0 +#undef case_stmt1 +default : return error_node(); +} +} + +template +static inline bool compile(expression_generator& expr_gen, const std::string& id, +T0 t0, T1 t1, T2 t2, T3 t3, +expression_node_ptr& result) +{ +details::operator_type sf4opr; + +if (!expr_gen.sf4_optimisable(id,sf4opr)) +return false; +else +result = synthesize_sf4ext_expression::template process +(expr_gen, sf4opr, t0, t1, t2, t3); + +return true; +} + +// T o (sf3ext) +template +static inline bool compile_right(expression_generator& expr_gen, +ExternalType t, +const details::operator_type& operation, +expression_node_ptr& sf3node, +expression_node_ptr& result) +{ +if (!details::is_sf3ext_node(sf3node)) +return false; + +typedef details::T0oT1oT2_base_node* sf3ext_base_ptr; + +sf3ext_base_ptr n = static_cast(sf3node); +const std::string id = "t" + expr_gen.to_str(operation) + "(" + n->type_id() + ")"; + +switch (n->type()) +{ +case details::expression_node::e_covoc : return compile_right_impl + +(expr_gen, id, t, sf3node, result); + +case details::expression_node::e_covov : return compile_right_impl + +(expr_gen, id, t, sf3node, result); + +case details::expression_node::e_vocov : return compile_right_impl + +(expr_gen, id, t, sf3node, result); + +case details::expression_node::e_vovoc : return compile_right_impl + +(expr_gen, id, t, sf3node, result); + +case details::expression_node::e_vovov : return compile_right_impl + +(expr_gen, id, t, sf3node, result); + +default : return false; +} +} + +// (sf3ext) o T +template +static inline bool compile_left(expression_generator& expr_gen, +ExternalType t, +const details::operator_type& operation, +expression_node_ptr& sf3node, +expression_node_ptr& result) +{ +if (!details::is_sf3ext_node(sf3node)) +return false; + +typedef details::T0oT1oT2_base_node* sf3ext_base_ptr; + +sf3ext_base_ptr n = static_cast(sf3node); + +const std::string id = "(" + n->type_id() + ")" + expr_gen.to_str(operation) + "t"; + +switch (n->type()) +{ +case details::expression_node::e_covoc : return compile_left_impl + +(expr_gen, id, t, sf3node, result); + +case details::expression_node::e_covov : return compile_left_impl + +(expr_gen, id, t, sf3node, result); + +case details::expression_node::e_vocov : return compile_left_impl + +(expr_gen, id, t, sf3node, result); + +case details::expression_node::e_vovoc : return compile_left_impl + +(expr_gen, id, t, sf3node, result); + +case details::expression_node::e_vovov : return compile_left_impl + +(expr_gen, id, t, sf3node, result); + +default : return false; +} +} + +template +static inline bool compile_right_impl(expression_generator& expr_gen, +const std::string& id, +ExternalType t, +expression_node_ptr& node, +expression_node_ptr& result) +{ +SF3TypeNode* n = dynamic_cast(node); + +if (n) +{ +T0 t0 = n->t0(); +T1 t1 = n->t1(); +T2 t2 = n->t2(); + +return synthesize_sf4ext_expression::template compile +(expr_gen, id, t, t0, t1, t2, result); +} +else +return false; +} + +template +static inline bool compile_left_impl(expression_generator& expr_gen, +const std::string& id, +ExternalType t, +expression_node_ptr& node, +expression_node_ptr& result) +{ +SF3TypeNode* n = dynamic_cast(node); + +if (n) +{ +T0 t0 = n->t0(); +T1 t1 = n->t1(); +T2 t2 = n->t2(); + +return synthesize_sf4ext_expression::template compile +(expr_gen, id, t0, t1, t2, t, result); +} +else +return false; +} +}; + +struct synthesize_vovov_expression0 +{ +typedef typename vovov_t::type0 node_type; +typedef typename vovov_t::sf3_type sf3_type; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// (v0 o0 v1) o1 (v2) +const details::vov_base_node* vov = static_cast*>(branch[0]); +const Type& v0 = vov->v0(); +const Type& v1 = vov->v1(); +const Type& v2 = static_cast*>(branch[1])->ref(); +const details::operator_type o0 = vov->operation(); +const details::operator_type o1 = operation; + +details::free_node(*(expr_gen.node_allocator_),branch[0]); + +expression_node_ptr result = error_node(); + +if (expr_gen.parser_->settings_.strength_reduction_enabled()) +{ +// (v0 / v1) / v2 --> (vovov) v0 / (v1 * v2) +if ((details::e_div == o0) && (details::e_div == o1)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "t/(t*t)", v0, v1, v2, result); + +exprtk_debug(("(v0 / v1) / v2 --> (vovov) v0 / (v1 * v2)\n")); + +return (synthesis_result) ? result : error_node(); +} +} + +const bool synthesis_result = +synthesize_sf3ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1), v0, v1, v2, result); + +if (synthesis_result) +return result; + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = reinterpret_cast(0); + +if (!expr_gen.valid_operator(o0,f0)) +return error_node(); +else if (!expr_gen.valid_operator(o1,f1)) +return error_node(); +else +return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, f0, f1); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1) +{ +return details::build_string() +<< "(t" << expr_gen.to_str(o0) +<< "t)" << expr_gen.to_str(o1) +<< "t"; +} +}; + +struct synthesize_vovov_expression1 +{ +typedef typename vovov_t::type1 node_type; +typedef typename vovov_t::sf3_type sf3_type; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// (v0) o0 (v1 o1 v2) +const details::vov_base_node* vov = static_cast*>(branch[1]); +const Type& v0 = static_cast*>(branch[0])->ref(); +const Type& v1 = vov->v0(); +const Type& v2 = vov->v1(); +const details::operator_type o0 = operation; +const details::operator_type o1 = vov->operation(); + +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +if (expr_gen.parser_->settings_.strength_reduction_enabled()) +{ +// v0 / (v1 / v2) --> (vovov) (v0 * v2) / v1 +if ((details::e_div == o0) && (details::e_div == o1)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t*t)/t", v0, v2, v1, result); + +exprtk_debug(("v0 / (v1 / v2) --> (vovov) (v0 * v2) / v1\n")); + +return (synthesis_result) ? result : error_node(); +} +} + +const bool synthesis_result = +synthesize_sf3ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1), v0, v1, v2, result); + +if (synthesis_result) +return result; + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = reinterpret_cast(0); + +if (!expr_gen.valid_operator(o0,f0)) +return error_node(); +else if (!expr_gen.valid_operator(o1,f1)) +return error_node(); +else +return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, f0, f1); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1) +{ +return details::build_string() +<< "t" << expr_gen.to_str(o0) +<< "(t" << expr_gen.to_str(o1) +<< "t)"; +} +}; + +struct synthesize_vovoc_expression0 +{ +typedef typename vovoc_t::type0 node_type; +typedef typename vovoc_t::sf3_type sf3_type; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// (v0 o0 v1) o1 (c) +const details::vov_base_node* vov = static_cast*>(branch[0]); +const Type& v0 = vov->v0(); +const Type& v1 = vov->v1(); +const Type c = static_cast*>(branch[1])->value(); +const details::operator_type o0 = vov->operation(); +const details::operator_type o1 = operation; + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +if (expr_gen.parser_->settings_.strength_reduction_enabled()) +{ +// (v0 / v1) / c --> (vovoc) v0 / (v1 * c) +if ((details::e_div == o0) && (details::e_div == o1)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "t/(t*t)", v0, v1, c, result); + +exprtk_debug(("(v0 / v1) / c --> (vovoc) v0 / (v1 * c)\n")); + +return (synthesis_result) ? result : error_node(); +} +} + +const bool synthesis_result = +synthesize_sf3ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1), v0, v1, c, result); + +if (synthesis_result) +return result; + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = reinterpret_cast(0); + +if (!expr_gen.valid_operator(o0,f0)) +return error_node(); +else if (!expr_gen.valid_operator(o1,f1)) +return error_node(); +else +return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, f0, f1); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1) +{ +return details::build_string() +<< "(t" << expr_gen.to_str(o0) +<< "t)" << expr_gen.to_str(o1) +<< "t"; +} +}; + +struct synthesize_vovoc_expression1 +{ +typedef typename vovoc_t::type1 node_type; +typedef typename vovoc_t::sf3_type sf3_type; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// (v0) o0 (v1 o1 c) +const details::voc_base_node* voc = static_cast*>(branch[1]); +const Type& v0 = static_cast*>(branch[0])->ref(); +const Type& v1 = voc->v(); +const Type c = voc->c(); +const details::operator_type o0 = operation; +const details::operator_type o1 = voc->operation(); + +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +if (expr_gen.parser_->settings_.strength_reduction_enabled()) +{ +// v0 / (v1 / c) --> (vocov) (v0 * c) / v1 +if ((details::e_div == o0) && (details::e_div == o1)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t*t)/t", v0, c, v1, result); + +exprtk_debug(("v0 / (v1 / c) --> (vocov) (v0 * c) / v1\n")); + +return (synthesis_result) ? result : error_node(); +} +} + +const bool synthesis_result = +synthesize_sf3ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1), v0, v1, c, result); + +if (synthesis_result) +return result; + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = reinterpret_cast(0); + +if (!expr_gen.valid_operator(o0,f0)) +return error_node(); +else if (!expr_gen.valid_operator(o1,f1)) +return error_node(); +else +return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, f0, f1); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1) +{ +return details::build_string() +<< "t" << expr_gen.to_str(o0) +<< "(t" << expr_gen.to_str(o1) +<< "t)"; +} +}; + +struct synthesize_vocov_expression0 +{ +typedef typename vocov_t::type0 node_type; +typedef typename vocov_t::sf3_type sf3_type; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// (v0 o0 c) o1 (v1) +const details::voc_base_node* voc = static_cast*>(branch[0]); +const Type& v0 = voc->v(); +const Type c = voc->c(); +const Type& v1 = static_cast*>(branch[1])->ref(); +const details::operator_type o0 = voc->operation(); +const details::operator_type o1 = operation; + +details::free_node(*(expr_gen.node_allocator_),branch[0]); + +expression_node_ptr result = error_node(); + +if (expr_gen.parser_->settings_.strength_reduction_enabled()) +{ +// (v0 / c) / v1 --> (vovoc) v0 / (v1 * c) +if ((details::e_div == o0) && (details::e_div == o1)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "t/(t*t)", v0, v1, c, result); + +exprtk_debug(("(v0 / c) / v1 --> (vovoc) v0 / (v1 * c)\n")); + +return (synthesis_result) ? result : error_node(); +} +} + +const bool synthesis_result = +synthesize_sf3ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1), v0, c, v1, result); + +if (synthesis_result) +return result; + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = reinterpret_cast(0); + +if (!expr_gen.valid_operator(o0,f0)) +return error_node(); +else if (!expr_gen.valid_operator(o1,f1)) +return error_node(); +else +return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, f0, f1); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1) +{ +return details::build_string() +<< "(t" << expr_gen.to_str(o0) +<< "t)" << expr_gen.to_str(o1) +<< "t"; +} +}; + +struct synthesize_vocov_expression1 +{ +typedef typename vocov_t::type1 node_type; +typedef typename vocov_t::sf3_type sf3_type; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// (v0) o0 (c o1 v1) +const details::cov_base_node* cov = static_cast*>(branch[1]); +const Type& v0 = static_cast*>(branch[0])->ref(); +const Type c = cov->c(); +const Type& v1 = cov->v(); +const details::operator_type o0 = operation; +const details::operator_type o1 = cov->operation(); + +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +if (expr_gen.parser_->settings_.strength_reduction_enabled()) +{ +// v0 / (c / v1) --> (vovoc) (v0 * v1) / c +if ((details::e_div == o0) && (details::e_div == o1)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t*t)/t", v0, v1, c, result); + +exprtk_debug(("v0 / (c / v1) --> (vovoc) (v0 * v1) / c\n")); + +return (synthesis_result) ? result : error_node(); +} +} + +const bool synthesis_result = +synthesize_sf3ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1), v0, c, v1, result); + +if (synthesis_result) +return result; + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = reinterpret_cast(0); + +if (!expr_gen.valid_operator(o0,f0)) +return error_node(); +else if (!expr_gen.valid_operator(o1,f1)) +return error_node(); +else +return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, f0, f1); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1) +{ +return details::build_string() +<< "t" << expr_gen.to_str(o0) +<< "(t" << expr_gen.to_str(o1) +<< "t)"; +} +}; + +struct synthesize_covov_expression0 +{ +typedef typename covov_t::type0 node_type; +typedef typename covov_t::sf3_type sf3_type; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// (c o0 v0) o1 (v1) +const details::cov_base_node* cov = static_cast*>(branch[0]); +const Type c = cov->c(); +const Type& v0 = cov->v(); +const Type& v1 = static_cast*>(branch[1])->ref(); +const details::operator_type o0 = cov->operation(); +const details::operator_type o1 = operation; + +details::free_node(*(expr_gen.node_allocator_),branch[0]); + +expression_node_ptr result = error_node(); + +if (expr_gen.parser_->settings_.strength_reduction_enabled()) +{ +// (c / v0) / v1 --> (covov) c / (v0 * v1) +if ((details::e_div == o0) && (details::e_div == o1)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "t/(t*t)", c, v0, v1, result); + +exprtk_debug(("(c / v0) / v1 --> (covov) c / (v0 * v1)\n")); + +return (synthesis_result) ? result : error_node(); +} +} + +const bool synthesis_result = +synthesize_sf3ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1), c, v0, v1, result); + +if (synthesis_result) +return result; + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = reinterpret_cast(0); + +if (!expr_gen.valid_operator(o0,f0)) +return error_node(); +else if (!expr_gen.valid_operator(o1,f1)) +return error_node(); +else +return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, f0, f1); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1) +{ +return details::build_string() +<< "(t" << expr_gen.to_str(o0) +<< "t)" << expr_gen.to_str(o1) +<< "t"; +} +}; + +struct synthesize_covov_expression1 +{ +typedef typename covov_t::type1 node_type; +typedef typename covov_t::sf3_type sf3_type; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// (c) o0 (v0 o1 v1) +const details::vov_base_node* vov = static_cast*>(branch[1]); +const Type c = static_cast*>(branch[0])->value(); +const Type& v0 = vov->v0(); +const Type& v1 = vov->v1(); +const details::operator_type o0 = operation; +const details::operator_type o1 = vov->operation(); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +if (expr_gen.parser_->settings_.strength_reduction_enabled()) +{ +// c / (v0 / v1) --> (covov) (c * v1) / v0 +if ((details::e_div == o0) && (details::e_div == o1)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t*t)/t", c, v1, v0, result); + +exprtk_debug(("c / (v0 / v1) --> (covov) (c * v1) / v0\n")); + +return (synthesis_result) ? result : error_node(); +} +} + +const bool synthesis_result = +synthesize_sf3ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1), c, v0, v1, result); + +if (synthesis_result) +return result; + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = reinterpret_cast(0); + +if (!expr_gen.valid_operator(o0,f0)) +return error_node(); +else if (!expr_gen.valid_operator(o1,f1)) +return error_node(); +else +return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, f0, f1); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1) +{ +return details::build_string() +<< "t" << expr_gen.to_str(o0) +<< "(t" << expr_gen.to_str(o1) +<< "t)"; +} +}; + +struct synthesize_covoc_expression0 +{ +typedef typename covoc_t::type0 node_type; +typedef typename covoc_t::sf3_type sf3_type; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// (c0 o0 v) o1 (c1) +const details::cov_base_node* cov = static_cast*>(branch[0]); +const Type c0 = cov->c(); +const Type& v = cov->v(); +const Type c1 = static_cast*>(branch[1])->value(); +const details::operator_type o0 = cov->operation(); +const details::operator_type o1 = operation; + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +if (expr_gen.parser_->settings_.strength_reduction_enabled()) +{ +// (c0 + v) + c1 --> (cov) (c0 + c1) + v +if ((details::e_add == o0) && (details::e_add == o1)) +{ +exprtk_debug(("(c0 + v) + c1 --> (cov) (c0 + c1) + v\n")); + +return expr_gen.node_allocator_-> +template allocate_cr > >(c0 + c1, v); +} +// (c0 + v) - c1 --> (cov) (c0 - c1) + v +else if ((details::e_add == o0) && (details::e_sub == o1)) +{ +exprtk_debug(("(c0 + v) - c1 --> (cov) (c0 - c1) + v\n")); + +return expr_gen.node_allocator_-> +template allocate_cr > >(c0 - c1, v); +} +// (c0 - v) + c1 --> (cov) (c0 + c1) - v +else if ((details::e_sub == o0) && (details::e_add == o1)) +{ +exprtk_debug(("(c0 - v) + c1 --> (cov) (c0 + c1) - v\n")); + +return expr_gen.node_allocator_-> +template allocate_cr > >(c0 + c1, v); +} +// (c0 - v) - c1 --> (cov) (c0 - c1) - v +else if ((details::e_sub == o0) && (details::e_sub == o1)) +{ +exprtk_debug(("(c0 - v) - c1 --> (cov) (c0 - c1) - v\n")); + +return expr_gen.node_allocator_-> +template allocate_cr > >(c0 - c1, v); +} +// (c0 * v) * c1 --> (cov) (c0 * c1) * v +else if ((details::e_mul == o0) && (details::e_mul == o1)) +{ +exprtk_debug(("(c0 * v) * c1 --> (cov) (c0 * c1) * v\n")); + +return expr_gen.node_allocator_-> +template allocate_cr > >(c0 * c1, v); +} +// (c0 * v) / c1 --> (cov) (c0 / c1) * v +else if ((details::e_mul == o0) && (details::e_div == o1)) +{ +exprtk_debug(("(c0 * v) / c1 --> (cov) (c0 / c1) * v\n")); + +return expr_gen.node_allocator_-> +template allocate_cr > >(c0 / c1, v); +} +// (c0 / v) * c1 --> (cov) (c0 * c1) / v +else if ((details::e_div == o0) && (details::e_mul == o1)) +{ +exprtk_debug(("(c0 / v) * c1 --> (cov) (c0 * c1) / v\n")); + +return expr_gen.node_allocator_-> +template allocate_cr > >(c0 * c1, v); +} +// (c0 / v) / c1 --> (cov) (c0 / c1) / v +else if ((details::e_div == o0) && (details::e_div == o1)) +{ +exprtk_debug(("(c0 / v) / c1 --> (cov) (c0 / c1) / v\n")); + +return expr_gen.node_allocator_-> +template allocate_cr > >(c0 / c1, v); +} +} + +const bool synthesis_result = +synthesize_sf3ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1), c0, v, c1, result); + +if (synthesis_result) +return result; + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = reinterpret_cast(0); + +if (!expr_gen.valid_operator(o0,f0)) +return error_node(); +else if (!expr_gen.valid_operator(o1,f1)) +return error_node(); +else +return node_type::allocate(*(expr_gen.node_allocator_), c0, v, c1, f0, f1); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1) +{ +return details::build_string() +<< "(t" << expr_gen.to_str(o0) +<< "t)" << expr_gen.to_str(o1) +<< "t"; +} +}; + +struct synthesize_covoc_expression1 +{ +typedef typename covoc_t::type1 node_type; +typedef typename covoc_t::sf3_type sf3_type; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// (c0) o0 (v o1 c1) +const details::voc_base_node* voc = static_cast*>(branch[1]); +const Type c0 = static_cast*>(branch[0])->value(); +const Type& v = voc->v(); +const Type c1 = voc->c(); +const details::operator_type o0 = operation; +const details::operator_type o1 = voc->operation(); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +if (expr_gen.parser_->settings_.strength_reduction_enabled()) +{ +// (c0) + (v + c1) --> (cov) (c0 + c1) + v +if ((details::e_add == o0) && (details::e_add == o1)) +{ +exprtk_debug(("(c0) + (v + c1) --> (cov) (c0 + c1) + v\n")); + +return expr_gen.node_allocator_-> +template allocate_cr > >(c0 + c1, v); +} +// (c0) + (v - c1) --> (cov) (c0 - c1) + v +else if ((details::e_add == o0) && (details::e_sub == o1)) +{ +exprtk_debug(("(c0) + (v - c1) --> (cov) (c0 - c1) + v\n")); + +return expr_gen.node_allocator_-> +template allocate_cr > >(c0 - c1, v); +} +// (c0) - (v + c1) --> (cov) (c0 - c1) - v +else if ((details::e_sub == o0) && (details::e_add == o1)) +{ +exprtk_debug(("(c0) - (v + c1) --> (cov) (c0 - c1) - v\n")); + +return expr_gen.node_allocator_-> +template allocate_cr > >(c0 - c1, v); +} +// (c0) - (v - c1) --> (cov) (c0 + c1) - v +else if ((details::e_sub == o0) && (details::e_sub == o1)) +{ +exprtk_debug(("(c0) - (v - c1) --> (cov) (c0 + c1) - v\n")); + +return expr_gen.node_allocator_-> +template allocate_cr > >(c0 + c1, v); +} +// (c0) * (v * c1) --> (voc) v * (c0 * c1) +else if ((details::e_mul == o0) && (details::e_mul == o1)) +{ +exprtk_debug(("(c0) * (v * c1) --> (voc) v * (c0 * c1)\n")); + +return expr_gen.node_allocator_-> +template allocate_cr > >(c0 * c1, v); +} +// (c0) * (v / c1) --> (cov) (c0 / c1) * v +else if ((details::e_mul == o0) && (details::e_div == o1)) +{ +exprtk_debug(("(c0) * (v / c1) --> (cov) (c0 / c1) * v\n")); + +return expr_gen.node_allocator_-> +template allocate_cr > >(c0 / c1, v); +} +// (c0) / (v * c1) --> (cov) (c0 / c1) / v +else if ((details::e_div == o0) && (details::e_mul == o1)) +{ +exprtk_debug(("(c0) / (v * c1) --> (cov) (c0 / c1) / v\n")); + +return expr_gen.node_allocator_-> +template allocate_cr > >(c0 / c1, v); +} +// (c0) / (v / c1) --> (cov) (c0 * c1) / v +else if ((details::e_div == o0) && (details::e_div == o1)) +{ +exprtk_debug(("(c0) / (v / c1) --> (cov) (c0 * c1) / v\n")); + +return expr_gen.node_allocator_-> +template allocate_cr > >(c0 * c1, v); +} +} + +const bool synthesis_result = +synthesize_sf3ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1), c0, v, c1, result); + +if (synthesis_result) +return result; + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = reinterpret_cast(0); + +if (!expr_gen.valid_operator(o0,f0)) +return error_node(); +else if (!expr_gen.valid_operator(o1,f1)) +return error_node(); +else +return node_type::allocate(*(expr_gen.node_allocator_), c0, v, c1, f0, f1); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1) +{ +return details::build_string() +<< "t" << expr_gen.to_str(o0) +<< "(t" << expr_gen.to_str(o1) +<< "t)"; +} +}; + +struct synthesize_cocov_expression0 +{ +typedef typename cocov_t::type0 node_type; +static inline expression_node_ptr process(expression_generator&, +const details::operator_type&, +expression_node_ptr (&)[2]) +{ +// (c0 o0 c1) o1 (v) - Not possible. +return error_node(); +} +}; + +struct synthesize_cocov_expression1 +{ +typedef typename cocov_t::type1 node_type; +typedef typename cocov_t::sf3_type sf3_type; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// (c0) o0 (c1 o1 v) +const details::cov_base_node* cov = static_cast*>(branch[1]); +const Type c0 = static_cast*>(branch[0])->value(); +const Type c1 = cov->c(); +const Type& v = cov->v(); +const details::operator_type o0 = operation; +const details::operator_type o1 = cov->operation(); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +if (expr_gen.parser_->settings_.strength_reduction_enabled()) +{ +// (c0) + (c1 + v) --> (cov) (c0 + c1) + v +if ((details::e_add == o0) && (details::e_add == o1)) +{ +exprtk_debug(("(c0) + (c1 + v) --> (cov) (c0 + c1) + v\n")); + +return expr_gen.node_allocator_-> +template allocate_cr > >(c0 + c1, v); +} +// (c0) + (c1 - v) --> (cov) (c0 + c1) - v +else if ((details::e_add == o0) && (details::e_sub == o1)) +{ +exprtk_debug(("(c0) + (c1 - v) --> (cov) (c0 + c1) - v\n")); + +return expr_gen.node_allocator_-> +template allocate_cr > >(c0 + c1, v); +} +// (c0) - (c1 + v) --> (cov) (c0 - c1) - v +else if ((details::e_sub == o0) && (details::e_add == o1)) +{ +exprtk_debug(("(c0) - (c1 + v) --> (cov) (c0 - c1) - v\n")); + +return expr_gen.node_allocator_-> +template allocate_cr > >(c0 - c1, v); +} +// (c0) - (c1 - v) --> (cov) (c0 - c1) + v +else if ((details::e_sub == o0) && (details::e_sub == o1)) +{ +exprtk_debug(("(c0) - (c1 - v) --> (cov) (c0 - c1) + v\n")); + +return expr_gen.node_allocator_-> +template allocate_cr > >(c0 - c1, v); +} +// (c0) * (c1 * v) --> (cov) (c0 * c1) * v +else if ((details::e_mul == o0) && (details::e_mul == o1)) +{ +exprtk_debug(("(c0) * (c1 * v) --> (cov) (c0 * c1) * v\n")); + +return expr_gen.node_allocator_-> +template allocate_cr > >(c0 * c1, v); +} +// (c0) * (c1 / v) --> (cov) (c0 * c1) / v +else if ((details::e_mul == o0) && (details::e_div == o1)) +{ +exprtk_debug(("(c0) * (c1 / v) --> (cov) (c0 * c1) / v\n")); + +return expr_gen.node_allocator_-> +template allocate_cr > >(c0 * c1, v); +} +// (c0) / (c1 * v) --> (cov) (c0 / c1) / v +else if ((details::e_div == o0) && (details::e_mul == o1)) +{ +exprtk_debug(("(c0) / (c1 * v) --> (cov) (c0 / c1) / v\n")); + +return expr_gen.node_allocator_-> +template allocate_cr > >(c0 / c1, v); +} +// (c0) / (c1 / v) --> (cov) (c0 / c1) * v +else if ((details::e_div == o0) && (details::e_div == o1)) +{ +exprtk_debug(("(c0) / (c1 / v) --> (cov) (c0 / c1) * v\n")); + +return expr_gen.node_allocator_-> +template allocate_cr > >(c0 / c1, v); +} +} + +const bool synthesis_result = +synthesize_sf3ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1), c0, c1, v, result); + +if (synthesis_result) +return result; + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = reinterpret_cast(0); + +if (!expr_gen.valid_operator(o0,f0)) +return error_node(); +else if (!expr_gen.valid_operator(o1,f1)) +return error_node(); +else +return node_type::allocate(*(expr_gen.node_allocator_), c0, c1, v, f0, f1); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1) +{ +return details::build_string() +<< "t" << expr_gen.to_str(o0) +<< "(t" << expr_gen.to_str(o1) +<< "t)"; +} +}; + +struct synthesize_vococ_expression0 +{ +typedef typename vococ_t::type0 node_type; +typedef typename vococ_t::sf3_type sf3_type; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// (v o0 c0) o1 (c1) +const details::voc_base_node* voc = static_cast*>(branch[0]); +const Type& v = voc->v(); +const Type& c0 = voc->c(); +const Type& c1 = static_cast*>(branch[1])->value(); +const details::operator_type o0 = voc->operation(); +const details::operator_type o1 = operation; + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +if (expr_gen.parser_->settings_.strength_reduction_enabled()) +{ +// (v + c0) + c1 --> (voc) v + (c0 + c1) +if ((details::e_add == o0) && (details::e_add == o1)) +{ +exprtk_debug(("(v + c0) + c1 --> (voc) v + (c0 + c1)\n")); + +return expr_gen.node_allocator_-> +template allocate_rc > >(v, c0 + c1); +} +// (v + c0) - c1 --> (voc) v + (c0 - c1) +else if ((details::e_add == o0) && (details::e_sub == o1)) +{ +exprtk_debug(("(v + c0) - c1 --> (voc) v + (c0 - c1)\n")); + +return expr_gen.node_allocator_-> +template allocate_rc > >(v, c0 - c1); +} +// (v - c0) + c1 --> (voc) v - (c0 + c1) +else if ((details::e_sub == o0) && (details::e_add == o1)) +{ +exprtk_debug(("(v - c0) + c1 --> (voc) v - (c0 + c1)\n")); + +return expr_gen.node_allocator_-> +template allocate_rc > >(v, c1 - c0); +} +// (v - c0) - c1 --> (voc) v - (c0 + c1) +else if ((details::e_sub == o0) && (details::e_sub == o1)) +{ +exprtk_debug(("(v - c0) - c1 --> (voc) v - (c0 + c1)\n")); + +return expr_gen.node_allocator_-> +template allocate_rc > >(v, c0 + c1); +} +// (v * c0) * c1 --> (voc) v * (c0 * c1) +else if ((details::e_mul == o0) && (details::e_mul == o1)) +{ +exprtk_debug(("(v * c0) * c1 --> (voc) v * (c0 * c1)\n")); + +return expr_gen.node_allocator_-> +template allocate_rc > >(v, c0 * c1); +} +// (v * c0) / c1 --> (voc) v * (c0 / c1) +else if ((details::e_mul == o0) && (details::e_div == o1)) +{ +exprtk_debug(("(v * c0) / c1 --> (voc) v * (c0 / c1)\n")); + +return expr_gen.node_allocator_-> +template allocate_rc > >(v, c0 / c1); +} +// (v / c0) * c1 --> (voc) v * (c1 / c0) +else if ((details::e_div == o0) && (details::e_mul == o1)) +{ +exprtk_debug(("(v / c0) * c1 --> (voc) v * (c1 / c0)\n")); + +return expr_gen.node_allocator_-> +template allocate_rc > >(v, c1 / c0); +} +// (v / c0) / c1 --> (voc) v / (c0 * c1) +else if ((details::e_div == o0) && (details::e_div == o1)) +{ +exprtk_debug(("(v / c0) / c1 --> (voc) v / (c0 * c1)\n")); + +return expr_gen.node_allocator_-> +template allocate_rc > >(v, c0 * c1); +} +// (v ^ c0) ^ c1 --> (voc) v ^ (c0 * c1) +else if ((details::e_pow == o0) && (details::e_pow == o1)) +{ +exprtk_debug(("(v ^ c0) ^ c1 --> (voc) v ^ (c0 * c1)\n")); + +return expr_gen.node_allocator_-> +template allocate_rc > >(v, c0 * c1); +} +} + +const bool synthesis_result = +synthesize_sf3ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1), v, c0, c1, result); + +if (synthesis_result) +return result; + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = reinterpret_cast(0); + +if (!expr_gen.valid_operator(o0,f0)) +return error_node(); +else if (!expr_gen.valid_operator(o1,f1)) +return error_node(); +else +return node_type::allocate(*(expr_gen.node_allocator_), v, c0, c1, f0, f1); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1) +{ +return details::build_string() +<< "(t" << expr_gen.to_str(o0) +<< "t)" << expr_gen.to_str(o1) +<< "t"; +} +}; + +struct synthesize_vococ_expression1 +{ +typedef typename vococ_t::type0 node_type; + +static inline expression_node_ptr process(expression_generator&, +const details::operator_type&, +expression_node_ptr (&)[2]) +{ +// (v) o0 (c0 o1 c1) - Not possible. +exprtk_debug(("(v) o0 (c0 o1 c1) - Not possible.\n")); +return error_node(); +} +}; + +struct synthesize_vovovov_expression0 +{ +typedef typename vovovov_t::type0 node_type; +typedef typename vovovov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// (v0 o0 v1) o1 (v2 o2 v3) +const details::vov_base_node* vov0 = static_cast*>(branch[0]); +const details::vov_base_node* vov1 = static_cast*>(branch[1]); +const Type& v0 = vov0->v0(); +const Type& v1 = vov0->v1(); +const Type& v2 = vov1->v0(); +const Type& v3 = vov1->v1(); +const details::operator_type o0 = vov0->operation(); +const details::operator_type o1 = operation; +const details::operator_type o2 = vov1->operation(); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +if (expr_gen.parser_->settings_.strength_reduction_enabled()) +{ +// (v0 / v1) * (v2 / v3) --> (vovovov) (v0 * v2) / (v1 * v3) +if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf4ext_expression:: +template compile(expr_gen, "(t*t)/(t*t)", v0, v2, v1, v3, result); + +exprtk_debug(("(v0 / v1) * (v2 / v3) --> (vovovov) (v0 * v2) / (v1 * v3)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 / v1) / (v2 / v3) --> (vovovov) (v0 * v3) / (v1 * v2) +else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf4ext_expression:: +template compile(expr_gen, "(t*t)/(t*t)", v0, v3, v1, v2, result); + +exprtk_debug(("(v0 / v1) / (v2 / v3) --> (vovovov) (v0 * v3) / (v1 * v2)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 + v1) / (v2 / v3) --> (vovovov) (v0 + v1) * (v3 / v2) +else if ((details::e_add == o0) && (details::e_div == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf4ext_expression:: +template compile(expr_gen, "(t+t)*(t/t)", v0, v1, v3, v2, result); + +exprtk_debug(("(v0 + v1) / (v2 / v3) --> (vovovov) (v0 + v1) * (v3 / v2)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 - v1) / (v2 / v3) --> (vovovov) (v0 + v1) * (v3 / v2) +else if ((details::e_sub == o0) && (details::e_div == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf4ext_expression:: +template compile(expr_gen, "(t-t)*(t/t)", v0, v1, v3, v2, result); + +exprtk_debug(("(v0 - v1) / (v2 / v3) --> (vovovov) (v0 - v1) * (v3 / v2)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 * v1) / (v2 / v3) --> (vovovov) ((v0 * v1) * v3) / v2 +else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf4ext_expression:: +template compile(expr_gen, "((t*t)*t)/t", v0, v1, v3, v2, result); + +exprtk_debug(("(v0 * v1) / (v2 / v3) --> (vovovov) ((v0 * v1) * v3) / v2\n")); + +return (synthesis_result) ? result : error_node(); +} +} + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); + +if (synthesis_result) +return result; + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = reinterpret_cast(0); +binary_functor_t f2 = reinterpret_cast(0); + +if (!expr_gen.valid_operator(o0,f0)) +return error_node(); +else if (!expr_gen.valid_operator(o1,f1)) +return error_node(); +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); +else +return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, v3, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "(t" << expr_gen.to_str(o0) +<< "t)" << expr_gen.to_str(o1) +<< "(t" << expr_gen.to_str(o2) +<< "t)"; +} +}; + +struct synthesize_vovovoc_expression0 +{ +typedef typename vovovoc_t::type0 node_type; +typedef typename vovovoc_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// (v0 o0 v1) o1 (v2 o2 c) +const details::vov_base_node* vov = static_cast*>(branch[0]); +const details::voc_base_node* voc = static_cast*>(branch[1]); +const Type& v0 = vov->v0(); +const Type& v1 = vov->v1(); +const Type& v2 = voc->v (); +const Type c = voc->c (); +const details::operator_type o0 = vov->operation(); +const details::operator_type o1 = operation; +const details::operator_type o2 = voc->operation(); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +if (expr_gen.parser_->settings_.strength_reduction_enabled()) +{ +// (v0 / v1) * (v2 / c) --> (vovovoc) (v0 * v2) / (v1 * c) +if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf4ext_expression:: +template compile(expr_gen, "(t*t)/(t*t)", v0, v2, v1, c, result); + +exprtk_debug(("(v0 / v1) * (v2 / c) --> (vovovoc) (v0 * v2) / (v1 * c)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 / v1) / (v2 / c) --> (vocovov) (v0 * c) / (v1 * v2) +if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf4ext_expression:: +template compile(expr_gen, "(t*t)/(t*t)", v0, c, v1, v2, result); + +exprtk_debug(("(v0 / v1) / (v2 / c) --> (vocovov) (v0 * c) / (v1 * v2)\n")); + +return (synthesis_result) ? result : error_node(); +} +} + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); + +if (synthesis_result) +return result; + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = reinterpret_cast(0); +binary_functor_t f2 = reinterpret_cast(0); + +if (!expr_gen.valid_operator(o0,f0)) +return error_node(); +else if (!expr_gen.valid_operator(o1,f1)) +return error_node(); +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); +else +return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "(t" << expr_gen.to_str(o0) +<< "t)" << expr_gen.to_str(o1) +<< "(t" << expr_gen.to_str(o2) +<< "t)"; +} +}; + +struct synthesize_vovocov_expression0 +{ +typedef typename vovocov_t::type0 node_type; +typedef typename vovocov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// (v0 o0 v1) o1 (c o2 v2) +const details::vov_base_node* vov = static_cast*>(branch[0]); +const details::cov_base_node* cov = static_cast*>(branch[1]); +const Type& v0 = vov->v0(); +const Type& v1 = vov->v1(); +const Type& v2 = cov->v (); +const Type c = cov->c (); +const details::operator_type o0 = vov->operation(); +const details::operator_type o1 = operation; +const details::operator_type o2 = cov->operation(); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +if (expr_gen.parser_->settings_.strength_reduction_enabled()) +{ +// (v0 / v1) * (c / v2) --> (vocovov) (v0 * c) / (v1 * v2) +if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf4ext_expression:: +template compile(expr_gen, "(t*t)/(t*t)", v0, c, v1, v2, result); + +exprtk_debug(("(v0 / v1) * (c / v2) --> (vocovov) (v0 * c) / (v1 * v2)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 / v1) / (c / v2) --> (vovovoc) (v0 * v2) / (v1 * c) +if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf4ext_expression:: +template compile(expr_gen, "(t*t)/(t*t)", v0, v2, v1, c, result); + +exprtk_debug(("(v0 / v1) / (c / v2) --> (vovovoc) (v0 * v2) / (v1 * c)\n")); + +return (synthesis_result) ? result : error_node(); +} +} + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); + +if (synthesis_result) +return result; + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = reinterpret_cast(0); +binary_functor_t f2 = reinterpret_cast(0); + +if (!expr_gen.valid_operator(o0,f0)) +return error_node(); +else if (!expr_gen.valid_operator(o1,f1)) +return error_node(); +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); +else +return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "(t" << expr_gen.to_str(o0) +<< "t)" << expr_gen.to_str(o1) +<< "(t" << expr_gen.to_str(o2) +<< "t)"; +} +}; + +struct synthesize_vocovov_expression0 +{ +typedef typename vocovov_t::type0 node_type; +typedef typename vocovov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// (v0 o0 c) o1 (v1 o2 v2) +const details::voc_base_node* voc = static_cast*>(branch[0]); +const details::vov_base_node* vov = static_cast*>(branch[1]); +const Type c = voc->c (); +const Type& v0 = voc->v (); +const Type& v1 = vov->v0(); +const Type& v2 = vov->v1(); +const details::operator_type o0 = voc->operation(); +const details::operator_type o1 = operation; +const details::operator_type o2 = vov->operation(); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +if (expr_gen.parser_->settings_.strength_reduction_enabled()) +{ +// (v0 / c) * (v1 / v2) --> (vovocov) (v0 * v1) / (c * v2) +if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf4ext_expression:: +template compile(expr_gen, "(t*t)/(t*t)", v0, v1, c, v2, result); + +exprtk_debug(("(v0 / c) * (v1 / v2) --> (vovocov) (v0 * v1) / (c * v2)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 / c) / (v1 / v2) --> (vovocov) (v0 * v2) / (c * v1) +if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf4ext_expression:: +template compile(expr_gen, "(t*t)/(t*t)", v0, v2, c, v1, result); + +exprtk_debug(("(v0 / c) / (v1 / v2) --> (vovocov) (v0 * v2) / (c * v1)\n")); + +return (synthesis_result) ? result : error_node(); +} +} + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); + +if (synthesis_result) +return result; + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = reinterpret_cast(0); +binary_functor_t f2 = reinterpret_cast(0); + +if (!expr_gen.valid_operator(o0,f0)) +return error_node(); +else if (!expr_gen.valid_operator(o1,f1)) +return error_node(); +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); +else +return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "(t" << expr_gen.to_str(o0) +<< "t)" << expr_gen.to_str(o1) +<< "(t" << expr_gen.to_str(o2) +<< "t)"; +} +}; + +struct synthesize_covovov_expression0 +{ +typedef typename covovov_t::type0 node_type; +typedef typename covovov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// (c o0 v0) o1 (v1 o2 v2) +const details::cov_base_node* cov = static_cast*>(branch[0]); +const details::vov_base_node* vov = static_cast*>(branch[1]); +const Type c = cov->c (); +const Type& v0 = cov->v (); +const Type& v1 = vov->v0(); +const Type& v2 = vov->v1(); +const details::operator_type o0 = cov->operation(); +const details::operator_type o1 = operation; +const details::operator_type o2 = vov->operation(); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +if (expr_gen.parser_->settings_.strength_reduction_enabled()) +{ +// (c / v0) * (v1 / v2) --> (covovov) (c * v1) / (v0 * v2) +if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf4ext_expression:: +template compile(expr_gen, "(t*t)/(t*t)", c, v1, v0, v2, result); + +exprtk_debug(("(c / v0) * (v1 / v2) --> (covovov) (c * v1) / (v0 * v2)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (c / v0) / (v1 / v2) --> (covovov) (c * v2) / (v0 * v1) +if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf4ext_expression:: +template compile(expr_gen, "(t*t)/(t*t)", c, v2, v0, v1, result); + +exprtk_debug(("(c / v0) / (v1 / v2) --> (covovov) (c * v2) / (v0 * v1)\n")); + +return (synthesis_result) ? result : error_node(); +} +} + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); + +if (synthesis_result) +return result; + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = reinterpret_cast(0); +binary_functor_t f2 = reinterpret_cast(0); + +if (!expr_gen.valid_operator(o0,f0)) +return error_node(); +else if (!expr_gen.valid_operator(o1,f1)) +return error_node(); +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); +else +return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "(t" << expr_gen.to_str(o0) +<< "t)" << expr_gen.to_str(o1) +<< "(t" << expr_gen.to_str(o2) +<< "t)"; +} +}; + +struct synthesize_covocov_expression0 +{ +typedef typename covocov_t::type0 node_type; +typedef typename covocov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// (c0 o0 v0) o1 (c1 o2 v1) +const details::cov_base_node* cov0 = static_cast*>(branch[0]); +const details::cov_base_node* cov1 = static_cast*>(branch[1]); +const Type c0 = cov0->c(); +const Type& v0 = cov0->v(); +const Type c1 = cov1->c(); +const Type& v1 = cov1->v(); +const details::operator_type o0 = cov0->operation(); +const details::operator_type o1 = operation; +const details::operator_type o2 = cov1->operation(); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +if (expr_gen.parser_->settings_.strength_reduction_enabled()) +{ +// (c0 + v0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1 +if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); + +exprtk_debug(("(c0 + v0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1\n")); + +return (synthesis_result) ? result : error_node(); +} +// (c0 + v0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1 +else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); + +exprtk_debug(("(c0 + v0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1\n")); + +return (synthesis_result) ? result : error_node(); +} +// (c0 - v0) - (c1 - v1) --> (covov) (c0 - c1) - v0 + v1 +else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t-t)+t", (c0 - c1), v0, v1, result); + +exprtk_debug(("(c0 - v0) - (c1 - v1) --> (covov) (c0 - c1) - v0 + v1\n")); + +return (synthesis_result) ? result : error_node(); +} +// (c0 * v0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1 +else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); + +exprtk_debug(("(c0 * v0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1\n")); + +return (synthesis_result) ? result : error_node(); +} +// (c0 * v0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 / v1) +else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); + +exprtk_debug(("(c0 * v0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 / v1)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (c0 / v0) * (c1 / v1) --> (covov) (c0 * c1) / (v0 * v1) +else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "t/(t*t)", (c0 * c1), v0, v1, result); + +exprtk_debug(("(c0 / v0) * (c1 / v1) --> (covov) (c0 * c1) / (v0 * v1)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (c0 / v0) / (c1 / v1) --> (covov) ((c0 / c1) * v1) / v0 +else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t*t)/t", (c0 / c1), v1, v0, result); + +exprtk_debug(("(c0 / v0) / (c1 / v1) --> (covov) ((c0 / c1) * v1) / v0\n")); + +return (synthesis_result) ? result : error_node(); +} +// (c0 * v0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1) +else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "t*(t*t)", (c0 / c1), v0, v1, result); + +exprtk_debug(("(c0 * v0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (c0 / v0) / (c1 * v1) --> (covov) (c0 / c1) / (v0 * v1) +else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "t/(t*t)", (c0 / c1), v0, v1, result); + +exprtk_debug(("(c0 / v0) / (c1 * v1) --> (covov) (c0 / c1) / (v0 * v1)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (c * v0) +/- (c * v1) --> (covov) c * (v0 +/- v1) +else if ( +(std::equal_to()(c0,c1)) && +(details::e_mul == o0) && +(details::e_mul == o2) && +( +(details::e_add == o1) || +(details::e_sub == o1) +) +) +{ +std::string specfunc; + +switch (o1) +{ +case details::e_add : specfunc = "t*(t+t)"; break; +case details::e_sub : specfunc = "t*(t-t)"; break; +default : return error_node(); +} + +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, specfunc, c0, v0, v1, result); + +exprtk_debug(("(c * v0) +/- (c * v1) --> (covov) c * (v0 +/- v1)\n")); + +return (synthesis_result) ? result : error_node(); +} +} + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); + +if (synthesis_result) +return result; + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = reinterpret_cast(0); +binary_functor_t f2 = reinterpret_cast(0); + +if (!expr_gen.valid_operator(o0,f0)) +return error_node(); +else if (!expr_gen.valid_operator(o1,f1)) +return error_node(); +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); +else +return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "(t" << expr_gen.to_str(o0) +<< "t)" << expr_gen.to_str(o1) +<< "(t" << expr_gen.to_str(o2) +<< "t)"; +} +}; + +struct synthesize_vocovoc_expression0 +{ +typedef typename vocovoc_t::type0 node_type; +typedef typename vocovoc_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// (v0 o0 c0) o1 (v1 o2 c1) +const details::voc_base_node* voc0 = static_cast*>(branch[0]); +const details::voc_base_node* voc1 = static_cast*>(branch[1]); +const Type c0 = voc0->c(); +const Type& v0 = voc0->v(); +const Type c1 = voc1->c(); +const Type& v1 = voc1->v(); +const details::operator_type o0 = voc0->operation(); +const details::operator_type o1 = operation; +const details::operator_type o2 = voc1->operation(); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +if (expr_gen.parser_->settings_.strength_reduction_enabled()) +{ +// (v0 + c0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1 +if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); + +exprtk_debug(("(v0 + c0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 + c0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1 +else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); + +exprtk_debug(("(v0 + c0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 - c0) - (v1 - c1) --> (covov) (c1 - c0) + v0 - v1 +else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t+t)-t", (c1 - c0), v0, v1, result); + +exprtk_debug(("(v0 - c0) - (v1 - c1) --> (covov) (c1 - c0) + v0 - v1\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 * c0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1 +else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); + +exprtk_debug(("(v0 * c0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 * c0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1) +else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); + +exprtk_debug(("(v0 * c0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 / c0) * (v1 / c1) --> (covov) (1 / (c0 * c1)) * v0 * v1 +else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t*t)*t", Type(1) / (c0 * c1), v0, v1, result); + +exprtk_debug(("(v0 / c0) * (v1 / c1) --> (covov) (1 / (c0 * c1)) * v0 * v1\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 / c0) / (v1 / c1) --> (covov) ((c1 / c0) * v0) / v1 +else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t*t)/t", (c1 / c0), v0, v1, result); + +exprtk_debug(("(v0 / c0) / (v1 / c1) --> (covov) ((c1 / c0) * v0) / v1\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 * c0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1) +else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "t*(t/t)", (c0 * c1), v0, v1, result); + +exprtk_debug(("(v0 * c0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 / c0) / (v1 * c1) --> (covov) (1 / (c0 * c1)) * v0 / v1 +else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "t*(t/t)", Type(1) / (c0 * c1), v0, v1, result); + +exprtk_debug(("(v0 / c0) / (v1 * c1) --> (covov) (1 / (c0 * c1)) * v0 / v1\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 / c0) * (v1 + c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 + c1) +else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_add == o2)) +{ +const bool synthesis_result = +synthesize_sf4ext_expression:: +template compile(expr_gen, "(t*t)*(t+t)", v0, T(1) / c0, v1, c1, result); + +exprtk_debug(("(v0 / c0) * (v1 + c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 + c1)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 / c0) * (v1 - c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 - c1) +else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_sub == o2)) +{ +const bool synthesis_result = +synthesize_sf4ext_expression:: +template compile(expr_gen, "(t*t)*(t-t)", v0, T(1) / c0, v1, c1, result); + +exprtk_debug(("(v0 / c0) * (v1 - c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 - c1)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 * c) +/- (v1 * c) --> (covov) c * (v0 +/- v1) +else if ( +(std::equal_to()(c0,c1)) && +(details::e_mul == o0) && +(details::e_mul == o2) && +( +(details::e_add == o1) || +(details::e_sub == o1) +) +) +{ +std::string specfunc; + +switch (o1) +{ +case details::e_add : specfunc = "t*(t+t)"; break; +case details::e_sub : specfunc = "t*(t-t)"; break; +default : return error_node(); +} + +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, specfunc, c0, v0, v1, result); + +exprtk_debug(("(v0 * c) +/- (v1 * c) --> (covov) c * (v0 +/- v1)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 / c) +/- (v1 / c) --> (vovoc) (v0 +/- v1) / c +else if ( +(std::equal_to()(c0,c1)) && +(details::e_div == o0) && +(details::e_div == o2) && +( +(details::e_add == o1) || +(details::e_sub == o1) +) +) +{ +std::string specfunc; + +switch (o1) +{ +case details::e_add : specfunc = "(t+t)/t"; break; +case details::e_sub : specfunc = "(t-t)/t"; break; +default : return error_node(); +} + +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, specfunc, v0, v1, c0, result); + +exprtk_debug(("(v0 / c) +/- (v1 / c) --> (vovoc) (v0 +/- v1) / c\n")); + +return (synthesis_result) ? result : error_node(); +} +} + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); + +if (synthesis_result) +return result; + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = reinterpret_cast(0); +binary_functor_t f2 = reinterpret_cast(0); + +if (!expr_gen.valid_operator(o0,f0)) +return error_node(); +else if (!expr_gen.valid_operator(o1,f1)) +return error_node(); +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); +else +return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "(t" << expr_gen.to_str(o0) +<< "t)" << expr_gen.to_str(o1) +<< "(t" << expr_gen.to_str(o2) +<< "t)"; +} +}; + +struct synthesize_covovoc_expression0 +{ +typedef typename covovoc_t::type0 node_type; +typedef typename covovoc_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// (c0 o0 v0) o1 (v1 o2 c1) +const details::cov_base_node* cov = static_cast*>(branch[0]); +const details::voc_base_node* voc = static_cast*>(branch[1]); +const Type c0 = cov->c(); +const Type& v0 = cov->v(); +const Type c1 = voc->c(); +const Type& v1 = voc->v(); +const details::operator_type o0 = cov->operation(); +const details::operator_type o1 = operation; +const details::operator_type o2 = voc->operation(); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +if (expr_gen.parser_->settings_.strength_reduction_enabled()) +{ +// (c0 + v0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1 +if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); + +exprtk_debug(("(c0 + v0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1\n")); + +return (synthesis_result) ? result : error_node(); +} +// (c0 + v0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1 +else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); + +exprtk_debug(("(c0 + v0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1\n")); + +return (synthesis_result) ? result : error_node(); +} +// (c0 - v0) - (v1 - c1) --> (covov) (c0 + c1) - v0 - v1 +else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "t-(t+t)", (c0 + c1), v0, v1, result); + +exprtk_debug(("(c0 - v0) - (v1 - c1) --> (covov) (c0 + c1) - v0 - v1\n")); + +return (synthesis_result) ? result : error_node(); +} +// (c0 * v0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1 +else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); + +exprtk_debug(("(c0 * v0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1\n")); + +return (synthesis_result) ? result : error_node(); +} +// (c0 * v0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1) +else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); + +exprtk_debug(("(c0 * v0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (c0 / v0) * (v1 / c1) --> (covov) (c0 / c1) * (v1 / v0) +else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "t*(t/t)", (c0 / c1), v1, v0, result); + +exprtk_debug(("(c0 / v0) * (v1 / c1) --> (covov) (c0 / c1) * (v1 / v0)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (c0 / v0) / (v1 / c1) --> (covov) (c0 * c1) / (v0 * v1) +else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "t/(t*t)", (c0 * c1), v0, v1, result); + +exprtk_debug(("(c0 / v0) / (v1 / c1) --> (covov) (c0 * c1) / (v0 * v1)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (c0 * v0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1) +else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t*t)/t", (c0 * c1), v0, v1, result); + +exprtk_debug(("(c0 * v0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (c0 / v0) / (v1 * c1) --> (covov) (c0 / c1) / (v0 * v1) +else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "t/(t*t)", (c0 / c1), v0, v1, result); + +exprtk_debug(("(c0 / v0) / (v1 * c1) --> (covov) (c0 / c1) / (v0 * v1)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (c * v0) +/- (v1 * c) --> (covov) c * (v0 +/- v1) +else if ( +(std::equal_to()(c0,c1)) && +(details::e_mul == o0) && +(details::e_mul == o2) && +( +(details::e_add == o1) || +(details::e_sub == o1) +) +) +{ +std::string specfunc; + +switch (o1) +{ +case details::e_add : specfunc = "t*(t+t)"; break; +case details::e_sub : specfunc = "t*(t-t)"; break; +default : return error_node(); +} + +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, specfunc, c0, v0, v1, result); + +exprtk_debug(("(c * v0) +/- (v1 * c) --> (covov) c * (v0 +/- v1)\n")); + +return (synthesis_result) ? result : error_node(); +} +} + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); + +if (synthesis_result) +return result; + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = reinterpret_cast(0); +binary_functor_t f2 = reinterpret_cast(0); + +if (!expr_gen.valid_operator(o0,f0)) +return error_node(); +else if (!expr_gen.valid_operator(o1,f1)) +return error_node(); +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); +else +return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "(t" << expr_gen.to_str(o0) +<< "t)" << expr_gen.to_str(o1) +<< "(t" << expr_gen.to_str(o2) +<< "t)"; +} +}; + +struct synthesize_vococov_expression0 +{ +typedef typename vococov_t::type0 node_type; +typedef typename vococov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// (v0 o0 c0) o1 (c1 o2 v1) +const details::voc_base_node* voc = static_cast*>(branch[0]); +const details::cov_base_node* cov = static_cast*>(branch[1]); +const Type c0 = voc->c(); +const Type& v0 = voc->v(); +const Type c1 = cov->c(); +const Type& v1 = cov->v(); +const details::operator_type o0 = voc->operation(); +const details::operator_type o1 = operation; +const details::operator_type o2 = cov->operation(); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +if (expr_gen.parser_->settings_.strength_reduction_enabled()) +{ +// (v0 + c0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1 +if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); + +exprtk_debug(("(v0 + c0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 + c0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1 +else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); + +exprtk_debug(("(v0 + c0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 - c0) - (c1 - v1) --> (vovoc) v0 + v1 - (c1 + c0) +else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t+t)-t", v0, v1, (c1 + c0), result); + +exprtk_debug(("(v0 - c0) - (c1 - v1) --> (vovoc) v0 + v1 - (c1 + c0)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 * c0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1 +else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); + +exprtk_debug(("(v0 * c0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 * c0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 * v1) +else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); + +exprtk_debug(("(v0 * c0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 / c0) * (c1 / v1) --> (covov) (c1 / c0) * (v0 / v1) +else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t*t)/t", (c1 / c0), v0, v1, result); + +exprtk_debug(("(v0 / c0) * (c1 / v1) --> (covov) (c1 / c0) * (v0 / v1)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 * c0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1) +else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t*t)*t", (c0 / c1), v0, v1, result); + +exprtk_debug(("(v0 * c0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 / c0) / (c1 * v1) --> (covov) (1 / (c0 * c1)) * (v0 / v1) +else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t*t)/t", Type(1) / (c0 * c1), v0, v1, result); + +exprtk_debug(("(v0 / c0) / (c1 * v1) --> (covov) (1 / (c0 * c1)) * (v0 / v1)\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 / c0) / (c1 / v1) --> (vovoc) (v0 * v1) * (1 / (c0 * c1)) +else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) +{ +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, "(t*t)*t", v0, v1, Type(1) / (c0 * c1), result); + +exprtk_debug(("(v0 / c0) / (c1 / v1) --> (vovoc) (v0 * v1) * (1 / (c0 * c1))\n")); + +return (synthesis_result) ? result : error_node(); +} +// (v0 * c) +/- (c * v1) --> (covov) c * (v0 +/- v1) +else if ( +(std::equal_to()(c0,c1)) && +(details::e_mul == o0) && +(details::e_mul == o2) && +( +(details::e_add == o1) || (details::e_sub == o1) +) +) +{ +std::string specfunc; + +switch (o1) +{ +case details::e_add : specfunc = "t*(t+t)"; break; +case details::e_sub : specfunc = "t*(t-t)"; break; +default : return error_node(); +} + +const bool synthesis_result = +synthesize_sf3ext_expression:: +template compile(expr_gen, specfunc, c0, v0, v1, result); + +exprtk_debug(("(v0 * c) +/- (c * v1) --> (covov) c * (v0 +/- v1)\n")); + +return (synthesis_result) ? result : error_node(); +} +} + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, c0, c1, v1, result); + +if (synthesis_result) +return result; + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = reinterpret_cast(0); +binary_functor_t f2 = reinterpret_cast(0); + +if (!expr_gen.valid_operator(o0,f0)) +return error_node(); +else if (!expr_gen.valid_operator(o1,f1)) +return error_node(); +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); +else +return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, c1, v1, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "(t" << expr_gen.to_str(o0) +<< "t)" << expr_gen.to_str(o1) +<< "(t" << expr_gen.to_str(o2) +<< "t)"; +} +}; + +struct synthesize_vovovov_expression1 +{ +typedef typename vovovov_t::type1 node_type; +typedef typename vovovov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// v0 o0 (v1 o1 (v2 o2 v3)) +typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; + +const lcl_vovov_t* vovov = static_cast(branch[1]); +const Type& v0 = static_cast*>(branch[0])->ref(); +const Type& v1 = vovov->t0(); +const Type& v2 = vovov->t1(); +const Type& v3 = vovov->t2(); +const details::operator_type o0 = operation; +const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); +const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = vovov->f0(); +binary_functor_t f2 = vovov->f1(); + +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen,id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o0,f0)) +return error_node(); + +exprtk_debug(("v0 o0 (v1 o1 (v2 o2 v3))\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, v3, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "t" << expr_gen.to_str(o0) +<< "(t" << expr_gen.to_str(o1) +<< "(t" << expr_gen.to_str(o2) +<< "t))"; +} +}; + +struct synthesize_vovovoc_expression1 +{ +typedef typename vovovoc_t::type1 node_type; +typedef typename vovovoc_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// v0 o0 (v1 o1 (v2 o2 c)) +typedef typename synthesize_vovoc_expression1::node_type lcl_vovoc_t; + +const lcl_vovoc_t* vovoc = static_cast(branch[1]); +const Type& v0 = static_cast*>(branch[0])->ref(); +const Type& v1 = vovoc->t0(); +const Type& v2 = vovoc->t1(); +const Type c = vovoc->t2(); +const details::operator_type o0 = operation; +const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); +const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = vovoc->f0(); +binary_functor_t f2 = vovoc->f1(); + +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o0,f0)) +return error_node(); + +exprtk_debug(("v0 o0 (v1 o1 (v2 o2 c))\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "t" << expr_gen.to_str(o0) +<< "(t" << expr_gen.to_str(o1) +<< "(t" << expr_gen.to_str(o2) +<< "t))"; +} +}; + +struct synthesize_vovocov_expression1 +{ +typedef typename vovocov_t::type1 node_type; +typedef typename vovocov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// v0 o0 (v1 o1 (c o2 v2)) +typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; + +const lcl_vocov_t* vocov = static_cast(branch[1]); +const Type& v0 = static_cast*>(branch[0])->ref(); +const Type& v1 = vocov->t0(); +const Type c = vocov->t1(); +const Type& v2 = vocov->t2(); +const details::operator_type o0 = operation; +const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); +const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = vocov->f0(); +binary_functor_t f2 = vocov->f1(); + +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); + +if (synthesis_result) +return result; +if (!expr_gen.valid_operator(o0,f0)) +return error_node(); + +exprtk_debug(("v0 o0 (v1 o1 (c o2 v2))\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "t" << expr_gen.to_str(o0) +<< "(t" << expr_gen.to_str(o1) +<< "(t" << expr_gen.to_str(o2) +<< "t))"; +} +}; + +struct synthesize_vocovov_expression1 +{ +typedef typename vocovov_t::type1 node_type; +typedef typename vocovov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// v0 o0 (c o1 (v1 o2 v2)) +typedef typename synthesize_covov_expression1::node_type lcl_covov_t; + +const lcl_covov_t* covov = static_cast(branch[1]); +const Type& v0 = static_cast*>(branch[0])->ref(); +const Type c = covov->t0(); +const Type& v1 = covov->t1(); +const Type& v2 = covov->t2(); +const details::operator_type o0 = operation; +const details::operator_type o1 = expr_gen.get_operator(covov->f0()); +const details::operator_type o2 = expr_gen.get_operator(covov->f1()); + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = covov->f0(); +binary_functor_t f2 = covov->f1(); + +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o0,f0)) +return error_node(); + +exprtk_debug(("v0 o0 (c o1 (v1 o2 v2))\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "t" << expr_gen.to_str(o0) +<< "(t" << expr_gen.to_str(o1) +<< "(t" << expr_gen.to_str(o2) +<< "t))"; +} +}; + +struct synthesize_covovov_expression1 +{ +typedef typename covovov_t::type1 node_type; +typedef typename covovov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// c o0 (v0 o1 (v1 o2 v2)) +typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; + +const lcl_vovov_t* vovov = static_cast(branch[1]); +const Type c = static_cast*>(branch[0])->value(); +const Type& v0 = vovov->t0(); +const Type& v1 = vovov->t1(); +const Type& v2 = vovov->t2(); +const details::operator_type o0 = operation; +const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); +const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = vovov->f0(); +binary_functor_t f2 = vovov->f1(); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); + +if (synthesis_result) +return result; +if (!expr_gen.valid_operator(o0,f0)) +return error_node(); + +exprtk_debug(("c o0 (v0 o1 (v1 o2 v2))\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "t" << expr_gen.to_str(o0) +<< "(t" << expr_gen.to_str(o1) +<< "(t" << expr_gen.to_str(o2) +<< "t))"; +} +}; + +struct synthesize_covocov_expression1 +{ +typedef typename covocov_t::type1 node_type; +typedef typename covocov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// c0 o0 (v0 o1 (c1 o2 v1)) +typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; + +const lcl_vocov_t* vocov = static_cast(branch[1]); +const Type c0 = static_cast*>(branch[0])->value(); +const Type& v0 = vocov->t0(); +const Type c1 = vocov->t1(); +const Type& v1 = vocov->t2(); +const details::operator_type o0 = operation; +const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); +const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = vocov->f0(); +binary_functor_t f2 = vocov->f1(); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o0,f0)) +return error_node(); + +exprtk_debug(("c0 o0 (v0 o1 (c1 o2 v1))\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "t" << expr_gen.to_str(o0) +<< "(t" << expr_gen.to_str(o1) +<< "(t" << expr_gen.to_str(o2) +<< "t))"; +} +}; + +struct synthesize_vocovoc_expression1 +{ +typedef typename vocovoc_t::type1 node_type; +typedef typename vocovoc_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// v0 o0 (c0 o1 (v1 o2 c2)) +typedef typename synthesize_covoc_expression1::node_type lcl_covoc_t; + +const lcl_covoc_t* covoc = static_cast(branch[1]); +const Type& v0 = static_cast*>(branch[0])->ref(); +const Type c0 = covoc->t0(); +const Type& v1 = covoc->t1(); +const Type c1 = covoc->t2(); +const details::operator_type o0 = operation; +const details::operator_type o1 = expr_gen.get_operator(covoc->f0()); +const details::operator_type o2 = expr_gen.get_operator(covoc->f1()); + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = covoc->f0(); +binary_functor_t f2 = covoc->f1(); + +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o0,f0)) +return error_node(); + +exprtk_debug(("v0 o0 (c0 o1 (v1 o2 c2))\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "t" << expr_gen.to_str(o0) +<< "(t" << expr_gen.to_str(o1) +<< "(t" << expr_gen.to_str(o2) +<< "t))"; +} +}; + +struct synthesize_covovoc_expression1 +{ +typedef typename covovoc_t::type1 node_type; +typedef typename covovoc_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// c0 o0 (v0 o1 (v1 o2 c1)) +typedef typename synthesize_vovoc_expression1::node_type lcl_vovoc_t; + +const lcl_vovoc_t* vovoc = static_cast(branch[1]); +const Type c0 = static_cast*>(branch[0])->value(); +const Type& v0 = vovoc->t0(); +const Type& v1 = vovoc->t1(); +const Type c1 = vovoc->t2(); +const details::operator_type o0 = operation; +const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); +const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = vovoc->f0(); +binary_functor_t f2 = vovoc->f1(); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o0,f0)) +return error_node(); + +exprtk_debug(("c0 o0 (v0 o1 (v1 o2 c1))\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "t" << expr_gen.to_str(o0) +<< "(t" << expr_gen.to_str(o1) +<< "(t" << expr_gen.to_str(o2) +<< "t))"; +} +}; + +struct synthesize_vococov_expression1 +{ +typedef typename vococov_t::type1 node_type; +typedef typename vococov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// v0 o0 (c0 o1 (c1 o2 v1)) +typedef typename synthesize_cocov_expression1::node_type lcl_cocov_t; + +const lcl_cocov_t* cocov = static_cast(branch[1]); +const Type& v0 = static_cast*>(branch[0])->ref(); +const Type c0 = cocov->t0(); +const Type c1 = cocov->t1(); +const Type& v1 = cocov->t2(); +const details::operator_type o0 = operation; +const details::operator_type o1 = expr_gen.get_operator(cocov->f0()); +const details::operator_type o2 = expr_gen.get_operator(cocov->f1()); + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = cocov->f0(); +binary_functor_t f2 = cocov->f1(); + +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, c0, c1, v1, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o0,f0)) +return error_node(); + +exprtk_debug(("v0 o0 (c0 o1 (c1 o2 v1))\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, c1, v1, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "t" << expr_gen.to_str(o0) +<< "(t" << expr_gen.to_str(o1) +<< "(t" << expr_gen.to_str(o2) +<< "t))"; +} +}; + +struct synthesize_vovovov_expression2 +{ +typedef typename vovovov_t::type2 node_type; +typedef typename vovovov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// v0 o0 ((v1 o1 v2) o2 v3) +typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; + +const lcl_vovov_t* vovov = static_cast(branch[1]); +const Type& v0 = static_cast*>(branch[0])->ref(); +const Type& v1 = vovov->t0(); +const Type& v2 = vovov->t1(); +const Type& v3 = vovov->t2(); +const details::operator_type o0 = operation; +const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); +const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = vovov->f0(); +binary_functor_t f2 = vovov->f1(); + +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o0,f0)) +return error_node(); + +exprtk_debug(("v0 o0 ((v1 o1 v2) o2 v3)\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, v3, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "t" << expr_gen.to_str(o0) +<< "((t" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t)"; +} +}; + +struct synthesize_vovovoc_expression2 +{ +typedef typename vovovoc_t::type2 node_type; +typedef typename vovovoc_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// v0 o0 ((v1 o1 v2) o2 c) +typedef typename synthesize_vovoc_expression0::node_type lcl_vovoc_t; + +const lcl_vovoc_t* vovoc = static_cast(branch[1]); +const Type& v0 = static_cast*>(branch[0])->ref(); +const Type& v1 = vovoc->t0(); +const Type& v2 = vovoc->t1(); +const Type c = vovoc->t2(); +const details::operator_type o0 = operation; +const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); +const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = vovoc->f0(); +binary_functor_t f2 = vovoc->f1(); + +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o0,f0)) +return error_node(); + +exprtk_debug(("v0 o0 ((v1 o1 v2) o2 c)\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "t" << expr_gen.to_str(o0) +<< "((t" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t)"; +} +}; + +struct synthesize_vovocov_expression2 +{ +typedef typename vovocov_t::type2 node_type; +typedef typename vovocov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// v0 o0 ((v1 o1 c) o2 v2) +typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; + +const lcl_vocov_t* vocov = static_cast(branch[1]); +const Type& v0 = static_cast*>(branch[0])->ref(); +const Type& v1 = vocov->t0(); +const Type c = vocov->t1(); +const Type& v2 = vocov->t2(); +const details::operator_type o0 = operation; +const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); +const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = vocov->f0(); +binary_functor_t f2 = vocov->f1(); + +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o0,f0)) +return error_node(); + +exprtk_debug(("v0 o0 ((v1 o1 c) o2 v2)\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "t" << expr_gen.to_str(o0) +<< "((t" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t)"; +} +}; + +struct synthesize_vocovov_expression2 +{ +typedef typename vocovov_t::type2 node_type; +typedef typename vocovov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// v0 o0 ((c o1 v1) o2 v2) +typedef typename synthesize_covov_expression0::node_type lcl_covov_t; + +const lcl_covov_t* covov = static_cast(branch[1]); +const Type& v0 = static_cast*>(branch[0])->ref(); +const Type c = covov->t0(); +const Type& v1 = covov->t1(); +const Type& v2 = covov->t2(); +const details::operator_type o0 = operation; +const details::operator_type o1 = expr_gen.get_operator(covov->f0()); +const details::operator_type o2 = expr_gen.get_operator(covov->f1()); + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = covov->f0(); +binary_functor_t f2 = covov->f1(); + +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o0,f0)) +return error_node(); + +exprtk_debug(("v0 o0 ((c o1 v1) o2 v2)\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "t" << expr_gen.to_str(o0) +<< "((t" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t)"; +} +}; + +struct synthesize_covovov_expression2 +{ +typedef typename covovov_t::type2 node_type; +typedef typename covovov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// c o0 ((v1 o1 v2) o2 v3) +typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; + +const lcl_vovov_t* vovov = static_cast(branch[1]); +const Type c = static_cast*>(branch[0])->value(); +const Type& v0 = vovov->t0(); +const Type& v1 = vovov->t1(); +const Type& v2 = vovov->t2(); +const details::operator_type o0 = operation; +const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); +const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = vovov->f0(); +binary_functor_t f2 = vovov->f1(); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o0,f0)) +return error_node(); + +exprtk_debug(("c o0 ((v1 o1 v2) o2 v3)\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "t" << expr_gen.to_str(o0) +<< "((t" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t)"; +} +}; + +struct synthesize_covocov_expression2 +{ +typedef typename covocov_t::type2 node_type; +typedef typename covocov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// c0 o0 ((v0 o1 c1) o2 v1) +typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; + +const lcl_vocov_t* vocov = static_cast(branch[1]); +const Type c0 = static_cast*>(branch[0])->value(); +const Type& v0 = vocov->t0(); +const Type c1 = vocov->t1(); +const Type& v1 = vocov->t2(); +const details::operator_type o0 = operation; +const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); +const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = vocov->f0(); +binary_functor_t f2 = vocov->f1(); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o0,f0)) +return error_node(); + +exprtk_debug(("c0 o0 ((v0 o1 c1) o2 v1)\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "t" << expr_gen.to_str(o0) +<< "((t" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t)"; +} +}; + +struct synthesize_vocovoc_expression2 +{ +typedef typename vocovoc_t::type2 node_type; +typedef typename vocovoc_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// v0 o0 ((c0 o1 v1) o2 c1) +typedef typename synthesize_covoc_expression0::node_type lcl_covoc_t; + +const lcl_covoc_t* covoc = static_cast(branch[1]); +const Type& v0 = static_cast*>(branch[0])->ref(); +const Type c0 = covoc->t0(); +const Type& v1 = covoc->t1(); +const Type c1 = covoc->t2(); +const details::operator_type o0 = operation; +const details::operator_type o1 = expr_gen.get_operator(covoc->f0()); +const details::operator_type o2 = expr_gen.get_operator(covoc->f1()); + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = covoc->f0(); +binary_functor_t f2 = covoc->f1(); + +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o0,f0)) +return error_node(); + +exprtk_debug(("v0 o0 ((c0 o1 v1) o2 c1)\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "t" << expr_gen.to_str(o0) +<< "((t" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t)"; +} +}; + +struct synthesize_covovoc_expression2 +{ +typedef typename covovoc_t::type2 node_type; +typedef typename covovoc_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// c0 o0 ((v0 o1 v1) o2 c1) +typedef typename synthesize_vovoc_expression0::node_type lcl_vovoc_t; + +const lcl_vovoc_t* vovoc = static_cast(branch[1]); +const Type c0 = static_cast*>(branch[0])->value(); +const Type& v0 = vovoc->t0(); +const Type& v1 = vovoc->t1(); +const Type c1 = vovoc->t2(); +const details::operator_type o0 = operation; +const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); +const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); + +binary_functor_t f0 = reinterpret_cast(0); +binary_functor_t f1 = vovoc->f0(); +binary_functor_t f2 = vovoc->f1(); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o0,f0)) +return error_node(); + +exprtk_debug(("c0 o0 ((v0 o1 v1) o2 c1)\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "t" << expr_gen.to_str(o0) +<< "((t" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t)"; +} +}; + +struct synthesize_vococov_expression2 +{ +typedef typename vococov_t::type2 node_type; +static inline expression_node_ptr process(expression_generator&, +const details::operator_type&, +expression_node_ptr (&)[2]) +{ +// v0 o0 ((c0 o1 c1) o2 v1) - Not possible +exprtk_debug(("v0 o0 ((c0 o1 c1) o2 v1) - Not possible\n")); +return error_node(); +} + +static inline std::string id(expression_generator&, +const details::operator_type, +const details::operator_type, +const details::operator_type) +{ +return "INVALID"; +} +}; + +struct synthesize_vovovov_expression3 +{ +typedef typename vovovov_t::type3 node_type; +typedef typename vovovov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// ((v0 o0 v1) o1 v2) o2 v3 +typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; + +const lcl_vovov_t* vovov = static_cast(branch[0]); +const Type& v0 = vovov->t0(); +const Type& v1 = vovov->t1(); +const Type& v2 = vovov->t2(); +const Type& v3 = static_cast*>(branch[1])->ref(); +const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); +const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); +const details::operator_type o2 = operation; + +binary_functor_t f0 = vovov->f0(); +binary_functor_t f1 = vovov->f1(); +binary_functor_t f2 = reinterpret_cast(0); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); + +exprtk_debug(("((v0 o0 v1) o1 v2) o2 v3\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, v3, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "((t" << expr_gen.to_str(o0) +<< "t)" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t"; +} +}; + +struct synthesize_vovovoc_expression3 +{ +typedef typename vovovoc_t::type3 node_type; +typedef typename vovovoc_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// ((v0 o0 v1) o1 v2) o2 c +typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; + +const lcl_vovov_t* vovov = static_cast(branch[0]); +const Type& v0 = vovov->t0(); +const Type& v1 = vovov->t1(); +const Type& v2 = vovov->t2(); +const Type c = static_cast*>(branch[1])->value(); +const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); +const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); +const details::operator_type o2 = operation; + +binary_functor_t f0 = vovov->f0(); +binary_functor_t f1 = vovov->f1(); +binary_functor_t f2 = reinterpret_cast(0); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); + +exprtk_debug(("((v0 o0 v1) o1 v2) o2 c\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "((t" << expr_gen.to_str(o0) +<< "t)" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t"; +} +}; + +struct synthesize_vovocov_expression3 +{ +typedef typename vovocov_t::type3 node_type; +typedef typename vovocov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// ((v0 o0 v1) o1 c) o2 v2 +typedef typename synthesize_vovoc_expression0::node_type lcl_vovoc_t; + +const lcl_vovoc_t* vovoc = static_cast(branch[0]); +const Type& v0 = vovoc->t0(); +const Type& v1 = vovoc->t1(); +const Type c = vovoc->t2(); +const Type& v2 = static_cast*>(branch[1])->ref(); +const details::operator_type o0 = expr_gen.get_operator(vovoc->f0()); +const details::operator_type o1 = expr_gen.get_operator(vovoc->f1()); +const details::operator_type o2 = operation; + +binary_functor_t f0 = vovoc->f0(); +binary_functor_t f1 = vovoc->f1(); +binary_functor_t f2 = reinterpret_cast(0); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); + +exprtk_debug(("((v0 o0 v1) o1 c) o2 v2\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "((t" << expr_gen.to_str(o0) +<< "t)" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t"; +} +}; + +struct synthesize_vocovov_expression3 +{ +typedef typename vocovov_t::type3 node_type; +typedef typename vocovov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// ((v0 o0 c) o1 v1) o2 v2 +typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; + +const lcl_vocov_t* vocov = static_cast(branch[0]); +const Type& v0 = vocov->t0(); +const Type c = vocov->t1(); +const Type& v1 = vocov->t2(); +const Type& v2 = static_cast*>(branch[1])->ref(); +const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); +const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); +const details::operator_type o2 = operation; + +binary_functor_t f0 = vocov->f0(); +binary_functor_t f1 = vocov->f1(); +binary_functor_t f2 = reinterpret_cast(0); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); + +exprtk_debug(("((v0 o0 c) o1 v1) o2 v2\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "((t" << expr_gen.to_str(o0) +<< "t)" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t"; +} +}; + +struct synthesize_covovov_expression3 +{ +typedef typename covovov_t::type3 node_type; +typedef typename covovov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// ((c o0 v0) o1 v1) o2 v2 +typedef typename synthesize_covov_expression0::node_type lcl_covov_t; + +const lcl_covov_t* covov = static_cast(branch[0]); +const Type c = covov->t0(); +const Type& v0 = covov->t1(); +const Type& v1 = covov->t2(); +const Type& v2 = static_cast*>(branch[1])->ref(); +const details::operator_type o0 = expr_gen.get_operator(covov->f0()); +const details::operator_type o1 = expr_gen.get_operator(covov->f1()); +const details::operator_type o2 = operation; + +binary_functor_t f0 = covov->f0(); +binary_functor_t f1 = covov->f1(); +binary_functor_t f2 = reinterpret_cast(0); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); + +exprtk_debug(("((c o0 v0) o1 v1) o2 v2\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "((t" << expr_gen.to_str(o0) +<< "t)" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t"; +} +}; + +struct synthesize_covocov_expression3 +{ +typedef typename covocov_t::type3 node_type; +typedef typename covocov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// ((c0 o0 v0) o1 c1) o2 v1 +typedef typename synthesize_covoc_expression0::node_type lcl_covoc_t; + +const lcl_covoc_t* covoc = static_cast(branch[0]); +const Type c0 = covoc->t0(); +const Type& v0 = covoc->t1(); +const Type c1 = covoc->t2(); +const Type& v1 = static_cast*>(branch[1])->ref(); +const details::operator_type o0 = expr_gen.get_operator(covoc->f0()); +const details::operator_type o1 = expr_gen.get_operator(covoc->f1()); +const details::operator_type o2 = operation; + +binary_functor_t f0 = covoc->f0(); +binary_functor_t f1 = covoc->f1(); +binary_functor_t f2 = reinterpret_cast(0); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); + +exprtk_debug(("((c0 o0 v0) o1 c1) o2 v1\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "((t" << expr_gen.to_str(o0) +<< "t)" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t"; +} +}; + +struct synthesize_vocovoc_expression3 +{ +typedef typename vocovoc_t::type3 node_type; +typedef typename vocovoc_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// ((v0 o0 c0) o1 v1) o2 c1 +typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; + +const lcl_vocov_t* vocov = static_cast(branch[0]); +const Type& v0 = vocov->t0(); +const Type c0 = vocov->t1(); +const Type& v1 = vocov->t2(); +const Type c1 = static_cast*>(branch[1])->value(); +const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); +const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); +const details::operator_type o2 = operation; + +binary_functor_t f0 = vocov->f0(); +binary_functor_t f1 = vocov->f1(); +binary_functor_t f2 = reinterpret_cast(0); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); + +exprtk_debug(("((v0 o0 c0) o1 v1) o2 c1\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "((t" << expr_gen.to_str(o0) +<< "t)" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t"; +} +}; + +struct synthesize_covovoc_expression3 +{ +typedef typename covovoc_t::type3 node_type; +typedef typename covovoc_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// ((c0 o0 v0) o1 v1) o2 c1 +typedef typename synthesize_covov_expression0::node_type lcl_covov_t; + +const lcl_covov_t* covov = static_cast(branch[0]); +const Type c0 = covov->t0(); +const Type& v0 = covov->t1(); +const Type& v1 = covov->t2(); +const Type c1 = static_cast*>(branch[1])->value(); +const details::operator_type o0 = expr_gen.get_operator(covov->f0()); +const details::operator_type o1 = expr_gen.get_operator(covov->f1()); +const details::operator_type o2 = operation; + +binary_functor_t f0 = covov->f0(); +binary_functor_t f1 = covov->f1(); +binary_functor_t f2 = reinterpret_cast(0); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); + +exprtk_debug(("((c0 o0 v0) o1 v1) o2 c1\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "((t" << expr_gen.to_str(o0) +<< "t)" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t"; +} +}; + +struct synthesize_vococov_expression3 +{ +typedef typename vococov_t::type3 node_type; +typedef typename vococov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// ((v0 o0 c0) o1 c1) o2 v1 +typedef typename synthesize_vococ_expression0::node_type lcl_vococ_t; + +const lcl_vococ_t* vococ = static_cast(branch[0]); +const Type& v0 = vococ->t0(); +const Type c0 = vococ->t1(); +const Type c1 = vococ->t2(); +const Type& v1 = static_cast*>(branch[1])->ref(); +const details::operator_type o0 = expr_gen.get_operator(vococ->f0()); +const details::operator_type o1 = expr_gen.get_operator(vococ->f1()); +const details::operator_type o2 = operation; + +binary_functor_t f0 = vococ->f0(); +binary_functor_t f1 = vococ->f1(); +binary_functor_t f2 = reinterpret_cast(0); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, c0, c1, v1, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); + +exprtk_debug(("((v0 o0 c0) o1 c1) o2 v1\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, c1, v1, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "((t" << expr_gen.to_str(o0) +<< "t)" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t"; +} +}; + +struct synthesize_vovovov_expression4 +{ +typedef typename vovovov_t::type4 node_type; +typedef typename vovovov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// (v0 o0 (v1 o1 v2)) o2 v3 +typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; + +const lcl_vovov_t* vovov = static_cast(branch[0]); +const Type& v0 = vovov->t0(); +const Type& v1 = vovov->t1(); +const Type& v2 = vovov->t2(); +const Type& v3 = static_cast*>(branch[1])->ref(); +const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); +const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); +const details::operator_type o2 = operation; + +binary_functor_t f0 = vovov->f0(); +binary_functor_t f1 = vovov->f1(); +binary_functor_t f2 = reinterpret_cast(0); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); + +exprtk_debug(("(v0 o0 (v1 o1 v2)) o2 v3\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, v3, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "(t" << expr_gen.to_str(o0) +<< "(t" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t"; +} +}; + +struct synthesize_vovovoc_expression4 +{ +typedef typename vovovoc_t::type4 node_type; +typedef typename vovovoc_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// ((v0 o0 (v1 o1 v2)) o2 c) +typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; + +const lcl_vovov_t* vovov = static_cast(branch[0]); +const Type& v0 = vovov->t0(); +const Type& v1 = vovov->t1(); +const Type& v2 = vovov->t2(); +const Type c = static_cast*>(branch[1])->value(); +const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); +const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); +const details::operator_type o2 = operation; + +binary_functor_t f0 = vovov->f0(); +binary_functor_t f1 = vovov->f1(); +binary_functor_t f2 = reinterpret_cast(0); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); + +exprtk_debug(("((v0 o0 (v1 o1 v2)) o2 c)\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "(t" << expr_gen.to_str(o0) +<< "(t" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t"; +} +}; + +struct synthesize_vovocov_expression4 +{ +typedef typename vovocov_t::type4 node_type; +typedef typename vovocov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// ((v0 o0 (v1 o1 c)) o2 v1) +typedef typename synthesize_vovoc_expression1::node_type lcl_vovoc_t; + +const lcl_vovoc_t* vovoc = static_cast(branch[0]); +const Type& v0 = vovoc->t0(); +const Type& v1 = vovoc->t1(); +const Type c = vovoc->t2(); +const Type& v2 = static_cast*>(branch[1])->ref(); +const details::operator_type o0 = expr_gen.get_operator(vovoc->f0()); +const details::operator_type o1 = expr_gen.get_operator(vovoc->f1()); +const details::operator_type o2 = operation; + +binary_functor_t f0 = vovoc->f0(); +binary_functor_t f1 = vovoc->f1(); +binary_functor_t f2 = reinterpret_cast(0); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); + +exprtk_debug(("((v0 o0 (v1 o1 c)) o2 v1)\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "(t" << expr_gen.to_str(o0) +<< "(t" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t"; +} +}; + +struct synthesize_vocovov_expression4 +{ +typedef typename vocovov_t::type4 node_type; +typedef typename vocovov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// ((v0 o0 (c o1 v1)) o2 v2) +typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; + +const lcl_vocov_t* vocov = static_cast(branch[0]); +const Type& v0 = vocov->t0(); +const Type c = vocov->t1(); +const Type& v1 = vocov->t2(); +const Type& v2 = static_cast*>(branch[1])->ref(); +const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); +const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); +const details::operator_type o2 = operation; + +binary_functor_t f0 = vocov->f0(); +binary_functor_t f1 = vocov->f1(); +binary_functor_t f2 = reinterpret_cast(0); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); + +exprtk_debug(("((v0 o0 (c o1 v1)) o2 v2)\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "(t" << expr_gen.to_str(o0) +<< "(t" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t"; +} +}; + +struct synthesize_covovov_expression4 +{ +typedef typename covovov_t::type4 node_type; +typedef typename covovov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// ((c o0 (v0 o1 v1)) o2 v2) +typedef typename synthesize_covov_expression1::node_type lcl_covov_t; + +const lcl_covov_t* covov = static_cast(branch[0]); +const Type c = covov->t0(); +const Type& v0 = covov->t1(); +const Type& v1 = covov->t2(); +const Type& v2 = static_cast*>(branch[1])->ref(); +const details::operator_type o0 = expr_gen.get_operator(covov->f0()); +const details::operator_type o1 = expr_gen.get_operator(covov->f1()); +const details::operator_type o2 = operation; + +binary_functor_t f0 = covov->f0(); +binary_functor_t f1 = covov->f1(); +binary_functor_t f2 = reinterpret_cast(0); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); + +exprtk_debug(("((c o0 (v0 o1 v1)) o2 v2)\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "(t" << expr_gen.to_str(o0) +<< "(t" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t"; +} +}; + +struct synthesize_covocov_expression4 +{ +typedef typename covocov_t::type4 node_type; +typedef typename covocov_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// ((c0 o0 (v0 o1 c1)) o2 v1) +typedef typename synthesize_covoc_expression1::node_type lcl_covoc_t; + +const lcl_covoc_t* covoc = static_cast(branch[0]); +const Type c0 = covoc->t0(); +const Type& v0 = covoc->t1(); +const Type c1 = covoc->t2(); +const Type& v1 = static_cast*>(branch[1])->ref(); +const details::operator_type o0 = expr_gen.get_operator(covoc->f0()); +const details::operator_type o1 = expr_gen.get_operator(covoc->f1()); +const details::operator_type o2 = operation; + +binary_functor_t f0 = covoc->f0(); +binary_functor_t f1 = covoc->f1(); +binary_functor_t f2 = reinterpret_cast(0); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); + +exprtk_debug(("((c0 o0 (v0 o1 c1)) o2 v1)\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "(t" << expr_gen.to_str(o0) +<< "(t" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t"; +} +}; + +struct synthesize_vocovoc_expression4 +{ +typedef typename vocovoc_t::type4 node_type; +typedef typename vocovoc_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// ((v0 o0 (c0 o1 v1)) o2 c1) +typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; + +const lcl_vocov_t* vocov = static_cast(branch[0]); +const Type& v0 = vocov->t0(); +const Type c0 = vocov->t1(); +const Type& v1 = vocov->t2(); +const Type c1 = static_cast*>(branch[1])->value(); +const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); +const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); +const details::operator_type o2 = operation; + +binary_functor_t f0 = vocov->f0(); +binary_functor_t f1 = vocov->f1(); +binary_functor_t f2 = reinterpret_cast(0); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); + +exprtk_debug(("((v0 o0 (c0 o1 v1)) o2 c1)\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "(t" << expr_gen.to_str(o0) +<< "(t" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t"; +} +}; + +struct synthesize_covovoc_expression4 +{ +typedef typename covovoc_t::type4 node_type; +typedef typename covovoc_t::sf4_type sf4_type; +typedef typename node_type::T0 T0; +typedef typename node_type::T1 T1; +typedef typename node_type::T2 T2; +typedef typename node_type::T3 T3; + +static inline expression_node_ptr process(expression_generator& expr_gen, +const details::operator_type& operation, +expression_node_ptr (&branch)[2]) +{ +// ((c0 o0 (v0 o1 v1)) o2 c1) +typedef typename synthesize_covov_expression1::node_type lcl_covov_t; + +const lcl_covov_t* covov = static_cast(branch[0]); +const Type c0 = covov->t0(); +const Type& v0 = covov->t1(); +const Type& v1 = covov->t2(); +const Type c1 = static_cast*>(branch[1])->value(); +const details::operator_type o0 = expr_gen.get_operator(covov->f0()); +const details::operator_type o1 = expr_gen.get_operator(covov->f1()); +const details::operator_type o2 = operation; + +binary_functor_t f0 = covov->f0(); +binary_functor_t f1 = covov->f1(); +binary_functor_t f2 = reinterpret_cast(0); + +details::free_node(*(expr_gen.node_allocator_),branch[0]); +details::free_node(*(expr_gen.node_allocator_),branch[1]); + +expression_node_ptr result = error_node(); + +const bool synthesis_result = +synthesize_sf4ext_expression::template compile +(expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); + +if (synthesis_result) +return result; +else if (!expr_gen.valid_operator(o2,f2)) +return error_node(); + +exprtk_debug(("((c0 o0 (v0 o1 v1)) o2 c1)\n")); + +return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); +} + +static inline std::string id(expression_generator& expr_gen, +const details::operator_type o0, +const details::operator_type o1, +const details::operator_type o2) +{ +return details::build_string() +<< "(t" << expr_gen.to_str(o0) +<< "(t" << expr_gen.to_str(o1) +<< "t)" << expr_gen.to_str(o2) +<< "t"; +} +}; + +struct synthesize_vococov_expression4 +{ +typedef typename vococov_t::type4 node_type; +static inline expression_node_ptr process(expression_generator&, +const details::operator_type&, +expression_node_ptr (&)[2]) +{ +// ((v0 o0 (c0 o1 c1)) o2 v1) - Not possible +exprtk_debug(("((v0 o0 (c0 o1 c1)) o2 v1) - Not possible\n")); +return error_node(); +} + +static inline std::string id(expression_generator&, +const details::operator_type, +const details::operator_type, +const details::operator_type) +{ +return "INVALID"; +} +}; +#endif + +inline expression_node_ptr synthesize_uvouv_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) +{ +// Definition: uv o uv +details::operator_type o0 = static_cast*>(branch[0])->operation(); +details::operator_type o1 = static_cast*>(branch[1])->operation(); +const Type& v0 = static_cast*>(branch[0])->v(); +const Type& v1 = static_cast*>(branch[1])->v(); +unary_functor_t u0 = reinterpret_cast (0); +unary_functor_t u1 = reinterpret_cast (0); +binary_functor_t f = reinterpret_cast(0); + +if (!valid_operator(o0,u0)) +return error_node(); +else if (!valid_operator(o1,u1)) +return error_node(); +else if (!valid_operator(operation,f)) +return error_node(); + +expression_node_ptr result = error_node(); + +if ( +(details::e_neg == o0) && +(details::e_neg == o1) +) +{ +switch (operation) +{ +// (-v0 + -v1) --> -(v0 + v1) +case details::e_add : result = (*this)(details::e_neg, +node_allocator_-> +allocate_rr > >(v0, v1)); +exprtk_debug(("(-v0 + -v1) --> -(v0 + v1)\n")); +break; + +// (-v0 - -v1) --> (v1 - v0) +case details::e_sub : result = node_allocator_-> +allocate_rr > >(v1, v0); +exprtk_debug(("(-v0 - -v1) --> (v1 - v0)\n")); +break; + +// (-v0 * -v1) --> (v0 * v1) +case details::e_mul : result = node_allocator_-> +allocate_rr > >(v0, v1); +exprtk_debug(("(-v0 * -v1) --> (v0 * v1)\n")); +break; + +// (-v0 / -v1) --> (v0 / v1) +case details::e_div : result = node_allocator_-> +allocate_rr > >(v0, v1); +exprtk_debug(("(-v0 / -v1) --> (v0 / v1)\n")); +break; + +default : break; +} +} + +if (0 == result) +{ +result = node_allocator_-> +allocate_rrrrr >(v0, v1, u0, u1, f); +} + +details::free_all_nodes(*node_allocator_,branch); +return result; +} + +#undef basic_opr_switch_statements +#undef extended_opr_switch_statements +#undef unary_opr_switch_statements + +#ifndef exprtk_disable_string_capabilities + +#define string_opr_switch_statements \ + case_stmt(details::e_lt , details::lt_op ) \ + case_stmt(details::e_lte , details::lte_op ) \ + case_stmt(details::e_gt , details::gt_op ) \ + case_stmt(details::e_gte , details::gte_op ) \ + case_stmt(details::e_eq , details::eq_op ) \ + case_stmt(details::e_ne , details::ne_op ) \ + case_stmt(details::e_in , details::in_op ) \ + case_stmt(details::e_like , details::like_op ) \ + case_stmt(details::e_ilike , details::ilike_op) \ + +template +inline expression_node_ptr synthesize_str_xrox_expression_impl(const details::operator_type& opr, +T0 s0, T1 s1, +range_t rp0) +{ +switch (opr) +{ +#define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + allocate_ttt >,T0,T1> \ + (s0, s1, rp0); \ + +string_opr_switch_statements +#undef case_stmt +default : return error_node(); +} +} + +template +inline expression_node_ptr synthesize_str_xoxr_expression_impl(const details::operator_type& opr, +T0 s0, T1 s1, +range_t rp1) +{ +switch (opr) +{ +#define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + allocate_ttt >,T0,T1> \ + (s0, s1, rp1); \ + +string_opr_switch_statements +#undef case_stmt +default : return error_node(); +} +} + +template +inline expression_node_ptr synthesize_str_xroxr_expression_impl(const details::operator_type& opr, +T0 s0, T1 s1, +range_t rp0, range_t rp1) +{ +switch (opr) +{ +#define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + allocate_tttt >,T0,T1> \ + (s0, s1, rp0, rp1); \ + +string_opr_switch_statements +#undef case_stmt +default : return error_node(); +} +} + +template +inline expression_node_ptr synthesize_sos_expression_impl(const details::operator_type& opr, T0 s0, T1 s1) +{ +switch (opr) +{ +#define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + allocate_tt >,T0,T1>(s0, s1); \ + +string_opr_switch_statements +#undef case_stmt +default : return error_node(); +} +} + +inline expression_node_ptr synthesize_sos_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) +{ +std::string& s0 = static_cast*>(branch[0])->ref(); +std::string& s1 = static_cast*>(branch[1])->ref(); + +return synthesize_sos_expression_impl(opr, s0, s1); +} + +inline expression_node_ptr synthesize_sros_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) +{ +std::string& s0 = static_cast*>(branch[0])->ref (); +std::string& s1 = static_cast*> (branch[1])->ref (); +range_t rp0 = static_cast*>(branch[0])->range(); + +static_cast*>(branch[0])->range_ref().clear(); + +details::free_node(*node_allocator_,branch[0]); + +return synthesize_str_xrox_expression_impl(opr, s0, s1, rp0); +} + +inline expression_node_ptr synthesize_sosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) +{ +std::string& s0 = static_cast*> (branch[0])->ref (); +std::string& s1 = static_cast*>(branch[1])->ref (); +range_t rp1 = static_cast*>(branch[1])->range(); + +static_cast*>(branch[1])->range_ref().clear(); + +details::free_node(*node_allocator_,branch[1]); + +return synthesize_str_xoxr_expression_impl(opr, s0, s1, rp1); +} + +inline expression_node_ptr synthesize_socsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) +{ +std::string& s0 = static_cast*> (branch[0])->ref (); +std::string s1 = static_cast*>(branch[1])->str (); +range_t rp1 = static_cast*>(branch[1])->range(); + +static_cast*>(branch[1])->range_ref().clear(); + +details::free_node(*node_allocator_,branch[1]); + +return synthesize_str_xoxr_expression_impl(opr, s0, s1, rp1); +} + +inline expression_node_ptr synthesize_srosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) +{ +std::string& s0 = static_cast*>(branch[0])->ref (); +std::string& s1 = static_cast*>(branch[1])->ref (); +range_t rp0 = static_cast*>(branch[0])->range(); +range_t rp1 = static_cast*>(branch[1])->range(); + +static_cast*>(branch[0])->range_ref().clear(); +static_cast*>(branch[1])->range_ref().clear(); + +details::free_node(*node_allocator_,branch[0]); +details::free_node(*node_allocator_,branch[1]); + +return synthesize_str_xroxr_expression_impl(opr, s0, s1, rp0, rp1); +} + +inline expression_node_ptr synthesize_socs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) +{ +std::string& s0 = static_cast< details::stringvar_node*>(branch[0])->ref(); +std::string s1 = static_cast*>(branch[1])->str(); + +details::free_node(*node_allocator_,branch[1]); + +return synthesize_sos_expression_impl(opr, s0, s1); +} + +inline expression_node_ptr synthesize_csos_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) +{ +std::string s0 = static_cast*>(branch[0])->str(); +std::string& s1 = static_cast* >(branch[1])->ref(); + +details::free_node(*node_allocator_,branch[0]); + +return synthesize_sos_expression_impl(opr, s0, s1); +} + +inline expression_node_ptr synthesize_csosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) +{ +std::string s0 = static_cast*>(branch[0])->str (); +std::string& s1 = static_cast* >(branch[1])->ref (); +range_t rp1 = static_cast* >(branch[1])->range(); + +static_cast*>(branch[1])->range_ref().clear(); + +details::free_node(*node_allocator_,branch[0]); +details::free_node(*node_allocator_,branch[1]); + +return synthesize_str_xoxr_expression_impl(opr, s0, s1, rp1); +} + +inline expression_node_ptr synthesize_srocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) +{ +std::string& s0 = static_cast* >(branch[0])->ref (); +std::string s1 = static_cast*>(branch[1])->str (); +range_t rp0 = static_cast* >(branch[0])->range(); + +static_cast*>(branch[0])->range_ref().clear(); + +details::free_node(*node_allocator_,branch[0]); +details::free_node(*node_allocator_,branch[1]); + +return synthesize_str_xrox_expression_impl(opr, s0, s1, rp0); +} + +inline expression_node_ptr synthesize_srocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) +{ +std::string& s0 = static_cast* >(branch[0])->ref (); +std::string s1 = static_cast*>(branch[1])->str (); +range_t rp0 = static_cast* >(branch[0])->range(); +range_t rp1 = static_cast*>(branch[1])->range(); + +static_cast*> (branch[0])->range_ref().clear(); +static_cast*>(branch[1])->range_ref().clear(); + +details::free_node(*node_allocator_,branch[0]); +details::free_node(*node_allocator_,branch[1]); + +return synthesize_str_xroxr_expression_impl(opr, s0, s1, rp0, rp1); +} + +inline expression_node_ptr synthesize_csocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) +{ +const std::string s0 = static_cast*>(branch[0])->str(); +const std::string s1 = static_cast*>(branch[1])->str(); + +expression_node_ptr result = error_node(); + +if (details::e_add == opr) +result = node_allocator_->allocate_c >(s0 + s1); +else if (details::e_in == opr) +result = node_allocator_->allocate_c >(details::in_op ::process(s0,s1)); +else if (details::e_like == opr) +result = node_allocator_->allocate_c >(details::like_op ::process(s0,s1)); +else if (details::e_ilike == opr) +result = node_allocator_->allocate_c >(details::ilike_op::process(s0,s1)); +else +{ +expression_node_ptr temp = synthesize_sos_expression_impl(opr, s0, s1); + +const Type v = temp->value(); + +details::free_node(*node_allocator_,temp); + +result = node_allocator_->allocate(v); +} + +details::free_all_nodes(*node_allocator_,branch); + +return result; +} + +inline expression_node_ptr synthesize_csocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) +{ +const std::string s0 = static_cast* >(branch[0])->str (); +std::string s1 = static_cast*>(branch[1])->str (); +range_t rp1 = static_cast*>(branch[1])->range(); + +static_cast*>(branch[1])->range_ref().clear(); + +details::free_node(*node_allocator_,branch[0]); +details::free_node(*node_allocator_,branch[1]); + +return synthesize_str_xoxr_expression_impl(opr, s0, s1, rp1); +} + +inline expression_node_ptr synthesize_csros_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) +{ +std::string s0 = static_cast*>(branch[0])->str (); +std::string& s1 = static_cast* >(branch[1])->ref (); +range_t rp0 = static_cast*>(branch[0])->range(); + +static_cast*>(branch[0])->range_ref().clear(); + +details::free_node(*node_allocator_,branch[0]); + +return synthesize_str_xrox_expression_impl(opr, s0, s1, rp0); +} + +inline expression_node_ptr synthesize_csrosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) +{ +const std::string s0 = static_cast*>(branch[0])->str (); +std::string& s1 = static_cast* >(branch[1])->ref (); +const range_t rp0 = static_cast*>(branch[0])->range(); +const range_t rp1 = static_cast* >(branch[1])->range(); + +static_cast*>(branch[0])->range_ref().clear(); +static_cast*> (branch[1])->range_ref().clear(); + +details::free_node(*node_allocator_,branch[0]); +details::free_node(*node_allocator_,branch[1]); + +return synthesize_str_xroxr_expression_impl(opr, s0, s1, rp0, rp1); +} + +inline expression_node_ptr synthesize_csrocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) +{ +const std::string s0 = static_cast*>(branch[0])->str (); +const std::string s1 = static_cast* >(branch[1])->str (); +const range_t rp0 = static_cast*>(branch[0])->range(); + +static_cast*>(branch[0])->range_ref().clear(); + +details::free_all_nodes(*node_allocator_,branch); + +return synthesize_str_xrox_expression_impl(opr, s0, s1, rp0); +} + +inline expression_node_ptr synthesize_csrocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) +{ +const std::string s0 = static_cast*>(branch[0])->str (); +const std::string s1 = static_cast*>(branch[1])->str (); +const range_t rp0 = static_cast*>(branch[0])->range(); +const range_t rp1 = static_cast*>(branch[1])->range(); + +static_cast*>(branch[0])->range_ref().clear(); +static_cast*>(branch[1])->range_ref().clear(); + +details::free_all_nodes(*node_allocator_,branch); + +return synthesize_str_xroxr_expression_impl(opr, s0, s1, rp0, rp1); +} + +inline expression_node_ptr synthesize_strogen_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) +{ +switch (opr) +{ +#define case_stmt(op0, op1) \ + case op0 : return node_allocator_-> \ + allocate_ttt > > \ + (opr, branch[0], branch[1]); \ + +string_opr_switch_statements +#undef case_stmt +default : return error_node(); +} +} +#endif + +#ifndef exprtk_disable_string_capabilities +inline expression_node_ptr synthesize_string_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) +{ +if ((0 == branch[0]) || (0 == branch[1])) +{ +details::free_all_nodes(*node_allocator_,branch); + +return error_node(); +} + +const bool b0_is_s = details::is_string_node (branch[0]); +const bool b0_is_cs = details::is_const_string_node (branch[0]); +const bool b0_is_sr = details::is_string_range_node (branch[0]); +const bool b0_is_csr = details::is_const_string_range_node(branch[0]); + +const bool b1_is_s = details::is_string_node (branch[1]); +const bool b1_is_cs = details::is_const_string_node (branch[1]); +const bool b1_is_sr = details::is_string_range_node (branch[1]); +const bool b1_is_csr = details::is_const_string_range_node(branch[1]); + +const bool b0_is_gen = details::is_string_assignment_node (branch[0]) || +details::is_genricstring_range_node(branch[0]) || +details::is_string_concat_node (branch[0]) || +details::is_string_function_node (branch[0]) || +details::is_string_condition_node (branch[0]) || +details::is_string_ccondition_node (branch[0]) || +details::is_string_vararg_node (branch[0]) ; + +const bool b1_is_gen = details::is_string_assignment_node (branch[1]) || +details::is_genricstring_range_node(branch[1]) || +details::is_string_concat_node (branch[1]) || +details::is_string_function_node (branch[1]) || +details::is_string_condition_node (branch[1]) || +details::is_string_ccondition_node (branch[1]) || +details::is_string_vararg_node (branch[1]) ; + +if (details::e_add == opr) +{ +if (!b0_is_cs || !b1_is_cs) +{ +return synthesize_expression(opr,branch); +} +} + +if (b0_is_gen || b1_is_gen) +{ +return synthesize_strogen_expression(opr,branch); +} +else if (b0_is_s) +{ +if (b1_is_s ) return synthesize_sos_expression (opr,branch); +else if (b1_is_cs ) return synthesize_socs_expression (opr,branch); +else if (b1_is_sr ) return synthesize_sosr_expression (opr,branch); +else if (b1_is_csr) return synthesize_socsr_expression (opr,branch); +} +else if (b0_is_cs) +{ +if (b1_is_s ) return synthesize_csos_expression (opr,branch); +else if (b1_is_cs ) return synthesize_csocs_expression (opr,branch); +else if (b1_is_sr ) return synthesize_csosr_expression (opr,branch); +else if (b1_is_csr) return synthesize_csocsr_expression(opr,branch); +} +else if (b0_is_sr) +{ +if (b1_is_s ) return synthesize_sros_expression (opr,branch); +else if (b1_is_sr ) return synthesize_srosr_expression (opr,branch); +else if (b1_is_cs ) return synthesize_srocs_expression (opr,branch); +else if (b1_is_csr) return synthesize_srocsr_expression(opr,branch); +} +else if (b0_is_csr) +{ +if (b1_is_s ) return synthesize_csros_expression (opr,branch); +else if (b1_is_sr ) return synthesize_csrosr_expression (opr,branch); +else if (b1_is_cs ) return synthesize_csrocs_expression (opr,branch); +else if (b1_is_csr) return synthesize_csrocsr_expression(opr,branch); +} + +return error_node(); +} +#else +inline expression_node_ptr synthesize_string_expression(const details::operator_type&, expression_node_ptr (&branch)[2]) +{ +details::free_all_nodes(*node_allocator_,branch); +return error_node(); +} +#endif + +#ifndef exprtk_disable_string_capabilities +inline expression_node_ptr synthesize_string_expression(const details::operator_type& opr, expression_node_ptr (&branch)[3]) +{ +if (details::e_inrange != opr) +return error_node(); +else if ((0 == branch[0]) || (0 == branch[1]) || (0 == branch[2])) +{ +details::free_all_nodes(*node_allocator_,branch); + +return error_node(); +} +else if ( +details::is_const_string_node(branch[0]) && +details::is_const_string_node(branch[1]) && +details::is_const_string_node(branch[2]) +) +{ +const std::string s0 = static_cast*>(branch[0])->str(); +const std::string s1 = static_cast*>(branch[1])->str(); +const std::string s2 = static_cast*>(branch[2])->str(); + +const Type v = (((s0 <= s1) && (s1 <= s2)) ? Type(1) : Type(0)); + +details::free_all_nodes(*node_allocator_,branch); + +return node_allocator_->allocate_c >(v); +} +else if ( +details::is_string_node(branch[0]) && +details::is_string_node(branch[1]) && +details::is_string_node(branch[2]) +) +{ +std::string& s0 = static_cast*>(branch[0])->ref(); +std::string& s1 = static_cast*>(branch[1])->ref(); +std::string& s2 = static_cast*>(branch[2])->ref(); + +typedef typename details::sosos_node > inrange_t; + +return node_allocator_->allocate_type(s0, s1, s2); +} +else if ( +details::is_const_string_node(branch[0]) && +details::is_string_node(branch[1]) && +details::is_const_string_node(branch[2]) +) +{ +std::string s0 = static_cast*>(branch[0])->str(); +std::string& s1 = static_cast* >(branch[1])->ref(); +std::string s2 = static_cast*>(branch[2])->str(); + +typedef typename details::sosos_node > inrange_t; + +details::free_node(*node_allocator_,branch[0]); +details::free_node(*node_allocator_,branch[2]); + +return node_allocator_->allocate_type(s0, s1, s2); +} +else if ( +details::is_string_node(branch[0]) && +details::is_const_string_node(branch[1]) && +details::is_string_node(branch[2]) +) +{ +std::string& s0 = static_cast* >(branch[0])->ref(); +std::string s1 = static_cast*>(branch[1])->str(); +std::string& s2 = static_cast* >(branch[2])->ref(); + +typedef typename details::sosos_node > inrange_t; + +details::free_node(*node_allocator_,branch[1]); + +return node_allocator_->allocate_type(s0, s1, s2); +} +else if ( +details::is_string_node(branch[0]) && +details::is_string_node(branch[1]) && +details::is_const_string_node(branch[2]) +) +{ +std::string& s0 = static_cast* >(branch[0])->ref(); +std::string& s1 = static_cast* >(branch[1])->ref(); +std::string s2 = static_cast*>(branch[2])->str(); + +typedef typename details::sosos_node > inrange_t; + +details::free_node(*node_allocator_,branch[2]); + +return node_allocator_->allocate_type(s0, s1, s2); +} +else if ( +details::is_const_string_node(branch[0]) && +details:: is_string_node(branch[1]) && +details:: is_string_node(branch[2]) +) +{ +std::string s0 = static_cast*>(branch[0])->str(); +std::string& s1 = static_cast* >(branch[1])->ref(); +std::string& s2 = static_cast* >(branch[2])->ref(); + +typedef typename details::sosos_node > inrange_t; + +details::free_node(*node_allocator_,branch[0]); + +return node_allocator_->allocate_type(s0, s1, s2); +} +else +return error_node(); +} +#else +inline expression_node_ptr synthesize_string_expression(const details::operator_type&, expression_node_ptr (&branch)[3]) +{ +details::free_all_nodes(*node_allocator_,branch); +return error_node(); +} +#endif + +inline expression_node_ptr synthesize_null_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) +{ +/* + Note: The following are the type promotion rules + that relate to operations that include 'null': + 0. null ==/!= null --> true false + 1. null operation null --> null + 2. x ==/!= null --> true/false + 3. null ==/!= x --> true/false + 4. x operation null --> x + 5. null operation x --> x + */ + +typedef typename details::null_eq_node nulleq_node_t; + +const bool b0_null = details::is_null_node(branch[0]); +const bool b1_null = details::is_null_node(branch[1]); + +if (b0_null && b1_null) +{ +expression_node_ptr result = error_node(); + +if (details::e_eq == operation) +result = node_allocator_->allocate_c(T(1)); +else if (details::e_ne == operation) +result = node_allocator_->allocate_c(T(0)); + +if (result) +{ +details::free_node(*node_allocator_,branch[0]); +details::free_node(*node_allocator_,branch[1]); + +return result; +} + +details::free_node(*node_allocator_,branch[1]); + +return branch[0]; +} +else if (details::e_eq == operation) +{ +expression_node_ptr result = node_allocator_-> +allocate_rc(branch[b0_null ? 0 : 1],true); + +details::free_node(*node_allocator_,branch[b0_null ? 1 : 0]); + +return result; +} +else if (details::e_ne == operation) +{ +expression_node_ptr result = node_allocator_-> +allocate_rc(branch[b0_null ? 0 : 1],false); + +details::free_node(*node_allocator_,branch[b0_null ? 1 : 0]); + +return result; +} +else if (b0_null) +{ +details::free_node(*node_allocator_,branch[0]); +branch[0] = branch[1]; +branch[1] = error_node(); +} +else if (b1_null) +{ +details::free_node(*node_allocator_,branch[1]); +branch[1] = error_node(); +} + +if ( +(details::e_add == operation) || (details::e_sub == operation) || +(details::e_mul == operation) || (details::e_div == operation) || +(details::e_mod == operation) || (details::e_pow == operation) +) +{ +return branch[0]; +} + +details::free_node(*node_allocator_, branch[0]); + +if ( +(details::e_lt == operation) || (details::e_lte == operation) || +(details::e_gt == operation) || (details::e_gte == operation) || +(details::e_and == operation) || (details::e_nand == operation) || +(details::e_or == operation) || (details::e_nor == operation) || +(details::e_xor == operation) || (details::e_xnor == operation) || +(details::e_in == operation) || (details::e_like == operation) || +(details::e_ilike == operation) +) +{ +return node_allocator_->allocate_c(T(0)); +} + +return node_allocator_->allocate >(); +} + +template +inline expression_node_ptr synthesize_expression(const details::operator_type& operation, expression_node_ptr (&branch)[N]) +{ +if ( +(details::e_in == operation) || +(details::e_like == operation) || +(details::e_ilike == operation) +) +{ +free_all_nodes(*node_allocator_,branch); + +return error_node(); +} +else if (!details::all_nodes_valid(branch)) +{ +free_all_nodes(*node_allocator_,branch); + +return error_node(); +} +else if ((details::e_default != operation)) +{ +// Attempt simple constant folding optimisation. +expression_node_ptr expression_point = node_allocator_->allocate(operation,branch); + +if (is_constant_foldable(branch)) +{ +const Type v = expression_point->value(); +details::free_node(*node_allocator_,expression_point); + +return node_allocator_->allocate(v); +} +else +return expression_point; +} +else +return error_node(); +} + +template +inline expression_node_ptr synthesize_expression(F* f, expression_node_ptr (&branch)[N]) +{ +if (!details::all_nodes_valid(branch)) +{ +free_all_nodes(*node_allocator_,branch); + +return error_node(); +} + +typedef typename details::function_N_node function_N_node_t; + +// Attempt simple constant folding optimisation. + +expression_node_ptr expression_point = node_allocator_->allocate(f); +function_N_node_t* func_node_ptr = dynamic_cast(expression_point); + +if (0 == func_node_ptr) +{ +free_all_nodes(*node_allocator_,branch); + +return error_node(); +} +else +func_node_ptr->init_branches(branch); + +if (is_constant_foldable(branch) && !f->has_side_effects()) +{ +Type v = expression_point->value(); +details::free_node(*node_allocator_,expression_point); + +return node_allocator_->allocate(v); +} + +parser_->state_.activate_side_effect("synthesize_expression(function)"); + +return expression_point; +} + +bool strength_reduction_enabled_; +details::node_allocator* node_allocator_; +synthesize_map_t synthesize_map_; +unary_op_map_t* unary_op_map_; +binary_op_map_t* binary_op_map_; +inv_binary_op_map_t* inv_binary_op_map_; +sf3_map_t* sf3_map_; +sf4_map_t* sf4_map_; +parser_t* parser_; +}; // class expression_generator + +inline void set_error(const parser_error::type& error_type) +{ +error_list_.push_back(error_type); +} + +inline void remove_last_error() +{ +if (!error_list_.empty()) +{ +error_list_.pop_back(); +} +} + +inline void set_synthesis_error(const std::string& synthesis_error_message) +{ +if (synthesis_error_.empty()) +{ +synthesis_error_ = synthesis_error_message; +} +} + +inline void register_local_vars(expression& e) +{ +for (std::size_t i = 0; i < sem_.size(); ++i) +{ +scope_element& se = sem_.get_element(i); + +if ( +(scope_element::e_variable == se.type) || +(scope_element::e_vecelem == se.type) +) +{ +if (se.var_node) +{ +e.register_local_var(se.var_node); +} + +if (se.data) +{ +e.register_local_data(se.data, 1, 0); +} +} +else if (scope_element::e_vector == se.type) +{ +if (se.vec_node) +{ +e.register_local_var(se.vec_node); +} + +if (se.data) +{ +e.register_local_data(se.data, se.size, 1); +} +} +#ifndef exprtk_disable_string_capabilities +else if (scope_element::e_string == se.type) +{ +if (se.str_node) +{ +e.register_local_var(se.str_node); +} + +if (se.data) +{ +e.register_local_data(se.data, se.size, 2); +} +} +#endif + +se.var_node = 0; +se.vec_node = 0; +#ifndef exprtk_disable_string_capabilities +se.str_node = 0; +#endif +se.data = 0; +se.ref_count = 0; +se.active = false; +} +} + +inline void register_return_results(expression& e) +{ +e.register_return_results(results_context_); +results_context_ = 0; +} + +inline void load_unary_operations_map(unary_op_map_t& m) +{ +#define register_unary_op(Op, UnaryFunctor) \ + m.insert(std::make_pair(Op,UnaryFunctor::process)); \ + +register_unary_op(details::e_abs , details::abs_op ) +register_unary_op(details::e_acos , details::acos_op ) +register_unary_op(details::e_acosh , details::acosh_op) +register_unary_op(details::e_asin , details::asin_op ) +register_unary_op(details::e_asinh , details::asinh_op) +register_unary_op(details::e_atanh , details::atanh_op) +register_unary_op(details::e_ceil , details::ceil_op ) +register_unary_op(details::e_cos , details::cos_op ) +register_unary_op(details::e_cosh , details::cosh_op ) +register_unary_op(details::e_exp , details::exp_op ) +register_unary_op(details::e_expm1 , details::expm1_op) +register_unary_op(details::e_floor , details::floor_op) +register_unary_op(details::e_log , details::log_op ) +register_unary_op(details::e_log10 , details::log10_op) +register_unary_op(details::e_log2 , details::log2_op ) +register_unary_op(details::e_log1p , details::log1p_op) +register_unary_op(details::e_neg , details::neg_op ) +register_unary_op(details::e_pos , details::pos_op ) +register_unary_op(details::e_round , details::round_op) +register_unary_op(details::e_sin , details::sin_op ) +register_unary_op(details::e_sinc , details::sinc_op ) +register_unary_op(details::e_sinh , details::sinh_op ) +register_unary_op(details::e_sqrt , details::sqrt_op ) +register_unary_op(details::e_tan , details::tan_op ) +register_unary_op(details::e_tanh , details::tanh_op ) +register_unary_op(details::e_cot , details::cot_op ) +register_unary_op(details::e_sec , details::sec_op ) +register_unary_op(details::e_csc , details::csc_op ) +register_unary_op(details::e_r2d , details::r2d_op ) +register_unary_op(details::e_d2r , details::d2r_op ) +register_unary_op(details::e_d2g , details::d2g_op ) +register_unary_op(details::e_g2d , details::g2d_op ) +register_unary_op(details::e_notl , details::notl_op ) +register_unary_op(details::e_sgn , details::sgn_op ) +register_unary_op(details::e_erf , details::erf_op ) +register_unary_op(details::e_erfc , details::erfc_op ) +register_unary_op(details::e_ncdf , details::ncdf_op ) +register_unary_op(details::e_frac , details::frac_op ) +register_unary_op(details::e_trunc , details::trunc_op) +#undef register_unary_op +} + +inline void load_binary_operations_map(binary_op_map_t& m) +{ +typedef typename binary_op_map_t::value_type value_type; + +#define register_binary_op(Op, BinaryFunctor) \ + m.insert(value_type(Op,BinaryFunctor::process)); \ + +register_binary_op(details::e_add , details::add_op ) +register_binary_op(details::e_sub , details::sub_op ) +register_binary_op(details::e_mul , details::mul_op ) +register_binary_op(details::e_div , details::div_op ) +register_binary_op(details::e_mod , details::mod_op ) +register_binary_op(details::e_pow , details::pow_op ) +register_binary_op(details::e_lt , details::lt_op ) +register_binary_op(details::e_lte , details::lte_op ) +register_binary_op(details::e_gt , details::gt_op ) +register_binary_op(details::e_gte , details::gte_op ) +register_binary_op(details::e_eq , details::eq_op ) +register_binary_op(details::e_ne , details::ne_op ) +register_binary_op(details::e_and , details::and_op ) +register_binary_op(details::e_nand , details::nand_op) +register_binary_op(details::e_or , details::or_op ) +register_binary_op(details::e_nor , details::nor_op ) +register_binary_op(details::e_xor , details::xor_op ) +register_binary_op(details::e_xnor , details::xnor_op) +#undef register_binary_op +} + +inline void load_inv_binary_operations_map(inv_binary_op_map_t& m) +{ +typedef typename inv_binary_op_map_t::value_type value_type; + +#define register_binary_op(Op, BinaryFunctor) \ + m.insert(value_type(BinaryFunctor::process,Op)); \ + +register_binary_op(details::e_add , details::add_op ) +register_binary_op(details::e_sub , details::sub_op ) +register_binary_op(details::e_mul , details::mul_op ) +register_binary_op(details::e_div , details::div_op ) +register_binary_op(details::e_mod , details::mod_op ) +register_binary_op(details::e_pow , details::pow_op ) +register_binary_op(details::e_lt , details::lt_op ) +register_binary_op(details::e_lte , details::lte_op ) +register_binary_op(details::e_gt , details::gt_op ) +register_binary_op(details::e_gte , details::gte_op ) +register_binary_op(details::e_eq , details::eq_op ) +register_binary_op(details::e_ne , details::ne_op ) +register_binary_op(details::e_and , details::and_op ) +register_binary_op(details::e_nand , details::nand_op) +register_binary_op(details::e_or , details::or_op ) +register_binary_op(details::e_nor , details::nor_op ) +register_binary_op(details::e_xor , details::xor_op ) +register_binary_op(details::e_xnor , details::xnor_op) +#undef register_binary_op +} + +inline void load_sf3_map(sf3_map_t& sf3_map) +{ +typedef std::pair pair_t; + +#define register_sf3(Op) \ + sf3_map[details::sf##Op##_op::id()] = pair_t(details::sf##Op##_op::process,details::e_sf##Op); \ + +register_sf3(00) register_sf3(01) register_sf3(02) register_sf3(03) +register_sf3(04) register_sf3(05) register_sf3(06) register_sf3(07) +register_sf3(08) register_sf3(09) register_sf3(10) register_sf3(11) +register_sf3(12) register_sf3(13) register_sf3(14) register_sf3(15) +register_sf3(16) register_sf3(17) register_sf3(18) register_sf3(19) +register_sf3(20) register_sf3(21) register_sf3(22) register_sf3(23) +register_sf3(24) register_sf3(25) register_sf3(26) register_sf3(27) +register_sf3(28) register_sf3(29) register_sf3(30) +#undef register_sf3 + +#define register_sf3_extid(Id, Op) \ + sf3_map[Id] = pair_t(details::sf##Op##_op::process,details::e_sf##Op); \ + +register_sf3_extid("(t-t)-t",23) // (t-t)-t --> t-(t+t) +#undef register_sf3_extid +} + +inline void load_sf4_map(sf4_map_t& sf4_map) +{ +typedef std::pair pair_t; + +#define register_sf4(Op) \ + sf4_map[details::sf##Op##_op::id()] = pair_t(details::sf##Op##_op::process,details::e_sf##Op); \ + +register_sf4(48) register_sf4(49) register_sf4(50) register_sf4(51) +register_sf4(52) register_sf4(53) register_sf4(54) register_sf4(55) +register_sf4(56) register_sf4(57) register_sf4(58) register_sf4(59) +register_sf4(60) register_sf4(61) register_sf4(62) register_sf4(63) +register_sf4(64) register_sf4(65) register_sf4(66) register_sf4(67) +register_sf4(68) register_sf4(69) register_sf4(70) register_sf4(71) +register_sf4(72) register_sf4(73) register_sf4(74) register_sf4(75) +register_sf4(76) register_sf4(77) register_sf4(78) register_sf4(79) +register_sf4(80) register_sf4(81) register_sf4(82) register_sf4(83) +#undef register_sf4 + +#define register_sf4ext(Op) \ + sf4_map[details::sfext##Op##_op::id()] = pair_t(details::sfext##Op##_op::process,details::e_sf4ext##Op); \ + +register_sf4ext(00) register_sf4ext(01) register_sf4ext(02) register_sf4ext(03) +register_sf4ext(04) register_sf4ext(05) register_sf4ext(06) register_sf4ext(07) +register_sf4ext(08) register_sf4ext(09) register_sf4ext(10) register_sf4ext(11) +register_sf4ext(12) register_sf4ext(13) register_sf4ext(14) register_sf4ext(15) +register_sf4ext(16) register_sf4ext(17) register_sf4ext(18) register_sf4ext(19) +register_sf4ext(20) register_sf4ext(21) register_sf4ext(22) register_sf4ext(23) +register_sf4ext(24) register_sf4ext(25) register_sf4ext(26) register_sf4ext(27) +register_sf4ext(28) register_sf4ext(29) register_sf4ext(30) register_sf4ext(31) +register_sf4ext(32) register_sf4ext(33) register_sf4ext(34) register_sf4ext(35) +register_sf4ext(36) register_sf4ext(36) register_sf4ext(38) register_sf4ext(39) +register_sf4ext(40) register_sf4ext(41) register_sf4ext(42) register_sf4ext(43) +register_sf4ext(44) register_sf4ext(45) register_sf4ext(46) register_sf4ext(47) +register_sf4ext(48) register_sf4ext(49) register_sf4ext(50) register_sf4ext(51) +register_sf4ext(52) register_sf4ext(53) register_sf4ext(54) register_sf4ext(55) +register_sf4ext(56) register_sf4ext(57) register_sf4ext(58) register_sf4ext(59) +register_sf4ext(60) register_sf4ext(61) +#undef register_sf4ext +} + +inline results_context_t& results_ctx() +{ +if (0 == results_context_) +{ +results_context_ = new results_context_t(); +} + +return (*results_context_); +} + +inline void return_cleanup() +{ +#ifndef exprtk_disable_return_statement +if (results_context_) +{ +delete results_context_; +results_context_ = 0; +} + +state_.return_stmt_present = false; +#endif +} + +private: + +parser(const parser&) exprtk_delete; +parser& operator=(const parser&) exprtk_delete; + +settings_store settings_; +expression_generator expression_generator_; +details::node_allocator node_allocator_; +symtab_store symtab_store_; +dependent_entity_collector dec_; +std::deque error_list_; +std::deque brkcnt_list_; +parser_state state_; +bool resolve_unknown_symbol_; +results_context_t* results_context_; +unknown_symbol_resolver* unknown_symbol_resolver_; +unknown_symbol_resolver default_usr_; +base_ops_map_t base_ops_map_; +unary_op_map_t unary_op_map_; +binary_op_map_t binary_op_map_; +inv_binary_op_map_t inv_binary_op_map_; +sf3_map_t sf3_map_; +sf4_map_t sf4_map_; +std::string synthesis_error_; +scope_element_manager sem_; + +immutable_memory_map_t immutable_memory_map_; +immutable_symtok_map_t immutable_symtok_map_; + +lexer::helper::helper_assembly helper_assembly_; + +lexer::helper::commutative_inserter commutative_inserter_; +lexer::helper::operator_joiner operator_joiner_2_; +lexer::helper::operator_joiner operator_joiner_3_; +lexer::helper::symbol_replacer symbol_replacer_; +lexer::helper::bracket_checker bracket_checker_; +lexer::helper::numeric_checker numeric_checker_; +lexer::helper::sequence_validator sequence_validator_; +lexer::helper::sequence_validator_3tokens sequence_validator_3tkns_; + +loop_runtime_check_ptr loop_runtime_check_; + +template +friend void details::disable_type_checking(ParserType& p); +}; // class parser + +namespace details +{ +template +struct collector_helper +{ +typedef exprtk::symbol_table symbol_table_t; +typedef exprtk::expression expression_t; +typedef exprtk::parser parser_t; +typedef typename parser_t::dependent_entity_collector::symbol_t symbol_t; +typedef typename parser_t::unknown_symbol_resolver usr_t; + +struct resolve_as_vector : public parser_t::unknown_symbol_resolver +{ +typedef exprtk::parser parser_t; + +resolve_as_vector() +: usr_t(usr_t::e_usrmode_extended) +{} + +virtual bool process(const std::string& unknown_symbol, +symbol_table_t& symbol_table, +std::string&) +{ +static T v[1]; +symbol_table.add_vector(unknown_symbol,v); +return true; +} +}; + +static inline bool collection_pass(const std::string& expression_string, +std::set& symbol_set, +const bool collect_variables, +const bool collect_functions, +const bool vector_pass, +symbol_table_t& ext_symbol_table) +{ +symbol_table_t symbol_table; +expression_t expression; +parser_t parser; + +resolve_as_vector vect_resolver; + +expression.register_symbol_table(symbol_table ); +expression.register_symbol_table(ext_symbol_table); + +if (vector_pass) +parser.enable_unknown_symbol_resolver(&vect_resolver); +else +parser.enable_unknown_symbol_resolver(); + +if (collect_variables) +parser.dec().collect_variables() = true; + +if (collect_functions) +parser.dec().collect_functions() = true; + +bool pass_result = false; + +details::disable_type_checking(parser); + +if (parser.compile(expression_string, expression)) +{ +pass_result = true; + +std::deque symb_list; +parser.dec().symbols(symb_list); + +for (std::size_t i = 0; i < symb_list.size(); ++i) +{ +symbol_set.insert(symb_list[i].first); +} +} + +return pass_result; +} +}; +} + +template class Sequence> +inline bool collect_variables(const std::string& expression, +Sequence& symbol_list) +{ +typedef double T; +typedef details::collector_helper collect_t; + +collect_t::symbol_table_t null_symbol_table; + +std::set symbol_set; + +const bool variable_pass = collect_t::collection_pass +(expression, symbol_set, true, false, false, null_symbol_table); +const bool vector_pass = collect_t::collection_pass +(expression, symbol_set, true, false, true, null_symbol_table); + +if (!variable_pass && !vector_pass) +return false; + +std::set::iterator itr = symbol_set.begin(); + +while (symbol_set.end() != itr) +{ +symbol_list.push_back(*itr); +++itr; +} + +return true; +} + +template class Sequence> +inline bool collect_variables(const std::string& expression, +exprtk::symbol_table& extrnl_symbol_table, +Sequence& symbol_list) +{ +typedef details::collector_helper collect_t; + +std::set symbol_set; + +const bool variable_pass = collect_t::collection_pass +(expression, symbol_set, true, false, false, extrnl_symbol_table); +const bool vector_pass = collect_t::collection_pass +(expression, symbol_set, true, false, true, extrnl_symbol_table); + +if (!variable_pass && !vector_pass) +return false; + +std::set::iterator itr = symbol_set.begin(); + +while (symbol_set.end() != itr) +{ +symbol_list.push_back(*itr); +++itr; +} + +return true; +} + +template class Sequence> +inline bool collect_functions(const std::string& expression, +Sequence& symbol_list) +{ +typedef double T; +typedef details::collector_helper collect_t; + +collect_t::symbol_table_t null_symbol_table; + +std::set symbol_set; + +const bool variable_pass = collect_t::collection_pass +(expression, symbol_set, false, true, false, null_symbol_table); +const bool vector_pass = collect_t::collection_pass +(expression, symbol_set, false, true, true, null_symbol_table); + +if (!variable_pass && !vector_pass) +return false; + +std::set::iterator itr = symbol_set.begin(); + +while (symbol_set.end() != itr) +{ +symbol_list.push_back(*itr); +++itr; +} + +return true; +} + +template class Sequence> +inline bool collect_functions(const std::string& expression, +exprtk::symbol_table& extrnl_symbol_table, +Sequence& symbol_list) +{ +typedef details::collector_helper collect_t; + +std::set symbol_set; + +const bool variable_pass = collect_t::collection_pass +(expression, symbol_set, false, true, false, extrnl_symbol_table); +const bool vector_pass = collect_t::collection_pass +(expression, symbol_set, false, true, true, extrnl_symbol_table); + +if (!variable_pass && !vector_pass) +return false; + +std::set::iterator itr = symbol_set.begin(); + +while (symbol_set.end() != itr) +{ +symbol_list.push_back(*itr); +++itr; +} + +return true; +} + +template +inline T integrate(const expression& e, +T& x, +const T& r0, const T& r1, +const std::size_t number_of_intervals = 1000000) +{ +if (r0 > r1) +return T(0); + +const T h = (r1 - r0) / (T(2) * number_of_intervals); +T total_area = T(0); + +for (std::size_t i = 0; i < number_of_intervals; ++i) +{ +x = r0 + T(2) * i * h; +const T y0 = e.value(); x += h; +const T y1 = e.value(); x += h; +const T y2 = e.value(); x += h; +total_area += h * (y0 + T(4) * y1 + y2) / T(3); +} + +return total_area; +} + +template +inline T integrate(const expression& e, +const std::string& variable_name, +const T& r0, const T& r1, +const std::size_t number_of_intervals = 1000000) +{ +const symbol_table& sym_table = e.get_symbol_table(); + +if (!sym_table.valid()) +return std::numeric_limits::quiet_NaN(); + +details::variable_node* var = sym_table.get_variable(variable_name); + +if (var) +{ +T& x = var->ref(); +const T x_original = x; +const T result = integrate(e, x, r0, r1, number_of_intervals); +x = x_original; + +return result; +} +else +return std::numeric_limits::quiet_NaN(); +} + +template +inline T derivative(const expression& e, +T& x, +const T& h = T(0.00000001)) +{ +const T x_init = x; +const T _2h = T(2) * h; + +x = x_init + _2h; +const T y0 = e.value(); +x = x_init + h; +const T y1 = e.value(); +x = x_init - h; +const T y2 = e.value(); +x = x_init - _2h; +const T y3 = e.value(); +x = x_init; + +return (-y0 + T(8) * (y1 - y2) + y3) / (T(12) * h); +} + +template +inline T second_derivative(const expression& e, +T& x, +const T& h = T(0.00001)) +{ +const T x_init = x; +const T _2h = T(2) * h; + +const T y = e.value(); +x = x_init + _2h; +const T y0 = e.value(); +x = x_init + h; +const T y1 = e.value(); +x = x_init - h; +const T y2 = e.value(); +x = x_init - _2h; +const T y3 = e.value(); +x = x_init; + +return (-y0 + T(16) * (y1 + y2) - T(30) * y - y3) / (T(12) * h * h); +} + +template +inline T third_derivative(const expression& e, +T& x, +const T& h = T(0.0001)) +{ +const T x_init = x; +const T _2h = T(2) * h; + +x = x_init + _2h; +const T y0 = e.value(); +x = x_init + h; +const T y1 = e.value(); +x = x_init - h; +const T y2 = e.value(); +x = x_init - _2h; +const T y3 = e.value(); +x = x_init; + +return (y0 + T(2) * (y2 - y1) - y3) / (T(2) * h * h * h); +} + +template +inline T derivative(const expression& e, +const std::string& variable_name, +const T& h = T(0.00000001)) +{ +const symbol_table& sym_table = e.get_symbol_table(); + +if (!sym_table.valid()) +{ +return std::numeric_limits::quiet_NaN(); +} + +details::variable_node* var = sym_table.get_variable(variable_name); + +if (var) +{ +T& x = var->ref(); +const T x_original = x; +const T result = derivative(e, x, h); +x = x_original; + +return result; +} +else +return std::numeric_limits::quiet_NaN(); +} + +template +inline T second_derivative(const expression& e, +const std::string& variable_name, +const T& h = T(0.00001)) +{ +const symbol_table& sym_table = e.get_symbol_table(); + +if (!sym_table.valid()) +{ +return std::numeric_limits::quiet_NaN(); +} + +details::variable_node* var = sym_table.get_variable(variable_name); + +if (var) +{ +T& x = var->ref(); +const T x_original = x; +const T result = second_derivative(e, x, h); +x = x_original; + +return result; +} +else +return std::numeric_limits::quiet_NaN(); +} + +template +inline T third_derivative(const expression& e, +const std::string& variable_name, +const T& h = T(0.0001)) +{ +const symbol_table& sym_table = e.get_symbol_table(); + +if (!sym_table.valid()) +{ +return std::numeric_limits::quiet_NaN(); +} + +details::variable_node* var = sym_table.get_variable(variable_name); + +if (var) +{ +T& x = var->ref(); +const T x_original = x; +const T result = third_derivative(e, x, h); +x = x_original; + +return result; +} +else +return std::numeric_limits::quiet_NaN(); +} + +/* + Note: The following 'compute' routines are simple helpers, + for quickly setting up the required pieces of code in order + to evaluate an expression. By virtue of how they operate + there will be an overhead with regards to their setup and + teardown and hence should not be used in time critical + sections of code. + Furthermore they only assume a small sub set of variables, + no string variables or user defined functions. + */ +template +inline bool compute(const std::string& expression_string, T& result) +{ +// No variables +symbol_table symbol_table; +symbol_table.add_constants(); + +expression expression; +expression.register_symbol_table(symbol_table); + +parser parser; + +if (parser.compile(expression_string,expression)) +{ +result = expression.value(); + +return true; +} +else +return false; +} + +template +inline bool compute(const std::string& expression_string, +const T& x, +T& result) +{ +// Only 'x' +static const std::string x_var("x"); + +symbol_table symbol_table; +symbol_table.add_constants(); +symbol_table.add_constant(x_var,x); + +expression expression; +expression.register_symbol_table(symbol_table); + +parser parser; + +if (parser.compile(expression_string,expression)) +{ +result = expression.value(); + +return true; +} +else +return false; +} + +template +inline bool compute(const std::string& expression_string, +const T&x, const T& y, +T& result) +{ +// Only 'x' and 'y' +static const std::string x_var("x"); +static const std::string y_var("y"); + +symbol_table symbol_table; +symbol_table.add_constants(); +symbol_table.add_constant(x_var,x); +symbol_table.add_constant(y_var,y); + +expression expression; +expression.register_symbol_table(symbol_table); + +parser parser; + +if (parser.compile(expression_string,expression)) +{ +result = expression.value(); + +return true; +} +else +return false; +} + +template +inline bool compute(const std::string& expression_string, +const T& x, const T& y, const T& z, +T& result) +{ +// Only 'x', 'y' or 'z' +static const std::string x_var("x"); +static const std::string y_var("y"); +static const std::string z_var("z"); + +symbol_table symbol_table; +symbol_table.add_constants(); +symbol_table.add_constant(x_var,x); +symbol_table.add_constant(y_var,y); +symbol_table.add_constant(z_var,z); + +expression expression; +expression.register_symbol_table(symbol_table); + +parser parser; + +if (parser.compile(expression_string,expression)) +{ +result = expression.value(); + +return true; +} +else +return false; +} + +template +class polynomial : public ifunction +{ +private: + +template +struct poly_impl { }; + +template +struct poly_impl +{ +static inline T evaluate(const Type x, +const Type c12, const Type c11, const Type c10, const Type c9, const Type c8, +const Type c7, const Type c6, const Type c5, const Type c4, const Type c3, +const Type c2, const Type c1, const Type c0) +{ +// p(x) = c_12x^12 + c_11x^11 + c_10x^10 + c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 +return ((((((((((((c12 * x + c11) * x + c10) * x + c9) * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); +} +}; + +template +struct poly_impl +{ +static inline T evaluate(const Type x, +const Type c11, const Type c10, const Type c9, const Type c8, const Type c7, +const Type c6, const Type c5, const Type c4, const Type c3, const Type c2, +const Type c1, const Type c0) +{ +// p(x) = c_11x^11 + c_10x^10 + c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 +return (((((((((((c11 * x + c10) * x + c9) * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); +} +}; + +template +struct poly_impl +{ +static inline T evaluate(const Type x, +const Type c10, const Type c9, const Type c8, const Type c7, const Type c6, +const Type c5, const Type c4, const Type c3, const Type c2, const Type c1, +const Type c0) +{ +// p(x) = c_10x^10 + c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 +return ((((((((((c10 * x + c9) * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); +} +}; + +template +struct poly_impl +{ +static inline T evaluate(const Type x, +const Type c9, const Type c8, const Type c7, const Type c6, const Type c5, +const Type c4, const Type c3, const Type c2, const Type c1, const Type c0) +{ +// p(x) = c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 +return (((((((((c9 * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); +} +}; + +template +struct poly_impl +{ +static inline T evaluate(const Type x, +const Type c8, const Type c7, const Type c6, const Type c5, const Type c4, +const Type c3, const Type c2, const Type c1, const Type c0) +{ +// p(x) = c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 +return ((((((((c8 * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); +} +}; + +template +struct poly_impl +{ +static inline T evaluate(const Type x, +const Type c7, const Type c6, const Type c5, const Type c4, const Type c3, +const Type c2, const Type c1, const Type c0) +{ +// p(x) = c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 +return (((((((c7 * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); +} +}; + +template +struct poly_impl +{ +static inline T evaluate(const Type x, +const Type c6, const Type c5, const Type c4, const Type c3, const Type c2, +const Type c1, const Type c0) +{ +// p(x) = c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 +return ((((((c6 * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); +} +}; + +template +struct poly_impl +{ +static inline T evaluate(const Type x, +const Type c5, const Type c4, const Type c3, const Type c2, +const Type c1, const Type c0) +{ +// p(x) = c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 +return (((((c5 * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); +} +}; + +template +struct poly_impl +{ +static inline T evaluate(const Type x, const Type c4, const Type c3, const Type c2, const Type c1, const Type c0) +{ +// p(x) = c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 +return ((((c4 * x + c3) * x + c2) * x + c1) * x + c0); +} +}; + +template +struct poly_impl +{ +static inline T evaluate(const Type x, const Type c3, const Type c2, const Type c1, const Type c0) +{ +// p(x) = c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 +return (((c3 * x + c2) * x + c1) * x + c0); +} +}; + +template +struct poly_impl +{ +static inline T evaluate(const Type x, const Type c2, const Type c1, const Type c0) +{ +// p(x) = c_2x^2 + c_1x^1 + c_0x^0 +return ((c2 * x + c1) * x + c0); +} +}; + +template +struct poly_impl +{ +static inline T evaluate(const Type x, const Type c1, const Type c0) +{ +// p(x) = c_1x^1 + c_0x^0 +return (c1 * x + c0); +} +}; + +public: + +using ifunction::operator(); + +polynomial() +: ifunction((N+2 <= 20) ? (N + 2) : std::numeric_limits::max()) +{ +disable_has_side_effects(*this); +} + +virtual ~polynomial() {} + +#define poly_rtrn(NN) \ + return (NN != N) ? std::numeric_limits::quiet_NaN() : + +inline virtual T operator() (const T& x, const T& c1, const T& c0) +{ +poly_rtrn(1) (poly_impl::evaluate(x, c1, c0)); +} + +inline virtual T operator() (const T& x, const T& c2, const T& c1, const T& c0) +{ +poly_rtrn(2) (poly_impl::evaluate(x, c2, c1, c0)); +} + +inline virtual T operator() (const T& x, const T& c3, const T& c2, const T& c1, const T& c0) +{ +poly_rtrn(3) (poly_impl::evaluate(x, c3, c2, c1, c0)); +} + +inline virtual T operator() (const T& x, const T& c4, const T& c3, const T& c2, const T& c1, +const T& c0) +{ +poly_rtrn(4) (poly_impl::evaluate(x, c4, c3, c2, c1, c0)); +} + +inline virtual T operator() (const T& x, const T& c5, const T& c4, const T& c3, const T& c2, +const T& c1, const T& c0) +{ +poly_rtrn(5) (poly_impl::evaluate(x, c5, c4, c3, c2, c1, c0)); +} + +inline virtual T operator() (const T& x, const T& c6, const T& c5, const T& c4, const T& c3, +const T& c2, const T& c1, const T& c0) +{ +poly_rtrn(6) (poly_impl::evaluate(x, c6, c5, c4, c3, c2, c1, c0)); +} + +inline virtual T operator() (const T& x, const T& c7, const T& c6, const T& c5, const T& c4, +const T& c3, const T& c2, const T& c1, const T& c0) +{ +poly_rtrn(7) (poly_impl::evaluate(x, c7, c6, c5, c4, c3, c2, c1, c0)); +} + +inline virtual T operator() (const T& x, const T& c8, const T& c7, const T& c6, const T& c5, +const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) +{ +poly_rtrn(8) (poly_impl::evaluate(x, c8, c7, c6, c5, c4, c3, c2, c1, c0)); +} + +inline virtual T operator() (const T& x, const T& c9, const T& c8, const T& c7, const T& c6, +const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, +const T& c0) +{ +poly_rtrn(9) (poly_impl::evaluate(x, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); +} + +inline virtual T operator() (const T& x, const T& c10, const T& c9, const T& c8, const T& c7, +const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, +const T& c1, const T& c0) +{ +poly_rtrn(10) (poly_impl::evaluate(x, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); +} + +inline virtual T operator() (const T& x, const T& c11, const T& c10, const T& c9, const T& c8, +const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, +const T& c2, const T& c1, const T& c0) +{ +poly_rtrn(11) (poly_impl::evaluate(x, c11, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); +} + +inline virtual T operator() (const T& x, const T& c12, const T& c11, const T& c10, const T& c9, +const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, +const T& c3, const T& c2, const T& c1, const T& c0) +{ +poly_rtrn(12) (poly_impl::evaluate(x, c12, c11, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); +} + +#undef poly_rtrn + +inline virtual T operator() () +{ +return std::numeric_limits::quiet_NaN(); +} + +inline virtual T operator() (const T&) +{ +return std::numeric_limits::quiet_NaN(); +} + +inline virtual T operator() (const T&, const T&) +{ +return std::numeric_limits::quiet_NaN(); +} +}; + +template +class function_compositor +{ +public: + +typedef exprtk::expression expression_t; +typedef exprtk::symbol_table symbol_table_t; +typedef exprtk::parser parser_t; +typedef typename parser_t::settings_store settings_t; + +struct function +{ +function() +{} + +function(const std::string& n) +: name_(n) +{} + +function(const std::string& name, +const std::string& expression) +: name_(name) +, expression_(expression) +{} + +function(const std::string& name, +const std::string& expression, +const std::string& v0) +: name_(name) +, expression_(expression) +{ +v_.push_back(v0); +} + +function(const std::string& name, +const std::string& expression, +const std::string& v0, const std::string& v1) +: name_(name) +, expression_(expression) +{ +v_.push_back(v0); v_.push_back(v1); +} + +function(const std::string& name, +const std::string& expression, +const std::string& v0, const std::string& v1, +const std::string& v2) +: name_(name) +, expression_(expression) +{ +v_.push_back(v0); v_.push_back(v1); +v_.push_back(v2); +} + +function(const std::string& name, +const std::string& expression, +const std::string& v0, const std::string& v1, +const std::string& v2, const std::string& v3) +: name_(name) +, expression_(expression) +{ +v_.push_back(v0); v_.push_back(v1); +v_.push_back(v2); v_.push_back(v3); +} + +function(const std::string& name, +const std::string& expression, +const std::string& v0, const std::string& v1, +const std::string& v2, const std::string& v3, +const std::string& v4) +: name_(name) +, expression_(expression) +{ +v_.push_back(v0); v_.push_back(v1); +v_.push_back(v2); v_.push_back(v3); +v_.push_back(v4); +} + +inline function& name(const std::string& n) +{ +name_ = n; +return (*this); +} + +inline function& expression(const std::string& e) +{ +expression_ = e; +return (*this); +} + +inline function& var(const std::string& v) +{ +v_.push_back(v); +return (*this); +} + +std::string name_; +std::string expression_; +std::deque v_; +}; + +private: + +struct base_func : public exprtk::ifunction +{ +typedef const T& type; +typedef exprtk::ifunction function_t; +typedef std::vector varref_t; +typedef std::vector var_t; +typedef std::pair lvarref_t; +typedef std::vector lvr_vec_t; + +using exprtk::ifunction::operator(); + +base_func(const std::size_t& pc = 0) +: exprtk::ifunction(pc) +, local_var_stack_size(0) +, stack_depth(0) +{ +v.resize(pc); +} + +virtual ~base_func() {} + +#define exprtk_assign(Index) \ + (*v[Index]) = v##Index; \ + +inline void update(const T& v0) +{ +exprtk_assign(0) +} + +inline void update(const T& v0, const T& v1) +{ +exprtk_assign(0) exprtk_assign(1) +} + +inline void update(const T& v0, const T& v1, const T& v2) +{ +exprtk_assign(0) exprtk_assign(1) +exprtk_assign(2) +} + +inline void update(const T& v0, const T& v1, const T& v2, const T& v3) +{ +exprtk_assign(0) exprtk_assign(1) +exprtk_assign(2) exprtk_assign(3) +} + +inline void update(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4) +{ +exprtk_assign(0) exprtk_assign(1) +exprtk_assign(2) exprtk_assign(3) +exprtk_assign(4) +} + +inline void update(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) +{ +exprtk_assign(0) exprtk_assign(1) +exprtk_assign(2) exprtk_assign(3) +exprtk_assign(4) exprtk_assign(5) +} + +#ifdef exprtk_assign +#undef exprtk_assign +#endif + +inline function_t& setup(expression_t& expr) +{ +expression = expr; + +typedef typename expression_t::control_block::local_data_list_t ldl_t; + +const ldl_t ldl = expr.local_data_list(); + +std::vector index_list; + +for (std::size_t i = 0; i < ldl.size(); ++i) +{ +if (ldl[i].size) +{ +index_list.push_back(i); +} +} + +std::size_t input_param_count = 0; + +for (std::size_t i = 0; i < index_list.size(); ++i) +{ +const std::size_t index = index_list[i]; + +if (i < (index_list.size() - v.size())) +{ +lv.push_back( +std::make_pair( +reinterpret_cast(ldl[index].pointer), +ldl[index].size)); + +local_var_stack_size += ldl[index].size; +} +else +v[input_param_count++] = reinterpret_cast(ldl[index].pointer); +} + +clear_stack(); + +return (*this); +} + +inline void pre() +{ +if (stack_depth++) +{ +if (!v.empty()) +{ +var_t var_stack(v.size(),T(0)); +copy(v,var_stack); +param_stack.push_back(var_stack); +} + +if (!lv.empty()) +{ +var_t local_var_stack(local_var_stack_size,T(0)); +copy(lv,local_var_stack); +local_stack.push_back(local_var_stack); +} +} +} + +inline void post() +{ +if (--stack_depth) +{ +if (!v.empty()) +{ +copy(param_stack.back(),v); +param_stack.pop_back(); +} + +if (!lv.empty()) +{ +copy(local_stack.back(),lv); +local_stack.pop_back(); +} +} +} + +void copy(const varref_t& src_v, var_t& dest_v) +{ +for (std::size_t i = 0; i < src_v.size(); ++i) +{ +dest_v[i] = (*src_v[i]); +} +} + +void copy(const var_t& src_v, varref_t& dest_v) +{ +for (std::size_t i = 0; i < src_v.size(); ++i) +{ +(*dest_v[i]) = src_v[i]; +} +} + +void copy(const lvr_vec_t& src_v, var_t& dest_v) +{ +typename var_t::iterator itr = dest_v.begin(); +typedef typename std::iterator_traits::difference_type diff_t; + +for (std::size_t i = 0; i < src_v.size(); ++i) +{ +lvarref_t vr = src_v[i]; + +if (1 == vr.second) +*itr++ = (*vr.first); +else +{ +std::copy(vr.first, vr.first + vr.second, itr); +itr += static_cast(vr.second); +} +} +} + +void copy(const var_t& src_v, lvr_vec_t& dest_v) +{ +typename var_t::const_iterator itr = src_v.begin(); +typedef typename std::iterator_traits::difference_type diff_t; + +for (std::size_t i = 0; i < src_v.size(); ++i) +{ +lvarref_t vr = dest_v[i]; + +if (1 == vr.second) +(*vr.first) = *itr++; +else +{ +std::copy(itr, itr + static_cast(vr.second), vr.first); +itr += static_cast(vr.second); +} +} +} + +inline void clear_stack() +{ +for (std::size_t i = 0; i < v.size(); ++i) +{ +(*v[i]) = 0; +} +} + +inline virtual T value(expression_t& e) +{ +return e.value(); +} + +expression_t expression; +varref_t v; +lvr_vec_t lv; +std::size_t local_var_stack_size; +std::size_t stack_depth; +std::deque param_stack; +std::deque local_stack; +}; + +typedef std::map funcparam_t; + +struct func_0param : public base_func +{ +using exprtk::ifunction::operator(); + +func_0param() : base_func(0) {} + +inline T operator() () +{ +return this->value(base_func::expression); +} +}; + +typedef const T& type; + +template +struct scoped_bft +{ +explicit scoped_bft(BaseFuncType& bft) +: bft_(bft) +{ +bft_.pre (); +} + +~scoped_bft() +{ +bft_.post(); +} + +BaseFuncType& bft_; + +private: + +scoped_bft(const scoped_bft&) exprtk_delete; +scoped_bft& operator=(const scoped_bft&) exprtk_delete; +}; + +struct func_1param : public base_func +{ +using exprtk::ifunction::operator(); + +func_1param() : base_func(1) {} + +inline T operator() (type v0) +{ +scoped_bft sb(*this); +base_func::update(v0); +return this->value(base_func::expression); +} +}; + +struct func_2param : public base_func +{ +using exprtk::ifunction::operator(); + +func_2param() : base_func(2) {} + +inline T operator() (type v0, type v1) +{ +scoped_bft sb(*this); +base_func::update(v0, v1); +return this->value(base_func::expression); +} +}; + +struct func_3param : public base_func +{ +using exprtk::ifunction::operator(); + +func_3param() : base_func(3) {} + +inline T operator() (type v0, type v1, type v2) +{ +scoped_bft sb(*this); +base_func::update(v0, v1, v2); +return this->value(base_func::expression); +} +}; + +struct func_4param : public base_func +{ +using exprtk::ifunction::operator(); + +func_4param() : base_func(4) {} + +inline T operator() (type v0, type v1, type v2, type v3) +{ +scoped_bft sb(*this); +base_func::update(v0, v1, v2, v3); +return this->value(base_func::expression); +} +}; + +struct func_5param : public base_func +{ +using exprtk::ifunction::operator(); + +func_5param() : base_func(5) {} + +inline T operator() (type v0, type v1, type v2, type v3, type v4) +{ +scoped_bft sb(*this); +base_func::update(v0, v1, v2, v3, v4); +return this->value(base_func::expression); +} +}; + +struct func_6param : public base_func +{ +using exprtk::ifunction::operator(); + +func_6param() : base_func(6) {} + +inline T operator() (type v0, type v1, type v2, type v3, type v4, type v5) +{ +scoped_bft sb(*this); +base_func::update(v0, v1, v2, v3, v4, v5); +return this->value(base_func::expression); +} +}; + +static T return_value(expression_t& e) +{ +typedef exprtk::results_context results_context_t; +typedef typename results_context_t::type_store_t type_t; +typedef typename type_t::scalar_view scalar_t; + +const T result = e.value(); + +if (e.return_invoked()) +{ +// Due to the post compilation checks, it can be safely +// assumed that there will be at least one parameter +// and that the first parameter will always be scalar. +return scalar_t(e.results()[0])(); +} + +return result; +} + +#define def_fp_retval(N) \ + struct func_##N##param_retval : public func_##N##param \ + { \ + inline T value(expression_t& e) \ + { \ + return return_value(e); \ + } \ + }; \ + +def_fp_retval(0) +def_fp_retval(1) +def_fp_retval(2) +def_fp_retval(3) +def_fp_retval(4) +def_fp_retval(5) +def_fp_retval(6) + +template class Sequence> +inline bool add(const std::string& name, +const std::string& expression, +const Sequence& var_list, +const bool override = false) +{ +const typename std::map::iterator itr = expr_map_.find(name); + +if (expr_map_.end() != itr) +{ +if (!override) +{ +exprtk_debug(("Compositor error(add): function '%s' already defined\n", +name.c_str())); + +return false; +} + +remove(name, var_list.size()); +} + +if (compile_expression(name, expression, var_list)) +{ +const std::size_t n = var_list.size(); + +fp_map_[n][name]->setup(expr_map_[name]); + +return true; +} +else +{ +exprtk_debug(("Compositor error(add): Failed to compile function '%s'\n", +name.c_str())); + +return false; +} +} + +public: + +function_compositor() +: parser_(settings_t::compile_all_opts + +settings_t::e_disable_zero_return) +, fp_map_(7) +{} + +function_compositor(const symbol_table_t& st) +: symbol_table_(st) +, parser_(settings_t::compile_all_opts + +settings_t::e_disable_zero_return) +, fp_map_(7) +{} + +~function_compositor() +{ +clear(); +} + +inline symbol_table_t& symbol_table() +{ +return symbol_table_; +} + +inline const symbol_table_t& symbol_table() const +{ +return symbol_table_; +} + +inline void add_auxiliary_symtab(symbol_table_t& symtab) +{ +auxiliary_symtab_list_.push_back(&symtab); +} + +void clear() +{ +symbol_table_.clear(); +expr_map_ .clear(); + +for (std::size_t i = 0; i < fp_map_.size(); ++i) +{ +typename funcparam_t::iterator itr = fp_map_[i].begin(); +typename funcparam_t::iterator end = fp_map_[i].end (); + +while (itr != end) +{ +delete itr->second; +++itr; +} + +fp_map_[i].clear(); +} +} + +inline bool add(const function& f, const bool override = false) +{ +return add(f.name_, f.expression_, f.v_,override); +} + +private: + +template class Sequence> +bool compile_expression(const std::string& name, +const std::string& expression, +const Sequence& input_var_list, +bool return_present = false) +{ +expression_t compiled_expression; +symbol_table_t local_symbol_table; + +local_symbol_table.load_from(symbol_table_); +local_symbol_table.add_constants(); + +if (!valid(name,input_var_list.size())) +return false; + +if (!forward(name, +input_var_list.size(), +local_symbol_table, +return_present)) +return false; + +compiled_expression.register_symbol_table(local_symbol_table); + +for (std::size_t i = 0; i < auxiliary_symtab_list_.size(); ++i) +{ +compiled_expression.register_symbol_table((*auxiliary_symtab_list_[i])); +} + +std::string mod_expression; + +for (std::size_t i = 0; i < input_var_list.size(); ++i) +{ +mod_expression += " var " + input_var_list[i] + "{};\n"; +} + +if ( +('{' == details::front(expression)) && +('}' == details::back (expression)) +) +mod_expression += "~" + expression + ";"; +else +mod_expression += "~{" + expression + "};"; + +if (!parser_.compile(mod_expression,compiled_expression)) +{ +exprtk_debug(("Compositor Error: %s\n",parser_.error().c_str())); +exprtk_debug(("Compositor modified expression: \n%s\n",mod_expression.c_str())); + +remove(name,input_var_list.size()); + +return false; +} + +if (!return_present && parser_.dec().return_present()) +{ +remove(name,input_var_list.size()); + +return compile_expression(name, expression, input_var_list, true); +} + +// Make sure every return point has a scalar as its first parameter +if (parser_.dec().return_present()) +{ +typedef std::vector str_list_t; + +str_list_t ret_param_list = parser_.dec().return_param_type_list(); + +for (std::size_t i = 0; i < ret_param_list.size(); ++i) +{ +const std::string& params = ret_param_list[i]; + +if (params.empty() || ('T' != params[0])) +{ +exprtk_debug(("Compositor Error: Return statement in function '%s' is invalid\n", +name.c_str())); + +remove(name,input_var_list.size()); + +return false; +} +} +} + +expr_map_[name] = compiled_expression; + +exprtk::ifunction& ifunc = (*(fp_map_[input_var_list.size()])[name]); + +if (symbol_table_.add_function(name,ifunc)) +return true; +else +{ +exprtk_debug(("Compositor Error: Failed to add function '%s' to symbol table\n", +name.c_str())); +return false; +} +} + +inline bool symbol_used(const std::string& symbol) const +{ +return ( +symbol_table_.is_variable (symbol) || +symbol_table_.is_stringvar (symbol) || +symbol_table_.is_function (symbol) || +symbol_table_.is_vector (symbol) || +symbol_table_.is_vararg_function(symbol) +); +} + +inline bool valid(const std::string& name, +const std::size_t& arg_count) const +{ +if (arg_count > 6) +return false; +else if (symbol_used(name)) +return false; +else if (fp_map_[arg_count].end() != fp_map_[arg_count].find(name)) +return false; +else +return true; +} + +inline bool forward(const std::string& name, +const std::size_t& arg_count, +symbol_table_t& sym_table, +const bool ret_present = false) +{ +switch (arg_count) +{ +#define case_stmt(N) \ + case N : (fp_map_[arg_count])[name] = \ + (!ret_present) ? static_cast \ + (new func_##N##param) : \ + static_cast \ + (new func_##N##param_retval) ; \ + break; \ + +case_stmt(0) case_stmt(1) case_stmt(2) +case_stmt(3) case_stmt(4) case_stmt(5) +case_stmt(6) +#undef case_stmt +} + +exprtk::ifunction& ifunc = (*(fp_map_[arg_count])[name]); + +return sym_table.add_function(name,ifunc); +} + +inline void remove(const std::string& name, const std::size_t& arg_count) +{ +if (arg_count > 6) +return; + +const typename std::map::iterator em_itr = expr_map_.find(name); + +if (expr_map_.end() != em_itr) +{ +expr_map_.erase(em_itr); +} + +const typename funcparam_t::iterator fp_itr = fp_map_[arg_count].find(name); + +if (fp_map_[arg_count].end() != fp_itr) +{ +delete fp_itr->second; +fp_map_[arg_count].erase(fp_itr); +} + +symbol_table_.remove_function(name); +} + +private: + +symbol_table_t symbol_table_; +parser_t parser_; +std::map expr_map_; +std::vector fp_map_; +std::vector auxiliary_symtab_list_; +}; // class function_compositor + +} // namespace exprtk + +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +# ifndef NOMINMAX +# define NOMINMAX +# endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +#else +# include +# include +# include +#endif + +namespace exprtk +{ +class timer +{ +public: + +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +timer() +: in_use_(false) +{ +QueryPerformanceFrequency(&clock_frequency_); +} + +inline void start() +{ +in_use_ = true; +QueryPerformanceCounter(&start_time_); +} + +inline void stop() +{ +QueryPerformanceCounter(&stop_time_); +in_use_ = false; +} + +inline double time() const +{ +return (1.0 * (stop_time_.QuadPart - start_time_.QuadPart)) / (1.0 * clock_frequency_.QuadPart); +} + +#else + +timer() +: in_use_(false) +{ +start_time_.tv_sec = 0; +start_time_.tv_usec = 0; + +stop_time_.tv_sec = 0; +stop_time_.tv_usec = 0; +} + +inline void start() +{ +in_use_ = true; +gettimeofday(&start_time_,0); +} + +inline void stop() +{ +gettimeofday(&stop_time_, 0); +in_use_ = false; +} + +inline unsigned long long int usec_time() const +{ +if (!in_use_) +{ +if (stop_time_.tv_sec >= start_time_.tv_sec) +{ +return 1000000LLU * static_cast(stop_time_.tv_sec - start_time_.tv_sec ) + +static_cast(stop_time_.tv_usec - start_time_.tv_usec) ; +} +else +return std::numeric_limits::max(); +} +else +return std::numeric_limits::max(); +} + +inline double time() const +{ +return usec_time() * 0.000001; +} + +#endif + +inline bool in_use() const +{ +return in_use_; +} + +private: + +bool in_use_; + +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +LARGE_INTEGER start_time_; +LARGE_INTEGER stop_time_; +LARGE_INTEGER clock_frequency_; +#else +struct timeval start_time_; +struct timeval stop_time_; +#endif +}; + +template +struct type_defs +{ +typedef symbol_table symbol_table_t; +typedef expression expression_t; +typedef parser parser_t; +typedef parser_error::type error_t; +typedef function_compositor compositor_t; +typedef typename compositor_t::function function_t; +}; + +} // namespace exprtk + +#ifndef exprtk_disable_rtl_io +namespace exprtk +{ +namespace rtl { namespace io { namespace details +{ +template +inline void print_type(const std::string& fmt, +const T v, +exprtk::details::numeric::details::real_type_tag) +{ +printf(fmt.c_str(),v); +} + +template +struct print_impl +{ +typedef typename igeneric_function::generic_type generic_type; +typedef typename igeneric_function::parameter_list_t parameter_list_t; +typedef typename generic_type::scalar_view scalar_t; +typedef typename generic_type::vector_view vector_t; +typedef typename generic_type::string_view string_t; +typedef typename exprtk::details::numeric::details::number_type::type num_type; + +static void process(const std::string& scalar_format, parameter_list_t parameters) +{ +for (std::size_t i = 0; i < parameters.size(); ++i) +{ +generic_type& gt = parameters[i]; + +switch (gt.type) +{ +case generic_type::e_scalar : print(scalar_format,scalar_t(gt)); +break; + +case generic_type::e_vector : print(scalar_format,vector_t(gt)); +break; + +case generic_type::e_string : print(string_t(gt)); +break; + +default : continue; +} +} +} + +static inline void print(const std::string& scalar_format, const scalar_t& s) +{ +print_type(scalar_format,s(),num_type()); +} + +static inline void print(const std::string& scalar_format, const vector_t& v) +{ +for (std::size_t i = 0; i < v.size(); ++i) +{ +print_type(scalar_format,v[i],num_type()); + +if ((i + 1) < v.size()) +printf(" "); +} +} + +static inline void print(const string_t& s) +{ +printf("%s",to_str(s).c_str()); +} +}; + +} // namespace exprtk::rtl::io::details + +template +struct print : public exprtk::igeneric_function +{ +typedef typename igeneric_function::parameter_list_t parameter_list_t; + +using exprtk::igeneric_function::operator(); + +print(const std::string& scalar_format = "%10.5f") +: scalar_format_(scalar_format) +{ +exprtk::enable_zero_parameters(*this); +} + +inline T operator() (parameter_list_t parameters) +{ +details::print_impl::process(scalar_format_,parameters); +return T(0); +} + +std::string scalar_format_; +}; + +template +struct println : public exprtk::igeneric_function +{ +typedef typename igeneric_function::parameter_list_t parameter_list_t; + +using exprtk::igeneric_function::operator(); + +println(const std::string& scalar_format = "%10.5f") +: scalar_format_(scalar_format) +{ +exprtk::enable_zero_parameters(*this); +} + +inline T operator() (parameter_list_t parameters) +{ +details::print_impl::process(scalar_format_,parameters); +printf("\n"); +return T(0); +} + +std::string scalar_format_; +}; + +template +struct package +{ +print p; +println pl; + +bool register_package(exprtk::symbol_table& symtab) +{ +#define exprtk_register_function(FunctionName, FunctionType) \ + if (!symtab.add_function(FunctionName,FunctionType)) \ + { \ + exprtk_debug(( \ + "exprtk::rtl::io::register_package - Failed to add function: %s\n", \ + FunctionName)); \ + return false; \ + } \ + +exprtk_register_function("print" , p ) +exprtk_register_function("println", pl) +#undef exprtk_register_function + +return true; +} +}; + +} // namespace exprtk::rtl::io +} // namespace exprtk::rtl +} // namespace exprtk +#endif + +#ifndef exprtk_disable_rtl_io_file +#include +namespace exprtk +{ +namespace rtl { namespace io { namespace file { namespace details +{ +using ::exprtk::details::char_ptr; +using ::exprtk::details::char_cptr; + +enum file_mode +{ +e_error = 0, +e_read = 1, +e_write = 2, +e_rdwrt = 4 +}; + +struct file_descriptor +{ +file_descriptor(const std::string& fname, const std::string& access) +: stream_ptr(0) +, mode(get_file_mode(access)) +, file_name(fname) +{} + +void* stream_ptr; +file_mode mode; +std::string file_name; + +bool open() +{ +if (e_read == mode) +{ +std::ifstream* stream = new std::ifstream(file_name.c_str(),std::ios::binary); + +if (!(*stream)) +{ +file_name.clear(); +delete stream; + +return false; +} +else +stream_ptr = stream; + +return true; +} +else if (e_write == mode) +{ +std::ofstream* stream = new std::ofstream(file_name.c_str(),std::ios::binary); + +if (!(*stream)) +{ +file_name.clear(); +delete stream; + +return false; +} +else +stream_ptr = stream; + +return true; +} +else if (e_rdwrt == mode) +{ +std::fstream* stream = new std::fstream(file_name.c_str(),std::ios::binary); + +if (!(*stream)) +{ +file_name.clear(); +delete stream; + +return false; +} +else +stream_ptr = stream; + +return true; +} +else +return false; +} + +template +void close(Ptr& p) +{ +Stream* stream = reinterpret_cast(p); +stream->close(); +delete stream; +p = reinterpret_cast(0); +} + +bool close() +{ +switch (mode) +{ +case e_read : close(stream_ptr); +break; + +case e_write : close(stream_ptr); +break; + +case e_rdwrt : close (stream_ptr); +break; + +default : return false; +} + +return true; +} + +template +bool write(const View& view, const std::size_t amount, const std::size_t offset = 0) +{ +switch (mode) +{ +case e_write : reinterpret_cast(stream_ptr)-> +write(reinterpret_cast(view.begin() + offset), amount * sizeof(typename View::value_t)); +break; + +case e_rdwrt : reinterpret_cast(stream_ptr)-> +write(reinterpret_cast(view.begin() + offset) , amount * sizeof(typename View::value_t)); +break; + +default : return false; +} + +return true; +} + +template +bool read(View& view, const std::size_t amount, const std::size_t offset = 0) +{ +switch (mode) +{ +case e_read : reinterpret_cast(stream_ptr)-> +read(reinterpret_cast(view.begin() + offset), amount * sizeof(typename View::value_t)); +break; + +case e_rdwrt : reinterpret_cast(stream_ptr)-> +read(reinterpret_cast(view.begin() + offset) , amount * sizeof(typename View::value_t)); +break; + +default : return false; +} + +return true; +} + +bool getline(std::string& s) +{ +switch (mode) +{ +case e_read : return (!!std::getline(*reinterpret_cast(stream_ptr),s)); +case e_rdwrt : return (!!std::getline(*reinterpret_cast(stream_ptr),s)); +default : return false; +} +} + +bool eof() const +{ +switch (mode) +{ +case e_read : return reinterpret_cast(stream_ptr)->eof(); +case e_write : return reinterpret_cast(stream_ptr)->eof(); +case e_rdwrt : return reinterpret_cast(stream_ptr)->eof(); +default : return true; +} +} + +file_mode get_file_mode(const std::string& access) const +{ +if (access.empty() || access.size() > 2) +return e_error; + +std::size_t w_cnt = 0; +std::size_t r_cnt = 0; + +for (std::size_t i = 0; i < access.size(); ++i) +{ +switch (std::tolower(access[i])) +{ +case 'r' : r_cnt++; break; +case 'w' : w_cnt++; break; +default : return e_error; +} +} + +if ((0 == r_cnt) && (0 == w_cnt)) +return e_error; +else if ((r_cnt > 1) || (w_cnt > 1)) +return e_error; +else if ((1 == r_cnt) && (1 == w_cnt)) +return e_rdwrt; +else if (1 == r_cnt) +return e_read; +else +return e_write; +} +}; + +template +file_descriptor* make_handle(T v) +{ +const std::size_t fd_size = sizeof(details::file_descriptor*); +details::file_descriptor* fd = reinterpret_cast(0); + +std::memcpy(reinterpret_cast(&fd), +reinterpret_cast(&v ), +fd_size); +return fd; +} + +template +void perform_check() +{ +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif +if (sizeof(T) < sizeof(void*)) +{ +throw std::runtime_error("exprtk::rtl::io::file - Error - pointer size larger than holder."); +} +#ifdef _MSC_VER +#pragma warning(pop) +#endif +} + +} // namespace exprtk::rtl::io::file::details + +template +class open : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::string_view string_t; + +using exprtk::igeneric_function::operator(); + +open() +: exprtk::igeneric_function("S|SS") +{ details::perform_check(); } + +inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) +{ +const std::string file_name = to_str(string_t(parameters[0])); + +if (file_name.empty()) +return T(0); + +if ((1 == ps_index) && (0 == string_t(parameters[1]).size())) +{ +return T(0); +} + +const std::string access = +(0 == ps_index) ? "r" : to_str(string_t(parameters[1])); + +details::file_descriptor* fd = new details::file_descriptor(file_name,access); + +if (fd->open()) +{ +T t = T(0); + +const std::size_t fd_size = sizeof(details::file_descriptor*); + +std::memcpy(reinterpret_cast(&t ), +reinterpret_cast(&fd), +fd_size); +return t; +} +else +{ +delete fd; +return T(0); +} +} +}; + +template +struct close : public exprtk::ifunction +{ +using exprtk::ifunction::operator(); + +close() +: exprtk::ifunction(1) +{ details::perform_check(); } + +inline T operator() (const T& v) +{ +details::file_descriptor* fd = details::make_handle(v); + +if (!fd->close()) +return T(0); + +delete fd; + +return T(1); +} +}; + +template +class write : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::string_view string_t; +typedef typename generic_type::scalar_view scalar_t; +typedef typename generic_type::vector_view vector_t; + +using exprtk::igeneric_function::operator(); + +write() +: igfun_t("TS|TST|TV|TVT") +{ details::perform_check(); } + +inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) +{ +details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); + +switch (ps_index) +{ +case 0 : { +const string_t buffer(parameters[1]); +const std::size_t amount = buffer.size(); +return T(fd->write(buffer, amount) ? 1 : 0); +} + +case 1 : { +const string_t buffer(parameters[1]); +const std::size_t amount = +std::min(buffer.size(), +static_cast(scalar_t(parameters[2])())); +return T(fd->write(buffer, amount) ? 1 : 0); +} + +case 2 : { +const vector_t vec(parameters[1]); +const std::size_t amount = vec.size(); +return T(fd->write(vec, amount) ? 1 : 0); +} + +case 3 : { +const vector_t vec(parameters[1]); +const std::size_t amount = +std::min(vec.size(), +static_cast(scalar_t(parameters[2])())); +return T(fd->write(vec, amount) ? 1 : 0); +} +} + +return T(0); +} +}; + +template +class read : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::string_view string_t; +typedef typename generic_type::scalar_view scalar_t; +typedef typename generic_type::vector_view vector_t; + +using exprtk::igeneric_function::operator(); + +read() +: igfun_t("TS|TST|TV|TVT") +{ details::perform_check(); } + +inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) +{ +details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); + +switch (ps_index) +{ +case 0 : { +string_t buffer(parameters[1]); +const std::size_t amount = buffer.size(); +return T(fd->read(buffer,amount) ? 1 : 0); +} + +case 1 : { +string_t buffer(parameters[1]); +const std::size_t amount = +std::min(buffer.size(), +static_cast(scalar_t(parameters[2])())); +return T(fd->read(buffer,amount) ? 1 : 0); +} + +case 2 : { +vector_t vec(parameters[1]); +const std::size_t amount = vec.size(); +return T(fd->read(vec,amount) ? 1 : 0); +} + +case 3 : { +vector_t vec(parameters[1]); +const std::size_t amount = +std::min(vec.size(), +static_cast(scalar_t(parameters[2])())); +return T(fd->read(vec,amount) ? 1 : 0); +} +} + +return T(0); +} +}; + +template +class getline : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::string_view string_t; +typedef typename generic_type::scalar_view scalar_t; + +using exprtk::igeneric_function::operator(); + +getline() +: igfun_t("T",igfun_t::e_rtrn_string) +{ details::perform_check(); } + +inline T operator() (std::string& result, +parameter_list_t parameters) +{ +details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); +return T(fd->getline(result) ? 1 : 0); +} +}; + +template +struct eof : public exprtk::ifunction +{ +using exprtk::ifunction::operator(); + +eof() +: exprtk::ifunction(1) +{ details::perform_check(); } + +inline T operator() (const T& v) +{ +details::file_descriptor* fd = details::make_handle(v); + +return (fd->eof() ? T(1) : T(0)); +} +}; + +template +struct package +{ +open o; +close c; +write w; +read r; +getline g; +eof e; + +bool register_package(exprtk::symbol_table& symtab) +{ +#define exprtk_register_function(FunctionName, FunctionType) \ + if (!symtab.add_function(FunctionName,FunctionType)) \ + { \ + exprtk_debug(( \ + "exprtk::rtl::io::file::register_package - Failed to add function: %s\n", \ + FunctionName)); \ + return false; \ + } \ + +exprtk_register_function("open" , o) +exprtk_register_function("close" , c) +exprtk_register_function("write" , w) +exprtk_register_function("read" , r) +exprtk_register_function("getline" , g) +exprtk_register_function("eof" , e) +#undef exprtk_register_function + +return true; +} +}; + +} // namespace exprtk::rtl::io::file +} // namespace exprtk::rtl::io +} // namespace exprtk::rtl +} // namespace exprtk +#endif + +#ifndef exprtk_disable_rtl_vecops +namespace exprtk +{ +namespace rtl { namespace vecops { + +namespace helper +{ +template +inline bool invalid_range(const Vector& v, const std::size_t r0, const std::size_t r1) +{ +if (r0 > (v.size() - 1)) +return true; +else if (r1 > (v.size() - 1)) +return true; +else if (r1 < r0) +return true; +else +return false; +} + +template +struct load_vector_range +{ +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::scalar_view scalar_t; +typedef typename generic_type::vector_view vector_t; + +static inline bool process(parameter_list_t& parameters, +std::size_t& r0, std::size_t& r1, +const std::size_t& r0_prmidx, +const std::size_t& r1_prmidx, +const std::size_t vec_idx = 0) +{ +if (r0_prmidx >= parameters.size()) +return false; + +if (r1_prmidx >= parameters.size()) +return false; + +if (!scalar_t(parameters[r0_prmidx]).to_uint(r0)) +return false; + +if (!scalar_t(parameters[r1_prmidx]).to_uint(r1)) +return false; + +return !invalid_range(vector_t(parameters[vec_idx]), r0, r1); +} +}; +} + +namespace details +{ +template +inline void kahan_sum(T& sum, T& error, const T v) +{ +const T x = v - error; +const T y = sum + x; +error = (y - sum) - x; +sum = y; +} + +} // namespace exprtk::rtl::details + +template +class all_true : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::vector_view vector_t; + +using exprtk::igeneric_function::operator(); + +all_true() +: exprtk::igeneric_function("V|VTT") +/* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ +{} + +inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) +{ +const vector_t vec(parameters[0]); + +std::size_t r0 = 0; +std::size_t r1 = vec.size() - 1; + +if ( +(1 == ps_index) && +!helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) +) +return std::numeric_limits::quiet_NaN(); + +for (std::size_t i = r0; i <= r1; ++i) +{ +if (vec[i] == T(0)) +{ +return T(0); +} +} + +return T(1); +} +}; + +template +class all_false : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::vector_view vector_t; + +using exprtk::igeneric_function::operator(); + +all_false() +: exprtk::igeneric_function("V|VTT") +/* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ +{} + +inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) +{ +const vector_t vec(parameters[0]); + +std::size_t r0 = 0; +std::size_t r1 = vec.size() - 1; + +if ( +(1 == ps_index) && +!helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) +) +return std::numeric_limits::quiet_NaN(); + +for (std::size_t i = r0; i <= r1; ++i) +{ +if (vec[i] != T(0)) +{ +return T(0); +} +} + +return T(1); +} +}; + +template +class any_true : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::vector_view vector_t; + +using exprtk::igeneric_function::operator(); + +any_true() +: exprtk::igeneric_function("V|VTT") +/* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ +{} + +inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) +{ +const vector_t vec(parameters[0]); + +std::size_t r0 = 0; +std::size_t r1 = vec.size() - 1; + +if ( +(1 == ps_index) && +!helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) +) +return std::numeric_limits::quiet_NaN(); + +for (std::size_t i = r0; i <= r1; ++i) +{ +if (vec[i] != T(0)) +{ +return T(1); +} +} + +return T(0); +} +}; + +template +class any_false : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::vector_view vector_t; + +using exprtk::igeneric_function::operator(); + +any_false() +: exprtk::igeneric_function("V|VTT") +/* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ +{} + +inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) +{ +const vector_t vec(parameters[0]); + +std::size_t r0 = 0; +std::size_t r1 = vec.size() - 1; + +if ( +(1 == ps_index) && +!helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) +) +return std::numeric_limits::quiet_NaN(); + +for (std::size_t i = r0; i <= r1; ++i) +{ +if (vec[i] == T(0)) +{ +return T(1); +} +} + +return T(0); +} +}; + +template +class count : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::vector_view vector_t; + +using exprtk::igeneric_function::operator(); + +count() +: exprtk::igeneric_function("V|VTT") +/* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ +{} + +inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) +{ +const vector_t vec(parameters[0]); + +std::size_t r0 = 0; +std::size_t r1 = vec.size() - 1; + +if ( +(1 == ps_index) && +!helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) +) +return std::numeric_limits::quiet_NaN(); + +std::size_t cnt = 0; + +for (std::size_t i = r0; i <= r1; ++i) +{ +if (vec[i] != T(0)) ++cnt; +} + +return T(cnt); +} +}; + +template +class copy : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::scalar_view scalar_t; +typedef typename generic_type::vector_view vector_t; + +using exprtk::igeneric_function::operator(); + +copy() +: exprtk::igeneric_function("VV|VTTVTT") +/* + Overloads: + 0. VV - x(vector), y(vector) + 1. VTTVTT - x(vector), xr0, xr1, y(vector), yr0, yr1, + */ +{} + +inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) +{ +const vector_t x(parameters[0]); +vector_t y(parameters[(0 == ps_index) ? 1 : 3]); + +std::size_t xr0 = 0; +std::size_t xr1 = x.size() - 1; + +std::size_t yr0 = 0; +std::size_t yr1 = y.size() - 1; + +if (1 == ps_index) +{ +if ( +!helper::load_vector_range::process(parameters, xr0, xr1, 1, 2, 0) || +!helper::load_vector_range::process(parameters, yr0, yr1, 4, 5, 3) +) +return T(0); +} + +const std::size_t n = std::min(xr1 - xr0 + 1, yr1 - yr0 + 1); + +std::copy( +x.begin() + xr0, +x.begin() + xr0 + n, +y.begin() + yr0); + +return T(n); +} +}; + +template +class rol : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::scalar_view scalar_t; +typedef typename generic_type::vector_view vector_t; + +using exprtk::igeneric_function::operator(); + +rol() +: exprtk::igeneric_function("VT|VTTT") +/* + Overloads: + 0. VT - vector, N + 1. VTTT - vector, N, r0, r1 + */ +{} + +inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) +{ +vector_t vec(parameters[0]); + +std::size_t n = 0; +std::size_t r0 = 0; +std::size_t r1 = vec.size() - 1; + +if (!scalar_t(parameters[1]).to_uint(n)) +return T(0); + +if ( +(1 == ps_index) && +!helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0) +) +return T(0); + +const std::size_t dist = r1 - r0 + 1; +const std::size_t shift = n % dist; + +std::rotate( +vec.begin() + r0, +vec.begin() + r0 + shift, +vec.begin() + r1 + 1); + +return T(1); +} +}; + +template +class ror : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::scalar_view scalar_t; +typedef typename generic_type::vector_view vector_t; + +using exprtk::igeneric_function::operator(); + +ror() +: exprtk::igeneric_function("VT|VTTT") +/* + Overloads: + 0. VT - vector, N + 1. VTTT - vector, N, r0, r1 + */ +{} + +inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) +{ +vector_t vec(parameters[0]); + +std::size_t n = 0; +std::size_t r0 = 0; +std::size_t r1 = vec.size() - 1; + +if (!scalar_t(parameters[1]).to_uint(n)) +return T(0); + +if ( +(1 == ps_index) && +!helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0) +) +return T(0); + +std::size_t dist = r1 - r0 + 1; +std::size_t shift = (dist - (n % dist)) % dist; + +std::rotate( +vec.begin() + r0, +vec.begin() + r0 + shift, +vec.begin() + r1 + 1); + +return T(1); +} +}; + +template +class shift_left : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::scalar_view scalar_t; +typedef typename generic_type::vector_view vector_t; + +using exprtk::igeneric_function::operator(); + +shift_left() +: exprtk::igeneric_function("VT|VTTT") +/* + Overloads: + 0. VT - vector, N + 1. VTTT - vector, N, r0, r1 + */ +{} + +inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) +{ +vector_t vec(parameters[0]); + +std::size_t n = 0; +std::size_t r0 = 0; +std::size_t r1 = vec.size() - 1; + +if (!scalar_t(parameters[1]).to_uint(n)) +return T(0); + +if ( +(1 == ps_index) && +!helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0) +) +return T(0); + +const std::size_t dist = r1 - r0 + 1; + +if (n > dist) +return T(0); + +std::rotate( +vec.begin() + r0, +vec.begin() + r0 + n, +vec.begin() + r1 + 1); + +for (std::size_t i = r1 - n + 1; i <= r1; ++i) +{ +vec[i] = T(0); +} + +return T(1); +} +}; + +template +class shift_right : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::scalar_view scalar_t; +typedef typename generic_type::vector_view vector_t; + +using exprtk::igeneric_function::operator(); + +shift_right() +: exprtk::igeneric_function("VT|VTTT") +/* + Overloads: + 0. VT - vector, N + 1. VTTT - vector, N, r0, r1 + */ +{} + +inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) +{ +vector_t vec(parameters[0]); + +std::size_t n = 0; +std::size_t r0 = 0; +std::size_t r1 = vec.size() - 1; + +if (!scalar_t(parameters[1]).to_uint(n)) +return T(0); + +if ( +(1 == ps_index) && +!helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0) +) +return T(0); + +const std::size_t dist = r1 - r0 + 1; + +if (n > dist) +return T(0); + +const std::size_t shift = (dist - (n % dist)) % dist; + +std::rotate( +vec.begin() + r0, +vec.begin() + r0 + shift, +vec.begin() + r1 + 1); + +for (std::size_t i = r0; i < r0 + n; ++i) +{ +vec[i] = T(0); +} + +return T(1); +} +}; + +template +class sort : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::string_view string_t; +typedef typename generic_type::vector_view vector_t; + +using exprtk::igeneric_function::operator(); + +sort() +: exprtk::igeneric_function("V|VTT|VS|VSTT") +/* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + 2. VS - vector, string + 3. VSTT - vector, string, r0, r1 + */ +{} + +inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) +{ +vector_t vec(parameters[0]); + +std::size_t r0 = 0; +std::size_t r1 = vec.size() - 1; + +if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0)) +return T(0); +if ((3 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0)) +return T(0); + +bool ascending = true; + +if ((2 == ps_index) || (3 == ps_index)) +{ +if (exprtk::details::imatch(to_str(string_t(parameters[1])),"ascending")) +ascending = true; +else if (exprtk::details::imatch(to_str(string_t(parameters[1])),"descending")) +ascending = false; +else +return T(0); +} + +if (ascending) +std::sort( +vec.begin() + r0, +vec.begin() + r1 + 1, +std::less()); +else +std::sort( +vec.begin() + r0, +vec.begin() + r1 + 1, +std::greater()); + +return T(1); +} +}; + +template +class nthelement : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::scalar_view scalar_t; +typedef typename generic_type::vector_view vector_t; + +using exprtk::igeneric_function::operator(); + +nthelement() +: exprtk::igeneric_function("VT|VTTT") +/* + Overloads: + 0. VT - vector, nth-element + 1. VTTT - vector, nth-element, r0, r1 + */ +{} + +inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) +{ +vector_t vec(parameters[0]); + +std::size_t n = 0; +std::size_t r0 = 0; +std::size_t r1 = vec.size() - 1; + +if (!scalar_t(parameters[1]).to_uint(n)) +return T(0); + +if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0)) +return std::numeric_limits::quiet_NaN(); + +std::nth_element( +vec.begin() + r0, +vec.begin() + r0 + n , +vec.begin() + r1 + 1); + +return T(1); +} +}; + +template +class iota : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::scalar_view scalar_t; +typedef typename generic_type::vector_view vector_t; + +using exprtk::igeneric_function::operator(); + +iota() +: exprtk::igeneric_function("VT|VTT|VTTT|VTTTT") +/* + Overloads: + 0. VT - vector, increment + 1. VTT - vector, increment, base + 2. VTTTT - vector, increment, r0, r1 + 3. VTTTT - vector, increment, base, r0, r1 + */ +{} + +inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) +{ +vector_t vec(parameters[0]); + +T increment = scalar_t(parameters[1])(); +T base = ((1 == ps_index) || (3 == ps_index)) ? scalar_t(parameters[2])() : T(0); + +std::size_t r0 = 0; +std::size_t r1 = vec.size() - 1; + +if ((2 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0)) +return std::numeric_limits::quiet_NaN(); +else if ((3 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 3, 4, 0)) +return std::numeric_limits::quiet_NaN(); +else +{ +long long j = 0; + +for (std::size_t i = r0; i <= r1; ++i, ++j) +{ +vec[i] = base + (increment * j); +} +} + +return T(1); +} +}; + +template +class sumk : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::vector_view vector_t; + +using exprtk::igeneric_function::operator(); + +sumk() +: exprtk::igeneric_function("V|VTT") +/* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ +{} + +inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) +{ +const vector_t vec(parameters[0]); + +std::size_t r0 = 0; +std::size_t r1 = vec.size() - 1; + +if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0)) +return std::numeric_limits::quiet_NaN(); + +T result = T(0); +T error = T(0); + +for (std::size_t i = r0; i <= r1; ++i) +{ +details::kahan_sum(result, error, vec[i]); +} + +return result; +} +}; + +template +class axpy : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::scalar_view scalar_t; +typedef typename generic_type::vector_view vector_t; + +using exprtk::igeneric_function::operator(); + +axpy() +: exprtk::igeneric_function("TVV|TVVTT") +/* + y <- ax + y + Overloads: + 0. TVV - a, x(vector), y(vector) + 1. TVVTT - a, x(vector), y(vector), r0, r1 + */ +{} + +inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) +{ +const vector_t x(parameters[1]); +vector_t y(parameters[2]); + +std::size_t r0 = 0; +std::size_t r1 = std::min(x.size(),y.size()) - 1; + +if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 3, 4, 1)) +return std::numeric_limits::quiet_NaN(); +else if (helper::invalid_range(y, r0, r1)) +return std::numeric_limits::quiet_NaN(); + +const T a = scalar_t(parameters[0])(); + +for (std::size_t i = r0; i <= r1; ++i) +{ +y[i] = (a * x[i]) + y[i]; +} + +return T(1); +} +}; + +template +class axpby : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::scalar_view scalar_t; +typedef typename generic_type::vector_view vector_t; + +using exprtk::igeneric_function::operator(); + +axpby() +: exprtk::igeneric_function("TVTV|TVTVTT") +/* + y <- ax + by + Overloads: + 0. TVTV - a, x(vector), b, y(vector) + 1. TVTVTT - a, x(vector), b, y(vector), r0, r1 + */ +{} + +inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) +{ +const vector_t x(parameters[1]); +vector_t y(parameters[3]); + +std::size_t r0 = 0; +std::size_t r1 = std::min(x.size(),y.size()) - 1; + +if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 4, 5, 1)) +return std::numeric_limits::quiet_NaN(); +else if (helper::invalid_range(y, r0, r1)) +return std::numeric_limits::quiet_NaN(); + +const T a = scalar_t(parameters[0])(); +const T b = scalar_t(parameters[2])(); + +for (std::size_t i = r0; i <= r1; ++i) +{ +y[i] = (a * x[i]) + (b * y[i]); +} + +return T(1); +} +}; + +template +class axpyz : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::scalar_view scalar_t; +typedef typename generic_type::vector_view vector_t; + +using exprtk::igeneric_function::operator(); + +axpyz() +: exprtk::igeneric_function("TVVV|TVVVTT") +/* + z <- ax + y + Overloads: + 0. TVVV - a, x(vector), y(vector), z(vector) + 1. TVVVTT - a, x(vector), y(vector), z(vector), r0, r1 + */ +{} + +inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) +{ +const vector_t x(parameters[1]); +const vector_t y(parameters[2]); +vector_t z(parameters[3]); + +std::size_t r0 = 0; +std::size_t r1 = std::min(x.size(),y.size()) - 1; + +if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 3, 4, 1)) +return std::numeric_limits::quiet_NaN(); +else if (helper::invalid_range(y, r0, r1)) +return std::numeric_limits::quiet_NaN(); +else if (helper::invalid_range(z, r0, r1)) +return std::numeric_limits::quiet_NaN(); + +const T a = scalar_t(parameters[0])(); + +for (std::size_t i = r0; i <= r1; ++i) +{ +z[i] = (a * x[i]) + y[i]; +} + +return T(1); +} +}; + +template +class axpbyz : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::scalar_view scalar_t; +typedef typename generic_type::vector_view vector_t; + +using exprtk::igeneric_function::operator(); + +axpbyz() +: exprtk::igeneric_function("TVTVV|TVTVVTT") +/* + z <- ax + by + Overloads: + 0. TVTVV - a, x(vector), b, y(vector), z(vector) + 1. TVTVVTT - a, x(vector), b, y(vector), z(vector), r0, r1 + */ +{} + +inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) +{ +const vector_t x(parameters[1]); +const vector_t y(parameters[3]); +vector_t z(parameters[4]); + +std::size_t r0 = 0; +std::size_t r1 = std::min(x.size(),y.size()) - 1; + +if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 4, 5, 1)) +return std::numeric_limits::quiet_NaN(); +else if (helper::invalid_range(y, r0, r1)) +return std::numeric_limits::quiet_NaN(); +else if (helper::invalid_range(z, r0, r1)) +return std::numeric_limits::quiet_NaN(); + +const T a = scalar_t(parameters[0])(); +const T b = scalar_t(parameters[2])(); + +for (std::size_t i = r0; i <= r1; ++i) +{ +z[i] = (a * x[i]) + (b * y[i]); +} + +return T(1); +} +}; + +template +class axpbz : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::scalar_view scalar_t; +typedef typename generic_type::vector_view vector_t; + +using exprtk::igeneric_function::operator(); + +axpbz() +: exprtk::igeneric_function("TVTV|TVTVTT") +/* + z <- ax + b + Overloads: + 0. TVTV - a, x(vector), b, z(vector) + 1. TVTVTT - a, x(vector), b, z(vector), r0, r1 + */ +{} + +inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) +{ +const vector_t x(parameters[1]); +vector_t z(parameters[3]); + +std::size_t r0 = 0; +std::size_t r1 = x.size() - 1; + +if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 4, 5, 1)) +return std::numeric_limits::quiet_NaN(); +else if (helper::invalid_range(z, r0, r1)) +return std::numeric_limits::quiet_NaN(); + +const T a = scalar_t(parameters[0])(); +const T b = scalar_t(parameters[2])(); + +for (std::size_t i = r0; i <= r1; ++i) +{ +z[i] = (a * x[i]) + b; +} + +return T(1); +} +}; + +template +class dot : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::scalar_view scalar_t; +typedef typename generic_type::vector_view vector_t; + +using exprtk::igeneric_function::operator(); + +dot() +: exprtk::igeneric_function("VV|VVTT") +/* + Overloads: + 0. VV - x(vector), y(vector) + 1. VVTT - x(vector), y(vector), r0, r1 + */ +{} + +inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) +{ +const vector_t x(parameters[0]); +const vector_t y(parameters[1]); + +std::size_t r0 = 0; +std::size_t r1 = std::min(x.size(),y.size()) - 1; + +if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0)) +return std::numeric_limits::quiet_NaN(); +else if (helper::invalid_range(y, r0, r1)) +return std::numeric_limits::quiet_NaN(); + +T result = T(0); + +for (std::size_t i = r0; i <= r1; ++i) +{ +result += (x[i] * y[i]); +} + +return result; +} +}; + +template +class dotk : public exprtk::igeneric_function +{ +public: + +typedef typename exprtk::igeneric_function igfun_t; +typedef typename igfun_t::parameter_list_t parameter_list_t; +typedef typename igfun_t::generic_type generic_type; +typedef typename generic_type::scalar_view scalar_t; +typedef typename generic_type::vector_view vector_t; + +using exprtk::igeneric_function::operator(); + +dotk() +: exprtk::igeneric_function("VV|VVTT") +/* + Overloads: + 0. VV - x(vector), y(vector) + 1. VVTT - x(vector), y(vector), r0, r1 + */ +{} + +inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) +{ +const vector_t x(parameters[0]); +const vector_t y(parameters[1]); + +std::size_t r0 = 0; +std::size_t r1 = std::min(x.size(),y.size()) - 1; + +if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0)) +return std::numeric_limits::quiet_NaN(); +else if (helper::invalid_range(y, r0, r1)) +return std::numeric_limits::quiet_NaN(); + +T result = T(0); +T error = T(0); + +for (std::size_t i = r0; i <= r1; ++i) +{ +details::kahan_sum(result, error, (x[i] * y[i])); +} + +return result; +} +}; + +template +struct package +{ +all_true at; +all_false af; +any_true nt; +any_false nf; +count c; +copy cp; +rol rl; +ror rr; +shift_left sl; +shift_right sr; +sort st; +nthelement ne; +iota ia; +sumk sk; +axpy b1_axpy; +axpby b1_axpby; +axpyz b1_axpyz; +axpbyz b1_axpbyz; +axpbz b1_axpbz; +dot dt; +dotk dtk; + +bool register_package(exprtk::symbol_table& symtab) +{ +#define exprtk_register_function(FunctionName, FunctionType) \ + if (!symtab.add_function(FunctionName,FunctionType)) \ + { \ + exprtk_debug(( \ + "exprtk::rtl::vecops::register_package - Failed to add function: %s\n", \ + FunctionName)); \ + return false; \ + } \ + +exprtk_register_function("all_true" , at ) +exprtk_register_function("all_false" , af ) +exprtk_register_function("any_true" , nt ) +exprtk_register_function("any_false" , nf ) +exprtk_register_function("count" , c ) +exprtk_register_function("copy" , cp ) +exprtk_register_function("rotate_left" , rl ) +exprtk_register_function("rol" , rl ) +exprtk_register_function("rotate_right" , rr ) +exprtk_register_function("ror" , rr ) +exprtk_register_function("shftl" , sl ) +exprtk_register_function("shftr" , sr ) +exprtk_register_function("sort" , st ) +exprtk_register_function("nth_element" , ne ) +exprtk_register_function("iota" , ia ) +exprtk_register_function("sumk" , sk ) +exprtk_register_function("axpy" , b1_axpy ) +exprtk_register_function("axpby" , b1_axpby ) +exprtk_register_function("axpyz" , b1_axpyz ) +exprtk_register_function("axpbyz" , b1_axpbyz) +exprtk_register_function("axpbz" , b1_axpbz ) +exprtk_register_function("dot" , dt ) +exprtk_register_function("dotk" , dtk ) +#undef exprtk_register_function + +return true; +} +}; + +} // namespace exprtk::rtl::vecops +} // namespace exprtk::rtl +} // namespace exprtk +#endif + +namespace exprtk +{ +namespace information +{ +using ::exprtk::details::char_cptr; + +static char_cptr library = "Mathematical Expression Toolkit"; +static char_cptr version = "2.71828182845904523536028747135266" +"2497757247093699959574966967627724" +"0766303535475945713821785251664274" +"2746639193200305992181741359662904"; +static char_cptr date = "20230101"; +static char_cptr min_cpp = "199711L"; + +static inline std::string data() +{ +static const std::string info_str = std::string(library) + +std::string(" v") + std::string(version) + +std::string(" (") + date + std::string(")") + +std::string(" (") + min_cpp + std::string(")"); +return info_str; +} + +} // namespace information + +#ifdef exprtk_debug +#undef exprtk_debug +#endif + +#ifdef exprtk_error_location +#undef exprtk_error_location +#endif + +#ifdef exprtk_disable_fallthrough_begin +#undef exprtk_disable_fallthrough_begin +#endif + +#ifdef exprtk_disable_fallthrough_end +#undef exprtk_disable_fallthrough_end +#endif + +#ifdef exprtk_override +#undef exprtk_override +#endif + +#ifdef exprtk_final +#undef exprtk_final +#endif + +#ifdef exprtk_delete +#undef exprtk_delete +#endif + +} // namespace exprtk + +#endif \ No newline at end of file diff --git a/Code/ThirdParty/exprtk/simvascular_exprtk/readme.txt b/Code/ThirdParty/exprtk/simvascular_exprtk/readme.txt new file mode 100644 index 00000000..b16d4b7c --- /dev/null +++ b/Code/ThirdParty/exprtk/simvascular_exprtk/readme.txt @@ -0,0 +1,5033 @@ +C++ Mathematical Expression Toolkit Library Documentation + + Section 00 - Introduction + Section 01 - Capabilities + Section 02 - Example Expressions + Section 03 - Copyright Notice + Section 04 - Downloads & Updates + Section 05 - Installation + Section 06 - Compilation + Section 07 - Compiler Compatibility + Section 08 - Built-In Operations & Functions + Section 09 - Fundamental Types + Section 10 - Components + Section 11 - Compilation Options + Section 12 - Expression Structures + Section 13 - Variable, Vector & String Definition + Section 14 - Vector Processing + Section 15 - User Defined Functions + Section 16 - Expression Dependents + Section 17 - Hierarchies Of Symbol Tables + Section 18 - Unknown Unknowns + Section 19 - Enabling & Disabling Features + Section 20 - Expression Return Values + Section 21 - Compilation Errors + Section 22 - Runtime Library Packages + Section 23 - Helpers & Utils + Section 24 - Benchmarking + Section 25 - Exprtk Notes + Section 26 - Simple Exprtk Example + Section 27 - Build Options + Section 28 - Files + Section 29 - Language Structure + + +[SECTION 00 - INTRODUCTION] +The C++ Mathematical Expression Toolkit Library (ExprTk) is a simple +to use, easy to integrate and extremely efficient run-time +mathematical expression parsing and evaluation engine. The parsing +engine supports numerous forms of functional and logic processing +semantics and is easily extensible. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 01 - CAPABILITIES] +The ExprTk expression evaluator supports the following fundamental +arithmetic operations, functions and processes: + + (00) Types: Scalar, Vector, String + + (01) Basic operators: +, -, *, /, %, ^ + + (02) Assignment: :=, +=, -=, *=, /=, %= + + (03) Equalities & + Inequalities: =, ==, <>, !=, <, <=, >, >= + + (04) Logic operators: and, mand, mor, nand, nor, not, or, shl, shr, + xnor, xor, true, false + + (05) Functions: abs, avg, ceil, clamp, equal, erf, erfc, exp, + expm1, floor, frac, log, log10, log1p, log2, + logn, max, min, mul, ncdf, not_equal, root, + round, roundn, sgn, sqrt, sum, swap, trunc + + (06) Trigonometry: acos, acosh, asin, asinh, atan, atanh, atan2, + cos, cosh, cot, csc, sec, sin, sinc, sinh, + tan, tanh, hypot, rad2deg, deg2grad, deg2rad, + grad2deg + + (07) Control + structures: if-then-else, ternary conditional, switch-case, + return-statement + + (08) Loop statements: while, for, repeat-until, break, continue + + (09) String + processing: in, like, ilike, concatenation + + (10) Optimisations: constant-folding, simple strength reduction and + dead code elimination + + (11) Calculus: numerical integration and differentiation + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 02 - EXAMPLE EXPRESSIONS] +The following is a short listing of infix format based mathematical +expressions that can be parsed and evaluated using the ExprTk library. + + (01) sqrt(1 - (3 / x^2)) + (02) clamp(-1, sin(2 * pi * x) + cos(y / 2 * pi), +1) + (03) sin(2.34e-3 * x) + (04) if(((x[2] + 2) == 3) and ((y + 5) <= 9),1 + w, 2 / z) + (05) inrange(-2,m,+2) == if(({-2 <= m} and [m <= +2]),1,0) + (06) ({1/1}*[1/2]+(1/3))-{1/4}^[1/5]+(1/6)-({1/7}+[1/8]*(1/9)) + (07) a * exp(2.2 / 3.3 * t) + c + (08) z := x + sin(2.567 * pi / y) + (09) u := 2.123 * {pi * z} / (w := x + cos(y / pi)) + (10) 2x + 3y + 4z + 5w == 2 * x + 3 * y + 4 * z + 5 * w + (11) 3(x + y) / 2.9 + 1.234e+12 == 3 * (x + y) / 2.9 + 1.234e+12 + (12) (x + y)3.3 + 1 / 4.5 == [x + y] * 3.3 + 1 / 4.5 + (13) (x + y[i])z + 1.1 / 2.7 == (x + y[i]) * z + 1.1 / 2.7 + (14) (sin(x / pi) cos(2y) + 1) == (sin(x / pi) * cos(2 * y) + 1) + (15) 75x^17 + 25.1x^5 - 35x^4 - 15.2x^3 + 40x^2 - 15.3x + 1 + (16) (avg(x,y) <= x + y ? x - y : x * y) + 2.345 * pi / x + (17) while (x <= 100) { x -= 1; } + (18) x <= 'abc123' and (y in 'AString') or ('1x2y3z' != z) + (19) ((x + 'abc') like '*123*') or ('a123b' ilike y) + (20) sgn(+1.2^3.4z / -5.6y) <= {-7.8^9 / -10.11x } + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 03 - COPYRIGHT NOTICE] +Free use of the C++ Mathematical Expression Toolkit Library is +permitted under the guidelines and in accordance with the most current +version of the MIT License. + +https://www.opensource.org/licenses/MIT + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 04 - DOWNLOADS & UPDATES] +The most recent version of the C++ Mathematical Expression Toolkit +Library including all updates and tests can be found at the following +locations: + + (a) Download: https://www.partow.net/programming/exprtk/index.html + (b) Repository: https://github.com/ArashPartow/exprtk + https://github.com/ArashPartow/exprtk-extras + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 05 - INSTALLATION] +The header file exprtk.hpp should be placed in a project or system +include path (e.g: /usr/include/). + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 06 - COMPILATION] + (a) For a complete build: make clean all + (b) For a PGO build: make clean pgo + (c) To strip executables: make strip_bin + (d) Execute valgrind check: make valgrind_check + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 07 - COMPILER COMPATIBILITY] +ExprTk has been built error and warning free using the following set +of C++ compilers: + + (*) GNU Compiler Collection (3.5+) + (*) Intel C++ Compiler (8.x+) + (*) Clang/LLVM (1.1+) + (*) PGI C++ (10.x+) + (*) Microsoft Visual Studio C++ Compiler (8.1+) + (*) IBM XL C/C++ (9.x+) + (*) C++ Builder (XE4+) + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 08 - BUILT-IN OPERATIONS & FUNCTIONS] + +(0) Arithmetic & Assignment Operators ++----------+---------------------------------------------------------+ +| OPERATOR | DEFINITION | ++----------+---------------------------------------------------------+ +| + | Addition between x and y. (eg: x + y) | ++----------+---------------------------------------------------------+ +| - | Subtraction between x and y. (eg: x - y) | ++----------+---------------------------------------------------------+ +| * | Multiplication between x and y. (eg: x * y) | ++----------+---------------------------------------------------------+ +| / | Division between x and y. (eg: x / y) | ++----------+---------------------------------------------------------+ +| % | Modulus of x with respect to y. (eg: x % y) | ++----------+---------------------------------------------------------+ +| ^ | x to the power of y. (eg: x ^ y) | ++----------+---------------------------------------------------------+ +| := | Assign the value of x to y. Where y is either a variable| +| | or vector type. (eg: y := x) | ++----------+---------------------------------------------------------+ +| += | Increment x by the value of the expression on the right | +| | hand side. Where x is either a variable or vector type. | +| | (eg: x += abs(y - z)) | ++----------+---------------------------------------------------------+ +| -= | Decrement x by the value of the expression on the right | +| | hand side. Where x is either a variable or vector type. | +| | (eg: x[i] -= abs(y + z)) | ++----------+---------------------------------------------------------+ +| *= | Assign the multiplication of x by the value of the | +| | expression on the righthand side to x. Where x is either| +| | a variable or vector type. | +| | (eg: x *= abs(y / z)) | ++----------+---------------------------------------------------------+ +| /= | Assign the division of x by the value of the expression | +| | on the right-hand side to x. Where x is either a | +| | variable or vector type. (eg: x[i + j] /= abs(y * z)) | ++----------+---------------------------------------------------------+ +| %= | Assign x modulo the value of the expression on the right| +| | hand side to x. Where x is either a variable or vector | +| | type. (eg: x[2] %= y ^ 2) | ++----------+---------------------------------------------------------+ + +(1) Equalities & Inequalities ++----------+---------------------------------------------------------+ +| OPERATOR | DEFINITION | ++----------+---------------------------------------------------------+ +| == or = | True only if x is strictly equal to y. (eg: x == y) | ++----------+---------------------------------------------------------+ +| <> or != | True only if x does not equal y. (eg: x <> y or x != y) | ++----------+---------------------------------------------------------+ +| < | True only if x is less than y. (eg: x < y) | ++----------+---------------------------------------------------------+ +| <= | True only if x is less than or equal to y. (eg: x <= y) | ++----------+---------------------------------------------------------+ +| > | True only if x is greater than y. (eg: x > y) | ++----------+---------------------------------------------------------+ +| >= | True only if x greater than or equal to y. (eg: x >= y) | ++----------+---------------------------------------------------------+ + +(2) Boolean Operations ++----------+---------------------------------------------------------+ +| OPERATOR | DEFINITION | ++----------+---------------------------------------------------------+ +| true | True state or any value other than zero (typically 1). | ++----------+---------------------------------------------------------+ +| false | False state, value of exactly zero. | ++----------+---------------------------------------------------------+ +| and | Logical AND, True only if x and y are both true. | +| | (eg: x and y) | ++----------+---------------------------------------------------------+ +| mand | Multi-input logical AND, True only if all inputs are | +| | true. Left to right short-circuiting of expressions. | +| | (eg: mand(x > y, z < w, u or v, w and x)) | ++----------+---------------------------------------------------------+ +| mor | Multi-input logical OR, True if at least one of the | +| | inputs are true. Left to right short-circuiting of | +| | expressions. (eg: mor(x > y, z < w, u or v, w and x)) | ++----------+---------------------------------------------------------+ +| nand | Logical NAND, True only if either x or y is false. | +| | (eg: x nand y) | ++----------+---------------------------------------------------------+ +| nor | Logical NOR, True only if the result of x or y is false | +| | (eg: x nor y) | ++----------+---------------------------------------------------------+ +| not | Logical NOT, Negate the logical sense of the input. | +| | (eg: not(x and y) == x nand y) | ++----------+---------------------------------------------------------+ +| or | Logical OR, True if either x or y is true. (eg: x or y) | ++----------+---------------------------------------------------------+ +| xor | Logical XOR, True only if the logical states of x and y | +| | differ. (eg: x xor y) | ++----------+---------------------------------------------------------+ +| xnor | Logical XNOR, True iff the biconditional of x and y is | +| | satisfied. (eg: x xnor y) | ++----------+---------------------------------------------------------+ +| & | Similar to AND but with left to right expression short | +| | circuiting optimisation. (eg: (x & y) == (y and x)) | ++----------+---------------------------------------------------------+ +| | | Similar to OR but with left to right expression short | +| | circuiting optimisation. (eg: (x | y) == (y or x)) | ++----------+---------------------------------------------------------+ + +(3) General Purpose Functions ++----------+---------------------------------------------------------+ +| FUNCTION | DEFINITION | ++----------+---------------------------------------------------------+ +| abs | Absolute value of x. (eg: abs(x)) | ++----------+---------------------------------------------------------+ +| avg | Average of all the inputs. | +| | (eg: avg(x,y,z,w,u,v) == (x + y + z + w + u + v) / 6) | ++----------+---------------------------------------------------------+ +| ceil | Smallest integer that is greater than or equal to x. | ++----------+---------------------------------------------------------+ +| clamp | Clamp x in range between r0 and r1, where r0 < r1. | +| | (eg: clamp(r0,x,r1)) | ++----------+---------------------------------------------------------+ +| equal | Equality test between x and y using normalised epsilon | ++----------+---------------------------------------------------------+ +| erf | Error function of x. (eg: erf(x)) | ++----------+---------------------------------------------------------+ +| erfc | Complimentary error function of x. (eg: erfc(x)) | ++----------+---------------------------------------------------------+ +| exp | e to the power of x. (eg: exp(x)) | ++----------+---------------------------------------------------------+ +| expm1 | e to the power of x minus 1, where x is very small. | +| | (eg: expm1(x)) | ++----------+---------------------------------------------------------+ +| floor | Largest integer that is less than or equal to x. | +| | (eg: floor(x)) | ++----------+---------------------------------------------------------+ +| frac | Fractional portion of x. (eg: frac(x)) | ++----------+---------------------------------------------------------+ +| hypot | Hypotenuse of x and y (eg: hypot(x,y) = sqrt(x*x + y*y))| ++----------+---------------------------------------------------------+ +| iclamp | Inverse-clamp x outside of the range r0 and r1. Where | +| | r0 < r1. If x is within the range it will snap to the | +| | closest bound. (eg: iclamp(r0,x,r1) | ++----------+---------------------------------------------------------+ +| inrange | In-range returns 'true' when x is within the range r0 | +| | and r1. Where r0 < r1. (eg: inrange(r0,x,r1) | ++----------+---------------------------------------------------------+ +| log | Natural logarithm of x. (eg: log(x)) | ++----------+---------------------------------------------------------+ +| log10 | Base 10 logarithm of x. (eg: log10(x)) | ++----------+---------------------------------------------------------+ +| log1p | Natural logarithm of 1 + x, where x is very small. | +| | (eg: log1p(x)) | ++----------+---------------------------------------------------------+ +| log2 | Base 2 logarithm of x. (eg: log2(x)) | ++----------+---------------------------------------------------------+ +| logn | Base N logarithm of x. where n is a positive integer. | +| | (eg: logn(x,8)) | ++----------+---------------------------------------------------------+ +| max | Largest value of all the inputs. (eg: max(x,y,z,w,u,v)) | ++----------+---------------------------------------------------------+ +| min | Smallest value of all the inputs. (eg: min(x,y,z,w,u)) | ++----------+---------------------------------------------------------+ +| mul | Product of all the inputs. | +| | (eg: mul(x,y,z,w,u,v,t) == (x * y * z * w * u * v * t)) | ++----------+---------------------------------------------------------+ +| ncdf | Normal cumulative distribution function. (eg: ncdf(x)) | ++----------+---------------------------------------------------------+ +| not_equal| Not-equal test between x and y using normalised epsilon | ++----------+---------------------------------------------------------+ +| pow | x to the power of y. (eg: pow(x,y) == x ^ y) | ++----------+---------------------------------------------------------+ +| root | Nth-Root of x. where n is a positive integer. | +| | (eg: root(x,3) == x^(1/3)) | ++----------+---------------------------------------------------------+ +| round | Round x to the nearest integer. (eg: round(x)) | ++----------+---------------------------------------------------------+ +| roundn | Round x to n decimal places (eg: roundn(x,3)) | +| | where n > 0 and is an integer. | +| | (eg: roundn(1.2345678,4) == 1.2346) | ++----------+---------------------------------------------------------+ +| sgn | Sign of x, -1 where x < 0, +1 where x > 0, else zero. | +| | (eg: sgn(x)) | ++----------+---------------------------------------------------------+ +| sqrt | Square root of x, where x >= 0. (eg: sqrt(x)) | ++----------+---------------------------------------------------------+ +| sum | Sum of all the inputs. | +| | (eg: sum(x,y,z,w,u,v,t) == (x + y + z + w + u + v + t)) | ++----------+---------------------------------------------------------+ +| swap | Swap the values of the variables x and y and return the | +| <=> | current value of y. (eg: swap(x,y) or x <=> y) | ++----------+---------------------------------------------------------+ +| trunc | Integer portion of x. (eg: trunc(x)) | ++----------+---------------------------------------------------------+ + +(4) Trigonometry Functions ++----------+---------------------------------------------------------+ +| FUNCTION | DEFINITION | ++----------+---------------------------------------------------------+ +| acos | Arc cosine of x expressed in radians. Interval [-1,+1] | +| | (eg: acos(x)) | ++----------+---------------------------------------------------------+ +| acosh | Inverse hyperbolic cosine of x expressed in radians. | +| | (eg: acosh(x)) | ++----------+---------------------------------------------------------+ +| asin | Arc sine of x expressed in radians. Interval [-1,+1] | +| | (eg: asin(x)) | ++----------+---------------------------------------------------------+ +| asinh | Inverse hyperbolic sine of x expressed in radians. | +| | (eg: asinh(x)) | ++----------+---------------------------------------------------------+ +| atan | Arc tangent of x expressed in radians. Interval [-1,+1] | +| | (eg: atan(x)) | ++----------+---------------------------------------------------------+ +| atan2 | Arc tangent of (x / y) expressed in radians. [-pi,+pi] | +| | eg: atan2(x,y) | ++----------+---------------------------------------------------------+ +| atanh | Inverse hyperbolic tangent of x expressed in radians. | +| | (eg: atanh(x)) | ++----------+---------------------------------------------------------+ +| cos | Cosine of x. (eg: cos(x)) | ++----------+---------------------------------------------------------+ +| cosh | Hyperbolic cosine of x. (eg: cosh(x)) | ++----------+---------------------------------------------------------+ +| cot | Cotangent of x. (eg: cot(x)) | ++----------+---------------------------------------------------------+ +| csc | Cosecant of x. (eg: csc(x)) | ++----------+---------------------------------------------------------+ +| sec | Secant of x. (eg: sec(x)) | ++----------+---------------------------------------------------------+ +| sin | Sine of x. (eg: sin(x)) | ++----------+---------------------------------------------------------+ +| sinc | Sine cardinal of x. (eg: sinc(x)) | ++----------+---------------------------------------------------------+ +| sinh | Hyperbolic sine of x. (eg: sinh(x)) | ++----------+---------------------------------------------------------+ +| tan | Tangent of x. (eg: tan(x)) | ++----------+---------------------------------------------------------+ +| tanh | Hyperbolic tangent of x. (eg: tanh(x)) | ++----------+---------------------------------------------------------+ +| deg2rad | Convert x from degrees to radians. (eg: deg2rad(x)) | ++----------+---------------------------------------------------------+ +| deg2grad | Convert x from degrees to gradians. (eg: deg2grad(x)) | ++----------+---------------------------------------------------------+ +| rad2deg | Convert x from radians to degrees. (eg: rad2deg(x)) | ++----------+---------------------------------------------------------+ +| grad2deg | Convert x from gradians to degrees. (eg: grad2deg(x)) | ++----------+---------------------------------------------------------+ + +(5) String Processing ++----------+---------------------------------------------------------+ +| FUNCTION | DEFINITION | ++----------+---------------------------------------------------------+ +| = , == | All common equality/inequality operators are applicable | +| !=, <> | to strings and are applied in a case sensitive manner. | +| <=, >= | In the following example x, y and z are of type string. | +| < , > | (eg: not((x <= 'AbC') and ('1x2y3z' <> y)) or (z == x) | ++----------+---------------------------------------------------------+ +| in | True only if x is a substring of y. | +| | (eg: x in y or 'abc' in 'abcdefgh') | ++----------+---------------------------------------------------------+ +| like | True only if the string x matches the pattern y. | +| | Available wildcard characters are '*' and '?' denoting | +| | zero or more and zero or one matches respectively. | +| | (eg: x like y or 'abcdefgh' like 'a?d*h') | ++----------+---------------------------------------------------------+ +| ilike | True only if the string x matches the pattern y in a | +| | case insensitive manner. Available wildcard characters | +| | are '*' and '?' denoting zero or more and zero or one | +| | matches respectively. | +| | (eg: x ilike y or 'a1B2c3D4e5F6g7H' ilike 'a?d*h') | ++----------+---------------------------------------------------------+ +| [r0:r1] | The closed interval [r0,r1] of the specified string. | +| | eg: Given a string x with a value of 'abcdefgh' then: | +| | 1. x[1:4] == 'bcde' | +| | 2. x[ :5] == x[:10 / 2] == 'abcdef' | +| | 3. x[2 + 1: ] == x[3:] =='defgh' | +| | 4. x[ : ] == x[:] == 'abcdefgh' | +| | 5. x[4/2:3+2] == x[2:5] == 'cdef' | +| | | +| | Note: Both r0 and r1 are assumed to be integers, where | +| | r0 <= r1. They may also be the result of an expression, | +| | in the event they have fractional components truncation | +| | will be performed. (eg: 1.67 --> 1) | ++----------+---------------------------------------------------------+ +| := | Assign the value of x to y. Where y is a mutable string | +| | or string range and x is either a string or a string | +| | range. eg: | +| | 1. y := x | +| | 2. y := 'abc' | +| | 3. y := x[:i + j] | +| | 4. y := '0123456789'[2:7] | +| | 5. y := '0123456789'[2i + 1:7] | +| | 6. y := (x := '0123456789'[2:7]) | +| | 7. y[i:j] := x | +| | 8. y[i:j] := (x + 'abcdefg'[8 / 4:5])[m:n] | +| | | +| | Note: For options 7 and 8 the shorter of the two ranges | +| | will denote the number characters that are to be copied.| ++----------+---------------------------------------------------------+ +| + | Concatenation of x and y. Where x and y are strings or | +| | string ranges. eg | +| | 1. x + y | +| | 2. x + 'abc' | +| | 3. x + y[:i + j] | +| | 4. x[i:j] + y[2:3] + '0123456789'[2:7] | +| | 5. 'abc' + x + y | +| | 6. 'abc' + '1234567' | +| | 7. (x + 'a1B2c3D4' + y)[i:2j] | ++----------+---------------------------------------------------------+ +| += | Append to x the value of y. Where x is a mutable string | +| | and y is either a string or a string range. eg: | +| | 1. x += y | +| | 2. x += 'abc' | +| | 3. x += y[:i + j] + 'abc' | +| | 4. x += '0123456789'[2:7] | ++----------+---------------------------------------------------------+ +| <=> | Swap the values of x and y. Where x and y are mutable | +| | strings. (eg: x <=> y) | ++----------+---------------------------------------------------------+ +| [] | The string size operator returns the size of the string | +| | being actioned. | +| | eg: | +| | 1. 'abc'[] == 3 | +| | 2. var max_str_length := max(s0[],s1[],s2[],s3[]) | +| | 3. ('abc' + 'xyz')[] == 6 | +| | 4. (('abc' + 'xyz')[1:4])[] == 4 | ++----------+---------------------------------------------------------+ + +(6) Control Structures ++----------+---------------------------------------------------------+ +|STRUCTURE | DEFINITION | ++----------+---------------------------------------------------------+ +| if | If x is true then return y else return z. | +| | eg: | +| | 1. if (x, y, z) | +| | 2. if ((x + 1) > 2y, z + 1, w / v) | +| | 3. if (x > y) z; | +| | 4. if (x <= 2*y) { z + w }; | ++----------+---------------------------------------------------------+ +| if-else | The if-else/else-if statement. Subject to the condition | +| | branch the statement will return either the value of the| +| | consequent or the alternative branch. | +| | eg: | +| | 1. if (x > y) z; else w; | +| | 2. if (x > y) z; else if (w != u) v; | +| | 3. if (x < y) { z; w + 1; } else u; | +| | 4. if ((x != y) and (z > w)) | +| | { | +| | y := sin(x) / u; | +| | z := w + 1; | +| | } | +| | else if (x > (z + 1)) | +| | { | +| | w := abs (x - y) + z; | +| | u := (x + 1) > 2y ? 2u : 3u; | +| | } | ++----------+---------------------------------------------------------+ +| switch | The first true case condition that is encountered will | +| | determine the result of the switch. If none of the case | +| | conditions hold true, the default action is assumed as | +| | the final return value. This is sometimes also known as | +| | a multi-way branch mechanism. | +| | eg: | +| | switch | +| | { | +| | case x > (y + z) : 2 * x / abs(y - z); | +| | case x < 3 : sin(x + y); | +| | default : 1 + x; | +| | } | ++----------+---------------------------------------------------------+ +| while | The structure will repeatedly evaluate the internal | +| | statement(s) 'while' the condition is true. The final | +| | statement in the final iteration will be used as the | +| | return value of the loop. | +| | eg: | +| | while ((x -= 1) > 0) | +| | { | +| | y := x + z; | +| | w := u + y; | +| | } | ++----------+---------------------------------------------------------+ +| repeat/ | The structure will repeatedly evaluate the internal | +| until | statement(s) 'until' the condition is true. The final | +| | statement in the final iteration will be used as the | +| | return value of the loop. | +| | eg: | +| | repeat | +| | y := x + z; | +| | w := u + y; | +| | until ((x += 1) > 100) | ++----------+---------------------------------------------------------+ +| for | The structure will repeatedly evaluate the internal | +| | statement(s) while the condition is true. On each loop | +| | iteration, an 'incrementing' expression is evaluated. | +| | The conditional is mandatory whereas the initialiser | +| | and incrementing expressions are optional. | +| | eg: | +| | for (var x := 0; (x < n) and (x != y); x += 1) | +| | { | +| | y := y + x / 2 - z; | +| | w := u + y; | +| | } | ++----------+---------------------------------------------------------+ +| break | Break terminates the execution of the nearest enclosed | +| break[] | loop, allowing for the execution to continue on external| +| | to the loop. The default break statement will set the | +| | return value of the loop to NaN, where as the return | +| | based form will set the value to that of the break | +| | expression. | +| | eg: | +| | while ((i += 1) < 10) | +| | { | +| | if (i < 5) | +| | j -= i + 2; | +| | else if (i % 2 == 0) | +| | break; | +| | else | +| | break[2i + 3]; | +| | } | ++----------+---------------------------------------------------------+ +| continue | Continue results in the remaining portion of the nearest| +| | enclosing loop body to be skipped. | +| | eg: | +| | for (var i := 0; i < 10; i += 1) | +| | { | +| | if (i < 5) | +| | continue; | +| | j -= i + 2; | +| | } | ++----------+---------------------------------------------------------+ +| return | Return immediately from within the current expression. | +| | With the option of passing back a variable number of | +| | values (scalar, vector or string). eg: | +| | 1. return [1]; | +| | 2. return [x, 'abx']; | +| | 3. return [x, x + y,'abx']; | +| | 4. return []; | +| | 5. if (x < y) | +| | return [x, x - y, 'result-set1', 123.456]; | +| | else | +| | return [y, x + y, 'result-set2']; | ++----------+---------------------------------------------------------+ +| ?: | Ternary conditional statement, similar to that of the | +| | above denoted if-statement. | +| | eg: | +| | 1. x ? y : z | +| | 2. x + 1 > 2y ? z + 1 : (w / v) | +| | 3. min(x,y) > z ? (x < y + 1) ? x : y : (w * v) | ++----------+---------------------------------------------------------+ +| ~ | Evaluate each sub-expression, then return as the result | +| | the value of the last sub-expression. This is sometimes | +| | known as multiple sequence point evaluation. | +| | eg: | +| | ~(i := x + 1, j := y / z, k := sin(w/u)) == (sin(w/u))) | +| | ~{i := x + 1; j := y / z; k := sin(w/u)} == (sin(w/u))) | ++----------+---------------------------------------------------------+ +| [*] | Evaluate any consequent for which its case statement is | +| | true. The return value will be either zero or the result| +| | of the last consequent to have been evaluated. | +| | eg: | +| | [*] | +| | { | +| | case (x + 1) > (y - 2) : x := z / 2 + sin(y / pi); | +| | case (x + 2) < abs(y + 3) : w / 4 + min(5y,9); | +| | case (x + 3) == (y * 4) : y := abs(z / 6) + 7y; | +| | } | ++----------+---------------------------------------------------------+ +| [] | The vector size operator returns the size of the vector | +| | being actioned. | +| | eg: | +| | 1. v[] | +| | 2. max_size := max(v0[],v1[],v2[],v3[]) | ++----------+---------------------------------------------------------+ + +Note: In the tables above, the symbols x, y, z, w, u and v where +appropriate may represent any of one the following: + + 1. Literal numeric/string value + 2. A variable + 3. A vector element + 4. A vector + 5. A string + 6. An expression comprised of [1], [2] or [3] (eg: 2 + x / vec[3]) + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 09 - FUNDAMENTAL TYPES] +ExprTk supports three fundamental types which can be used freely in +expressions. The types are as follows: + + (1) Scalar + (2) Vector + (3) String + + +(1) Scalar Type +The scalar type is a singular numeric value. The underlying type is +that used to specialise the ExprTk components (float, double, long +double, MPFR et al). + + +(2) Vector Type +The vector type is a fixed size sequence of contiguous scalar values. +A vector can be indexed resulting in a scalar value. Operations +between a vector and scalar will result in a vector with a size equal +to that of the original vector, whereas operations between vectors +will result in a vector of size equal to that of the smaller of the +two. In both mentioned cases, the operations will occur element-wise. + + +(3) String Type +The string type is a variable length sequence of 8-bit chars. Strings +can be assigned and concatenated to one another, they can also be +manipulated via sub-ranges using the range definition syntax. Strings +however can not interact with scalar or vector types. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 10 - COMPONENTS] +There are three primary components, that are specialised upon a given +numeric type, which make up the core of ExprTk. The components are as +follows: + + (1) Symbol Table exprtk::symbol_table + (2) Expression exprtk::expression + (3) Parser exprtk::parser + + +(1) Symbol Table +A structure that is used to store references to variables, constants +and functions that are to be used within expressions. Furthermore in +the context of composited recursive functions the symbol table can +also be thought of as a simple representation of a stack specific for +the expression(s) that reference it. The following is a list of the +types a symbol table can handle: + + (a) Numeric variables + (b) Numeric constants + (c) Numeric vector elements + (d) String variables + (e) String constants + (f) Functions + (g) Vararg functions + +During the compilation process if an expression is found to require +any of the elements noted above, the expression's associated +symbol_table will be queried for the element and if present a +reference to the element will be embedded within the expression's AST. +This allows for the original element to be modified independently of +the expression instance and to also allow the expression to be +evaluated using the current value of the element. + +Note: Any variable reference provided to a given symbol_table +instance, must have a life-time at least as long as the life-time of +the symbol_table instance. In the event the variable reference is +invalidated before the symbol_table or any dependent expression +instances have been destructed, then any associated expression +evaluations or variable referencing via the symbol_table instance will +result in undefined behaviour. + +The following bit of code instantiates a symbol_table and expression +instance, then proceeds to demonstrate various ways in which +references to variables can be added to the symbol_table, and how +those references are subsequently invalidated resulting in various +forms of undefined behaviour. + + typedef exprtk::symbol_table symbol_table_t; + + symbol_table_t symbol_table; + expression_t expression; + + { + double x = 123.4567; + symbol_table.add_variable("x", x); + } // Reference to variable x has been invalidated + + std::deque y {1.1, 2.2, 3.3}; + + symbol_table.add_variable("y", y.back()); + + y.pop_back(); // Reference to variable y has been invalidated + + std::vector z {4.4, 5.5, 6.6}; + + symbol_table.add_variable("z", z.front()); + + z.erase(z.begin()); + // Reference to variable z has been invalidated + + double* w = new double(123.456); + + symbol_table.add_variable("w", *w); + + delete w; // Reference to variable w has been invalidated + + const std::string expression_str = "x + y / z * w"; + + // Compilation of expression will succeed + parser.compile(expression_str,expression); + + expression.value(); + // Evaluation will result in undefined behaviour + + symbol_table.get_variable("x")->ref() = 135.791; + // Assignment will result in undefined behaviour + + +The example below demonstrates the relationship between variables, +symbol_table and expression. Note the variables are modified as they +normally would in a program, and when the expression is evaluated the +current values assigned to the variables will be used. + + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + + symbol_table_t symbol_table; + expression_t expression; + parser_t parser; + + double x = 0; + double y = 0; + + std::string expression_string = "x * y + 3"; + symbol_table.add_variable("x",x); + symbol_table.add_variable("y",y); + + expression.register_symbol_table(symbol_table); + + parser.compile(expression_string,expression); + + x = 1.0; + y = 2.0; + expression.value(); // 1 * 2 + 3 + + x = 3.7; + expression.value(); // 3.7 * 2 + 3 + + y = -9.0; + expression.value(); // 3.7 * -9 + 3 + + // 'x * -9 + 3' for x in range of [0,100) in steps of 0.0001 + for (x = 0.0; x < 100.0; x += 0.0001) + { + expression.value(); // x * -9 + 3 + } + + +Note: It is possible to register multiple symbol_tables with a single +expression object. In the event an expression has multiple symbol +tables, and where there exists conflicts between symbols, the +compilation stage will resolve the conflicts based on the order of +registration of the symbol_tables to the expression. For a more +expansive discussion please review section [17 - Hierarchies Of +Symbol Tables] + + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + + symbol_table_t symbol_table0; + symbol_table_t symbol_table1; + + expression_t expression; + parser_t parser; + + double x0 = 123.0; + double x1 = 678.0; + + std::string expression_string = "x + 1"; + + symbol_table0.add_variable("x",x0); + symbol_table1.add_variable("x",x1); + + expression.register_symbol_table(symbol_table0); + expression.register_symbol_table(symbol_table1); + + parser.compile(expression_string,expression); + + expression.value(); // 123 + 1 + + +The symbol table supports adding references to external instances of +types that can be accessed within expressions via the following +methods: + + 1. bool add_variable (const std::string& name, scalar_t&) + 2. bool add_constant (const std::string& name, const scalar_t&) + 3. bool add_stringvar(const std::string& name, std::string&) + 4. bool add_vector (const std::string& name, vector_type&) + + +Note: The 'vector' type must be comprised from a contiguous array of +scalars with a size that is larger than zero. The vector type itself +can be any one of the following: + + 1. std::vector + 2. scalar_t(&v)[N] + 3. scalar_t* and array size + 4. exprtk::vector_view + + +When registering a variable, vector, string or function with an +instance of a symbol_table, the call to 'add_...' may fail and return +a false result due to one or more of the following reasons: + + 1. Variable name contains invalid characters or is ill-formed + 2. Variable name conflicts with a reserved word (eg: 'while') + 3. Variable name conflicts with a previously registered variable + 4. A vector of size (length) zero is being registered + 5. A free function exceeding fifteen parameters is being registered + 6. The symbol_table instance is in an invalid state + + +A further property of symbol tables is that they can be classified at +instantiation as either being mutable (by default) or immutable. The +following demonstrates construction of an immutable symbol table +instance: + + symbol_table_t immutable_symbol_table + (symbol_table_t::symtab_mutability_type::e_immutable); + + +When a symbol table, that has been constructed as being immutable, is +registered with an expression, any statements in the expression string +that modify the variables that are managed by the immutable symbol +table will result in a compilation error. The operations that trigger +the mutability constraint are the following assignment operators: + + 1. Assignment: := + 2. Assign operation: +=, -=, *=, /= , %= + + +The main reason for this functionality is that, one may want the +immutability properties that come with constness of a variable such as +scalars, vectors and strings, but not necessarily the accompanying +compile time const-folding optimisations, that would result in the +value of the variables being retrieved only once at compile time, +causing external updates to the variables to not be part of the +expression evaluation. + + symbol_table_t immutable_symbol_table + (symbol_table_t::symtab_mutability_type::e_immutable); + + T x = 0.0; + + const std::string expression_str = "x + (y + y)"; + + immutable_symbol_table.add_variable("x" , x ); + immutable_symbol_table.add_constant("y" , 123.0); + + expression_t expression; + expression.register_symbol_table(immutabile_symbol_table); + + parser_t parser; + parser.compile(expression_str, expression) + + for (; x < 10.0; ++x) + { + const auto expected_value = x + (123.0 + 123.0); + const auto result_value = expression.value(); + assert(expression.value() != expected_value); + } + + +In the above example, there are two variables X and Y. Where Y is a +constant and X is a normal variable. Both are registered with a symbol +table that is immutable. The expression when compiled will result in +the "(y + y)" part being const-folded at compile time to the literal +value of 246. Whereas the current value of X, being updated via the +for-loop, externally to the expression and the symbol table will be +available to the expression upon each evaluation. + + +(2) Expression +A structure that holds an Abstract Syntax Tree or AST for a specified +expression and is used to evaluate said expression. Evaluation of the +expression is accomplished by performing a post-order traversal of the +AST. If a compiled Expression uses variables or user defined +functions, it will have an associated Symbol Table, which will contain +references to said variables, functions or strings. An example AST +structure for the denoted expression is as follows: + +Expression: z := (x + y^-2.345) * sin(pi / min(w - 7.3,v)) + + [Root] + | + [Assignment] + ________/ \_____ + / \ + Variable(z) [Multiplication] + ____________/ \___________ + / \ + / [Unary-Function(sin)] + [Addition] | + ____/ \____ [Division] + / \ ___/ \___ + Variable(x) [Exponentiation] / \ + ______/ \______ Constant(pi) [Binary-Function(min)] + / \ ____/ \____ + Variable(y) [Negation] / \ + | / Variable(v) + Constant(2.345) / + / + [Subtraction] + ____/ \____ + / \ + Variable(w) Constant(7.3) + + +The above denoted AST will be evaluated in the following order: + + (01) Load Variable (z) (10) Load Constant (7.3) + (02) Load Variable (x) (11) Subtraction (09 & 10) + (03) Load Variable (y) (12) Load Variable (v) + (04) Load Constant (2.345) (13) Min (11 & 12) + (05) Negation (04) (14) Division (08 & 13) + (06) Exponentiation (03 & 05) (15) Sin (14) + (07) Addition (02 & 06) (16) Multiplication (07 & 15) + (08) Load Constant (pi) (17) Assignment (01 & 16) + (09) Load Variable (w) + + +Generally an expression in ExprTk can be thought of as a free function +similar to those found in imperative languages. This form of pseudo +function will have a name, it may have a set of one or more inputs and +will return at least one value as its result. Furthermore the function +when invoked, may cause a side-effect that changes the state of the +host program. + +As an example the following is a pseudo-code definition of a free +function that performs a computation taking four inputs, modifying one +of them and returning a value based on some arbitrary calculation: + + ResultType foo(InputType x, InputType y, InputType z, InputType w) + { + w = 2 * x^y + z; // Side-Effect + return abs(x - y) / z; // Return Result + } + + +Given the above definition the following is a functionally equivalent +version using ExprTk: + + const std::string foo_str = " w := 2 * x^y + z; " + " abs(x - y) / z; "; + + T x, y, z, w; + + symbol_table_t symbol_table; + symbol_table.add_variable("x",x); + symbol_table.add_variable("y",y); + symbol_table.add_variable("z",z); + symbol_table.add_variable("w",w); + + expression_t foo; + foo.register_symbol_table(symbol_table); + + parser_t parser; + if (!parser.compile(foo_str,foo)) + { + // Error in expression... + return; + } + + T result = foo.value(); + + +(3) Parser +A component which takes as input a string representation of an +expression and attempts to compile said input with the result being an +instance of Expression. If an error is encountered during the +compilation process, the parser will stop compiling and return an +error status code, with a more detailed description of the error(s) +and its location within the input provided by the 'get_error' +interface. + + +Note: The exprtk::expression and exprtk::symbol_table components are +reference counted entities. Copy constructing or assigning to or from +either component will result in a shallow copy and a reference count +increment, rather than a complete replication. Furthermore the +expression and symbol_table components being Default-Constructible, +Copy-Constructible and Copy-Assignable make them compatible with +various C++ standard library containers and adaptors such as +std::vector, std::map, std::stack etc. + +The following is an example of two unique expressions, after having +being instantiated and compiled, one expression is assigned to the +other. The diagrams depict their initial and post assignment states, +including which control block each expression references and their +associated reference counts. + + + exprtk::expression e0; // constructed expression, eg: x + 1 + exprtk::expression e1; // constructed expression, eg: 2z + y + + +-----[ e0 cntrl block]----+ +-----[ e1 cntrl block]-----+ + | 1. Expression Node 'x+1' | | 1. Expression Node '2z+y' | + | 2. Ref Count: 1 |<-+ | 2. Ref Count: 1 |<-+ + +--------------------------+ | +---------------------------+ | + | | + +--[ e0 expression]--+ | +--[ e1 expression]--+ | + | 1. Reference to ]------+ | 1. Reference to ]-------+ + | e0 Control Block | | e1 Control Block | + +--------------------+ +--------------------+ + + + e0 = e1; // e0 and e1 are now 2z+y + + +-----[ e1 cntrl block]-----+ + | 1. Expression Node '2z+y' | + +----------->| 2. Ref Count: 2 |<----------+ + | +---------------------------+ | + | | + | +--[ e0 expression]--+ +--[ e1 expression]--+ | + +---[ 1. Reference to | | 1. Reference to ]---+ + | e1 Control Block | | e1 Control Block | + +--------------------+ +--------------------+ + +The reason for the above complexity and restrictions of deep copies +for the expression and symbol_table components is because expressions +may include user defined variables or functions. These are embedded as +references into the expression's AST. When copying an expression, said +references need to also be copied. If the references are blindly +copied, it will then result in two or more identical expressions +utilising the exact same references for variables. This obviously is +not the default assumed scenario and will give rise to non-obvious +behaviours when using the expressions in various contexts such as +multi-threading et al. + +The prescribed method for cloning an expression is to compile it from +its string form. Doing so will allow the 'user' to properly consider +the exact source of user defined variables and functions. + +Note: The exprtk::parser is a non-copyable and non-thread safe +component, and should only be shared via either a reference, a shared +pointer or a std::ref mechanism, and considerations relating to +synchronisation taken into account where appropriate. The parser +represents an object factory, specifically a factory of expressions, +and generally should not be instantiated solely on a per expression +compilation basis. + +The following diagram and example depicts the flow of data and +operations for compiling multiple expressions via the parser and +inserting the newly minted exprtk::expression instances into a +std::vector. + + +----[exprtk::parser]---+ + | Expression Factory | + | parser_t::compile(...)| + +--> ~.~.~.~.~.~.~.~.~.~ ->--+ + | +-----------------------+ | + Expressions in | | Expressions as + string form A V exprtk::expression + | | instances + [s0:'x+1']--->--+ | | +-[e0: x+1] + | | | | + [s1:'2z+y']-->--+--+ +->+-[e1: 2z+y] + | | + [s2:'sin(k+w)']-+ +-[e2: sin(k+w)] + + + const std::string expression_str[3] + = { "x + 1", "2x + y", "sin(k + w)" }; + + std::vector expression_list; + + parser_t parser; + expression_t expression; + symbol_table_t symbol_table; + + expression.register_symbol_table(symbol_table); + + for (std::size_t i = 0; i < 3; ++i) + { + if (parser.compile(expression_str[i],expression)) + { + expression_list.push_back(expression); + } + else + std::cout << "Error in " << expression_str[i] << "\n"; + } + + for (auto& e : expression_list) + { + e.value(); + } + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 11 - COMPILATION OPTIONS] +The exprtk::parser when being instantiated takes as input a set of +options to be used during the compilation process of expressions. +An example instantiation of exprtk::parser where only the joiner, +commutative and strength reduction options are enabled is as follows: + + typedef exprtk::parser::settings_t settings_t; + + std::size_t compile_options = settings_t::e_joiner + + settings_t::e_commutative_check + + settings_t::e_strength_reduction; + + parser_t parser(compile_options); + + +Currently seven types of compile time options are supported, and +enabled by default. The options and their explanations are as follows: + + (1) Replacer + (2) Joiner + (3) Numeric Check + (4) Bracket Check + (5) Sequence Check + (6) Commutative Check + (7) Strength Reduction Check + (8) Stack And Node Depth Check + + +(1) Replacer (e_replacer) +Enable replacement of specific tokens with other tokens. For example +the token "true" of type symbol will be replaced with the numeric +token of value one. + + (a) (x < y) == true ---> (x < y) == 1 + (b) false == (x > y) ---> 0 == (x > y) + + +(2) Joiner (e_joiner) +Enable joining of multi-character operators that may have been +incorrectly disjoint in the string representation of the specified +expression. For example the consecutive tokens of ">" "=" will become +">=" representing the "greater than or equal to" operator. If not +properly resolved the original form will cause a compilation error. +The following is a listing of the scenarios that the joiner can +handle: + + (a) '>' '=' ---> '>=' (gte) + (b) '<' '=' ---> '<=' (lte) + (c) '=' '=' ---> '==' (equal) + (d) '!' '=' ---> '!=' (not-equal) + (e) '<' '>' ---> '<>' (not-equal) + (f) ':' '=' ---> ':=' (assignment) + (g) '+' '=' ---> '+=' (addition assignment) + (h) '-' '=' ---> '-=' (subtraction assignment) + (i) '*' '=' ---> '*=' (multiplication assignment) + (j) '/' '=' ---> '/=' (division assignment) + (k) '%' '=' ---> '%=' (modulo assignment) + (l) '+' '-' ---> '-' (subtraction) + (m) '-' '+' ---> '-' (subtraction) + (n) '-' '-' ---> '+' (addition) + (o) '<=' '>' ---> '<=>' (swap) + + +An example of the transformation that takes place is as follows: + + (a) (x > = y) and (z ! = w) ---> (x >= y) and (z != w) + + +(3) Numeric Check (e_numeric_check) +Enable validation of tokens representing numeric types so as to catch +any errors prior to the costly process of the main compilation step +commencing. + + +(4) Bracket Check (e_bracket_check) +Enable the check for validating the ordering of brackets in the +specified expression. + + +(5) Sequence Check (e_sequence_check) +Enable the check for validating that sequences of either pairs or +triplets of tokens make sense. For example the following sequence of +tokens when encountered will raise an error: + + (a) (x + * 3) ---> sequence error + + +(6) Commutative Check (e_commutative_check) +Enable the check that will transform sequences of pairs of tokens that +imply a multiplication operation. The following are some examples of +such transformations: + + (a) 2x ---> 2 * x + (b) 25x^3 ---> 25 * x^3 + (c) 3(x + 1) ---> 3 * (x + 1) + (d) (x + 1)4 ---> (x + 1) * 4 + (e) 5foo(x,y) ---> 5 * foo(x,y) + (f) foo(x,y)6 + 1 ---> foo(x,y) * 6 + 1 + (g) (4((2x)3)) ---> 4 * ((2 * x) * 3) + (h) w(x) + (y)z ---> w * x + y * z + + +(7) Strength Reduction Check (e_strength_reduction) +Enable the use of strength reduction optimisations during the +compilation process. In ExprTk strength reduction optimisations +predominantly involve transforming sub-expressions into other forms +that are algebraically equivalent yet less costly to compute. The +following are examples of the various transformations that can occur: + + (a) (x / y) / z ---> x / (y * z) + (b) (x / y) / (z / w) ---> (x * w) / (y * z) + (c) (2 * x) - (2 * y) ---> 2 * (x - y) + (d) (2 / x) / (3 / y) ---> (2 / 3) / (x * y) + (e) (2 * x) * (3 * y) ---> (2 * 3) * (x * y) + + +Note: +When using strength reduction in conjunction with expressions whose +inputs or sub-expressions may result in values nearing either of the +bounds of the underlying numeric type (eg: double), there may be the +possibility of a decrease in the precision of results. + +In the following example the given expression which represents an +attempt at computing the average between x and y will be transformed +as follows: + + (0.5 * x) + (y * 0.5) ---> 0.5 * (x + y) + +There may be situations where the above transformation will cause +numerical overflows and that the original form of the expression is +desired over the strength reduced form. In these situations it is best +to turn off strength reduction optimisations or to use a type with a +larger numerical bound. + + +(8) Stack And Node Depth Check +ExprTk incorporates a recursive descent parser. When parsing +expressions comprising inner sub-expressions, the recursive nature of +the parsing process causes the stack to grow. If the expression causes +the stack to grow beyond the stack size limit, this would lead to a +stackoverflow and its associated stack corruption and security +vulnerability issues. + +Similarly to parsing, evaluating an expression may cause the stack to +grow. Such things like user defined functions, composite functions and +the general nature of the AST being evaluated can cause the stack to +grow, and may result in potential stackoverflow issues as denoted +above. + +ExprTk provides a set of checks that prevent both of the above denoted +problems at compile time. These check rely on two specific limits +being set on the parser instance, these limits are: + + 1. max_stack_depth (default: 400) + 2. max_node_depth (default: 10000) + + +The following demonstrates how these two parser parameters can be set: + + parser_t parser; + + parser.set_max_stack_depth(100); + parser.set_max_node_depth(200); + + +In the above code, during parsing if the stack depth reaches or +exceeds 100 levels, the parsing process will immediately halt and +return with a failure. Similarly, during synthesizing the AST nodes, +if the compilation process detects an AST tree depth exceeding 200 +levels the parsing process will halt and return a parsing failure. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 12 - EXPRESSION STRUCTURES] +Exprtk supports mathematical expressions in numerous forms based on a +simple imperative programming model. This section will cover the +following topics related to general structure and programming of +expression using ExprTk: + + (1) Multi-Statement Expressions + (2) Statements And Side-Effects + (3) Conditional Statements + (4) Special Functions + + +(1) Multi-Statement Expressions +Expressions in ExprTk can be comprised of one more statements, which +may sometimes be called sub-expressions. The following are two +examples of expressions stored in std::string variables, the first a +single statement and the second a multi-statement expression: + + std::string single_statement = " z := x + y "; + + std::string multi_statement = " var temp := x; " + " x := y + z; " + " y := temp; "; + + +In a multi-statement expression, the final statement will determine +the overall result of the expression. In the following multi-statement +expression, the result of the expression when evaluated will be '2.3', +which will also be the value stored in the 'y' variable. + + z := x + y; + y := 2.3; + + +As demonstrated in the expression above, statements within an +expression are separated using the semi-colon ';' operator. In the +event two statements are not separated by a semi-colon, and the +implied multiplication feature is active (enabled by default), the +compiler will assume a multiplication operation between the two +statements. + +In the following example we have a multi-statement expression composed +of two variable definitions and initialisations for variables x and y +and two seemingly separate mathematical operations. + + var x:= 2; + var y:= 3; + x + 1 + y * 2 + + +However the result of the expression will not be 6 as may have been +assumed based on the calculation of 'y * 2', but rather the result +will be 8. This is because the compiler will have conjoined the two +mathematical statements into one via a multiplication operation. The +expression when compiled will actually evaluate as the following: + + var x:= 2; + var y:= 3; + x + 1 * y * 2; // 2 + 1 * 3 * 2 == 8 + + +In ExprTk any valid statement will itself return a value. This value +can further be used in conjunction with other statements. This +includes language structures such as if-statements, loops (for, while) +and the switch statement. Typically the last statement executed in the +given construct (conditional, loop etc), will be the value that is +returned. + +In the following example, the return value of the expression will be +11, which is the sum of the variable 'x' and the final value computed +within the loop body on its last iteration: + + var x := 1; + x + for (var i := x; i < 10; i += 1) + { + i / 2; + i + 1; + } + + +(2) Statements And Side-Effects +Statements themselves may have side effects, which in-turn effect the +proceeding statements in multi-statement expressions. + +A statement is said to have a side-effect if it causes the state of +the expression to change in some way - this includes but is not +limited to the modification of the state of external variables used +within the expression. Currently the following actions being present +in a statement will cause it to have a side-effect: + + (a) Assignment operation (explicit or potentially) + (b) Invoking a user-defined function that has side-effects + +The following are examples of expressions where the side-effect status +of the statements (sub-expressions) within the expressions have been +noted: + + +-+----------------------+------------------------------+ + |#| Expression | Side Effect Status | + +-+----------------------+------------------------------+ + |0| x + y | False | + +-+----------------------+------------------------------+ + |1| z := x + y | True - Due to assignment | + +-+----------------------+------------------------------+ + |2| abs(x - y) | False | + +-+----------------------+------------------------------+ + |3| abs(x - y); | False | + | | z := (x += y); | True - Due to assignments | + +-+----------------------+------------------------------+ + |4| abs(x - y); | False | + | | z := (x += y); | True - Due to assignments | + +-+----------------------+------------------------------+ + |5| var t := abs(x - y); | True - Due to initialisation | + | | t + x; | False | + | | z := (x += y); | True - Due to assignments | + +-+----------------------+------------------------------+ + |6| foo(x - y) | True - user defined function | + +-+----------------------+------------------------------+ + + +Note: In example 6 from the above set, it is assumed the user defined +function foo has been registered as having a side-effect. By default +all user defined functions are assumed to have side-effects, unless +they are configured in their constructors to not have side-effects +using the 'disable_has_side_effects' free function. For more +information review Section 15 - User Defined Functions sub-section 7 +Function Side-Effects. + +At this point we can see that there will be expressions composed of +certain kinds of statements that when executed will not effect the +nature of the expression's result. These statements are typically +called 'dead code'. These statements though not effecting the final +result will still be executed and as such they will consume processing +time that could otherwise be saved. As such ExprTk attempts to detect +and remove such statements from expressions. + +The 'Dead Code Elimination' (DCE) optimisation process, which is +enabled by default, will remove any statements that are determined to +not have a side effect in a multi-statement expression, excluding the +final or last statement. + +By default the final statement in an expression will always be present +regardless of its side-effect status, as it is the statement whose +value will be used as the result of the expression. + +In order to further explain the actions taken during the DCE process, +lets review the following expression: + + var x := 2; // Statement 1 + var y := x + 2; // Statement 2 + x + y; // Statement 3 + y := x + 3y; // Statement 4 + x - y; // Statement 5 + + +The above expression has five statements. Three of them (1, 2 and 4) +actively have side-effects. The first two are variable declaration and +initialisations, where as the third is due to an assignment operation. +There are two statements (3 and 5), that do not explicitly have +side-effects, however the latter, statement 5, is the final statement +in the expression and hence will be assumed to have a side-effect. + +During compilation when the DCE optimisation is applied to the above +expression, statement 3 will be removed from the expression, as it has +no bearing on the final result of expression, the rest of the +statements will all remain. The optimised form of the expression is as +follows: + + var x := 2; // Statement 1 + var y := x + 2; // Statement 2 + y := x + 3y; // Statement 3 + x - y; // Statement 4 + + +(3) Conditional Statements (If-Then-Else) +ExprTk support two forms of conditional branching or otherwise known +as if-statements. The first form, is a simple function based +conditional statement, that takes exactly three input expressions: +condition, consequent and alternative. The following is an example +expression that utilises the function based if-statement. + + x := if (y < z, y + 1, 2 * z) + + +In the example above, if the condition 'y < z' is true, then the +consequent 'y + 1' will be evaluated, its value will be returned and +subsequently assigned to the variable 'x'. Otherwise the alternative +'2 * z' will be evaluated and its value will be returned. This is +essentially the simplest form of an if-then-else statement. A simple +variation of the expression where the value of the if-statement is +used within another statement is as follows: + + x := 3 * if (y < z, y + 1, 2 * z) / 2 + + +The second form of if-statement resembles the standard syntax found in +most imperative languages. There are two variations of the statement: + + (a) If-Statement + (b) If-Then-Else Statement + + +(a) If-Statement +This version of the conditional statement returns the value of the +consequent expression when the condition expression is true, else it +will return a quiet NaN value as its result. + + Example 1: + x := if (y < z) y + 3; + + Example 2: + x := if (y < z) + { + y + 3 + } + +The two example expressions above are equivalent. If the condition +'y < z' is true, the 'x' variable will be assigned the value of the +consequent 'y + 3', otherwise it will be assigned the value of quiet +NaN. As previously discussed, if-statements are value returning +constructs, and if not properly terminated using a semi-colon, will +end-up combining with the next statement via a multiplication +operation. The following example will NOT result in the expected value +of 'w + x' being returned: + + x := if (y < z) y + 3 // missing semi-colon ';' + w + x + + +When the above supposed multi-statement expression is compiled, the +expression will have a multiplication inserted between the two +'intended' statements resulting in the unanticipated expression: + + x := (if (y < z) y + 3) * w + x + + +The solution to the above situation is to simply terminate the +conditional statement with a semi-colon as follows: + + x := if (y < z) y + 3; + w + x + + +(b) If-Then-Else Statement +The second variation of the if-statement is to allow for the use of +Else and If-Else cascading statements. Examples of such statements are +as follows: + + Example 1: Example 2: Example 3: + if (x < y) if (x < y) if (x > y + 1) + z := x + 3; { y := abs(x - z); + else y := z + x; else + y := x - z; z := x + 3; { + } y := z + x; + else z := x + 3; + y := x - z; }; + + + Example 4: Example 5: Example 6: + if (2 * x < max(y,3)) if (x < y) if (x < y or (x + z) > y) + { z := x + 3; { + y := z + x; else if (2y != z) z := x + 3; + z := x + 3; { y := x - z; + } z := x + 3; } + else if (2y - z) y := x - z; else if (abs(2y - z) >= 3) + y := x - z; } y := x - z; + else else + x * x; { + z := abs(x * x); + x * y * z; + }; + + +In the case where there is no final else statement and the flow +through the conditional arrives at this final point, the same rules +apply to this form of if-statement as to the previous. That is a quiet +NaN will be returned as the result of the if-statement. Furthermore +the same requirements of terminating the statement with a semi-colon +apply. + +(4) Special Functions +The purpose of special functions in ExprTk is to provide compiler +generated equivalents of common mathematical expressions which can be +invoked by using the 'special function' syntax (eg: $f12(x,y,z) or +$f82(x,y,z,w)). + +Special functions dramatically decrease the total evaluation time of +expressions which would otherwise have been written using the common +form by reducing the total number of nodes in the evaluation tree of +an expression and by also leveraging the compiler's ability to +correctly optimise such expressions for a given architecture. + + 3-Parameter 4-Parameter + +-------------+-------------+ +--------------+------------------+ + | Prototype | Operation | | Prototype | Operation | + +-------------+-------------+ +--------------+------------------+ + $f00(x,y,z) | (x + y) / z $f48(x,y,z,w) | x + ((y + z) / w) + $f01(x,y,z) | (x + y) * z $f49(x,y,z,w) | x + ((y + z) * w) + $f02(x,y,z) | (x + y) - z $f50(x,y,z,w) | x + ((y - z) / w) + $f03(x,y,z) | (x + y) + z $f51(x,y,z,w) | x + ((y - z) * w) + $f04(x,y,z) | (x - y) + z $f52(x,y,z,w) | x + ((y * z) / w) + $f05(x,y,z) | (x - y) / z $f53(x,y,z,w) | x + ((y * z) * w) + $f06(x,y,z) | (x - y) * z $f54(x,y,z,w) | x + ((y / z) + w) + $f07(x,y,z) | (x * y) + z $f55(x,y,z,w) | x + ((y / z) / w) + $f08(x,y,z) | (x * y) - z $f56(x,y,z,w) | x + ((y / z) * w) + $f09(x,y,z) | (x * y) / z $f57(x,y,z,w) | x - ((y + z) / w) + $f10(x,y,z) | (x * y) * z $f58(x,y,z,w) | x - ((y + z) * w) + $f11(x,y,z) | (x / y) + z $f59(x,y,z,w) | x - ((y - z) / w) + $f12(x,y,z) | (x / y) - z $f60(x,y,z,w) | x - ((y - z) * w) + $f13(x,y,z) | (x / y) / z $f61(x,y,z,w) | x - ((y * z) / w) + $f14(x,y,z) | (x / y) * z $f62(x,y,z,w) | x - ((y * z) * w) + $f15(x,y,z) | x / (y + z) $f63(x,y,z,w) | x - ((y / z) / w) + $f16(x,y,z) | x / (y - z) $f64(x,y,z,w) | x - ((y / z) * w) + $f17(x,y,z) | x / (y * z) $f65(x,y,z,w) | ((x + y) * z) - w + $f18(x,y,z) | x / (y / z) $f66(x,y,z,w) | ((x - y) * z) - w + $f19(x,y,z) | x * (y + z) $f67(x,y,z,w) | ((x * y) * z) - w + $f20(x,y,z) | x * (y - z) $f68(x,y,z,w) | ((x / y) * z) - w + $f21(x,y,z) | x * (y * z) $f69(x,y,z,w) | ((x + y) / z) - w + $f22(x,y,z) | x * (y / z) $f70(x,y,z,w) | ((x - y) / z) - w + $f23(x,y,z) | x - (y + z) $f71(x,y,z,w) | ((x * y) / z) - w + $f24(x,y,z) | x - (y - z) $f72(x,y,z,w) | ((x / y) / z) - w + $f25(x,y,z) | x - (y / z) $f73(x,y,z,w) | (x * y) + (z * w) + $f26(x,y,z) | x - (y * z) $f74(x,y,z,w) | (x * y) - (z * w) + $f27(x,y,z) | x + (y * z) $f75(x,y,z,w) | (x * y) + (z / w) + $f28(x,y,z) | x + (y / z) $f76(x,y,z,w) | (x * y) - (z / w) + $f29(x,y,z) | x + (y + z) $f77(x,y,z,w) | (x / y) + (z / w) + $f30(x,y,z) | x + (y - z) $f78(x,y,z,w) | (x / y) - (z / w) + $f31(x,y,z) | x * y^2 + z $f79(x,y,z,w) | (x / y) - (z * w) + $f32(x,y,z) | x * y^3 + z $f80(x,y,z,w) | x / (y + (z * w)) + $f33(x,y,z) | x * y^4 + z $f81(x,y,z,w) | x / (y - (z * w)) + $f34(x,y,z) | x * y^5 + z $f82(x,y,z,w) | x * (y + (z * w)) + $f35(x,y,z) | x * y^6 + z $f83(x,y,z,w) | x * (y - (z * w)) + $f36(x,y,z) | x * y^7 + z $f84(x,y,z,w) | x*y^2 + z*w^2 + $f37(x,y,z) | x * y^8 + z $f85(x,y,z,w) | x*y^3 + z*w^3 + $f38(x,y,z) | x * y^9 + z $f86(x,y,z,w) | x*y^4 + z*w^4 + $f39(x,y,z) | x * log(y)+z $f87(x,y,z,w) | x*y^5 + z*w^5 + $f40(x,y,z) | x * log(y)-z $f88(x,y,z,w) | x*y^6 + z*w^6 + $f41(x,y,z) | x * log10(y)+z $f89(x,y,z,w) | x*y^7 + z*w^7 + $f42(x,y,z) | x * log10(y)-z $f90(x,y,z,w) | x*y^8 + z*w^8 + $f43(x,y,z) | x * sin(y)+z $f91(x,y,z,w) | x*y^9 + z*w^9 + $f44(x,y,z) | x * sin(y)-z $f92(x,y,z,w) | (x and y) ? z : w + $f45(x,y,z) | x * cos(y)+z $f93(x,y,z,w) | (x or y) ? z : w + $f46(x,y,z) | x * cos(y)-z $f94(x,y,z,w) | (x < y) ? z : w + $f47(x,y,z) | x ? y : z $f95(x,y,z,w) | (x <= y) ? z : w + $f96(x,y,z,w) | (x > y) ? z : w + $f97(x,y,z,w) | (x >= y) ? z : w + $f98(x,y,z,w) | (x == y) ? z : w + $f99(x,y,z,w) | x*sin(y)+z*cos(w) + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 13 - VARIABLE, VECTOR & STRING DEFINITION] +ExprTk supports the definition of expression local variables, vectors +and strings. The definitions must be unique as shadowing is not +allowed and object life-times are based on scope. Definitions use the +following general form: + + var := ; + +(1) Variable Definition +Variables are of numeric type denoting a single value. They can be +explicitly initialised to a value, otherwise they will be defaulted to +zero. The following are examples of variable definitions: + + (a) Initialise x to zero + var x; + + (b) Initialise y to three + var y := 3; + + (c) Initialise z to the expression + var z := if (max(1, x + y) > 2, w, v); + + +(2) Vector Definition +Vectors are arrays of a common numeric type. The elements in a vector +can be explicitly initialised, otherwise they will all be defaulted to +zero. The following are examples of vector definitions: + + (a) Initialise all values to zero + var x[3]; + + (b) Initialise all values to zero + var x[3] := {}; + + (c) Initialise all values to given expression + var x[3] := [123 + 3y + sin(w / z)]; + + (d) Initialise the first two values, all other elements to zero + var x[3] := { 1 + x[2], sin(y[0] / x[]) + 3 }; + + (e) Initialise the first three (all) values + var x[3] := { 1, 2, 3 }; + + (f) Initialise vector from a vector + var x[4] := { 1, 2, 3, 4 }; + var y[3] := x; + + (g) Initialise vector from a smaller vector + var x[3] := { 1, 2, 3 }; + var y[5] := x; // 1, 2, 3, ??, ?? + + (h) Non-initialised vector + var x[3] := null; // ?? ?? ?? + + (i) Error as there are too many initialisers + var x[3] := { 1, 2, 3, 4 }; + + (j) Error as a vector of size zero is not allowed. + var x[0]; + + +(3) String Definition +Strings are sequences comprised of 8-bit characters. They can only be +defined with an explicit initialisation value. The following are +examples of string variable definitions: + + (a) Initialise to a string + var x := 'abc'; + + (b) Initialise to an empty string + var x := ''; + + (c) Initialise to a string expression + var x := 'abc' + '123'; + + (d) Initialise to a string range + var x := 'abc123'[2:4]; + + (e) Initialise to another string variable + var x := 'abc'; + var y := x; + + (f) Initialise to another string variable range + var x := 'abc123'; + var y := x[2:4]; + + (g) Initialise to a string expression + var x := 'abc'; + var y := x + '123'; + + (h) Initialise to a string expression range + var x := 'abc'; + var y := (x + '123')[1:3]; + + +(4) Return Value +Variable and vector definitions have a return value. In the case of +variable definitions, the value to which the variable is initialised +will be returned. Where as for vectors, the value of the first element +(eg: v[0]) will be returned. + + 8 == ((var x := 7;) + 1) + 4 == (var y[3] := {4, 5, 6};) + + +(5) Variable/Vector Assignment +The value of a variable can be assigned to a vector and a vector or a +vector expression can be assigned to a variable. + + (a) Variable To Vector: + Every element of the vector is assigned the value of the variable + or expression. + var x := 3; + var y[3] := { 1, 2, 3 }; + y := x + 1; + + (b) Vector To Variable: + The variable is assigned the value of the first element of the + vector (aka vec[0]) + var x := 3; + var y[3] := { 1, 2, 3 }; + x := y + 1; + + +Note: During the expression compilation phase, tokens are classified +based on the following priorities: + + (a) Reserved keywords or operators (+, -, and, or, etc) + (b) Base functions (abs, sin, cos, min, max etc) + (c) Symbol table variables + (d) Expression local defined variables + (e) Symbol table functions + (f) Unknown symbol resolver based variables + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 14 - VECTOR PROCESSING] +ExprTk provides support for various forms of vector oriented +arithmetic, inequalities and processing. The various supported pairs +are as follows: + + (a) vector and vector (eg: v0 + v1) + (b) vector and scalar (eg: v + 33) + (c) scalar and vector (eg: 22 * v) + +The following is a list of operations that can be used in conjunction +with vectors: + + (a) Arithmetic: +, -, *, /, % + (b) Exponentiation: vector ^ scalar + (c) Assignment: :=, +=, -=, *=, /=, %=, <=> + (d) Inequalities: <, <=, >, >=, ==, =, equal + (e) Boolean logic: and, nand, nor, or, xnor, xor + (f) Unary operations: + abs, acos, acosh, asin, asinh, atan, atanh, ceil, cos, cosh, + cot, csc, deg2grad, deg2rad, erf, erfc, exp, expm1, floor, + frac, grad2deg, log, log10, log1p, log2, rad2deg, round, sec, + sgn, sin, sinc, sinh, sqrt, swap, tan, tanh, trunc + (g) Aggregate and Reduce operations: + avg, max, min, mul, dot, dotk, sum, sumk, count, all_true, + all_false, any_true, any_false + (h) Transformation operations: + copy, rotate-left/right, shift-left/right, sort, nth_element + (i) BLAS-L1: + axpy, axpby, axpyz, axpbyz, axpbz + +Note: When one of the above described operations is being performed +between two vectors, the operation will only span the size of the +smallest vector. The elements of the larger vector outside of the +range will not be included. The operation itself will be processed +element-wise over values the smaller of the two ranges. + +The following simple example demonstrates the vector processing +capabilities by computing the dot-product of the vectors v0 and v1 and +then assigning it to the variable v0dotv1: + + var v0[3] := { 1, 2, 3 }; + var v1[3] := { 4, 5, 6 }; + var v0dotv1 := sum(v0 * v1); + + +The following is a for-loop based implementation that is equivalent to +the previously mentioned dot-product computation expression: + + var v0[3] := { 1, 2, 3 }; + var v1[3] := { 4, 5, 6 }; + var v0dotv1; + + for (var i := 0; i < min(v0[],v1[]); i += 1) + { + v0dotv1 += (v0[i] * v1[i]); + } + + +Note: When the aggregate or reduction operations denoted above are +used in conjunction with a vector or vector expression, the return +value is not a vector but rather a single value. + + var x[3] := { 1, 2, 3 }; + + sum(x) == 6 + sum(1 + 2x) == 15 + avg(3x + 1) == 7 + min(1 / x) == (1 / 3) + max(x / 2) == (3 / 2) + sum(x > 0 and x < 5) == x[] + + +When utilising external user defined vectors via the symbol table as +opposed to expression local defined vectors, the typical 'add_vector' +method from the symbol table will register the entirety of the vector +that is passed. The following example attempts to evaluate the sum of +elements of the external user defined vector within a typical yet +trivial expression: + + std::string reduce_program = " sum(2 * v + 1) "; + + std::vector v0 { T(1.1), T(2.2), ..... , T(99.99) }; + + symbol_table_t symbol_table; + symbol_table.add_vector("v",v); + + expression_t expression; + expression.register_symbol_table(symbol_table); + + parser_t parser; + parser.compile(reduce_program,expression); + + T sum = expression.value(); + + +For the most part, this is a very common use-case. However there may +be situations where one may want to evaluate the same vector oriented +expression many times over, but using different vectors or sub ranges +of the same vector of the same size to that of the original upon every +evaluation. + +The usual solution is to either recompile the expression for the new +vector instance, or to copy the contents from the new vector to the +symbol table registered vector and then perform the evaluation. When +the vectors are large or the re-evaluation attempts are numerous, +these solutions can become rather time consuming and generally +inefficient. + + std::vector v1 { T(2.2), T(2.2), ..... , T(2.2) }; + std::vector v2 { T(3.3), T(3.3), ..... , T(3.3) }; + std::vector v3 { T(4.4), T(4.4), ..... , T(4.4) }; + + std::vector> vv { v1, v2, v3 }; + ... + T sum = T(0); + + for (auto& new_vec : vv) + { + v = new_vec; // update vector + sum += expression.value(); + } + + +A solution to the above 'efficiency' problem, is to use the +exprtk::vector_view object. The vector_view is instantiated with a +size and backing based upon a vector. Upon evaluations if the backing +needs to be 'updated' to either another vector or sub-range, the +vector_view instance can be efficiently rebased, and the expression +evaluated as normal. + + exprtk::vector_view view = exprtk::make_vector_view(v,v.size()); + + symbol_table_t symbol_table; + symbol_table.add_vector("v",view); + + ... + + T sum = T(0); + + for (auto& new_vec : vv) + { + view.rebase(new_vec.data()); // update vector + sum += expression.value(); + } + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 15 - USER DEFINED FUNCTIONS] +ExprTk provides a means whereby custom functions can be defined and +utilised within expressions. The concept requires the user to +provide a reference to the function coupled with an associated name +that will be invoked within expressions. Functions may take numerous +inputs but will always return a single value of the underlying numeric +type. + +During expression compilation when required the reference to the +function will be obtained from the associated symbol_table and be +embedded into the expression. + +There are five types of function interface: + + +---+----------------------+--------------+----------------------+ + | # | Name | Return Type | Input Types | + +---+----------------------+--------------+----------------------+ + | 1 | ifunction | Scalar | Scalar | + | 2 | ivararg_function | Scalar | Scalar | + | 3 | igeneric_function | Scalar | Scalar,Vector,String | + | 4 | igeneric_function II | String | Scalar,Vector,String | + | 5 | igeneric_function III| String/Scalar| Scalar,Vector,String | + | 6 | function_compositor | Scalar | Scalar | + +---+----------------------+--------------+----------------------+ + +(1) ifunction +This interface supports zero to 20 input parameters of only the scalar +type (numbers). The usage requires a custom function be derived from +ifunction and to override one of the 21 function operators. As part of +the constructor the custom function will define how many parameters it +expects to handle. The following example defines a 3 parameter +function called 'foo': + + template + struct foo : public exprtk::ifunction + { + foo() : exprtk::ifunction(3) + {} + + T operator()(const T& v1, const T& v2, const T& v3) + { + return T(1) + (v1 * v2) / T(v3); + } + }; + + +(2) ivararg_function +This interface supports a variable number of scalar arguments as input +into the function. The function operator interface uses a std::vector +specialised upon type T to facilitate parameter passing. The following +example defines a vararg function called 'boo': + + template + struct boo : public exprtk::ivararg_function + { + inline T operator()(const std::vector& arglist) + { + T result = T(0); + + for (std::size_t i = 0; i < arglist.size(); ++i) + { + result += arglist[i] / arglist[i > 0 ? (i - 1) : 0]; + } + + return result; + } + }; + + +(3) igeneric_function +This interface supports a variable number of arguments and types as +input into the function. The function operator interface uses a +std::vector specialised upon the type_store type to facilitate +parameter passing. + + Scalar <-- function(i_0, i_1, i_2....., i_N) + + +The fundamental types that can be passed into the function as +parameters and their views are as follows: + + (1) Scalar - scalar_view + (2) Vector - vector_view + (3) String - string_view + + +The above denoted type views provide non-const reference-like access +to each parameter, as such modifications made to the input parameters +will persist after the function call has completed. The following +example defines a generic function called 'too': + + template + struct too : public exprtk::igeneric_function + { + typedef typename exprtk::igeneric_function::parameter_list_t + parameter_list_t; + + too() + {} + + inline T operator()(parameter_list_t parameters) + { + for (std::size_t i = 0; i < parameters.size(); ++i) + { + ... + } + + return T(0); + } + }; + + +In the example above, the input 'parameters' to the function operator, +parameter_list_t, is a type of std::vector of type_store. Each +type_store instance has a member called 'type' which holds the +enumeration pertaining to the underlying type of the type_store. There +are three type enumerations: + + (1) e_scalar - literals, variables, vector elements, expressions + eg: 123.456, x, vec[3x + 1], 2x + 3 + + (2) e_vector - vectors, vector expressions + eg: vec1, 2 * vec1 + vec2 / 3 + + (3) e_string - strings, string literals and range variants of both + eg: 'AString', s0, 'AString'[x:y], s1[1 + x:] + 'AString' + + +Each of the parameters can be accessed using its designated view. A +typical loop for processing the parameters is as follows: + + inline T operator()(parameter_list_t parameters) + { + typedef typename exprtk::igeneric_function::generic_type + generic_type; + + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + typedef typename generic_type::string_view string_t; + + for (std::size_t i = 0; i < parameters.size(); ++i) + { + generic_type& gt = parameters[i]; + + if (generic_type::e_scalar == gt.type) + { + scalar_t x(gt); + ... + } + else if (generic_type::e_vector == gt.type) + { + vector_t vector(gt); + ... + } + else if (generic_type::e_string == gt.type) + { + string_t string(gt); + ... + } + } + + return T(0); + } + + +Most often than not a custom generic function will require a specific +sequence of parameters, rather than some arbitrary sequence of types. +In those situations, ExprTk can perform compile-time type checking to +validate that function invocations are carried out using the correct +sequence of parameters. Furthermore performing the checks at compile +-time rather than at run-time (aka every time the function is invoked) +will result in expression evaluation performance gains. + +Compile-time type checking of input parameters can be requested by +passing a string to the constructor of the igeneric_function that +represents the required sequence of parameter types. When no parameter +sequence is provided, it is implied the function can accept a variable +number of parameters comprised of any of the fundamental types. + +Each fundamental type has an associated character. The following is a +listing of said characters and their meanings: + + (1) T - Scalar + (2) V - Vector + (3) S - String + (4) Z - Zero or no parameters + (5) ? - Any type (Scalar, Vector or String) + (6) * - Wildcard operator + (7) | - Parameter sequence delimiter + + +No other characters other than the seven denoted above may be included +in the parameter sequence definition. If any such invalid characters +do exist, registration of the associated generic function to a symbol +table ('add_function' method) will fail. If the parameter sequence is +modified resulting in it becoming invalid after having been added to +the symbol table but before the compilation step, a compilation error +will be incurred. + +The following example demonstrates a simple generic function +implementation with a user specified parameter sequence: + + template + struct moo : public exprtk::igeneric_function + { + typedef typename exprtk::igeneric_function::parameter_list_t + parameter_list_t; + + moo() + : exprtk::igeneric_function("SVTT") + {} + + inline T operator()(parameter_list_t parameters) + { + ... + } + }; + + +In the example above the generic function 'moo' expects exactly four +parameters in the following sequence: + + (1) String + (2) Vector + (3) Scalar + (4) Scalar + +Note: The 'Z' or no parameter option may not be used in conjunction +with any other type option in a parameter sequence. When incorporated +in the parameter sequence list, the no parameter option indicates that +the function may be invoked without any parameters being passed. For +more information refer to the section: 'Zero Parameter Functions' + + +(4) igeneric_function II +This interface is identical to the igeneric_function, in that in can +consume an arbitrary number of parameters of varying type, but the +difference being that the function returns a string and as such is +treated as a string when invoked within expressions. As a result the +function call can alias a string and interact with other strings in +situations such as concatenation and equality operations. + + String <-- function(i_0, i_1, i_2....., i_N) + + +The following example defines a generic function named 'toupper' with +the string return type function operator being explicitly overridden: + + template + struct toupper : public exprtk::igeneric_function + { + typedef exprtk::igeneric_function igenfunct_t + typedef typename igenfunct_t::generic_type generic_t; + typedef typename igenfunct_t::parameter_list_t parameter_list_t; + typedef typename generic_t::string_view string_t; + + toupper() + : exprtk::igeneric_function("S",igenfunct_t::e_rtrn_string) + {} + + inline T operator()(std::string& result, + parameter_list_t parameters) + { + result.clear(); + + string_t string(params[0]); + + for (std::size_t i = 0; i < string.size(); ++i) + { + result += std::toupper(string[i]); + } + + return T(0); + } + }; + + +In the example above the generic function 'toupper' expects only one +input parameter of type string, as noted by the parameter sequence +string passed during the constructor. Furthermore a second parameter +is passed to the constructor indicating that it should be treated as a +string returning function - by default it is assumed to be a scalar +returning function. + +When executed, the function will return as a result a copy of the +input string converted to uppercase form. An example expression using +the toupper function registered as the symbol 'toupper' is as follows: + + "'ABCDEF' == toupper('aBc') + toupper('DeF')" + + +Note: When adding a string type returning generic function to a symbol +table the 'add_function' is invoked. The example below demonstrates +how this can be done: + + toupper tu; + + exprtk::symbol_table symbol_table; + + symbol_table.add_function("toupper",tu); + + +Note: Two further refinements to the type checking facility are the +possibilities of a variable number of common types which can be +accomplished by using a wildcard '*' and a special 'any type' which is +done using the '?' character. It should be noted that the wildcard +operator is associated with the previous type in the sequence and +implies one or more of that type. + + template + struct zoo : public exprtk::igeneric_function + { + typedef typename exprtk::igeneric_function::parameter_list_t + parameter_list_t; + + zoo() + : exprtk::igeneric_function("SVT*V?") + {} + + inline T operator()(parameter_list_t parameters) + { + ... + } + }; + + +In the example above the generic function 'zoo' expects at least five +parameters in the following sequence: + + (1) String + (2) Vector + (3) One or more Scalars + (4) Vector + (5) Any type (one type of either a scalar, vector or string) + + +A final piece of type checking functionality is available for the +scenarios where a single function name is intended to be used for +multiple distinct parameter sequences, another name for this feature +is function overloading. The parameter sequences are passed to the +constructor as a single string delimited by the pipe '|' character. +Two specific overrides of the function operator are provided one for +standard generic functions and one for string returning functions. The +overrides are as follows: + + // Scalar <-- function(psi,i_0,i_1,....,i_N) + inline T operator()(const std::size_t& ps_index, + parameter_list_t parameters) + { + ... + } + + // String <-- function(psi,i_0,i_1,....,i_N) + inline T operator()(const std::size_t& ps_index, + std::string& result, + parameter_list_t parameters) + { + ... + } + + +When the function operator is invoked the 'ps_index' parameter will +have as its value the index of the parameter sequence that matches the +specific invocation. This way complex and time consuming type checking +conditions need not be executed in the function itself but rather a +simple and efficient dispatch to a specific implementation for that +particular parameter sequence can be performed. + + template + struct roo : public exprtk::igeneric_function + { + typedef typename exprtk::igeneric_function::parameter_list_t + parameter_list_t; + + moo() + : exprtk::igeneric_function("SVTT|SS|TTV|S?V*S") + {} + + inline T operator()(const std::size_t& ps_index, + parameter_list_t parameters) + { + ... + } + }; + + +In the example above there are four distinct parameter sequences that +can be processed by the generic function 'roo'. Any other parameter +sequences will cause a compilation error. The four valid sequences are +as follows: + + Sequence-0 Sequence-1 Sequence-2 Sequence-3 + 'SVTT' 'SS' 'TTV' 'S?V*S' + (1) String (1) String (1) Scalar (1) String + (2) Vector (2) String (2) Scalar (2) Any Type + (3) Scalar (3) Vector (3) One or more Vectors + (4) Scalar (4) String + + +(5) igeneric_function III +In this section we will discuss an extension of the igeneric_function +interface that will allow for the overloading of a user defined custom +function, where by it can return either a scalar or string value type +depending on the input parameter sequence with which the function is +invoked. + + template + struct foo : public exprtk::igeneric_function + { + typedef typename exprtk::igeneric_function::parameter_list_t + parameter_list_t; + + foo() + : exprtk::igeneric_function + ( + "T:T|S:TS", + igfun_t::e_rtrn_overload + ) + {} + + // Scalar value returning invocations + inline T operator()(const std::size_t& ps_index, + parameter_list_t parameters) + { + ... + } + + // String value returning invocations + inline T operator()(const std::size_t& ps_index, + std::string& result, + parameter_list_t& parameters) + { + ... + } + }; + + +In the example above the custom user defined function "foo" can be +invoked by using either one of two input parameter sequences, which +are defined as follows: + + Sequence-0 Sequence-1 + 'T' -> T 'TS' -> S + (1) Scalar (1) Scalar + (2) String + + +The parameter sequence definitions are identical to the previously +define igeneric_function, with the exception of the inclusion of the +return type - which can only be either a scalar T or a string S. + + +(6) function_compositor +The function compositor is a factory that allows one to define and +construct a function using ExprTk syntax. The functions are limited to +returning a single scalar value and consuming up to six parameters as +input. + +All composited functions are registered with a symbol table, allowing +them to call other functions that have been registered with the symbol +table instance. Furthermore the functions can be recursive in nature +due to the inherent function prototype forwarding that occurs during +construction. The following example defines, by using two different +methods, composited functions and implicitly registering the functions +with the denoted symbol table. + + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::function_compositor compositor_t; + typedef typename compositor_t::function function_t; + + symbol_table_t symbol_table; + + compositor_t compositor(symbol_table); + + // define function koo0(v1,v2) { ... } + compositor + .add( + function_t( + "koo0", + " 1 + cos(v1 * v2) / 3;", + "v1","v2")); + + // define function koo1(x,y,z) { ... } + compositor + .add(function_t() + .name("koo1") + .var("x").var("y").var("z") + .expression("1 + cos(x * y) / z;")); + + +(6) Using Functions In Expressions +For the above denoted custom and composited functions to be used in an +expression, an instance of each function needs to be registered with a +symbol_table that has been associated with the expression instance. +The following demonstrates how all the pieces are put together: + + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + typedef exprtk::function_compositor compositor_t; + typedef typename compositor_t::function function_t; + + foo f; + boo b; + too t; + toupper tu; + + symbol_table_t symbol_table; + compositor_t compositor(symbol_table); + + symbol_table.add_function("foo",f); + symbol_table.add_function("boo",b); + symbol_table.add_function("too",t); + + symbol_table.add_function("toupper", + tu, + symbol_table_t::e_ft_strfunc); + + compositor + .add(function_t() + .name("koo") + .var("v1") + .var("v2") + .expression("1 + cos(v1 * v2) / 3;")); + + expression_t expression; + expression.register_symbol_table(symbol_table); + + std::string expression_str = + " if (foo(1,2,3) + boo(1) > boo(1/2,2/3,3/4,4/5)) " + " koo(3,4); " + " else " + " too(2 * v1 + v2 / 3, 'abcdef'[2:4], 3.3); " + " "; + + parser_t parser; + parser.compile(expression_str,expression); + + expression.value(); + + +(7) Function Side-Effects +All function calls are assumed to have side-effects by default. This +assumption implicitly disables constant folding optimisations when all +parameters being passed to the function are deduced as being constants +at compile time. + +If it is certain that the function being registered does not have any +side effects and can be correctly constant folded where appropriate, +then during the construction of the function the side-effect trait of +the function can be disabled. + + template + struct foo : public exprtk::ifunction + { + foo() : exprtk::ifunction(3) + { + exprtk::disable_has_side_effects(*this); + } + + T operator()(const T& v1, const T& v2, const T& v3) + { ... } + }; + + +(8) Zero Parameter Functions +When either an ifunction, ivararg_function or igeneric_function +derived type is defined with zero number of parameters, there are two +calling conventions within expressions that are allowed. For a +function named 'foo' with zero input parameters the calling styles are +as follows: + + (1) x + sin(foo()- 2) / y + (2) x + sin(foo - 2) / y + + +By default the zero parameter trait is disabled. In order to enable +it, a process similar to that of enabling of the side effect trait is +carried out: + + template + struct foo : public exprtk::ivararg_function + { + foo() + { + exprtk::enable_zero_parameters(*this); + } + + inline T operator()(const std::vector& arglist) + { ... } + }; + + +Note: For the igeneric_function type, there also needs to be a 'Z' +parameter sequence defined in order for the zero parameter trait to +properly take effect otherwise a compilation error will occur. + + +(9) Free Functions +The ExprTk symbol table supports the registration of free functions +and lambdas (anonymous functors) for use in expressions. The basic +requirements are similar to those found in ifunction derived user +defined functions. This includes support for free functions using +anywhere from zero up to fifteen input parameters of scalar type, with +a return type that is also scalar. Furthermore such functions will by +default be assumed to have side-effects and hence will not participate +in constant folding optimisations. + +In the following example, a two input parameter free function named +'compute1', and a three input parameter lambda named 'compute2' will +be registered with the given symbol_table instance: + + + double compute1(double v0, double v1) + { + return 2.0 * v0 + v1 / 3.0; + } + + . + . + . + + typedef exprtk::symbol_table symbol_table_t; + + symbol_table_t symbol_table; + + symbol_table.add_function("compute1", compute1); + + symbol_table.add_function( + "compute2", + [](double v0, double v1, double v2) -> double + { return v0 / v1 + v2; }); + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 16 - EXPRESSION DEPENDENTS] +Any expression that is not a literal (aka constant) will have +dependencies. The types of 'dependencies' an expression can have are +as follows: + + (a) Variables + (b) Vectors + (c) Strings + (d) Functions + (e) Assignments + + +In the following example the denoted expression has its various +dependencies listed: + + z := abs(x + sin(2 * pi / y)) + + (a) Variables: x, y, z and pi + (b) Functions: abs, sin + (c) Assignments: z + + +ExprTk allows for the derivation of expression dependencies via the +'dependent_entity_collector' (DEC). When activated either through +'compile_options' at the construction of the parser or through calls +to enabler methods just prior to compilation, the DEC will proceed to +collect any of the relevant types that are encountered during the +parsing phase. Once the compilation process has successfully +completed, the caller can then obtain a list of symbols and their +associated types from the DEC. + +The kinds of questions one can ask regarding the dependent entities +within an expression are as follows: + + * What user defined variables, vectors or strings are used? + * What functions or custom user functions are used? + * Which variables, vectors or strings have values assigned to them? + + +The following example demonstrates usage of the DEC in determining the +dependents of the given expression: + + typedef typename parser_t:: + dependent_entity_collector::symbol_t symbol_t; + + std::string expression_string = + "z := abs(x + sin(2 * pi / y))"; + + T x,y,z; + + parser_t parser; + symbol_table_t symbol_table; + + symbol_table.add_variable("x",x); + symbol_table.add_variable("y",y); + symbol_table.add_variable("z",z); + + expression_t expression; + expression.register_symbol_table(symbol_table); + + //Collect only variable and function symbols + parser.dec().collect_variables() = true; + parser.dec().collect_functions() = true; + + if (!parser.compile(expression_string,expression)) + { + // error.... + } + + std::deque symbol_list; + + parser.dec().symbols(symbol_list); + + for (std::size_t i = 0; i < symbol_list.size(); ++i) + { + symbol_t& symbol = symbol_list[i]; + + switch (symbol.second) + { + case parser_t::e_st_variable : ... break; + case parser_t::e_st_vector : ... break; + case parser_t::e_st_string : ... break; + case parser_t::e_st_function : ... break; + } + } + + +Note: The 'symbol_t' type is a std::pair comprising of the symbol name +(std::string) and the associated type of the symbol as denoted by the +cases in the switch statement. + +Having particular symbols (variable or function) present in an +expression is one form of dependency. Another and just as interesting +and important type of dependency is that of assignments. Assignments +are the set of dependent symbols that 'may' have their values modified +within an expression. The following are example expressions and their +associated assignments: + + Assignments Expression + (1) x x := y + z + (2) x, y x += y += z + (3) x, y, z x := y += sin(z := w + 2) + (4) w, z if (x > y, z := x + 2, w := 'A String') + (5) None x + y + z + + +Note: In expression 4, both variables 'w' and 'z' are denoted as being +assignments even though only one of them can ever be modified at the +time of evaluation. Furthermore the determination of which of the two +variables the modification will occur upon can only be known with +certainty at evaluation time and not beforehand, hence both are listed +as being candidates for assignment. + +The following builds upon the previous example demonstrating the usage +of the DEC in determining the 'assignments' of the given expression: + + //Collect assignments + parser.dec().collect_assignments() = true; + + if (!parser.compile(expression_string,expression)) + { + // error.... + } + + std::deque symbol_list; + + parser.dec().assignment_symbols(symbol_list); + + for (std::size_t i = 0; i < symbol_list.size(); ++i) + { + symbol_t& symbol = symbol_list[i]; + + switch (symbol.second) + { + case parser_t::e_st_variable : ... break; + case parser_t::e_st_vector : ... break; + case parser_t::e_st_string : ... break; + } + } + + +Note: The assignments will only consist of variable types and as such +will not contain symbols denoting functions. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 17 - HIERARCHIES OF SYMBOL TABLES] +Most situations will only require a single symbol_table instance to be +associated with a given expression instance. + +However as an expression can have more than one symbol table instance +associated with itself, when building more complex systems that +utilise many expressions where each can in turn utilise one or more +variables from a large set of potential variables, functions or +constants, it becomes evident that grouping variables into layers of +symbol_tables will simplify and streamline the overall process. + +A suggested hierarchy of symbol tables is as follows: + + (a) Global constant value symbol table + (b) Global non side-effect functions symbol table + (c) Global variable symbol table + (d) Expression specific variable symbol table + + +(a) Global constant value symbol table +This symbol table will contain constant variables denoting immutable +values. These variables can be made available to all expressions, and +in turn expressions will assume the values themselves will never be +modified for the duration of the process run-time. Examples of such +variables are: + + (1) pi or e + (2) speed_of_light + (3) avogadro_number + (4) num_cpus + + +(b) Global non side-effect functions symbol table +This symbol table will contain only user defined functions that will +not incur any side-effects that are visible to any of the expressions +that invoke them. These functions will be thread-safe or threading +invariant and will not maintain any form of state between invocations. +Examples of such functions are: + + (1) calc_volume_of_sphere(r) + (2) distance(x0,y0,x1,y1) + + +(c) Global variable symbol table +This symbol table will contain variables that will be accessible to +all associated expressions and will not be specific or exclusive to +any one expression. This variant differs from (a) in that the values +of the variables can change (or be updated) between evaluations of +expressions - but through properly scheduled evaluations are +guaranteed to never change during the evaluation of any dependent +expressions. Furthermore it is assumed that these variables will be +used in a read-only context and that no expressions will attempt to +modify these variables via assignments or other means. + + (1) price_of_stock_xyz + (2) outside_temperature or inside_temperature + (3) fuel_in_tank + (4) num_customers_in_store + (5) num_items_on_shelf + + +(d) Expression specific variable symbol table +This symbol_table is the most common form, and is used to store +variables that are specific and exclusive to a particular expression. +That is to say references to variables in this symbol_table will not +be part of another expression. Though it may be possible to have +expressions that contain the variables with the same name, in that +case those variables will be distinctly different. Which would mean if +a particular expression were to be compiled twice, each expression +would have its own unique symbol_table which in turn would have its +own instances of those variables. Examples of such variables could be: + + (1) x or y + (2) customer_name + + +The following is a diagram depicting the possible version of the +denoted symbol table hierarchies. In the diagram there are two unique +expressions, each of which have a reference to the Global constant, +functions and variables symbol tables and an exclusive reference to a +local symbol table. + + +-------------------------+ +-------------------------+ + | Global Constants | | Global Functions | + | Symbol Table | | Symbol Table | + +----o--o-----------------+ +--------------------o----+ + | | | + | | +-------+ + | +------------------->----------------------------+ | + | +----------------------------+ | | + | | Global Variables | | | + | +------o Symbol Table o-----+ | V + | | +----------------------------+ | | | + | | | | | + | | +----------------+ +----------------+ | | | + | | | Symbol Table 0 | | Symbol Table 1 | | V | + | | +--o-------------+ +--o-------------+ | | | + | | | | | | | + | | | | | | | + +--V--V----V---------+ +-V---------------V--+ | | + | Expression 0 | | Expression 1 |<--+--+ + | '2 * sin(x) - y' | | 'k + abs(x - y)' | + +--------------------+ +--------------------+ + + +Bringing all of the above together, in the following example the +hierarchy of symbol tables are instantiated and initialised. An +expression that makes use of various elements of each symbol table is +then compiled and later on evaluated: + + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + + // Setup global constants symbol table + symbol_table_t glbl_const_symbol_table; + glbl_const_symbtab.add_constants(); // pi, epsilon and inf + glbl_const_symbtab.add_constant("speed_of_light",299e6); + glbl_const_symbtab.add_constant("avogadro_number",6e23); + + // Setup global function symbol table + symbol_table_t glbl_funcs_symbol_table; + glbl_func_symbtab.add_function('distance',distance); + glbl_func_symbtab.add_function('calc_spherevol',calc_sphrvol); + + ...... + + // Setup global variable symbol table + symbol_table_t glbl_variable_symbol_table; + glbl_variable_symbtab.add_variable('temp_outside',thermo.outside); + glbl_variable_symbtab.add_variable('temp_inside' ,thermo.inside ); + glbl_variable_symbtab.add_variable('num_cstmrs',store.num_cstmrs); + + ...... + + double x,y,z; + + // Setup expression specific symbol table + symbol_table_t symbol_table; + symbol_table.add_variable('x',x); + symbol_table.add_variable('y',y); + symbol_table.add_variable('z',z); + + expression_t expression; + + // Register the various symbol tables + expression + .register_symbol_table(symbol_table); + + expression + .register_symbol_table(glbl_funcs_symbol_table); + + expression + .register_symbol_table(glbl_const_symbol_table); + + expression + .register_symbol_table(glbl_variable_symbol_table); + + std::string expression_str = + "abs(temp_inside - temp_outside) + 2 * speed_of_light / x"; + + parser_t parser; + parser.compile(expression_str,expression); + + ...... + + while (keep_evaluating) + { + .... + + T result = expression.value(); + + .... + } + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 18 - UNKNOWN UNKNOWNS] +In this section we will discuss the process of handling expressions +with a mix of known and unknown variables. Initially a discussion into +the types of expressions that exist will be provided, then a series of +possible solutions will be presented for each scenario. + +When parsing an expression, there may be situations where one is not +fully aware of what if any variables will be used prior to the +expression being compiled. + +This can become problematic, as in the default scenario it is assumed +the symbol_table that is registered with the expression instance will +already possess the externally available variables, functions and +constants needed during the compilation of the expression. + +In the event there are symbols in the expression that can't be mapped +to either a reserved word, or located in the associated +symbol_table(s), an "Undefined symbol" error will be raised and the +compilation process will fail. + +The numerous scenarios that can occur when compiling an expression +with ExprTk generally fall into one of the following three categories: + + (a) No external variables + (b) Predetermined set of external variables + (c) Unknown set of variables + + +(a) No external variables +These are expressions that contain no external variables but may +contain local variables. As local variables cannot be accessed +externally from the expression, it is assumed that such expressions +will not have a need for a symbol_table and furthermore expressions +which don't make use of functions that have side-effects will be +evaluated completely at compile time resulting in a constant return +value. The following are examples of such expressions: + + (1) 1 + 2 + (2) var x := 3; 2 * x - 3 + (3) var x := 3; var y := abs(x - 8); x - y / 7 + + +(b) Predetermined set of external variables +These are expressions that are comprised of externally available +variables and functions and will only compile successfully if the +symbols that correspond to the variables and functions are already +defined in their associated symbol_table(s). This is by far the most +common scenario when using ExprTk. + +As an example, one may have three external variables: x, y and z which +have been registered with the associated symbol_table, and will then +need to compile and evaluate expressions comprised of any subset of +these three variables. The following are a few examples of such +expressions: + + (1) 1 + x + (2) x / y + (3) 2 * x * y / z + + +In this scenario one can use the 'dependent_entity_collector' +component as described in [Section 16] to further determine which of +the registered variables were actually used in the given expression. +As an example once the set of utilised variables are known, any +further 'attention' can be restricted to only those variables when +evaluating the expression. This can be quite useful when dealing with +expressions that can draw from a set of hundreds or even thousands of +variables. + + +(c) Unknown set of variables +These are expressions that are comprised of symbols other than the +standard ExprTk reserved words or what has been registered with their +associated symbol_table, and will normally fail compilation due to the +associated symbol_table not having a reference to them. As such this +scenario can be seen as a combination of scenario B, where one may +have a symbol_table with registered variables, but would also like to +handle the situation of variables that aren't present in said +symbol_table. + +When dealing with expressions of category (c), one must perform all of +the following: + + (1) Determine the variables used in the expression + (2) Populate a symbol_table(s) with the entities from (1) + (3) Compile the expression + (4) Provide a means by which the entities from (1) can be modified + + +Depending on the nature of processing, steps (1) and (2) can be done +either independently of each other or combined into one. The following +example will initially look at solving the problem of unknown +variables with the latter method using the 'unknown_symbol_resolver' +component. + + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + + symbol_table_t unknown_var_symbol_table; + + symbol_table_t symbol_table; + symbol_table.add_variable("x",x); + symbol_table.add_variable("y",y); + + expression_t expression; + expression.register_symbol_table(unknown_var_symbol_table); + expression.register_symbol_table(symbol_table); + + parser_t parser; + parser.enable_unknown_symbol_resolver(); + + std::string expression_str = "x + abs(y / 3k) * z + 2"; + + parser.compile(expression_str,expression); + + +In the example above, the symbols 'k' and 'z' will be treated as +unknown symbols. The parser in the example is set to handle unknown +symbols using the built-in default unknown_symbol_resolver (USR). The +default USR will automatically resolve any unknown symbols as a +variable (scalar type). The new variables will be added to the primary +symbol_table, which in this case is the 'unknown_var_symbol_table' +instance. Once the compilation has completed successfully, the +variables that were resolved during compilation can be accessed from +the primary symbol_table using the 'get_variable_list' and +'variable_ref' methods and then if needed can be modified accordingly +after which the expression itself can be evaluated. + + std::vector variable_list; + + unknown_var_symbol_table.get_variable_list(variable_list); + + for (auto& var_name : variable_list) + { + T& v = unknown_var_symbol_table.variable_ref(var_name); + + v = ...; + } + + ... + + expression.value(); + + +Note: As previously mentioned the default USR will automatically +assume any unknown symbol to be a valid scalar variable, and will then +proceed to add said symbol as a variable to the primary symbol_table +of the associated expression during the compilation process. However a +problem that may arise, is that expressions that are parsed with the +USR enabled, but contain 'typos' or otherwise syntactic errors may +inadvertently compile successfully due to the simplistic nature of the +default USR. The following are some example expressions: + + (1) 1 + abz(x + 1) + (2) sine(y / 2) - coz(3x) + + +The two expressions above contain misspelt symbols (abz, sine, coz) +which if implied multiplications and default USR are enabled during +compilation will result in them being assumed to be valid 'variables', +which obviously is not the intended outcome by the user. A possible +solution to this problem is for one to implement their own specific +USR that will perform a user defined business logic in determining if +an encountered unknown symbol should be treated as a variable or if it +should raise a compilation error. The following example demonstrates a +simple user defined USR: + + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + + template + struct my_usr : public parser_t::unknown_symbol_resolver + { + typedef typename parser_t::unknown_symbol_resolver usr_t; + + bool process(const std::string& unknown_symbol, + typename usr_t::usr_symbol_type& st, + T& default_value, + std::string& error_message) + { + if (0 != unknown_symbol.find("var_")) + { + error_message = "Invalid symbol: " + unknown_symbol; + return false; + } + + st = usr_t::e_usr_variable_type; + default_value = T(123.123); + + return true; + } + }; + + ... + + symbol_table_t unknown_var_symbol_table; + + symbol_table_t symbol_table; + symbol_table.add_variable("x",x); + symbol_table.add_variable("y",y); + + expression_t expression; + expression.register_symbol_table(unknown_var_symbol_table); + expression.register_symbol_table(symbol_table); + + my_usr musr; + + parser_t parser; + parser.enable_unknown_symbol_resolver(&musr); + + std::string expression_str = "var_x + abs(var_y - 3) * var_z"; + + parser.compile(expression_str,expression); + + +In the example above, a user specified USR is defined, and is +registered with the parser enabling the USR functionality. Then when +an unknown symbol is encountered during the compilation process, the +USR's process method will be invoked. The USR in the example will only +'accept' unknown symbols that have a prefix of 'var_' as being valid +variables, all other unknown symbols will result in a compilation +error being raised. + +In the example above the callback of the USR that is invoked during +the unknown symbol resolution process only allows for scalar variables +to be defined and resolved - as that is the simplest and most common +form. + +There is also an extended version of the callback that can be +overridden that will allow for more control and choice over the type +of symbol being resolved. The following is an example definition of +said extended callback: + + template + struct my_usr : public parser_t::unknown_symbol_resolver + { + typedef typename parser_t::unknown_symbol_resolver usr_t; + + my_usr() + : usr_t(usr_t::e_usrmode_extended) + {} + + virtual bool process(const std::string& unknown_symbol, + symbol_table_t& symbol_table, + std::string& error_message) + { + bool result = false; + + if (0 == unknown_symbol.find("var_")) + { + // Default value of zero + result = symbol_table.create_variable(unknown_symbol,0); + + if (!result) + { + error_message = "Failed to create variable..."; + } + } + else if (0 == unknown_symbol.find("str_")) + { + // Default value of empty string + result = symbol_table.create_stringvar(unknown_symbol,""); + + if (!result) + { + error_message = "Failed to create string variable..."; + } + } + else + error_message = "Indeterminable symbol type."; + + return result; + } + }; + + +In the example above, the USR callback when invoked will pass the +primary symbol table associated with the expression being parsed. The +symbol resolution business logic can then determine under what +conditions a symbol will be resolved including its type (scalar, +string, vector etc) and default value. When the callback successfully +returns the symbol parsing and resolution process will again be +executed by the parser. The idea here is that given the primary symbol +table will now have the previously detected unknown symbol registered, +it will be correctly resolved and the general parsing processing can +then resume as per normal. + +Note: In order to have the USR's extended mode callback be invoked It +is necessary to pass the e_usrmode_extended enum value during the +constructor of the user defined USR. + +Note: The primary symbol table for an expression is the first symbol +table to be registered with that instance of the expression. + +Note: For a successful symbol resolution using the normal USR all of +the following are required: + + (1) Only if successful shall the process method return TRUE + (2) The default_value parameter will have been set + (3) The error_message parameter will be empty + (4) usr_symbol_type input parameter field will be set to either: + (*) e_usr_variable_type + (*) e_usr_constant_type + +Note: For a successful symbol resolution using the extended USR all of +the following are required: + + (1) Only if successful shall the process method return TRUE + (2) symbol_table parameter will have had the newly resolved + variable or string added to it + (3) error_message parameter will be empty + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 19 - ENABLING & DISABLING FEATURES] +The parser can be configured via its settings instance to either allow +or disallow certain features that are available within the ExprTk +grammar. The features fall into one of the following six categories: + + (1) Base Functions + (2) Control Flow Structures + (3) Logical Operators + (4) Arithmetic Operators + (5) Inequality Operators + (6) Assignment Operators + + +(1) Base Functions +The list of available base functions is as follows: + + abs, acos, acosh, asin, asinh, atan, atanh, atan2, avg, ceil, + clamp, cos, cosh, cot, csc, equal, erf, erfc, exp, expm1, + floor, frac, hypot, iclamp, like, log, log10, log2, logn, + log1p, mand, max, min, mod, mor, mul, ncdf, pow, root, round, + roundn, sec, sgn, sin, sinc, sinh, sqrt, sum, swap, tan, tanh, + trunc, not_equal, inrange, deg2grad, deg2rad, rad2deg, grad2deg + + +The above mentioned base functions can be either enabled or disabled +'all' at once, as is demonstrated below: + + parser_t parser; + expression_t expression; + + parser.settings().disable_all_base_functions(); + + parser + .compile("2 * abs(2 - 3)",expression); // compilation failure + + parser.settings().enable_all_base_functions(); + + parser + .compile("2 * abs(2 - 3)",expression); // compilation success + + +One can also enable or disable specific base functions. The following +example demonstrates the disabling of the trigonometric functions +'sin' and 'cos': + + parser_t parser; + expression_t expression; + + parser.settings() + .disable_base_function(settings_t::e_bf_sin) + .disable_base_function(settings_t::e_bf_cos); + + parser + .compile("(sin(x) / cos(x)) == tan(x)",expression); // failure + + parser.settings() + .enable_base_function(settings_t::e_bf_sin) + .enable_base_function(settings_t::e_bf_cos); + + parser + .compile("(sin(x) / cos(x)) == tan(x)",expression); // success + + +(2) Control Flow Structures +The list of available control flow structures is as follows: + + (a) If or If-Else + (b) Switch statement + (c) For Loop + (d) While Loop + (e) Repeat Loop + + +The above mentioned control flow structures can be either enabled +or disabled 'all' at once, as is demonstrated below: + + parser_t parser; + expression_t expression; + + std::string program = + " var x := 0; " + " for (var i := 0; i < 10; i += 1) " + " { " + " x += i; " + " } "; + + parser.settings().disable_all_control_structures(); + + parser + .compile(program,expression); // compilation failure + + parser.settings().enable_all_control_structures(); + + parser + .compile(program,expression); // compilation success + + +One can also enable or disable specific control flow structures. The +following example demonstrates the disabling of the for-loop control +flow structure: + + parser_t parser; + expression_t expression; + + std::string program = + " var x := 0; " + " for (var i := 0; i < 10; i += 1) " + " { " + " x += i; " + " } "; + + parser.settings() + .disable_control_structure(settings_t::e_ctrl_for_loop); + + parser + .compile(program,expression); // failure + + parser.settings() + .enable_control_structure(settings_t::e_ctrl_for_loop); + + parser + .compile(program,expression); // success + + +(3) Logical Operators +The list of available logical operators is as follows: + + and, nand, nor, not, or, xnor, xor, &, | + + +The above mentioned logical operators can be either enabled or +disabled 'all' at once, as is demonstrated below: + + parser_t parser; + expression_t expression; + + parser.settings().disable_all_logic_ops(); + + parser + .compile("1 or not(0 and 1)",expression); // compilation failure + + parser.settings().enable_all_logic_ops(); + + parser + .compile("1 or not(0 and 1)",expression); // compilation success + + +One can also enable or disable specific logical operators. The +following example demonstrates the disabling of the 'and' logical +operator: + + parser_t parser; + expression_t expression; + + parser.settings() + .disable_logic_operation(settings_t::e_logic_and); + + parser + .compile("1 or not(0 and 1)",expression); // failure + + parser.settings() + .enable_logic_operation(settings_t::e_logic_and); + + parser + .compile("1 or not(0 and 1)",expression); // success + + +(4) Arithmetic Operators +The list of available arithmetic operators is as follows: + + +, -, *, /, %, ^ + + +The above mentioned arithmetic operators can be either enabled or +disabled 'all' at once, as is demonstrated below: + + parser_t parser; + expression_t expression; + + parser.settings().disable_all_arithmetic_ops(); + + parser + .compile("1 + 2 / 3",expression); // compilation failure + + parser.settings().enable_all_arithmetic_ops(); + + parser + .compile("1 + 2 / 3",expression); // compilation success + + +One can also enable or disable specific arithmetic operators. The +following example demonstrates the disabling of the addition '+' +arithmetic operator: + + parser_t parser; + expression_t expression; + + parser.settings() + .disable_arithmetic_operation(settings_t::e_arith_add); + + parser + .compile("1 + 2 / 3",expression); // failure + + parser.settings() + .enable_arithmetic_operation(settings_t::e_arith_add); + + parser + .compile("1 + 2 / 3",expression); // success + + +(5) Inequality Operators +The list of available inequality operators is as follows: + + <, <=, >, >=, ==, =, != <> + + +The above mentioned inequality operators can be either enabled or +disabled 'all' at once, as is demonstrated below: + + parser_t parser; + expression_t expression; + + parser.settings().disable_all_inequality_ops(); + + parser + .compile("1 < 3",expression); // compilation failure + + parser.settings().enable_all_inequality_ops(); + + parser + .compile("1 < 3",expression); // compilation success + + +One can also enable or disable specific inequality operators. The +following example demonstrates the disabling of the less-than '<' +inequality operator: + + parser_t parser; + expression_t expression; + + parser.settings() + .disable_inequality_operation(settings_t::e_ineq_lt); + + parser + .compile("1 < 3",expression); // failure + + parser.settings() + .enable_inequality_operation(settings_t::e_ineq_lt); + + parser + .compile("1 < 3",expression); // success + + +(6) Assignment Operators +The list of available assignment operators is as follows: + + :=, +=, -=, *=, /=, %= + + +The above mentioned assignment operators can be either enabled or +disabled 'all' at once, as is demonstrated below: + + parser_t parser; + expression_t expression; + symbol_table_t symbol_table; + + T x = T(0); + + symbol_table.add_variable("x",x); + + expression.register_symbol_table(symbol_table); + + parser.settings().disable_all_assignment_ops(); + + parser + .compile("x := 3",expression); // compilation failure + + parser.settings().enable_all_assignment_ops(); + + parser + .compile("x := 3",expression); // compilation success + + +One can also enable or disable specific assignment operators. The +following example demonstrates the disabling of the '+=' addition +assignment operator: + + parser_t parser; + expression_t expression; + symbol_table_t symbol_table; + + T x = T(0); + + symbol_table.add_variable("x",x); + + expression.register_symbol_table(symbol_table); + + parser.settings() + .disable_assignment_operation(settings_t::e_assign_addass); + + parser + .compile("x += 3",expression); // failure + + parser.settings() + .enable_assignment_operation(settings_t::e_assign_addass); + + parser + .compile("x += 3",expression); // success + + +Note: In the event of a base function being disabled, one can redefine +the base function using the standard custom function definition +process. In the following example the 'sin' function is disabled then +redefined as a function taking degree input. + + template + struct sine_deg : public exprtk::ifunction + { + sine_deg() : exprtk::ifunction(1) {} + + inline T operator()(const T& v) + { + const T pi = exprtk::details::numeric::constant::pi; + return std::sin((v * T(pi)) / T(180)); + } + }; + + ... + + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + + typedef typename parser_t::settings_store settings_t; + + sine_deg sine; + + symbol_table.add_reserved_function("sin",sine); + + expression_t expression; + + expression.register_symbol_table(symbol_table); + + parser_t parser; + + parser.settings() + .disable_base_function(settings_t::e_bf_sin); + + parser.compile("1 + sin(30)",expression); + + +In the example above, the custom 'sin' function is registered with the +symbol_table using the method 'add_reserved_function'. This is done so +as to bypass the checks for reserved words that are carried out on the +provided symbol names when calling the standard 'add_function' method. +Normally if a user specified symbol name conflicts with any of the +ExprTk reserved words, the add_function call will fail. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 20 - EXPRESSION RETURN VALUES] +ExprTk expressions can return immediately from any point by utilising +the return call. Furthermore the return call can be used to transfer +out multiple return values from within the expression. + +If an expression evaluation exits using a return point, the result of +the call to the 'value' method will be NaN, and it's expected that the +return values will be available from the results_context. + +In the following example there are three return points in the +expression. If neither of the return points are hit, then the +expression will return normally. + + std::string expression_string = + " if (x < y) " + " return [x + 1,'return-call 1']; " + " else if (x > y) " + " return [y / 2, y + 1, 'return-call 2']; " + " else if (equal(x,y)) " + " x + y; " + " return [x, y, x + y, x - y, 'return-call 3'] "; + + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + + symbol_table_t symbol_table; + expression_t expression; + parser_t parser; + + double x = 0; + double y = 0; + + symbol_table.add_variable("x",x); + symbol_table.add_variable("y",y); + + expression.register_symbol_table(symbol_table); + + parser.compile(expression_string,expression); + + T result = expression.value(); + + if (expression.results().count()) + { + typedef exprtk::results_context results_context_t; + typedef typename results_context_t::type_store_t type_t; + typedef typename type_t::scalar_view scalar_t; + typedef typename type_t::vector_view vector_t; + typedef typename type_t::string_view string_t; + + const results_context_t& results = expression.results(); + + for (std::size_t i = 0; i < results.count(); ++i) + { + type_t t = results[i]; + + switch (t.type) + { + case type_t::e_scalar : ... + break; + + case type_t::e_vector : ... + break; + + case type_t::e_string : ... + break; + + default : continue; + } + } + + +Note: Processing of the return results is similar to that of the +generic function call parameters. + +It is however recommended that if there is to be only a single flow of +execution through the expression, that the simpler approach of +registering external variables of appropriate type be used. + +This method simply requires the variables that are to hold the various +results that are to be computed within the expression to be registered +with an associated symbol_table instance. Then within the expression +itself to have the result variables be assigned the appropriate +values. + + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + + std::string expression_string = + " var x := 123.456; " + " var s := 'ijk'; " + " result0 := x + 78.90; " + " result1 := s + '123' "; + + double result0; + std::string result1; + + symbol_table_t symbol_table; + symbol_table.add_variable ("result0",result0); + symbol_table.add_stringvar("result1",result1); + + expression_t expression; + expression.register_symbol_table(symbol_table); + + parser_t parser; + parser.compile(expression_string,expression); + + expression.value(); + + printf("Result0: %15.5f\n", result0 ); + printf("Result1: %s\n" , result1.c_str()); + + +In the example above, the expression will compute two results. As such +two result variables are defined to hold the values named result0 and +result1 respectively. The first is of scalar type (double), the second +is of string type. Once the expression has been evaluated, the two +variables will have been updated with the new result values, and can +then be further utilised from within the calling program. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 21 - COMPILATION ERRORS] +When attempting to compile a malformed or otherwise erroneous ExprTk +expression, the compilation process will result in an error, as is +indicated by the 'compile' method returning a false value. A +diagnostic indicating the first error encountered and its cause can be +obtained by invoking the 'error' method, as is demonstrated in the +following example: + + if (!parser.compile(expression_string,expression)) + { + printf("Error: %s\n", parser.error().c_str()); + return false; + } + + +Any error(s) resulting from a failed compilation will be stored in the +parser instance until the next time a compilation is performed. Before +then errors can be enumerated in the order they occurred by invoking +the 'get_error' method which itself will return a 'parser_error' type. +A parser_error object will contain an error diagnostic, an error mode +(or class), and the character position of the error in the expression +string. The following example demonstrates the enumeration of error(s) +in the event of a failed compilation. + + if (!parser.compile(expression_string,expression)) + { + for (std::size_t i = 0; i < parser.error_count(); ++i) + { + typedef exprtk::parser_error::type error_t; + + error_t error = parser.get_error(i); + + printf("Error[%02d] Position: %02d Type: [%14s] Msg: %s\n", + i, + error.token.position, + exprtk::parser_error::to_str(error.mode).c_str(), + error.diagnostic.c_str()); + } + + return false; + } + + +Assuming the following expression '2 + (3 / log(1 + x))' which uses a +variable named 'x' that has not been registered with the appropriate +symbol_table instance and is not a locally defined variable, once +compiled the above denoted post compilation error handling code shall +produce the following output: + + Error: ERR184 - Undefined symbol: 'x' + Error[00] Pos:17 Type:[Syntax] Msg: ERR184 - Undefined symbol: 'x' + + +For expressions comprised of multiple lines, the error position +provided in the parser_error object can be converted into a pair of +line and column numbers by invoking the 'update_error' function as is +demonstrated by the following example: + + if (!parser.compile(program_str,expression)) + { + for (std::size_t i = 0; i < parser.error_count(); ++i) + { + typedef exprtk::parser_error::type error_t; + + error_t error = parser.get_error(i); + + exprtk::parser_error::update_error(error,program_str); + + printf("Error[%02d] at line: %d column: %d\n", + i, + error.line_no, + error.column_no); + } + + return false; + } + + +Note: There are five distinct error modes in ExprTk which denote the +class of an error. These classes are as follows: + + (a) Syntax + (b) Token + (c) Numeric + (d) Symbol Table + (e) Lexer + + +(a) Syntax Errors +These are errors related to invalid syntax found within the denoted +expression. Examples are invalid sequences of operators and variables, +incorrect number of parameters to functions, invalid conditional or +loop structures and invalid use of keywords. + + eg: 'for := sin(x,y,z) + 2 * equal > until[2 - x,3]' + + +(b) Token Errors +Errors in this class relate to token level errors detected by one or +more of the following checkers: + + (1) Bracket Checker + (2) Numeric Checker + (3) Sequence Checker + + +(c) Numeric Errors +This class of error is related to conversion of numeric values from +their string form to the underlying numerical type (float, double +etc). + +(d) Symbol Table Errors +This is the class of errors related to failures when interacting with +the registered symbol_table instance. Errors such as not being able to +find, within the symbol_table, symbols representing variables or +functions, to being unable to create new variables in the symbol_table +via the 'unknown symbol resolver' mechanism. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 22 - RUNTIME LIBRARY PACKAGES] +ExprTk contains a set of simple extensions, that provide +functionalities beyond basic numerical calculations. Currently the +available packages are: + + +---+--------------------+-----------------------------------+ + | # | Package Name | Namespace/Type | + +---+--------------------+-----------------------------------+ + | 1 | Basic I/O | exprtk::rtl::io::package | + | 2 | File I/O | exprtk::rtl::io::file::package | + | 3 | Vector Operations | exprtk::rtl::vecops::package | + +---+--------------------+-----------------------------------+ + + +In order to make the features of a specific package available within +an expression, an instance of the package must be added to the +expression's associated symbol table. In the following example, the +file I/O package is made available for the given expression: + + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + + exprtk::rtl::io::file::package fileio_package; + + std::string expression_string = + " var file_name := 'file.txt'; " + " var stream := null; " + " " + " stream := open(file_name,'w'); " + " " + " write(stream,'Hello world....\n'); " + " " + " close(stream); " + " "; + + symbol_table_t symbol_table; + symbol_table.add_package(fileio_package); + + expression_t expression; + expression.register_symbol_table(symbol_table); + + parser_t parser; + parser.compile(expression_string,expression); + + expression.value(); + + +(1) Basic I/O functions: + + (a) print + (b) println + +(2) File I/O functions: + + (a) open (b) close + (c) write (d) read + (e) getline (f) eof + +(3) Vector Operations functions: + + (a) all_true (b) all_false + (c) any_true (d) any_false + (e) count (f) copy + (g) rotate-left (h) rotate-right + (i) shift-left (j) shift-right + (k) sort (l) nth_element + (m) iota (n) sumk + (o) axpy (p) axpby + (q) axpyz (r) axpbyz + (s) axpbz (t) dot + (u) dotk + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 23 - HELPERS & UTILS] +The ExprTk library provides a series of usage simplifications via +helper routines that combine various processes into a single 'function +call' making certain actions easier to carry out though not +necessarily in the most efficient way possible. A list of the routines +are as follows: + + (a) collect_variables + (b) collect_functions + (c) compute + (d) integrate + (e) derivative + (f) second_derivative + (g) third_derivative + + +(a) collect_variables +This function will collect all the variable symbols in a given string +representation of an expression and return them in an STL compatible +sequence data structure (eg: std::vector, dequeue etc) specialised +upon a std::string type. If an error occurs during the parsing of the +expression then the return value of the function will be false, +otherwise it will be true. An example use of the given routine is as +follows: + + std::string expression = "x + abs(y / z)"; + + std::vector variable_list; + + if (exprtk::collect_variables(expression, variable_list)) + { + for (const auto& var : variable_list) + { + ... + } + } + else + printf("An error occurred."); + + +(b) collect_functions +This function will collect all the function symbols in a given string +representation of an expression and return them in an STL compatible +sequence data structure (eg: std::vector, dequeue etc) specialised +upon a std::string type. If an error occurs during the parsing of the +expression then the return value of the function will be false, +otherwise it will be true. An example use of the given routine is as +follows: + + std::string expression = "x + abs(y / cos(1 + z))"; + + std::deque function_list; + + if (exprtk::collect_functions(expression, function_list)) + { + for (const auto& func : function_list) + { + ... + } + } + else + printf("An error occurred."); + + +Note: When either the 'collect_variables' or 'collect_functions' free +functions return true - that does not necessarily indicate the +expression itself is valid. It is still possible that when compiled +the expression may have certain 'type' related errors - though it is +highly likely that no semantic errors will occur if either return +true. + +Note: The default interface provided for both the collect_variables +and collect_functions free_functions, assumes that expressions will +only be utilising the ExprTk reserved functions (eg: abs, cos, min +etc). When user defined functions are to be used in an expression, a +symbol_table instance containing said functions can be passed to +either routine, and will be incorporated during the compilation and +Dependent Entity Collection processes. In the following example, a +user defined free function named 'foo' is registered with a +symbol_table. Finally the symbol_table instance and associated +expression string are passed to the exprtk::collect_functions routine. + + template + T foo(T v) + { + return std::abs(v + T(2)) / T(3); + } + + ...... + + exprtk::symbol_table sym_tab; + + symbol_table.add_function("foo",foo); + + std::string expression = "x + foo(y / cos(1 + z))"; + + std::deque function_list; + + if (exprtk::collect_functions(expression, sym_tab, function_list)) + { + for (const auto& func : function_list) + { + ... + } + } + else + printf("An error occurred."); + + +(c) compute +This free function will compute the value of an expression from its +string form. If an invalid expression is passed, the result of the +function will be false indicating an error, otherwise the return value +will be true indicating success. The compute function has three +overloads, the definitions of which are: + + (1) No variables + (2) One variable called x + (3) Two variables called x and y + (3) Three variables called x, y and z + + +Example uses of each of the three overloads for the compute routine +are as follows: + + T result = T(0); + + // No variables overload + std::string no_vars = "abs(1 - (3 / pi)) * 5"; + + if (!exprtk::compute(no_vars,result)) + printf("Failed to compute: %s",no_vars.c_str()); + else + printf("Result: %15.5f\n",result); + + // One variable 'x' overload + T x = 123.456; + + std::string one_var = "abs(x - (3 / pi)) * 5"; + + if (!exprtk::compute(one_var, x, result)) + printf("Failed to compute: %s",one_var.c_str()); + else + printf("Result: %15.5f\n",result); + + // Two variables 'x' and 'y' overload + T y = 789.012; + + std::string two_var = "abs(x - (y / pi)) * 5"; + + if (!exprtk::compute(two_var, x, y, result)) + printf("Failed to compute: %s",two_var.c_str()); + else + printf("Result: %15.5f\n",result); + + // Three variables 'x', 'y' and 'z' overload + T z = 345.678; + + std::string three_var = "abs(x - (y / pi)) * z"; + + if (!exprtk::compute(three_var, x, y, z, result)) + printf("Failed to compute: %s",three_var.c_str()); + else + printf("Result: %15.5f\n",result); + + +(d) integrate +This free function will attempt to perform a numerical integration of +a single variable compiled expression over a specified range and step +size. The numerical integration is based on the three point form of +Simpson's rule. The integrate function has two overloads, where the +variable of integration can either be passed as a reference or as a +name in string form. Example usage of the function is as follows: + + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + + std::string expression_string = "sqrt(1 - (x^2))"; + + T x = T(0); + + symbol_table_t symbol_table; + symbol_table.add_variable("x",x); + + expression_t expression; + expression.register_symbol_table(symbol_table); + + parser_t parser; + parser.compile(expression_string,expression); + + .... + + // Integrate in domain [-1,1] using a reference to x variable + T area1 = exprtk::integrate(expression, x, T(-1), T(1)); + + // Integrate in domain [-1,1] using name of x variable + T area2 = exprtk::integrate(expression, "x", T(-1), T(1)); + + +(e) derivative +This free function will attempt to perform a numerical differentiation +of a single variable compiled expression at a given point for a given +epsilon, using a variant of Newton's difference quotient called the +five-point stencil method. The derivative function has two overloads, +where the variable of differentiation can either be passed as a +reference or as a name in string form. Example usage of the derivative +function is as follows: + + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + + std::string expression_string = "sqrt(1 - (x^2))"; + + T x = T(0); + + symbol_table_t symbol_table; + symbol_table.add_variable("x",x); + + expression_t expression; + expression.register_symbol_table(symbol_table); + + parser_t parser; + parser.compile(expression_string,expression); + + .... + + // Differentiate expression at value of x = 12.3 using a reference + // to the x variable + x = T(12.3); + T derivative1 = exprtk::derivative(expression, x); + + // Differentiate expression where value x = 45.6 using name + // of the x variable + x = T(45.6); + T derivative2 = exprtk::derivative(expression, "x"); + + +(f) second_derivative +This free function will attempt to perform a numerical second +derivative of a single variable compiled expression at a given point +for a given epsilon, using a variant of Newton's difference quotient +method. The second_derivative function has two overloads, where the +variable of differentiation can either be passed as a reference or as +a name in string form. Example usage of the second_derivative function +is as follows: + + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + + std::string expression_string = "sqrt(1 - (x^2))"; + + T x = T(0); + + symbol_table_t symbol_table; + symbol_table.add_variable("x",x); + + expression_t expression; + expression.register_symbol_table(symbol_table); + + parser_t parser; + parser.compile(expression_string,expression); + + .... + + // Second derivative of expression where value of x = 12.3 using a + // reference to x variable + x = T(12.3); + T derivative1 = exprtk::second_derivative(expression,x); + + // Second derivative of expression where value of x = 45.6 using + // name of x variable + x = T(45.6); + T derivative2 = exprtk::second_derivative(expression, "x"); + + +(g) third_derivative +This free function will attempt to perform a numerical third +derivative of a single variable compiled expression at a given point +for a given epsilon, using a variant of Newton's difference quotient +method. The third_derivative function has two overloads, where the +variable of differentiation can either be passed as a reference or as +a name in string form. Example usage of the third_derivative function +is as follows: + + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + + std::string expression_string = "sqrt(1 - (x^2))"; + + T x = T(0); + + symbol_table_t symbol_table; + symbol_table.add_variable("x",x); + + expression_t expression; + expression.register_symbol_table(symbol_table); + + parser_t parser; + parser.compile(expression_string,expression); + + .... + + // Third derivative of expression where value of x = 12.3 using a + // reference to the x variable + x = T(12.3); + T derivative1 = exprtk::third_derivative(expression, x); + + // Third derivative of expression where value of x = 45.6 using + // name of the x variable + x = T(45.6); + T derivative2 = exprtk::third_derivative(expression, "x"); + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 24 - BENCHMARKING] +As part of the ExprTk package there is an expression benchmark utility +named 'exprtk_benchmark'. The utility attempts to determine expression +evaluation speed (or rate of evaluations - evals per second), by +evaluating each expression numerous times and mutating the underlying +variables of the expression between each evaluation. The utility +assumes any valid ExprTk expression (containing conditionals, loops +etc), however it will only make use of a predefined set of scalar +variables, namely: a, b, c, x, y, z and w. That being said expressions +themselves can contain any number of local variables, vectors or +strings. There are two modes of operation: + + (1) Default + (2) User Specified Expressions + + +(1) Default +The default mode is enabled simply by executing the exprtk_benchmark +binary with no command line parameters. In this mode a predefined set +of expressions will be evaluated in three phases: + + (a) ExprTk evaluation + (b) Native evaluation + (c) ExprTk parse + + +In the first two phases (a and b) a list of predefined (hard-coded) +expressions will be evaluated using both ExprTk and native mode +implementations. This is done so as to compare evaluation times +between ExprTk and native implementations. The set of expressions used +are as follows: + + (01) (y + x) + (02) 2 * (y + x) + (03) (2 * y + 2 * x) + (04) ((1.23 * x^2) / y) - 123.123 + (05) (y + x / y) * (x - y / x) + (06) x / ((x + y) + (x - y)) / y + (07) 1 - ((x * y) + (y / x)) - 3 + (08) (5.5 + x) + (2 * x - 2 / 3 * y) * (x / 3 + y / 4) + (y + 7.7) + (09) 1.1x^1 + 2.2y^2 - 3.3x^3 + 4.4y^15 - 5.5x^23 + 6.6y^55 + (10) sin(2 * x) + cos(pi / y) + (11) 1 - sin(2 * x) + cos(pi / y) + (12) sqrt(111.111 - sin(2 * x) + cos(pi / y) / 333.333) + (13) (x^2 / sin(2 * pi / y)) - x / 2 + (14) x + (cos(y - sin(2 / x * pi)) - sin(x - cos(2 * y / pi))) - y + (15) clamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0) + (16) max(3.33, min(sqrt(1 - sin(2 * x) + cos(pi / y) / 3), 1.11)) + (17) if((y + (x * 2.2)) <= (x + y + 1.1), x - y, x*y) + 2 * pi / x + + +The third and final phase (c), is used to determine average +compilation rates (compiles per second) for expressions of varying +complexity. Each expression is compiled 100K times and the average for +each expression is output. + + +(2) User Specified Expressions +In this mode two parameters are passed to the utility via the command +line: + + (a) A name of a text file containing one expression per line + (b) An integer representing the number of evaluations per expression + + +An example execution of the benchmark utility in this mode is as +follows: + + ./exprtk_benchmark my_expressions.txt 1000000 + + +The above invocation will load the expressions from the file +'my_expressions.txt' and will then proceed to evaluate each expression +one million times, varying the above mentioned variables (x, y, z +etc.) between each evaluation, and at the end of each expression round +a print out of running times, result of a single evaluation and total +sum of results is provided as demonstrated below: + + Expression 1 of 7 4.770 ns 47700 ns ( 9370368.0) '((((x+y)+z)))' + Expression 2 of 7 4.750 ns 47500 ns ( 1123455.9) '((((x+y)-z)))' + Expression 3 of 7 4.766 ns 47659 ns (21635410.7) '((((x+y)*z)))' + Expression 4 of 7 5.662 ns 56619 ns ( 1272454.9) '((((x+y)/z)))' + Expression 5 of 7 4.950 ns 49500 ns ( 4123455.9) '((((x-y)+z)))' + Expression 6 of 7 7.581 ns 75810 ns (-4123455.9) '((((x-y)-z)))' + Expression 7 of 7 4.801 ns 48010 ns ( 0.0) '((((x-y)*z)))' + + +The benchmark utility can be very useful when investigating evaluation +efficiency issues with ExprTk or simply during the prototyping of +expressions. As an example, lets take the following expression: + + 1 / sqrt(2x) * e^(3y) + + +Lets say we would like to determine which sub-part of the expression +takes the most time to evaluate and perhaps attempt to rework the +expression based on the results. In order to do this we will create a +text file called 'test.txt' and then proceed to make some educated +guesses about how to break the expression up into its more +'interesting' sub-parts which we will then add as one expression per +line to the file. An example breakdown may be as follows: + + 1 / sqrt(2x) * e^(3y) + 1 / sqrt(2x) + e^(3y) + + +The benchmark with the given file, where each expression will be +evaluated 100K times can be executed as follows: + + ./exprtk_benchmark test.txt 100000 + Expr 1 of 3 90.340 ns 9034000 ns (296417859.3) '1/sqrt(2x)*e^(3y)' + Expr 2 of 3 11.100 ns 1109999 ns ( 44267.3) '1/sqrt(2x)' + Expr 3 of 3 77.830 ns 7783000 ns (615985286.6) 'e^(3y)' + [*] Number Of Evals: 300000 + [*] Total Time: 0.018sec + [*] Total Single Eval Time: 0.000ms + + +From the results above we conclude that the third expression (e^(3y)) +consumes the largest amount of time. The variable 'e', as used in both +the benchmark and in the expression, is an approximation of the +transcendental mathematical constant e (2.71828182845904...) hence the +sub-expression should perhaps be modified to use the generally more +efficient built-in 'exp' function. + + ./exprtk_benchmark test.txt 1000000 + Expr 1 of 5 86.563 ns 8656300ns (296417859.6) '1/sqrt(2x)*e^(3y)' + Expr 2 of 5 40.506 ns 4050600ns (296417859.6) '1/sqrt(2x)*exp(3y)' + Expr 3 of 5 14.248 ns 1424799ns ( 44267.2) '1/sqrt(2x)' + Expr 4 of 5 88.840 ns 8884000ns (615985286.9) 'e^(3y)' + Expr 5 of 5 29.267 ns 2926699ns (615985286.9) 'exp(3y)' + [*] Number Of Evals: 5000000 + [*] Total Time: 0.260sec + [*] Total Single Eval Time: 0.000ms + + +The above output demonstrates the results from making the previously +mentioned modification to the expression. As can be seen the new form +of the expression using the 'exp' function reduces the evaluation time +by over 50%, in other words increases the evaluation rate by two fold. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 25 - EXPRTK NOTES] +The following is a list of facts and suggestions one may want to take +into account when using ExprTk: + + (00) Precision and performance of expression evaluations are the + dominant principles of the ExprTk library. + + (01) ExprTk uses a rudimentary imperative programming model with + syntax based on languages such as Pascal and C. Furthermore + ExprTk is an LL(2) type grammar and is processed using a + recursive descent parsing algorithm. + + (02) Supported types are float, double, long double and MPFR/GMP. + + (03) Standard mathematical operator precedence is applied (BEDMAS). + + (04) Results of expressions that are deemed as being 'valid' are to + exist within the set of Real numbers. All other results will be + of the value: Not-A-Number (NaN). + + (05) Supported user defined types are numeric and string + variables, numeric vectors and functions. + + (06) All reserved words, keywords, variable, vector, string and + function names are case-insensitive. + + (07) Variable, vector, string variable and function names must begin + with a letter (A-Z or a-z), then can be comprised of any + combination of letters, digits, underscores and dots, ending in + either a letter (A-Z or a-z), digit or underscore. (eg: x, y2, + var1, power_func99, person.age, item.size.0). The associated + regex pattern is: [a-zA-Z]([a-zA-Z0-9_.]*|[a-zA-Z0-9_]) + + (08) Expression lengths and sub-expression lists are limited only by + storage capacity. + + (09) The life-time of objects registered with or created from a + specific symbol-table must span at least the life-time of the + compiled expressions which utilise objects, such as variables, + of that symbol-table, otherwise the result will be undefined + behavior. + + (10) Equal and not_equal are normalised-epsilon equality routines, + which use epsilons of 0.0000000001 and 0.000001 for double and + float types respectively. + + (11) All trigonometric functions assume radian input unless stated + otherwise. + + (12) Expressions may contain white-space characters such as space, + tabs, new-lines, control-feed et al. + ('\n', '\r', '\t', '\b', '\v', '\f') + + (13) Strings may be comprised of any combination of letters, digits + special characters including (~!@#$%^&*()[]|=+ ,./?<>;:"`~_) or + hexadecimal escaped sequences (eg: \0x30) and must be enclosed + with single-quotes. + eg: 'Frankly my dear, \0x49 do n0t give a damn!' + + (14) User defined normal functions can have up to 20 parameters, + where as user defined generic-functions and vararg-functions + can have an unlimited number of parameters. + + (15) The inbuilt polynomial functions can be at most of degree 12. + + (16) Where appropriate constant folding optimisations may be applied. + (eg: The expression '2 + (3 - (x / y))' becomes '5 - (x / y)') + + (17) If the strength reduction compilation option has been enabled, + then where applicable strength reduction optimisations may be + applied. + + (18) String processing capabilities are available by default. To + turn them off, the following needs to be defined at compile + time: exprtk_disable_string_capabilities + + (19) Composited functions can call themselves or any other functions + that have been defined prior to their own definition. + + (20) Recursive calls made from within composited functions will have + a stack size bound by the stack of the executing architecture. + + (21) User defined functions by default are assumed to have side + effects. As such an "all constant parameter" invocation of such + functions wont result in constant folding. If the function has + no side effects then that can be noted during the constructor + of the ifunction allowing it to be constant folded where + appropriate. + + (22) The entity relationship between symbol_table and an expression + is many-to-many. However the intended 'typical' use-case where + possible, is to have a single symbol table manage the variable + and function requirements of multiple expressions. + + (23) The common use-case for an expression is to have it compiled + only ONCE and then subsequently have it evaluated multiple + times. An extremely inefficient and suboptimal approach would + be to recompile an expression from its string form every time + it requires evaluating. + + (24) It is strongly recommended that the return value of method + invocations from the parser and symbol_table types be taken + into account. Specifically the 'compile' method of the parser + and the 'add_xxx' set of methods of the symbol_table as they + denote either the success or failure state of the invoked call. + Continued processing from a failed state without having first + rectified the underlying issue will in turn result in further + failures and undefined behaviours. + + (25) The following are examples of compliant floating point value + representations: + + (1) 12345 (5) -123.456 + (2) +123.456e+12 (6) 123.456E-12 + (3) +012.045e+07 (7) .1234 + (4) 123.456f (8) -321.654E+3L + + (26) Expressions may contain any of the following comment styles: + + (1) // .... \n + (2) # .... \n + (3) /* .... */ + + (27) The 'null' value type is a special non-zero type that + incorporates specific semantics when undergoing operations with + the standard numeric type. The following is a list of type and + boolean results associated with the use of 'null': + + (1) null +,-,*,/,% x --> x + (2) x +,-,*,/,% null --> x + (3) null +,-,*,/,% null --> null + (4) null == null --> true + (5) null == x --> true + (6) x == null --> true + (7) x != null --> false + (8) null != null --> false + (9) null != x --> false + + (28) The following is a list of reserved words and symbols used by + ExprTk. Attempting to add a variable or custom function to a + symbol table using any of the reserved words will result in a + failure. + + abs, acos, acosh, and, asin, asinh, atan, atan2, atanh, avg, + break, case, ceil, clamp, continue, cosh, cos, cot, csc, + default, deg2grad, deg2rad, else, equal, erfc, erf, exp, + expm1, false, floor, for, frac, grad2deg, hypot, iclamp, if, + ilike, in, inrange, in, like, log, log10, log1p, log2, logn, + mand, max, min, mod, mor, mul, nand, ncdf, nor, not, + not_equal, not, null, or, pow, rad2deg, repeat, return, + root, roundn, round, sec, sgn, shl, shr, sinc, sinh, sin, + sqrt, sum, swap, switch, tanh, tan, true, trunc, until, var, + while, xnor, xor, xor + + (29) Every valid ExprTk statement is a "value returning" expression. + Unlike some languages that limit the types of expressions that + can be performed in certain situations, in ExprTk any valid + expression can be used in any "value consuming" context. eg: + + var y := 3; + for (var x := switch + { + case 1 : 7; + case 2 : -1 + ~{var x{};}; + default : y > 2 ? 3 : 4; + }; + x != while (y > 0) { y -= 1; }; + x -= { + if (min(x,y) < 2 * max(x,y)) + x + 2; + else + x + y - 3; + } + ) + { + (x + y) / (x - y); + } + + (30) It is recommended when prototyping expressions that the ExprTk + REPL be utilised, as it supports all the features available in + the library, including complete error analysis, benchmarking + and dependency dumps etc which allows for rapid + coding/prototyping and debug cycles without the hassle of + having to recompile test programs with expressions that have + been hard-coded. It's also a good source of truth for how the + library's various features can be applied. + + (31) For performance considerations, one should assume the actions + of expression, symbol table and parser instance instantiation + and destruction, and the expression compilation process itself + to be of high latency. Hence none of them should be part of any + performance critical code paths, and should instead occur + entirely either before or after such code paths. + + (32) Deep copying an expression instance for the purposes of + persisting to disk or otherwise transmitting elsewhere with the + intent to 'resurrect' the expression instance later on is not + possible due to the reasons described in the final note of + Section 10. The recommendation is to instead simply persist the + string form of the expression and compile the expression at + run-time on the target. + + (33) Before jumping in and using ExprTk, do take the time to peruse + the documentation and all of the examples, both in the main and + the extras distributions. Having an informed general view of + what can and can't be done, and how something should be done + with ExprTk, will likely result in a far more productive and + enjoyable programming experience. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 26 - SIMPLE EXPRTK EXAMPLE] +The following is a simple yet complete example demonstrating typical +usage of the ExprTk Library. The example instantiates a symbol table +object, adding to it three variables named x, y and z, and a custom +user defined function, that accepts only two parameters, named myfunc. +The example then proceeds to instantiate an expression object and +register to it the symbol table instance. + +A parser is then instantiated, and the string representation of the +expression and the expression object are passed to the parser's +compile method for compilation. If an error occurred during +compilation, the compile method will return false, leading to a series +of error diagnostics being printed to stdout. Otherwise the newly +compiled expression is evaluated by invoking the expression object's +value method, and subsequently printing the result of the computation +to stdout. + + +--- snip --- +#include +#include + +#include "exprtk.hpp" + +template +struct myfunc : public exprtk::ifunction +{ + myfunc() : exprtk::ifunction(2) {} + + T operator()(const T& v1, const T& v2) + { + return T(1) + (v1 * v2) / T(3); + } +}; + +int main() +{ + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + typedef exprtk::parser_error::type error_t; + + std::string expression_str = + "z := 2 myfunc([4 + sin(x / pi)^3],y ^ 2)"; + + double x = 1.1; + double y = 2.2; + double z = 3.3; + + myfunc mf; + + symbol_table_t symbol_table; + symbol_table.add_constants(); + symbol_table.add_variable("x",x); + symbol_table.add_variable("y",y); + symbol_table.add_variable("z",z); + symbol_table.add_function("myfunc",mf); + + expression_t expression; + expression.register_symbol_table(symbol_table); + + parser_t parser; + + if (!parser.compile(expression_str,expression)) + { + // A compilation error has occurred. Attempt to + // print all errors to stdout. + + printf("Error: %s\tExpression: %s\n", + parser.error().c_str(), + expression_str.c_str()); + + for (std::size_t i = 0; i < parser.error_count(); ++i) + { + // Include the specific nature of each error + // and its position in the expression string. + + error_t error = parser.get_error(i); + + printf("Error: %02d Position: %02d " + "Type: [%s] " + "Message: %s " + "Expression: %s\n", + static_cast(i), + static_cast(error.token.position), + exprtk::parser_error::to_str(error.mode).c_str(), + error.diagnostic.c_str(), + expression_str.c_str()); + } + + return 1; + } + + // Evaluate the expression and obtain its result. + + double result = expression.value(); + + printf("Result: %10.5f\n",result); + + return 0; +} +--- snip --- + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 27 - BUILD OPTIONS] +When building ExprTk there are a number of defines that will enable or +disable certain features and capabilities. The defines can either be +part of a compiler command line switch or scoped around the include to +the ExprTk header. The defines are as follows: + + (01) exprtk_enable_debugging + (02) exprtk_disable_cardinal_pow_optimisation + (03) exprtk_disable_comments + (04) exprtk_disable_break_continue + (05) exprtk_disable_sc_andor + (06) exprtk_disable_return_statement + (07) exprtk_disable_enhanced_features + (08) exprtk_disable_string_capabilities + (09) exprtk_disable_superscalar_unroll + (10) exprtk_disable_rtl_io + (11) exprtk_disable_rtl_io_file + (12) exprtk_disable_rtl_vecops + (13) exprtk_disable_caseinsensitivity + (14) exprtk_enable_range_runtime_checks + +(01) exprtk_enable_debugging +This define will enable printing of debug information to stdout during +the compilation process. + +(02) exprtk_disable_cardinal_pow_optimisation +This define will disable the optimisation invoked when constant +integers are used as powers in exponentiation expressions (eg: x^7). + +(03) exprtk_disable_comments +This define will disable the ability for expressions to have comments. +Expressions that have comments when parsed with a build that has this +option, will result in a compilation failure. + +(04) exprtk_disable_break_continue +This define will disable the loop-wise 'break' and 'continue' +capabilities. Any expression that contains those keywords will result +in a compilation failure. + +(05) exprtk_disable_sc_andor +This define will disable the short-circuit '&' (and) and '|' (or) +operators + +(06) exprtk_disable_return_statement +This define will disable use of return statements within expressions. + +(07) exprtk_disable_enhanced_features +This define will disable all enhanced features such as strength +reduction and special function optimisations and expression specific +type instantiations. This feature will reduce compilation times and +binary sizes but will also result in massive performance degradation +of expression evaluations. + +(08) exprtk_disable_string_capabilities +This define will disable all string processing capabilities. Any +expression that contains a string or string related syntax will result +in a compilation failure. + +(09) exprtk_disable_superscalar_unroll +This define will set the loop unroll batch size to 4 operations per +loop instead of the default 8 operations. This define is used in +operations that involve vectors and aggregations over vectors. When +targeting non-superscalar architectures, it may be recommended to +build using this particular option if efficiency of evaluations is of +concern. + +(10) exprtk_disable_rtl_io +This define will disable all of basic IO RTL package features. When +present, any attempt to register the basic IO RTL package with a given +symbol table will fail causing a compilation error. + +(11) exprtk_disable_rtl_io_file +This define will disable the file I/O RTL package features. When +present, any attempts to register the file I/O package with a given +symbol table will fail causing a compilation error. + +(12) exprtk_disable_rtl_vecops +This define will disable the extended vector operations RTL package +features. When present, any attempts to register the vector operations +package with a given symbol table will fail causing a compilation +error. + +(13) exprtk_disable_caseinsensitivity +This define will disable case-insensitivity when matching variables +and functions. Furthermore all reserved and keywords will only be +acknowledged when in all lower-case. + +(14) exprtk_enable_range_runtime_checks +This define will enable run-time checks pertaining to vector indexing +operations used in any of the vector-to-vector and vector-to-scalar +operations. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 28 - FILES] +The source distribution of ExprTk is comprised of the following set of +files: + + (00) Makefile + (01) readme.txt + (02) exprtk.hpp + (03) exprtk_test.cpp + (04) exprtk_benchmark.cpp + (05) exprtk_simple_example_01.cpp + (06) exprtk_simple_example_02.cpp + (07) exprtk_simple_example_03.cpp + (08) exprtk_simple_example_04.cpp + (09) exprtk_simple_example_05.cpp + (10) exprtk_simple_example_06.cpp + (11) exprtk_simple_example_07.cpp + (12) exprtk_simple_example_08.cpp + (13) exprtk_simple_example_09.cpp + (14) exprtk_simple_example_10.cpp + (15) exprtk_simple_example_11.cpp + (16) exprtk_simple_example_12.cpp + (17) exprtk_simple_example_13.cpp + (18) exprtk_simple_example_14.cpp + (19) exprtk_simple_example_15.cpp + (20) exprtk_simple_example_16.cpp + (21) exprtk_simple_example_17.cpp + (22) exprtk_simple_example_18.cpp + (23) exprtk_simple_example_19.cpp + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[SECTION 29 - LANGUAGE STRUCTURE] +The following are the various language structures available within +ExprTk and their structural representations. + + (00) If Statement + (01) Else Statement + (02) Ternary Statement + (03) While Loop + (04) Repeat Until Loop + (05) For Loop + (06) Switch Statement + (07) Multi Subexpression Statement + (08) Multi Case-Consequent Statement + (09) Variable Definition Statement + (10) Vector Definition Statement + (11) String Definition Statement + (12) Range Statement + (13) Return Statement + + +(00) - If Statement ++-------------------------------------------------------------+ +| | +| [if] ---> [(] ---> [condition] -+-> [,] -+ | +| | | | +| +---------------<---------------+ | | +| | | | +| | +------------------<------------------+ | +| | | | +| | +--> [consequent] ---> [,] ---> [alternative] ---> [)] | +| | | +| +--> [)] --+-> [{] ---> [expression*] ---> [}] --+ | +| | | | +| | +---------<----------+ | +| +----<-----+ | | +| | v | +| +--> [consequent] --> [;] -{*}-> [else-statement] | +| | ++-------------------------------------------------------------+ + + +(01) - Else Statement ++-------------------------------------------------------------+ +| | +| [else] -+-> [alternative] ---> [;] | +| | | +| +--> [{] ---> [expression*] ---> [}] | +| | | +| +--> [if-statement] | +| | ++-------------------------------------------------------------+ + + +(02) - Ternary Statement ++-------------------------------------------------------------+ +| | +| [condition] ---> [?] ---> [consequent] ---> [:] --+ | +| | | +| +------------------------<------------------------+ | +| | | +| +--> [alternative] --> [;] | +| | ++-------------------------------------------------------------+ + + +(03) - While Loop ++-------------------------------------------------------------+ +| | +| [while] ---> [(] ---> [condition] ---> [)] ---+ | +| | | +| +----------------------<----------------------+ | +| | | +| +--> [{] ---> [expression*] ---> [}] | +| | ++-------------------------------------------------------------+ + + +(04) - Repeat Until Loop ++-------------------------------------------------------------+ +| | +| [repeat] ---> [expression*] ---+ | +| | | +| +--------------<---------------+ | +| | | +| +--> [until] ---> [(] ---> [condition] --->[)] | +| | ++-------------------------------------------------------------+ + + +(05) - For Loop ++-------------------------------------------------------------+ +| | +| [for] ---> [(] -+-> [initialise expression] --+--+ | +| | | | | +| +------------->---------------+ v | +| | | +| +-----------------------<------------------------+ | +| | | +| +--> [;] -+-> [condition] -+-> [;] ---+ | +| | | | | +| +------->--------+ v | +| | | +| +------------------<---------+--------+ | +| | | | +| +--> [increment expression] -+-> [)] --+ | +| | | +| +------------------<-------------------+ | +| | | +| +--> [{] ---> [expression*] ---> [}] | +| | ++-------------------------------------------------------------+ + + +(06) - Switch Statement ++-------------------------------------------------------------+ +| | +| [switch] ---> [{] ---+ | +| | | +| +---------<----------+-----------<-----------+ | +| | | | +| +--> [case] ---> [condition] ---> [:] ---+ | | +| | | | +| +-------------------<--------------------+ | | +| | | | +| +--> [consequent] ---> [;] --------->--------+ | +| | | | +| | | | +| +--> [default] ---> [consequent] ---> [;] ---+ | +| | | | +| +---------------------<----------------------+ | +| | | +| +--> [}] | +| | ++-------------------------------------------------------------+ + + +(07) - Multi Subexpression Statement ++-------------------------------------------------------------+ +| | +| +--------------<---------------+ | +| | | | +| [~] ---> [{\(] -+-> [expression] -+-> [;\,] ---+ | +| | | +| +----------------<----------------+ | +| | | +| +--> [}\)] | +| | ++-------------------------------------------------------------+ + + +(08) - Multi Case-Consequent Statement ++-------------------------------------------------------------+ +| | +| [[*]] ---> [{] ---+ | +| | | +| +--------<--------+--------------<----------+ | +| | | | +| +--> [case] ---> [condition] ---> [:] ---+ | | +| | | | +| +-------------------<--------------------+ | | +| | | | +| +--> [consequent] ---> [;] ---+------>------+ | +| | | +| +--> [}] | +| | ++-------------------------------------------------------------+ + + +(09) - Variable Definition Statement ++-------------------------------------------------------------+ +| | +| [var] ---> [symbol] -+-> [:=] -+-> [expression] -+-> [;] | +| | | | | +| | +-----> [{}] -->--+ | +| | | | +| +------------->-------------+ | +| | ++-------------------------------------------------------------+ + + +(10) - Vector Definition Statement ++-------------------------------------------------------------+ +| | +| [var] ---> [symbol] ---> [[] ---> [constant] ---> []] --+ | +| | | +| +---------------------------<---------------------------+ | +| | | +| | +--------->---------+ | +| | | | | +| +--> [:=] ---> [{] -+-+-> [expression] -+-> [}] ---> [;] | +| | | | +| +--<--- [,] <-----+ | +| | ++-------------------------------------------------------------+ + + +(11) - String Definition Statement ++-------------------------------------------------------------+ +| | +| [var] --> [symbol] --> [:=] --> [str-expression] ---> [;] | +| | ++-------------------------------------------------------------+ + + +(12) - Range Statement ++-------------------------------------------------------------+ +| | +| +-------->--------+ | +| | | | +| [[] -+-> [expression] -+-> [:] -+-> [expression] -+--> []] | +| | | | +| +-------->--------+ | +| | ++-------------------------------------------------------------+ + + +(13) - Return Statement ++-------------------------------------------------------------+ +| | +| [return] ---> [[] -+-> [expression] -+-> []] ---> [;] | +| | | | +| +--<--- [,] <-----+ | +| | ++-------------------------------------------------------------+ \ No newline at end of file