C++ Mathematical Expression Library (ExprTk)  https://www.partow.net/programming/exprtk/index.html
diff --git a/exprtk.hpp b/exprtk.hpp
index 4ebf2a6..29ac3a6 100644
--- a/exprtk.hpp
+++ b/exprtk.hpp
@@ -4333,7 +4333,7 @@
          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_sf4ext60 = 2060, e_sf4ext61 = 2061
       };
 
       inline std::string to_str(const operator_type opr)
@@ -5422,6 +5422,7 @@
          virtual const range_t& range_ref() const = 0;
       };
 
+      #ifndef exprtk_disable_string_capabilities
       template <typename T>
       class string_base_node
       {
@@ -5505,6 +5506,7 @@
          const std::string value_;
          range_t rp_;
       };
+      #endif
 
       template <typename T>
       class unary_node : public expression_node<T>
@@ -5532,6 +5534,7 @@
          inline T value() const
          {
             const T arg = branch_->value();
+
             return numeric::process<T>(operation_,arg);
          }
 
@@ -5664,6 +5667,7 @@
          {
             const T arg0 = branch_[0].first->value();
             const T arg1 = branch_[1].first->value();
+
             return numeric::process<T>(operation_,arg0,arg1);
          }
 
@@ -6229,6 +6233,7 @@
          inline T value() const
          {
             T result = T(0);
+
             while (is_true(condition_))
             {
                try
@@ -6242,6 +6247,7 @@
                catch(const continue_exception&)
                {}
             }
+
             return result;
          }
 
@@ -7375,6 +7381,7 @@
          {
             rp_.n1_c.second  = (*value_).size() - 1;
             rp_.cache.second = rp_.n1_c.second;
+
             return std::numeric_limits<T>::quiet_NaN();
          }
 
@@ -8876,57 +8883,58 @@
       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(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
@@ -11174,6 +11182,7 @@
                   ts.data = vi->vds().data();
                   ts.type = type_store_t::e_vector;
                }
+               #ifndef exprtk_disable_string_capabilities
                else if (is_generally_string_node(arg_list_[i]))
                {
                   string_base_node<T>* sbn = reinterpret_cast<string_base_node<T>*>(0);
@@ -11209,6 +11218,7 @@
                   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);
@@ -11282,10 +11292,11 @@
                      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<char*>(rdt.str_node->base()) + rp.cache.first;
                      else
+                     #endif
                         ts.data = static_cast<char*>(rdt.data) + (rp.cache.first * rdt.type_size);
                   }
                   else
@@ -11307,6 +11318,7 @@
          mutable range_list_t range_list_;
       };
 
+      #ifndef exprtk_disable_string_capabilities
       template <typename T, typename StringFunction>
       class string_function_node : public generic_function_node<T,StringFunction>,
                                    public string_base_node<T>,
@@ -11390,6 +11402,7 @@
          mutable range_t     range_;
          mutable std::string ret_string_;
       };
+      #endif
 
       template <typename T, typename GenericFunction>
       class multimode_genfunction_node : public generic_function_node<T,GenericFunction>
@@ -11434,6 +11447,7 @@
          std::size_t param_seq_index_;
       };
 
+      #ifndef exprtk_disable_string_capabilities
       template <typename T, typename StringFunction>
       class multimode_strfunction_node : public string_function_node<T,StringFunction>
       {
@@ -11482,6 +11496,7 @@
 
          std::size_t param_seq_index_;
       };
+      #endif
 
       class return_exception
       {};
@@ -16286,13 +16301,19 @@
          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_variables      ();
+         clear_functions      ();
+         clear_strings        ();
+         clear_vectors        ();
+         clear_local_constants();
       }
 
       inline std::size_t variable_count() const
@@ -18711,11 +18732,13 @@
                case e_st_string         :
                case e_st_local_variable :
                case e_st_local_vector   :
