C++ Mathematical Expression Library (ExprTk)  https://www.partow.net/programming/exprtk/index.html
diff --git a/Makefile b/Makefile
index 9a2042e..4a1a20f 100644
--- a/Makefile
+++ b/Makefile
@@ -41,6 +41,7 @@
 BUILD_LIST+=exprtk_simple_example_15
 BUILD_LIST+=exprtk_simple_example_16
 BUILD_LIST+=exprtk_simple_example_17
+BUILD_LIST+=exprtk_simple_example_18
 
 
 all: $(BUILD_LIST)
diff --git a/exprtk.hpp b/exprtk.hpp
index 4cce6f4..ac65825 100644
--- a/exprtk.hpp
+++ b/exprtk.hpp
@@ -40,6 +40,7 @@
 #include <complex>
 #include <cstdio>
 #include <cstdlib>
+#include <cstring>
 #include <deque>
 #include <exception>
 #include <functional>
@@ -16487,6 +16488,12 @@
          return add_constant("inf",local_infinity);
       }
 
+      template <typename Package>
+      inline bool add_package(Package& package)
+      {
+         return package.register_package(*this);
+      }
+
       template <typename Allocator,
                 template <typename, typename> class Sequence>
       inline std::size_t get_variable_list(Sequence<std::pair<std::string,T>,Allocator>& vlist) const
@@ -32153,7 +32160,7 @@
 
             free_node(*node_allocator_,branch[1]);
 
-            return synthesize_str_xoxr_expression_impl<std::string&,const std::string>(opr,s0,s1,rp1);
+            return synthesize_str_xoxr_expression_impl<std::string&, const std::string>(opr,s0,s1,rp1);
          }
 
          inline expression_node_ptr synthesize_srosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2])
@@ -32179,7 +32186,7 @@
 
             details::free_node(*node_allocator_,branch[1]);
 
-            return synthesize_sos_expression_impl<std::string&,const std::string>(opr,s0,s1);
+            return synthesize_sos_expression_impl<std::string&, const std::string>(opr,s0,s1);
          }
 
          inline expression_node_ptr synthesize_csos_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2])
@@ -32217,7 +32224,7 @@
             details::free_node(*node_allocator_,branch[0]);
             details::free_node(*node_allocator_,branch[1]);
 
-            return synthesize_str_xrox_expression_impl<std::string&,const std::string>(opr,s0,s1,rp0);
+            return synthesize_str_xrox_expression_impl<std::string&, const std::string>(opr,s0,s1,rp0);
          }
 
          inline expression_node_ptr synthesize_srocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2])
@@ -32233,7 +32240,7 @@
             details::free_node(*node_allocator_,branch[0]);
             details::free_node(*node_allocator_,branch[1]);
 
-            return synthesize_str_xroxr_expression_impl<std::string&,const std::string>(opr,s0,s1,rp0,rp1);
+            return synthesize_str_xroxr_expression_impl<std::string&, const std::string>(opr,s0,s1,rp0,rp1);
          }
 
          inline expression_node_ptr synthesize_csocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2])
@@ -32253,7 +32260,7 @@
                result = node_allocator_->allocate_c<details::literal_node<Type> >(details::ilike_op<Type>::process(s0,s1));
             else
             {
-               expression_node_ptr temp = synthesize_sos_expression_impl<const std::string,const std::string>(opr,s0,s1);
+               expression_node_ptr temp = synthesize_sos_expression_impl<const std::string, const std::string>(opr,s0,s1);
                Type v = temp->value();
                details::free_node(*node_allocator_,temp);
                result = node_allocator_->allocate<literal_node_t>(v);
@@ -32275,7 +32282,7 @@
             free_node(*node_allocator_,branch[0]);
             free_node(*node_allocator_,branch[1]);
 
-            return synthesize_str_xoxr_expression_impl<const std::string,const std::string>(opr,s0,s1,rp1);
+            return synthesize_str_xoxr_expression_impl<const std::string, const std::string>(opr,s0,s1,rp1);
          }
 
          inline expression_node_ptr synthesize_csros_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2])