-               case e_st_local_string   :
-               case e_st_function       :
-                  if (collect_variables_ || collect_functions_)
-                     symbol_name_list_.push_back(std::make_pair(symbol,st));
-                  break;
+               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;
             }
@@ -22776,6 +22799,7 @@
          return result;
       }
 
+      #ifndef exprtk_disable_string_capabilities
       inline expression_node_ptr parse_string_function_call(igeneric_function<T>* function, const std::string& function_name)
       {
          std::vector<expression_node_ptr> arg_list;
@@ -22856,6 +22880,7 @@
 
          return result;
       }
+      #endif
 
       template <typename Type, std::size_t NumberOfParameters>
       struct parse_special_function_impl
@@ -24235,6 +24260,7 @@
             }
          }
 
+         #ifndef exprtk_disable_string_capabilities
          {
             // Are we dealing with a vararg string returning function?
             igeneric_function<T>* string_function = symtab_store_.get_string_function(symbol);
@@ -24259,6 +24285,7 @@
                }
             }
          }
+         #endif
 
          // Are we dealing with a vector?
          if (symtab_store_.is_vector(symbol))
@@ -26373,6 +26400,7 @@
             }
          }
 
+         #ifndef exprtk_disable_string_capabilities
          inline expression_node_ptr string_function_call(igeneric_function_t* gf,
                                                          std::vector<expression_node_ptr>& arg_list,
                                                          const std::size_t& param_seq_index = std::numeric_limits<std::size_t>::max())
@@ -26425,6 +26453,7 @@
                return error_node();
             }
          }
+         #endif
 
          inline expression_node_ptr return_call(std::vector<expression_node_ptr>& arg_list)
          {
@@ -28078,6 +28107,7 @@
                return false;
 
             const std::string node_id = branch_to_id(branch);
+
             typename synthesize_map_t::iterator itr = synthesize_map_.find(node_id);
 
             if (synthesize_map_.end() != itr)
@@ -28278,7 +28308,7 @@
                   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(60) case_stmt1(61)
 
                   #undef case_stmt0
                   #undef case_stmt1
@@ -28357,6 +28387,7 @@
                typedef details::T0oT1oT2_base_node<Type>* sf3ext_base_ptr;
 
                sf3ext_base_ptr n = static_cast<sf3ext_base_ptr>(sf3node);
+
                std::string id = "(" + n->type_id() + ")" + expr_gen.to_str(operation) + "t";
 
                switch (n->type())
@@ -33404,7 +33435,7 @@
          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(60) register_sf4ext(61)
          #undef register_sf4ext
       }
 
@@ -33466,6 +33497,76 @@
       lexer::helper::sequence_validator   sequence_validator_;
    };
 
+   template <typename Allocator,
+             template <typename, typename> class Sequence>
+   inline bool collect_variables(const std::string& expr_str,
+                                 Sequence<std::string, Allocator>& symbol_list)
+   {
+      typedef double T;
+      typedef exprtk::symbol_table<T> symbol_table_t;
+      typedef exprtk::expression<T> expression_t;
+      typedef exprtk::parser<T> parser_t;
+      typedef parser_t::dependent_entity_collector::symbol_t symbol_t;
+
+      symbol_table_t symbol_table;
+      expression_t   expression;
+      parser_t       parser;
+
+      expression.register_symbol_table(symbol_table);
+
+      parser.enable_unknown_symbol_resolver();
+      parser.dec().collect_variables() = true;
+
+      if (!parser.compile(expr_str, expression))
+         return false;
+
+      std::deque<symbol_t> symb_list;
+
+      parser.dec().symbols(symb_list);
+
+      for (std::size_t i = 0; i < symb_list.size(); ++i)
+      {
+         symbol_list.push_back(symb_list[i].first);
+      }
+
+      return true;
+   }
+
+   template <typename Allocator,
+             template <typename, typename> class Sequence>
+   inline bool collect_functions(const std::string& expr_str,
+                                 Sequence<std::string, Allocator>& symbol_list)
+   {
+      typedef double T;
+      typedef exprtk::symbol_table<T> symbol_table_t;
+      typedef exprtk::expression<T> expression_t;
+      typedef exprtk::parser<T> parser_t;
+      typedef parser_t::dependent_entity_collector::symbol_t symbol_t;
+
+      symbol_table_t symbol_table;
+      expression_t   expression;
+      parser_t       parser;
+
+      expression.register_symbol_table(symbol_table);
+
+      parser.enable_unknown_symbol_resolver();
+      parser.dec().collect_functions() = true;
+
+      if (!parser.compile(expr_str, expression))
+         return false;
+
+      std::deque<symbol_t> symb_list;
+
+      parser.dec().symbols(symb_list);
+
+      for (std::size_t i = 0; i < symb_list.size(); ++i)
+      {
+         symbol_list.push_back(symb_list[i].first);
+      }
+
+      return true;
+   }
+
    template <typename T>
    inline T integrate(const expression<T>& e,
                       T& x,
@@ -33673,6 +33774,8 @@
       symbol_table.add_constants();
 
       expression<T> expression;
+      expression.register_symbol_table(symbol_table);
+
       parser<T> parser;
 
       if (parser.compile(expression_string,expression))
@@ -33695,9 +33798,11 @@
 
       symbol_table<T> symbol_table;
       symbol_table.add_constants();
-      symbol_table.add_variable(x_var,x);
+      symbol_table.add_constant(x_var,x);
 
       expression<T> expression;
+      expression.register_symbol_table(symbol_table);
+
       parser<T> parser;
 
       if (parser.compile(expression_string,expression))
@@ -33721,10 +33826,12 @@
 
       symbol_table<T> symbol_table;
       symbol_table.add_constants();
-      symbol_table.add_variable(x_var,x);
-      symbol_table.add_variable(y_var,y);
+      symbol_table.add_constant(x_var,x);
+      symbol_table.add_constant(y_var,y);
 
       expression<T> expression;
+      expression.register_symbol_table(symbol_table);
+
       parser<T> parser;
 
       if (parser.compile(expression_string,expression))
@@ -33749,11 +33856,13 @@
 
       symbol_table<T> symbol_table;
       symbol_table.add_constants();
-      symbol_table.add_variable(x_var,x);
-      symbol_table.add_variable(y_var,y);
-      symbol_table.add_variable(z_var,z);
+      symbol_table.add_constant(x_var,x);
+      symbol_table.add_constant(y_var,y);
+      symbol_table.add_constant(z_var,z);
 
       expression<T> expression;
+      expression.register_symbol_table(symbol_table);
+
       parser<T> parser;
 
       if (parser.compile(expression_string,expression))
@@ -34948,7 +35057,7 @@
             else_stmt(46) else_stmt(47) else_stmt(48) else_stmt(49)
             else_stmt(50) else_stmt(51) else_stmt(52) else_stmt(53)
             else_stmt(54) else_stmt(55) else_stmt(56) else_stmt(57)
-            else_stmt(58) else_stmt(59) else_stmt(60)
+            else_stmt(58) else_stmt(59) else_stmt(60) else_stmt(61)
          }
       }
 