@@ -32332,7 +32339,7 @@
 
             details::free_all_nodes(*node_allocator_,branch);
 
-            return synthesize_str_xroxr_expression_impl<const std::string,const std::string>(opr,s0,s1,rp0,rp1);
+            return synthesize_str_xroxr_expression_impl<const std::string, const std::string>(opr,s0,s1,rp0,rp1);
          }
 
          inline expression_node_ptr synthesize_strogen_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2])
@@ -34525,107 +34532,114 @@
       return true;
    }
 
-   namespace helper
+   namespace rtl
    {
-      namespace details
+      namespace io
       {
-         template <typename T>
-         inline void print_type(const std::string& fmt,
-                                const T v,
-                                exprtk::details::numeric::details::real_type_tag)
+         namespace details
          {
-            printf(fmt.c_str(),v);
-         }
-
-         template <typename T>
-         struct print_impl
-         {
-            typedef typename igeneric_function<T>::generic_type generic_type;
-            typedef typename igeneric_function<T>::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;
-
-            static void process(const std::string& scalar_format, parameter_list_t parameters)
+            template <typename T>
+            inline void print_type(const std::string& fmt,
+                                   const T v,
+                                   exprtk::details::numeric::details::real_type_tag)
             {
-               for (std::size_t i = 0; i < parameters.size(); ++i)
+               printf(fmt.c_str(),v);
+            }
+
+            template <typename T>
+            struct print_impl
+            {
+               typedef typename igeneric_function<T>::generic_type generic_type;
+               typedef typename igeneric_function<T>::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;
+
+               static void process(const std::string& scalar_format, parameter_list_t parameters)
                {
-                  generic_type& gt = parameters[i];
-
-                  typename exprtk::details::numeric::details::number_type<T>::type num_type;
-
-                  switch (gt.type)
+                  for (std::size_t i = 0; i < parameters.size(); ++i)
                   {
-                     case generic_type::e_scalar : print_type(scalar_format,scalar_t(gt)(),num_type);
-                                                   break;
+                     generic_type& gt = parameters[i];
 
-                     case generic_type::e_vector : {
-                                                      vector_t vector(gt);
+                     typename exprtk::details::numeric::details::number_type<T>::type num_type;
 
-                                                      for (std::size_t x = 0; x < vector.size(); ++x)
-                                                      {
-                                                         print_type(scalar_format,vector[x],num_type);
+                     switch (gt.type)
+                     {
+                        case generic_type::e_scalar : print_type(scalar_format,scalar_t(gt)(),num_type);
+                                                      break;
 
-                                                         if ((x + 1) < vector.size())
-                                                            printf(" ");
+                        case generic_type::e_vector : {
+                                                         vector_t vector(gt);
+
+                                                         for (std::size_t x = 0; x < vector.size(); ++x)
+                                                         {
+                                                            print_type(scalar_format,vector[x],num_type);
+
+                                                            if ((x + 1) < vector.size())
+                                                               printf(" ");
+                                                         }
                                                       }
-                                                   }
-                                                   break;
+                                                      break;
 
-                     case generic_type::e_string : printf("%s",to_str(string_t(gt)).c_str());
-                                                   break;
+                        case generic_type::e_string : printf("%s",to_str(string_t(gt)).c_str());
+                                                      break;
 
-                     default                     : continue;
+                        default                     : continue;
+                     }
                   }
                }
+            };
+
+         } // namespace exprtk::rtl::io::details
+
+         template <typename T>
+         struct print : public exprtk::igeneric_function<T>
+         {
+            typedef typename igeneric_function<T>::parameter_list_t parameter_list_t;
+
+            using exprtk::igeneric_function<T>::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<T>::process(scalar_format_,parameters);
+               return T(0);
+            }
+
+            std::string scalar_format_;
          };
-      }
 
-      template <typename T>
-      struct print : public exprtk::igeneric_function<T>
-      {
-         typedef typename igeneric_function<T>::parameter_list_t parameter_list_t;
-
-         using exprtk::igeneric_function<T>::operator();
-
-         print(const std::string& scalar_format = "%10.5f")
-         : scalar_format_(scalar_format)
+         template <typename T>
+         struct println : public exprtk::igeneric_function<T>
          {
-            exprtk::enable_zero_parameters(*this);
-         }
+            typedef typename igeneric_function<T>::parameter_list_t parameter_list_t;
 
-         inline T operator()(parameter_list_t parameters)
-         {
-            details::print_impl<T>::process(scalar_format_,parameters);
-            return T(0);
-         }
+            using exprtk::igeneric_function<T>::operator();
 
-         std::string scalar_format_;
-      };
+            println(const std::string& scalar_format = "%10.5f")
+            : scalar_format_(scalar_format)
+            {
+               exprtk::enable_zero_parameters(*this);
+            }
 
-      template <typename T>
-      struct println : public exprtk::igeneric_function<T>
-      {
-         typedef typename igeneric_function<T>::parameter_list_t parameter_list_t;
+            inline T operator()(parameter_list_t parameters)
+            {
+               details::print_impl<T>::process(scalar_format_,parameters);
+               printf("\n");
+               return T(0);
+            }
 
-         using exprtk::igeneric_function<T>::operator();
+            std::string scalar_format_;
+         };
 
-         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<T>::process(scalar_format_,parameters);
-            printf("\n");
-            return T(0);
-         }
 