@@ -36831,9 +36940,9 @@
    namespace information
    {
       static const char* library = "Mathematical Expression Toolkit";
-      static const char* version = "2.71828182845904523536028747135266249775"
-                                   "7247093699959574966967627724076630353547";
-      static const char* date    = "20161010";
+      static const char* version = "2.7182818284590452353602874713526624977572"
+                                   "470936999595749669676277240766303535475945";
+      static const char* date    = "20161212";
 
       static inline std::string data()
       {
diff --git a/exprtk_test.cpp b/exprtk_test.cpp
index def1d39..c44a7a0 100644
--- a/exprtk_test.cpp
+++ b/exprtk_test.cpp
@@ -4030,6 +4030,42 @@
    }
 
    {
+      T a = T(1);
+      T b = T(2);
+      T c = T(3);
+      T d = T(4);
+
+      std::string e = "a string";
+
+      exprtk::symbol_table<T> symbol_table0;
+      exprtk::symbol_table<T> symbol_table1;
+      expression_t expression;
+
+      for (std::size_t i = 0; i < 10000; ++i)
+      {
+         symbol_table0.clear();
+         symbol_table1.clear();
+
+         symbol_table0.add_variable ("a",a);
+         symbol_table0.add_variable ("b",b);
+         symbol_table0.add_variable ("c",c);
+         symbol_table0.add_variable ("d",d);
+         symbol_table0.add_stringvar("e",e);
+         symbol_table0.add_constants(     );
+
+         symbol_table1.add_variable ("a",a);
+         symbol_table1.add_variable ("b",b);
+         symbol_table1.add_variable ("c",c);
+         symbol_table1.add_variable ("d",d);
+         symbol_table1.add_stringvar("e",e);
+         symbol_table1.add_constants(     );
+
+         expression.register_symbol_table(symbol_table0);
+         expression.register_symbol_table(symbol_table1);
+      }
+   }
+
+   {
       std::string expression_list[] =
       {
         "var x; 1",
diff --git a/readme.txt b/readme.txt
index 0021bc4..c3ea903 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,11 +1,42 @@
-C++ Mathematical Expression Toolkit Library
+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 - Special Functions
+  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 - Exprtk Notes
+  Section 25 - Simple Exprtk Example
+  Section 26 - Build Options
+  Section 27 - Files
+  Section 28 - Language Structure
+
 
 [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 extendible.
+semantics and is easily extensible.
 
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -116,7 +147,7 @@
 ExprTk has been built error and warning free using the following set
 of C++ compilers:
 
-  (*) GNU Compiler Collection (3.3+)
+  (*) GNU Compiler Collection (3.5+)
   (*) Intel C++ Compiler (8.x+)
   (*) Clang/LLVM (1.1+)
   (*) PGI C++ (10.x+)
@@ -608,7 +639,7 @@
 
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-[09 - Fundamental Types]
+[09 - FUNDAMENTAL TYPES]
 ExprTk supports three fundamental types which can be used freely in
 expressions. The types are as follows:
 
@@ -719,7 +750,9 @@
 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.
+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<double> symbol_table_t;
    typedef exprtk::expression<double>     expression_t;
@@ -1144,7 +1177,7 @@
 
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-[13 - VARIABLE , VECTOR & STRING DEFINITION]
+[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
@@ -1964,7 +1997,7 @@
 
 
 Note: For  the igeneric_function  type, there  also needs  to be a 'Z'
-parameter sequence  defined inorder  for the  zero parameter  trait to
+parameter sequence  defined in order for the  zero parameter  trait to
 properly take effect otherwise a compilation error will occur.
 
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2115,7 +2148,410 @@
 
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-[17 - ENABLING AND DISABLING FEATURES]
+[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
+utilize many expressions  where each can  in turn utilize  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 to  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 distinct different. Which would mean if a
+particular expression were to be compiled twice, that each  expression
+would have it's own unique symbol_table which in turn would have  it's
+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<double> symbol_table_t;
+   typedef exprtk::expression<double>     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();
+
+     ....
+   }
+
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+[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  posses  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  utilized  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<T> symbol_table_t;
+   typedef exprtk::expression<T>     expression_t;
+   typedef exprtk::parser<T>             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<std::string> variable_list;
+
+   unknown_var_symbol_table.get_variable_list(variable_list);
+
+   for (auto& var_name : variable_list)
+   {
+      T& v = 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  expression 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 demonstrated a
+simple user defined USR:
+
+   typedef exprtk::symbol_table<T> symbol_table_t;
+   typedef exprtk::expression<T>     expression_t;
+   typedef exprtk::parser<T>             parser_t;
+
+   template <typename T>
+   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<T> 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. The 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.
+
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+[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:
@@ -2438,9 +2874,7 @@
        }
     };
 
-    .
-    .
-    .
+    ...
 
     typedef exprtk::symbol_table<T> symbol_table_t;
     typedef exprtk::expression<T>     expression_t;
@@ -2473,7 +2907,7 @@
 
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-[18 - EXPRESSION RETURN VALUES]
+[20 - EXPRESSION RETURN VALUES]
 ExprTk expressions can return immediately from any point by  utilizing
 the return call. Furthermore the  return call can be used  to transfer
 out multiple return values from within the expression.
@@ -2550,7 +2984,7 @@
 
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-[19 - COMPILATION ERRORS]
+[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
@@ -2670,7 +3104,7 @@
 
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-[20 - RUNTIME LIBRARY PACKAGES]
+[22 - RUNTIME LIBRARY PACKAGES]
 ExprTk   contains   a   set  of   simple   extensions,   that  provide
 functionalities  beyond  basic numerical  calculations.  Currently the
 available packages are:
@@ -2745,7 +3179,266 @@
 
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-[21 - EXPRTK NOTES]
+[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. An example use of the routine is as follows:
+
+   std::string expression = "x + abs(y / z)";
+
+   std::vector<std::string> variable_list;
+
+   exprtk::collect_variables(expression,variable_list);
+
+   for (auto var : variable_list)
+   {
+      ...
+   }
+
+
+(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. An example use of the routine is as follows:
+
+   std::string expression = "x + abs(y / cos(1 + z))";
+
+   std::deque<std::string> variable_list;
+
+   exprtk::collect_functions(expression,function_list);
+
+   for (auto func : function_list)
+   {
+      ...
+   }
+
+
+(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 variable called x and y
+   (3) Three variable called x, y and z
+
+
+An example use of each of the three overloads for the compute  routine
+is 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 defined range and  given
+step size. The numerical integration is based on the three point  form
+of the 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::parser<T>             parser_t;
+   typedef exprtk::expression<T>     expression_t;
+   typedef exprtk::symbol_table<T> symbol_table_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. A example usage of the function
+is as follows:
+
+   typedef exprtk::parser<T>             parser_t;
+   typedef exprtk::expression<T>     expression_t;
+   typedef exprtk::symbol_table<T> symbol_table_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 where value of x = 12.3 using a reference
+   // to x variable
+   x = T(12.3);
+   T derivative1 = exprtk::derivative(expression,x);
+
+   // Differentiate expression where value x = 45.6 using name
+   // of 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 function is as follows:
+
+   typedef exprtk::parser<T>             parser_t;
+   typedef exprtk::expression<T>     expression_t;
+   typedef exprtk::symbol_table<T> symbol_table_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 function is as follows:
+
+   typedef exprtk::parser<T>             parser_t;
+   typedef exprtk::expression<T>     expression_t;
+   typedef exprtk::symbol_table<T> symbol_table_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 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 x variable
+   x = T(45.6);
+   T derivative2 = exprtk::third_derivative(expression, "x");
+
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+[24 - EXPRTK NOTES]
 The following is a list of facts and suggestions one may want to take
 into account when using ExprTk:
 
@@ -2946,7 +3639,7 @@
 
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-[22 - SIMPLE EXPRTK EXAMPLE]
+[25 - 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
@@ -3051,7 +3744,7 @@
 
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-[23 - BUILD OPTIONS]
+[26 - 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
@@ -3118,7 +3811,7 @@
 
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-[24 - FILES]
+[27 - FILES]
 The source distribution of ExprTk is comprised of the following set of
 files:
 
@@ -3149,7 +3842,7 @@
 
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-[25 - LANGUAGE STRUCTURE]
+[28 - LANGUAGE STRUCTURE]
 +-------------------------------------------------------------+
 |00 - If Statement                                            |
 |                                                             |