-         std::string scalar_format_;
-      };
+      }  // namespace exprtk::rtl::io
    }
 }
 
@@ -34740,6 +34754,496 @@
       #endif
    };
 
+} // namespace exprtk
+
+#ifndef exprtk_disable_rtl_io_file
+#include <fstream>
+namespace exprtk
+{
+   namespace rtl { namespace io { namespace file { namespace details
+   {
+      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 <typename Stream, typename Ptr>
+         void close(Ptr& p)
+         {
+            Stream* stream = reinterpret_cast<Stream*>(p);
+            stream->close();
+            delete stream;
+            p = reinterpret_cast<Ptr>(0);
+         }
+
+         bool close()
+         {
+            switch (mode)
+            {
+               case e_read  : close<std::ifstream>(stream_ptr);
+                              break;
+
+               case e_write : close<std::ofstream>(stream_ptr);
+                              break;
+
+               case e_rdwrt : close<std::fstream> (stream_ptr);
+                              break;
+
+               default      : return false;
+            }
+
+            return true;
+         }
+
+         template <typename View>
+         bool write(const View& view, const std::size_t amount, const std::size_t offset = 0)
+         {
+            switch (mode)
+            {
+               case e_write : reinterpret_cast<std::ofstream*>(stream_ptr)->
+                                 write(reinterpret_cast<const char*>(view.begin() + offset), amount * sizeof(View::value_t));
+                              break;
+
+               case e_rdwrt : reinterpret_cast<std::fstream*>(stream_ptr)->
+                                 write(reinterpret_cast<const char*>(view.begin() + offset) , amount * sizeof(View::value_t));
+                              break;
+
+               default      : return false;
+            }
+
+            return true;
+         }
+
+         template <typename View>
+         bool read(View& view, const std::size_t amount, const std::size_t offset = 0)
+         {
+            switch (mode)
+            {
+               case e_read  : reinterpret_cast<std::ifstream*>(stream_ptr)->
+                                 read(reinterpret_cast<char*>(view.begin() + offset), amount * sizeof(View::value_t));
+                              break;
+
+               case e_rdwrt : reinterpret_cast<std::fstream*>(stream_ptr)->
+                                 read(reinterpret_cast<char*>(view.begin() + offset) , amount * sizeof(View::value_t));
+                              break;
+
+               default      : return false;
+            }
+
+            return true;
+         }
+
+         bool getline(std::string& s)
+         {
+            switch (mode)
+            {
+               case e_read  : return (!!std::getline(*reinterpret_cast<std::ifstream*>(stream_ptr),s));
+               case e_rdwrt : return (!!std::getline(*reinterpret_cast<std::fstream* >(stream_ptr),s));
+               default      : return false;
+            }
+
+            return true;
+         }
+
+         bool eof()
+         {
+            switch (mode)
+            {
+               case e_read  : return reinterpret_cast<std::ifstream*>(stream_ptr)->eof();
+               case e_write : return reinterpret_cast<std::ofstream*>(stream_ptr)->eof();
+               case e_rdwrt : return reinterpret_cast<std::fstream* >(stream_ptr)->eof();
+               default      : return true;
+            }
+         }
+
+         file_mode get_file_mode(const std::string& access)
+         {
+            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;
+               }
+            }
+
+            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 <typename T>
+      file_descriptor* make_handle(T v)
+      {
+         file_descriptor* fd = reinterpret_cast<file_descriptor*>(0);
+
+         std::memcpy(reinterpret_cast<char*>(&fd),
+                     reinterpret_cast<const char*>(&v),
+                     sizeof(fd));
+         return fd;
+      }
+
+      template <typename T>
+      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 <typename T>
+   class open : public exprtk::igeneric_function<T>
+   {
+   public:
+
+      typedef typename exprtk::igeneric_function<T> 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<T>::operator();
+
+      open()
+      : exprtk::igeneric_function<T>("S|SS")
+      { details::perform_check<T>(); }
+
+      inline T operator()(const std::size_t& ps_index, parameter_list_t parameters)
+      {
+         std::string file_name;
+         std::string access;
+
+         file_name = to_str(string_t(parameters[0]));
+
+         if (file_name.empty())
+            return T(0);
+
+         if (0 == ps_index)
+            access = "r";
+         else if (0 == string_t(parameters[1]).size())
+            return T(0);
+         else
+            access = to_str(string_t(parameters[1]));
+
+         details::file_descriptor* fd = new details::file_descriptor(file_name,access);
+
+         if (fd->open())
+         {
+            T t = T(0);
+
+            std::memcpy(reinterpret_cast<char*>(&t),
+                        reinterpret_cast<char*>(&fd),
+                        sizeof(fd));
+            return t;
+         }
+         else
+         {
+            delete fd;
+            return T(0);
+         }
+      }
+   };
+
+   template <typename T>
+   struct close : public exprtk::ifunction<T>
+   {
+      using exprtk::ifunction<T>::operator();
+
+      close()
+      : exprtk::ifunction<T>(1)
+      { details::perform_check<T>(); }
+
+      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 <typename T>
+   class write : public exprtk::igeneric_function<T>
+   {
+   public:
+
+      typedef typename exprtk::igeneric_function<T> 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<T>::operator();
+
+      write()
+      : igfun_t("TS|TST|TV|TVT")
+      { details::perform_check<T>(); }
+
+      inline T operator()(const std::size_t& ps_index, parameter_list_t parameters)
+      {
+         details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])());
+
+         std::size_t amount = 0;
+
+         switch (ps_index)
+         {
+            case 0  : {
+                         string_t buffer(parameters[1]);
+                         amount = buffer.size();
+                         return T(fd->write(buffer,amount) ? 1 : 0);
+                      }
+
+            case 1  : {
+                         string_t buffer(parameters[1]);
+                         amount = std::min(buffer.size(),
+                                           static_cast<std::size_t>(scalar_t(parameters[2])()));
+                         return T(fd->write(buffer,amount) ? 1 : 0);
+                      }
+
+            case 2  : {
+                         vector_t vec(parameters[1]);
+                         amount = vec.size();
+                         return T(fd->write(vec,amount) ? 1 : 0);
+                      }
+
+            case 3  : {
+                         vector_t vec(parameters[1]);
+                         amount = std::min(vec.size(),
+                                           static_cast<std::size_t>(scalar_t(parameters[2])()));
+                         return T(fd->write(vec,amount) ? 1 : 0);
+                      }
+         }
+
+         return T(0);
+      }
+   };
+
+   template <typename T>
+   class read : public exprtk::igeneric_function<T>
+   {
+   public:
+
+      typedef typename exprtk::igeneric_function<T> 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<T>::operator();
+
+      read()
+      : igfun_t("TS|TST|TV|TVT")
+      { details::perform_check<T>(); }
+
+      inline T operator()(const std::size_t& ps_index, parameter_list_t parameters)
+      {
+         details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])());
+
+         std::size_t amount = 0;
+
+         switch (ps_index)
+         {
+            case 0  : {
+                         string_t buffer(parameters[1]);
+                         amount = buffer.size();
+                         return T(fd->read(buffer,amount) ? 1 : 0);
+                      }
+
+            case 1  : {
+                         string_t buffer(parameters[1]);
+                         amount = std::min(buffer.size(),
+                                           static_cast<std::size_t>(scalar_t(parameters[2])()));
+                         return T(fd->read(buffer,amount) ? 1 : 0);
+                      }
+
+            case 2  : {
+                         vector_t vec(parameters[1]);
+                         amount = vec.size();
+                         return T(fd->read(vec,amount) ? 1 : 0);
+                      }
+
+            case 3  : {
+                         vector_t vec(parameters[1]);
+                         amount = std::min(vec.size(),
+                                           static_cast<std::size_t>(scalar_t(parameters[2])()));
+                         return T(fd->read(vec,amount) ? 1 : 0);
+                      }
+         }
+
+         return T(0);
+      }
+   };
+
+   template <typename T>
+   class getline : public exprtk::igeneric_function<T>
+   {
+   public:
+
+      typedef typename exprtk::igeneric_function<T> 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<T>::operator();
+
+      getline()
+      : igfun_t("T",igfun_t::e_rtrn_string)
+      { details::perform_check<T>(); }
+
+      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 <typename T>
+   struct eof : public exprtk::ifunction<T>
+   {
+      using exprtk::ifunction<T>::operator();
+
+      eof()
+      : exprtk::ifunction<T>(1)
+      { details::perform_check<T>(); }
+
+      inline T operator()(const T& v)
+      {
+         details::file_descriptor* fd = details::make_handle(v);
+
+         return (fd->eof() ? T(1) : T(0));
+      }
+   };
+
+   template <typename T>
+   struct package
+   {
+      open   <T> o;
+      close  <T> c;
+      write  <T> w;
+      read   <T> r;
+      getline<T> g;
+      eof    <T> e;
+
+      bool register_package(exprtk::symbol_table<T>& symtab)
+      {
+              if (!symtab.add_function("open"   ,o))
+            return false;
+         else if (!symtab.add_function("close"  ,c))
+            return false;
+         else if (!symtab.add_function("write"  ,w))
+            return false;
+         else if (!symtab.add_function("read"   ,r))
+            return false;
+         else if (!symtab.add_function("getline",g))
+            return false;
+         else if (!symtab.add_function("eof"    ,e))
+            return false;
+         else
+            return true;
+      }
+   };
+
+   } // namespace exprtk::rtl::io::file
+   } // namespace exprtk::rtl::io
+   } // namespace exprtk::rtl
+}    // namespace exprtk
+#endif
+
+namespace exprtk
+{
    namespace information
    {
       static const char* library = "Mathematical Expression Toolkit";
diff --git a/exprtk_simple_example_04.cpp b/exprtk_simple_example_04.cpp
index 71432c6..72f1ddf 100644
--- a/exprtk_simple_example_04.cpp
+++ b/exprtk_simple_example_04.cpp
@@ -34,7 +34,7 @@
 
    compositor
       .add(
-      function_t(
+      function_t( // define function: fibonacci(x)
            "fibonacci",
            " var w := 0;             "
            " var y := 0;             "
diff --git a/exprtk_simple_example_09.cpp b/exprtk_simple_example_09.cpp
index 58f495f..ef59202 100644
--- a/exprtk_simple_example_09.cpp
+++ b/exprtk_simple_example_09.cpp
@@ -42,7 +42,7 @@
    //Mode 1 - if statement based
    compositor
       .add(
-      function_t(
+      function_t( // define function: is_prime_impl1(x,y)
            "is_prime_impl1",
            " if (y == 1,true,                "
            "    if (0 == (x % y),false,      "
@@ -51,7 +51,7 @@
 
    compositor
       .add(
-      function_t(
+      function_t( // define function: is_prime1(x)
            "is_prime1",
            " if (frac(x) != 0, false,                                "
            "    if (x <= 0, false,                                   "
@@ -61,7 +61,7 @@
    //Mode 2 - switch statement based
    compositor
       .add(
-      function_t(
+      function_t( // define function: is_prime_impl2(x,y)
            "is_prime_impl2",
            " switch                                         "
            " {                                              "
@@ -73,7 +73,7 @@
 
    compositor
       .add(
-      function_t(
+      function_t( // define function: is_prime2(x)
            "is_prime2",
            " switch                                                                 "
            " {                                                                      "
@@ -86,7 +86,7 @@
    //Mode 3 - switch statement and while-loop based
    compositor
       .add(
-      function_t(
+      function_t( // define function: is_prime_impl3(x,y)
            "is_prime_impl3",
            " while (y > 0)                            "
            " {                                        "
@@ -101,7 +101,7 @@
 
    compositor
       .add(
-      function_t(
+      function_t( // define function: is_prime3(x)
            "is_prime3",
            " switch                                                                 "
            " {                                                                      "
diff --git a/exprtk_simple_example_10.cpp b/exprtk_simple_example_10.cpp
index ee53994..48f2078 100644
--- a/exprtk_simple_example_10.cpp
+++ b/exprtk_simple_example_10.cpp
@@ -42,7 +42,7 @@
 
    compositor
       .add(
-      function_t(
+      function_t( // define function: newton_sqrt(x)
            "newton_sqrt",
            " switch                               "
            " {                                    "
diff --git a/readme.txt b/readme.txt
index 6d02b8c..f1017ab 100644
--- a/readme.txt
+++ b/readme.txt
@@ -627,7 +627,7 @@
 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.
+two. In both mentioned cases, the operations will occur element-wise.
 
 
 (3) String Type
@@ -745,6 +745,25 @@
    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)
+
+
+The 'vector' type must consist of a contiguous array of scalars  which
+can be one of the following:
+
+   1. std::vector<scalar_t>
+   2. scalar_t(&v)[N]
+   3. scalar_t* and array size
+   4. exprtk::vector_view<scalar_t>
+
+
 (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
@@ -1284,7 +1303,8 @@
 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.
+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
@@ -1308,9 +1328,9 @@
    }
 
 
-Note:  When  the  aggregate  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.
+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 };
 
@@ -1321,6 +1341,80 @@
    max(x / 2)  == (3 / 2)
    sum(x > 0 and x < 5) == x[]
 
+
+When utilizing 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<T> 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<T> v1 { T(2.2), T(2.2), ..... , T(2.2) };
+   std::vector<T> v2 { T(3.3), T(3.3), ..... , T(3.3) };
+   std::vector<T> v3 { T(4.4), T(4.4), ..... , T(4.4) };
+
+   std::vector<std::vector<T>> vv { v1, v2, v3 };
+   ...
+   T sum = T(0);
+
+   for (auto& w : vv)
+   {
+      v = w; // 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<T> vv = exprtk::make_vector_view(v, v.size());
+
+   symbol_table_t symbol_table;
+   symbol_table.add_vector("v",vv);
+
+   ...
+
+   T sum = T(0);
+
+   for (auto& w : vv)
+   {
+      vv.rebase(new_vec.data()); // update vector
+      sum += expression.value();
+   }
+
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 [15 - USER DEFINED FUNCTIONS]
@@ -2745,14 +2839,23 @@
         (x + y) / (x - y);
       }
 
- (30) For performance considerations,  one should assume  the actions
+ (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.
 
- (31) Before jumping in and using ExprTk, do take the time to  peruse
+ (32) 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
@@ -2879,6 +2982,7 @@
    (5) exprtk_disable_enhanced_features
    (6) exprtk_disable_string_capabilities
    (7) exprtk_disable_superscalar_unroll
+   (8) exprtk_disable_rtl_io_file
 
 
 (1) exprtk_enable_debugging
@@ -2919,6 +3023,11 @@
 build using this particular option if efficiency of evaluations is  of
 concern.
 
+(8) 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.
+
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 [23 - FILES]
@@ -2947,6 +3056,7 @@
    (19) exprtk_simple_example_15.cpp
    (20) exprtk_simple_example_16.cpp
    (21) exprtk_simple_example_17.cpp
+   (22) exprtk_simple_example_18.cpp
 
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~